Guest User

kopalka v0.5.1

a guest
Feb 22nd, 2016
619
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- FORKED FROM http://pastebin.com/gqZ1Qdqi
  2. -- http://computercraft.ru/topic/1031-geokopatel-ili-stan-millionerom/
  3. -- v0.5.1
  4.  
  5. local shell = require "shell"
  6. local sides = require("sides")
  7. local term = require("term")
  8. local r = require("robot")
  9. local comp = require("component")
  10. local event = require("event")
  11. local computer = require("computer")
  12. local inv = comp.inventory_controller
  13. local KOPALKA = {}
  14. local inv_size = r.inventorySize()
  15. local inv_side = sides.back
  16. local charge_side = sides.left
  17. local battery_side = sides.bottom
  18. local temp_state = {x=0, y=0, z=0, dr=3}
  19. local lc = {x=0, y=0, z=0, dr=3, xMax = 0, zMax = 0}
  20. local way = 0
  21. local ore_count = 0
  22. local warp = false
  23. local bedrockWidth = 5
  24. local back_to_the_future_mode = false
  25. local minHardness = 2.05
  26. local maxHardness = 40
  27. local directives = {
  28.   pause = false,
  29.   home = false,
  30.   report = false,
  31.   move = false    
  32. }
  33.  
  34. local scrap = {
  35.   "minecraft:stone",
  36.   "minecraft:cobblestone",
  37.   "minecraft:dirt",
  38.   "minecraft:gravel",
  39.   "minecraft:sand",
  40.   "minecraft:grass",
  41.   "minecraft:sandstone",
  42.   "minecraft:mossy_cobblestone",
  43.   "minecraft:stonebrick",
  44.   "minecraft:brown_mushroom",
  45.   "minecraft:red_mushroom",
  46.   "minecraft:netherrack"
  47. }
  48.  
  49. local fuel_list = {
  50.   "minecraft:fence",
  51.   "minecraft:planks",
  52.   "minecraft:log",
  53.   "minecraft:coal_block",
  54.   "minecraft:coal"
  55. }
  56.  
  57. local mining_tools_list = {
  58.   "minecraft:iron_pickaxe",
  59.   "minecraft:golden_pickaxe",
  60.   "appliedenergistics2:item.ToolCertusQuartzPickaxe",
  61.   "appliedenergistics2:item.ToolNetherQuartzPickaxe",
  62.   "IC2:itemToolBronzePickaxe",
  63.   "Forestry:bronzePickaxe",
  64.   "minecraft:diamond_pickaxe",
  65.   "IC2:itemToolDrill",
  66.   "IC2:itemToolDDrill",
  67.   "IC2:itemToolIridiumDrill",
  68.   "GraviSuite:advDDrill"
  69. }
  70.  
  71. local function sprintf(s, ...)
  72.   return s:format(...)
  73. end
  74.  
  75. function pause()
  76.   os.sleep(0)
  77. end
  78.  
  79. local function sendSt(message) -- ОТПРАВКА СТАТУСНОГО СООБЩЕНИЯ ЧЕРЕЗ ТУННЕЛЬ
  80.   print(message)
  81.   if warp == true then
  82.     pcall(comp.tunnel.send(message))
  83.   end
  84. end
  85.  
  86. function KOPALKA.duster(tmr)
  87.   while true do
  88.     for i=1,7 do
  89.       local temp = inv.getStackInSlot(3,i)
  90.       if temp then
  91.         if temp.name == "IC2:itemDustSmall" and math.floor(temp.size/9) > 0 then
  92.           for j=1,3 do
  93.             r.select(j)
  94.             inv.suckFromSlot(3,i,math.floor(temp.size/9))
  95.           end
  96.           for j=5,7 do
  97.             r.select(j)
  98.             inv.suckFromSlot(3,i,math.floor(temp.size/9))
  99.           end
  100.           for j=9,11 do
  101.             r.select(j)
  102.             inv.suckFromSlot(3,i,math.floor(temp.size/9))
  103.           end
  104.             r.select(4)
  105.             require("component").crafting.craft(math.floor(temp.size/9))
  106.             r.drop()
  107.         end
  108.       end
  109.     end
  110.     os.sleep(tmr)
  111.   end
  112. end
  113.  
  114. function KOPALKA.charge(charge_side)
  115.   while computer.energy() < (computer.maxEnergy()/2) do
  116.     term.clear()
  117.     KOPALKA.use(charge_side)
  118.     sendSt("Зарядка...")
  119.     os.sleep(60)
  120.     KOPALKA.use(charge_side)
  121.   end
  122.   sendSt("Батарея заряжена")
  123.   return true
  124. end
  125.  
  126. function KOPALKA.charge_tool(chargerSide, slot)
  127.   local side = 3
  128.   local tool = nil
  129.  
  130.   if chargerSide == 1 then
  131.     side=1
  132.   elseif chargerSide == 0 then
  133.     side=0
  134.   end
  135.  
  136.   if r.durability() == nil then
  137.     return false
  138.   end
  139.  
  140.   if r.durability() < 0.3 then
  141.     r.select(slot)
  142.     inv.equip()
  143.     tool = inv.getStackInInternalSlot(slot)
  144.     inv.equip()
  145.     if not(lc.x == 0 and lc.y == 0 and lc.z == 0) then
  146.       return true
  147.     end
  148.   else
  149.     return false
  150.   end
  151.  
  152.   local function isElectric(device)
  153.     if device.maxCharge ~= nil then
  154.       return true
  155.     else
  156.       return false
  157.     end
  158.   end
  159.  
  160.   local function find_new_tool()
  161.     KOPALKA.rot(inv_side)
  162.     local temp = KOPALKA.inv_scaner(mining_tools_list, false, start_slot)
  163.     sendSt("Поиск замены инструменту в сундуке.")
  164.     while temp ~= 0 do
  165.       local temp_device = inv.getStackInSlot(3, temp)
  166.       if isElectric(temp_device) then
  167.         if temp_device.charge/temp_device.maxCharge > 0.6 then
  168.           break
  169.         else
  170.           temp = KOPALKA.inv_scaner(mining_tools_list, false, temp+1)
  171.         end
  172.       else
  173.         if temp_device.damage/temp_device.maxDamage < 0.4 then
  174.           break
  175.         else
  176.           temp = KOPALKA.inv_scaner(mining_tools_list, false, temp+1)
  177.         end
  178.       end
  179.     end
  180.     return temp
  181.   end
  182.  
  183.   local function service(device)
  184.     if isElectric(device) then
  185.       KOPALKA.rot(chargerSide)  
  186.       if not inv.getInventorySize(3) ~= nil then
  187.         sendSt("Зарядник не найден. Установите зарядник.")
  188.         while not inv.getInventorySize(3) ~= nil do
  189.           os.sleep(5)
  190.         end
  191.       end
  192.       r.select(slot)
  193.       inv.equip()
  194.       inv.dropIntoSlot(3,1)
  195.       sendSt("Зарядка инструмента.")
  196.       while inv.getStackInSlot(3,1).charge < device.maxCharge do
  197.         os.sleep(10)
  198.       end
  199.       inv.suckFromSlot(3,1)
  200.       inv.equip()            
  201.     else
  202.       sendSt("Поиск инструмента в сундуке.")
  203.       KOPALKA.rot(inv_side)
  204.       while true do
  205.         local temp = find_new_tool()
  206.         if temp ~= 0 then
  207.           r.select(slot)
  208.           inv.equip()
  209.           if not r.drop() then
  210.             sendSt("Нет места в сундуке. Освободите место.")
  211.             while not r.drop() do
  212.               os.sleep(10)
  213.             end
  214.           end
  215.           inv.suckFromSlot(3, temp)
  216.           inv.equip()
  217.           r.select(1)
  218.           break
  219.         end
  220.       end
  221.     end
  222.   end
  223.  
  224.   if lc.x == 0 and lc.y == 0 and lc.z == 0 then
  225.     sendSt("Сервис инструмента.")
  226.     service(tool)
  227.   else
  228.     return false
  229.   end  
  230. end
  231.  
  232. function KOPALKA.use(s)
  233.   if s == 1 then
  234.     r.useUp()
  235.   elseif s == 2 then
  236.     r.turnAround()
  237.     r.use()
  238.     r.turnAround()
  239.   elseif s == 3 then
  240.     r.use()
  241.   elseif s == 4 then
  242.     r.turnRight()
  243.     r.use()
  244.     r.turnLeft()
  245.   elseif s==5 then
  246.     r.turnLeft()
  247.     r.use()
  248.     r.turnRight()
  249.   else
  250.     r.useDown()
  251.   end
  252. end
  253.  
  254. function KOPALKA.drop() --функция дропа всего инвентаря в сундук, если таковой стоит перед носом
  255.   while true do
  256.     if r.detect() then
  257.       if inv.getInventorySize(3) ~= nil then
  258.         for i=1,inv_size-1 do
  259.           if inv.getStackInInternalSlot(i) ~= nil then
  260.             r.select(i)
  261.             if not r.drop() then
  262.               sendSt("Сундук переполнен. Освободите место под складирование.")
  263.               while not r.drop() do
  264.                 os.sleep(5)
  265.               end
  266.             end
  267.           end
  268.         end
  269.         break
  270.       else
  271.         sendSt("Блок не является сундуком.")
  272.         os.sleep(5)
  273.       end
  274.     else
  275.       sendSt("Установите сундук!")
  276.       os.sleep(5)
  277.     end
  278.   end
  279. end
  280.  
  281. function KOPALKA.isScrap(name) -- ПРОВЕРКА ПРЕДМЕТА, ЯВЛЯЕТСЯ ЛИ ОН МУСОРОМ
  282.   for i, nm in pairs(scrap) do
  283.     if name == nm then  
  284.       return true
  285.     end
  286.   end
  287.   return false
  288. end
  289.  
  290. function KOPALKA.ore_analyze(arg) -- АНАЛИЗ БЛОКА, ЯВЛЯЕТСЯ ЛИ ОН МУСОРОМ
  291.   if arg ~= nil then
  292.     if comp.isAvailable("geolyzer") then
  293.       local lyz = comp.geolyzer
  294.       if KOPALKA.isScrap(lyz.analyze(arg).name) then
  295.         return false
  296.       else
  297.         return true
  298.       end
  299.     else
  300.       print("Геолайзер не обнаружен в системе.")
  301.       return false
  302.     end
  303.   else
  304.     print("Не указан аргумент(сторона проверки).")
  305.   end
  306. end
  307.  
  308. function KOPALKA.drop_scrap()
  309.   for i=1, inv_size do  
  310.     local slot = inv.getStackInInternalSlot(i)
  311.     if slot ~= nil then  
  312.       if KOPALKA.isScrap(slot.name) then
  313.         r.select(i)
  314.         r.dropDown()
  315.       end
  316.     end
  317.   end
  318.   return KOPALKA.inv_sorting()  
  319. end
  320.  
  321.  
  322. -----------------------------------ДВИЖЕНИЕ СКВОЗЬ ПОРОДУ [BEGIN]
  323. local function hiver(a_side) --ДОБЫЧА УЛЬЯ
  324.   if comp.geolyzer.analyze(a_side).name == "ExtraBees:hive" then
  325.     if pcall(r.select, KOPALKA.inv_scaner("Forestry:scoop", true)) then
  326.       inv.equip()
  327.       comp.robot.swing(a_side)
  328.       inv.equip()
  329.       r.select(1)
  330.     end
  331.   end
  332. end
  333.  
  334. function KOPALKA.mUp()
  335.   local try = 1
  336.   repeat
  337.     r.swingUp()
  338.     try = try + 1
  339.     if try >= 15 then
  340.       sendSt("Препятствие у точки: x="..lc.x.." z="..lc.z.." y="..lc.y.." Направление Dr=вверх"..lc.dr)
  341.       local _, det = r.detectUp()
  342.       sendSt(det.." сверху.")
  343.       sendSt(comp.geolyzer.analyze(1).name)
  344.       KOPALKA.mTo(lc.x+2,lc.y,lc.z)
  345.       if not back_to_the_future_mode then
  346.         os.exit(1)
  347.         --KOPALKA.back_to_the_future()
  348.         return false
  349.       else
  350.     try = 1
  351.       end
  352.     elseif try > 12 then
  353.       hiver(1)
  354.     end
  355.   until not r.detectUp()
  356.   while try < 15 and not r.up() do
  357.     r.swingUp()
  358.     try = try + 1
  359.   end
  360.   if try < 15 then
  361.     lc.y = lc.y + 1
  362.     way = way + 1
  363.     return true
  364.    end
  365. end
  366.  
  367. function KOPALKA.mDown(action, arg)
  368.   local try = 1
  369.   if action ~= nil then
  370.     action(arg)
  371.   end
  372.   repeat
  373.     r.swingDown()
  374.     try = try + 1
  375.     if try >= 15 then
  376.       sendSt("Препятствие у точки: x="..lc.x.." z="..lc.z.." y="..lc.y.." Направление Dr= вниз"..lc.dr)
  377.       local _, det = r.detectDown()
  378.       sendSt(det.." снизу.")
  379.       sendSt(comp.geolyzer.analyze(0).name)
  380.       if not back_to_the_future_mode then
  381.         os.exit(1)
  382.         --KOPALKA.back_to_the_future()
  383.         return false
  384.       else
  385.     try = 1
  386.       end
  387.     elseif try > 12 then
  388.       hiver(0)
  389.     end
  390.   until not r.detectDown()
  391.   while try < 15 and not r.down() do
  392.     r.swingDown()
  393.     try = try + 1
  394.   end
  395.   if try < 15 then
  396.     lc.y = lc.y - 1
  397.     way = way + 1
  398.     return true
  399.   end
  400. end
  401.  
  402. function KOPALKA.mForw(action, arg)
  403.   local try = 1
  404.   if action ~= nil then
  405.     action(arg)
  406.   end
  407.   repeat
  408.     r.swing()
  409.     try = try + 1
  410.     if try >= 15 then
  411.       sendSt("Препятствие у точки: x="..lc.x.." z="..lc.z.." y="..lc.y.." Направление Dr="..lc.dr)
  412.       local _, det = r.detect()
  413.       sendSt(det.." спереди.")
  414.       sendSt(comp.geolyzer.analyze(3).name)
  415.       if not back_to_the_future_mode then
  416.         os.exit(1)
  417.         --KOPALKA.back_to_the_future()
  418.         return false
  419.       else
  420.     try = 1
  421.       end
  422.     elseif try > 12 then
  423.       hiver(3)
  424.     end
  425.   until not r.detect()
  426.   while try < 15 and not r.forward() do
  427.     r.swing()
  428.     try = try + 1
  429.   end
  430.   if try < 15 then
  431.     way = way + 1
  432.     if lc.dr==2 then
  433.       lc.x = lc.x - 1
  434.     elseif lc.dr==3 then
  435.       lc.x = lc.x + 1
  436.     elseif lc.dr==4 then
  437.       lc.z = lc.z + 1
  438.     elseif lc.dr==5 then
  439.       lc.z = lc.z - 1
  440.     end
  441.     return true
  442.   end
  443. end
  444. -----------------------------------ДВИЖЕНИЕ СКВОЗЬ ПОРОДУ [END]
  445.  
  446.  
  447. -----------------------------------ВРАЩЕНИЕ К ПРОГРАММНОЙ НАВИГАЦИИ [BEGIN]
  448. function KOPALKA.turnLeft()
  449.   r.turnLeft()
  450.   if lc.dr == 3 then
  451.     lc.dr = 5
  452.   elseif lc.dr == 4 then
  453.     lc.dr = 3
  454.   elseif lc.dr == 2 then
  455.     lc.dr = 4
  456.   elseif lc.dr == 5 then
  457.     lc.dr = 2
  458.   end
  459. end
  460.  
  461. function KOPALKA.turnRight()
  462.   r.turnRight()
  463.   if lc.dr == 3 then
  464.     lc.dr = 4
  465.   elseif lc.dr == 4 then
  466.     lc.dr = 2
  467.   elseif lc.dr == 2 then
  468.     lc.dr = 5
  469.   elseif lc.dr == 5 then
  470.     lc.dr = 3
  471.   end
  472. end
  473.  
  474. function KOPALKA.turnAround()
  475.   r.turnAround()
  476.   if lc.dr == 3 then
  477.     lc.dr = 2
  478.   elseif lc.dr == 4 then
  479.     lc.dr = 5
  480.   elseif lc.dr == 2 then
  481.     lc.dr = 3
  482.   elseif lc.dr == 5 then
  483.     lc.dr = 4
  484.   end
  485. end
  486.  
  487. function KOPALKA.rot(side) -- ВРАЩЕНИЕ С ЗАПОМИНАНИЕМ НАПРАВЛЕНИЯ
  488.   if (side ~= 1) and (side ~= 0) and lc.dr-side ~=0 then
  489.     if lc.dr == 3 then
  490.       if side == 4 then
  491.         KOPALKA.turnRight()
  492.       elseif side == 2 then
  493.         KOPALKA.turnAround()
  494.       elseif side == 5 then
  495.         KOPALKA.turnLeft()
  496.       end
  497.     elseif lc.dr == 4 then
  498.       if side == 2 then
  499.         KOPALKA.turnRight()
  500.       elseif side == 5 then
  501.         KOPALKA.turnAround()
  502.       elseif side == 3 then
  503.         KOPALKA.turnLeft()
  504.       end
  505.     elseif lc.dr == 2 then
  506.       if side == 5 then
  507.         KOPALKA.turnRight()
  508.       elseif side == 3 then
  509.         KOPALKA.turnAround()
  510.       elseif side == 4 then
  511.         KOPALKA.turnLeft()
  512.       end
  513.     else
  514.       if side == 3 then
  515.         KOPALKA.turnRight()
  516.       elseif side == 4 then
  517.         KOPALKA.turnAround()
  518.       elseif side == 2 then
  519.         KOPALKA.turnLeft()
  520.       end
  521.     end
  522.   end
  523. end
  524. -----------------------------------ВРАЩЕНИЕ К ПРОГРАММНОЙ НАВИГАЦИИ [END]
  525.  
  526.  
  527. -----------------------------------ДВИЖЕНИЕ С ПРОГРАММНОЙ НАВИГАЦИЕЙ [BEGIN]
  528. function KOPALKA.mTo(x, y, z, action, arg)
  529.   if directives.pause then
  530.     KOPALKA.execDirective()
  531.   end
  532.   if lc.x > x then
  533.     KOPALKA.rot(sides.back)
  534.     while lc.x > x do
  535.       KOPALKA.mForw(action,arg)
  536.     end
  537.   end
  538.   if lc.x < x then
  539.     KOPALKA.rot(sides.forward)
  540.     while lc.x < x do
  541.       KOPALKA.mForw(action,arg)
  542.     end
  543.   end
  544.   if lc.z > z then
  545.     KOPALKA.rot(sides.left)
  546.     while lc.z > z do
  547.       KOPALKA.mForw(action,arg)
  548.     end  
  549.   end
  550.   if lc.z < z then
  551.     KOPALKA.rot(sides.right)
  552.     while lc.z < z do
  553.       KOPALKA.mForw(action,arg)
  554.     end
  555.   end
  556.   while lc.y > y do
  557.     KOPALKA.mDown(action,arg)
  558.   end
  559.   while lc.y < y do
  560.     KOPALKA.mUp(action,arg)
  561.   end
  562. end
  563.  
  564. function KOPALKA.home(action, arg)
  565.   temp_state.x = lc.x
  566.   temp_state.y = lc.y
  567.   temp_state.z = lc.z
  568.   temp_state.dr = lc.dr
  569.   KOPALKA.mTo(0, 0, 0, action, arg)
  570.   KOPALKA.rot(2)
  571.   KOPALKA.drop_scrap()
  572.   KOPALKA.drop()
  573.   --KOPALKA.rot(3)
  574. end
  575.  
  576. function KOPALKA.back_to_mine(action, arg)
  577.   KOPALKA.mTo(0, temp_state.y, 0, action, arg)
  578.   KOPALKA.mTo(temp_state.x, temp_state.y, temp_state.z, action, arg)
  579.   KOPALKA.rot(temp_state.dr)
  580.   temp_state.x = 0
  581.   temp_state.y = 0
  582.   temp_state.z = 0
  583.   temp_state.dr = 3
  584. end
  585.  
  586. -----------------------------------ДВИЖЕНИЕ С ПРОГРАММНОЙ НАВИГАЦИЕЙ [END]
  587.  
  588.  
  589. function KOPALKA.check_inv()
  590.   return r.inventorySize()
  591. end
  592.  
  593. function KOPALKA.inv_sorting()
  594.   local items_stored = 0
  595.  
  596.   for i=1, inv_size-1 do
  597.     if r.count(i) == 0 then
  598.       for j=inv_size-1, 1, -1 do
  599.         if r.count(j) > 0 then
  600.           if j<i then
  601.             break
  602.           end
  603.           r.select(j)
  604.           r.transferTo(i)
  605.           break
  606.         end
  607.       end
  608.     end
  609.   end
  610.   for i=1,inv_size do
  611.     if r.count(i) > 0 then
  612.       items_stored = items_stored + 1
  613.     end
  614.   end
  615.   r.select(1)
  616.   return items_stored/inv_size
  617. end
  618.  
  619. function KOPALKA.check_state()
  620.   sendSt(sprintf("keep-alive %d", computer.uptime()))
  621.   local need_fuel = computer.energy() < (computer.maxEnergy()*0.90)
  622.  
  623.   local function inventory()
  624.     local need_to_home = false
  625.     if (r.count(inv_size-2) > 0) then  
  626.       if KOPALKA.drop_scrap() > 0.9 then
  627.         need_to_home = true
  628.       else
  629.         need_to_home = false
  630.       end
  631.     end
  632.     return need_to_home
  633.   end
  634.  
  635.   local function fuel(internal)
  636.     local need_to_home = false
  637.     if need_fuel and comp.isAvailable("generator") and comp.generator.count() == 0 then
  638.       local slt = KOPALKA.inv_scaner(fuel_list, internal)
  639.       if slt ~= 0 and not internal then
  640.         r.select(inv_size-2)
  641.         inv.suckFromSlot(3, slt)
  642.         comp.generator.insert()
  643.         r.select(1)
  644.         need_to_home = false
  645.       else
  646.         slt = KOPALKA.inv_scaner(fuel_list, internal)
  647.         if slt ~= 0 and internal then  
  648.           r.select(slt)
  649.           comp.generator.insert()
  650.           r.select(1)
  651.           need_to_home = false
  652.         else
  653.           need_to_home = true
  654.         end
  655.       end
  656.     elseif not comp.isAvailable("generator") and need_fuel then
  657.       need_to_home = true
  658.     end
  659.     return need_to_home
  660.   end
  661.  
  662.   if inventory() or fuel(true) or KOPALKA.charge_tool(charge_side, inv_size-2) then
  663.     KOPALKA.home()
  664.     os.sleep(15)
  665.     KOPALKA.charge_tool(charge_side, inv_size-2)  
  666.     fuel(false)
  667.     KOPALKA.back_to_mine()
  668.   end    
  669. end
  670.  
  671. function KOPALKA.inv_scaner(filter, internal, start_slot) --автопоисковик заданного итема в своем инвентаре по системному имени. возвращает номер ячейки итема, первого найденного от начала ивентаря.
  672.   ins = inv.getInventorySize(3)
  673.   if start_slot == nil then
  674.     start_slot = 1
  675.   end
  676.   if filter == "empty" then
  677.     if internal then
  678.       for i=start_slot, inv_size do
  679.         if inv.getStackInInternalSlot(i) == nil then
  680.           return i
  681.         end
  682.       end
  683.     else
  684.       for i=start_slot, inv.getInventorySize(3) do
  685.         if inv.getStackInSlot(3, i) == nil then
  686.           return i
  687.         end
  688.       end
  689.     end
  690.   end  
  691.   if internal then
  692.     for i=start_slot, inv_size do
  693.       if inv.getStackInInternalSlot(i) ~= nil then
  694.         if pcall(pairs, filter) then
  695.           for j, name in pairs(filter) do
  696.             if inv.getStackInInternalSlot(i).name == name then
  697.               return i
  698.             end
  699.           end
  700.         else
  701.           if inv.getStackInInternalSlot(i).name == filter then
  702.             return i
  703.           end
  704.         end
  705.       end
  706.     end
  707.     return 0  
  708.   else
  709.     if ins ~= nil  then
  710.       for i=start_slot, ins do
  711.         if inv.getStackInSlot(3, i) ~= nil then
  712.           if pcall(pairs, filter) then
  713.             for j, name in pairs(filter) do
  714.               if inv.getStackInSlot(3, i).name == name then
  715.                 return i
  716.               end
  717.             end
  718.           else
  719.             if inv.getStackInSlot(3, i).name == filter then
  720.               return i
  721.             end
  722.           end
  723.         end
  724.       end
  725.       return 0
  726.     else
  727.       return 0
  728.     end
  729.   end
  730. end
  731.  
  732. function KOPALKA.distance(blockA, blockB)
  733.   local dist = math.sqrt(math.pow(blockA.x - blockB.x,2) +
  734.   math.pow(blockA.z - blockB.z,2) + math.pow(blockA.y - blockB.y,2))
  735.   return dist
  736. end
  737.  
  738. function KOPALKA.closest_point(point, points)
  739.   local cl_num = 1
  740.   local length = KOPALKA.distance(point, points[1])
  741.   for i=1, #points do
  742.     local l = KOPALKA.distance(point, points[i])
  743.     if l < length then
  744.       cl_num = i
  745.       length = l
  746.     end
  747.   end
  748.   return cl_num
  749. end
  750.  
  751. function KOPALKA.waypoints(ores_table, last)
  752.   local yeildGuard = 0
  753.   local way_table = {}
  754.   local count = #ores_table
  755.   table.insert(way_table, {x=lc.x, z=lc.z, y=lc.y})
  756.   while count ~= #way_table - 1 do
  757.     yeildGuard = yeildGuard + 1
  758.     if yeildGuard == 100 then
  759.       yeildGuard = 0
  760.       pause()
  761.     end
  762.     local j = KOPALKA.closest_point(way_table[#way_table], ores_table)
  763.     table.insert(way_table, ores_table[j])
  764.     table.remove(ores_table, j)
  765.   end
  766.   return way_table, last
  767. end
  768.  
  769. function KOPALKA.scanVolume(xn, zn, bedrock, side, hight_border) --сканирование карьерного "этажа" заданного радиуса -10 блоков вниз+сканер+10 блоков вверх; bedrock - верхний уровень бедрока
  770.   local geo = comp.geolyzer
  771.   local ores_table = {}
  772.   local last = false
  773.   local x_limit = 0
  774.   local z_limit = 0
  775.   local x_increment = 1
  776.   local z_increment = 1
  777.   if side == "north" or side == "север" then
  778.     x_limit = zn
  779.     x_increment = 1
  780.     z_limit = -xn
  781.     z_increment = -1
  782.   elseif side == "west" or side == "запад" then
  783.     x_limit = -xn
  784.     x_increment = -1
  785.     z_limit = -zn
  786.     z_increment = -1
  787.   elseif side == "south" or side == "юг" then
  788.     x_limit = -zn
  789.     x_increment = -1
  790.     z_limit = xn
  791.     z_increment = 1
  792.    elseif side == "east" or side == "восток" or side == nil then
  793.      x_limit = xn
  794.      x_increment = 1
  795.     z_limit = zn
  796.     z_increment = 1
  797.   end
  798.  
  799.   for xt=0,x_limit,x_increment do
  800.     for zt=0,z_limit,z_increment do
  801.       local scan = geo.scan(xt,zt,true)
  802.       for yt=hight_border+33, 33+math.abs(hight_border) do
  803.         if scan[yt] > minHardness and scan[yt] < maxHardness and ((yt-33)+lc.y) > bedrock then
  804.           if side == "north" or side == "север" then
  805.             table.insert(ores_table, {x=math.abs(zt)+lc.x, z=math.abs(xt)+lc.z, y=(yt-33)+lc.y})
  806.           elseif side == "west" or side == "запад" then
  807.             table.insert(ores_table, {x=math.abs(xt)+lc.x, z=math.abs(zt)+lc.z, y=(yt-33)+lc.y})
  808.           elseif side == "south" or side == "юг" then
  809.             table.insert(ores_table, {x=math.abs(zt)+lc.x, z=math.abs(xt)+lc.z, y=(yt-33)+lc.y})
  810.           elseif side == "east" or side == "восток" or side == nil then
  811.             table.insert(ores_table, {x=math.abs(xt)+lc.x, z=math.abs(zt)+lc.z, y=(yt-33)+lc.y})
  812.           end    
  813.         end
  814.       end
  815.     end
  816.   end
  817.   return ores_table
  818. end
  819.  
  820. function KOPALKA.whatsSide()
  821.   local geo = comp.geolyzer
  822.   local function isBlock(dens)
  823.     if dens ~= nil and dens ~= 0 then
  824.       return 1
  825.     elseif dens == 0 then
  826.       return 0
  827.     end
  828.   end
  829.  
  830.   local function check(fig, front)
  831.     local figure1 = {
  832.       east = isBlock(geo.scan(1,0)[33]),
  833.       south = isBlock(geo.scan(0,1)[33]),
  834.       west = isBlock(geo.scan(-1,0)[33]),  
  835.       north = isBlock(geo.scan(0,-1)[33])
  836.     }  
  837.     if front then
  838.       if fig.east > figure1.east  then
  839.         return "east"
  840.       elseif fig.south > figure1.south then
  841.         return "south"
  842.       elseif fig.west > figure1.west then
  843.         return "west"
  844.       elseif fig.north > figure1.north then
  845.         return "north"
  846.       end
  847.     elseif not front then
  848.       if fig.east < figure1.east  then
  849.         return "east"
  850.       elseif fig.south < figure1.south then
  851.         return "south"
  852.       elseif fig.west < figure1.west then
  853.         return "west"
  854.       elseif fig.north < figure1.north then
  855.         return "north"
  856.       end  
  857.     end
  858.   end
  859.   local figure = {
  860.     east = isBlock(geo.scan(1,0)[33]),
  861.     south = isBlock(geo.scan(0,1)[33]),
  862.     west = isBlock(geo.scan(-1,0)[33]),  
  863.     north = isBlock(geo.scan(0,-1)[33])
  864.   }
  865.   KOPALKA.rot(3)
  866.   while true do
  867.     if r.detect() then
  868.       r.swing()
  869.       local direction = check(figure, true)
  870.       r.place()
  871.       return direction
  872.     elseif r.detectDown() then
  873.       r.swingDown()
  874.       r.place()
  875.       local direction = check(figure, false)
  876.       r.swing()
  877.       r.placeDown()
  878.       return direction
  879.     end
  880.     sendSt("Для ориентирования в пространстве недостаточно данных.")
  881.     sendSt("Пожалуйста установите любой блок перед или под роботом и повторите попытку")
  882.     os.exit(1)
  883.   end
  884. end
  885.  
  886. function KOPALKA.findoutBedrockLevel() -- нижний уровень бедрока
  887.   local bedrock = -1
  888.   local start_level = lc.y
  889.   local geo = comp.geolyzer
  890.   local function scan()
  891.     local tempr=geo.scan(0,0)
  892.     for i = 10, 1, -1 do
  893.       if tempr[33 - i] < -0.3 then
  894.         return lc.y - i, true
  895.       end
  896.     end
  897.     return 0, false
  898.   end
  899.   for i = lc.y, -256, -10 do
  900.     local bed, catch = scan()
  901.     if not catch then
  902.       KOPALKA.mTo(lc.x, i, lc.z)
  903.     else
  904.       bedrock = bed
  905.       break
  906.     end
  907.   end
  908.   KOPALKA.mTo(lc.x, start_level, lc.z)
  909.   return bedrock
  910. end
  911.  
  912. function KOPALKA.clusterDigger(start_point, x, z, bedrock, side)
  913.   sendSt(sprintf("cluster: %d %d %d (%d %d %d) %s", start_point.x, start_point.y, start_point.z, x, bedrock, z, side))
  914.   sendSt("Сканирование заданного объема, может занять несколько минут...")
  915.   if side == nil then
  916.     side = KOPALKA.whatsSide()
  917.   end
  918.   if start_point == nil then
  919.     start_point = lc
  920.   end
  921.   KOPALKA.mTo(start_point.x, start_point.y, start_point.z)
  922.   for Y=lc.y, bedrock+bedrockWidth+1, -1 do
  923.     if Y%21 == 0 or Y == bedrock + 9 then
  924.       KOPALKA.mTo(start_point.x, Y, start_point.z)
  925.       KOPALKA.rot(3)
  926.       arr=KOPALKA.waypoints(KOPALKA.scanVolume(x-1,z-1, bedrock+bedrockWidth-1, side, -11))
  927.       ore_count = ore_count + (#arr-1)
  928.       for i=1, #arr do
  929.         KOPALKA.mTo(arr[i].x, arr[i].y, arr[i].z)
  930.         if i%10 == 0 then
  931.           KOPALKA.check_state()
  932.         end
  933.         if way%30 == 0 then
  934.           KOPALKA.check_state()
  935.         end
  936.       end
  937.     end
  938.   end
  939. end
  940.  
  941. function KOPALKA.geoMiner(x, z, bedrock, side, x_lim, z_lim)
  942.   if bedrock == nil then
  943.     sendSt("Проверка уровня бедрока. Вертикальная шахта до дна и обратно.")
  944.     bedrock = KOPALKA.findoutBedrockLevel()
  945.   end
  946.   sendSt(sprintf("bedrock= %d\n", bedrock))
  947.   local start_point = {x=0, y=0, z=0}
  948.   local x_limit = x_lim
  949.   local z_limit = z_lim
  950.   if x_lim == nil then
  951.     x_limit = 32
  952.   end
  953.   if z_lim == nil then
  954.     z_limit = 32
  955.   end
  956.   if side == nil then
  957.     side = KOPALKA.whatsSide()
  958.   end
  959.  
  960.   local function z_glide()
  961.     if z/z_limit < 1 then
  962.       KOPALKA.clusterDigger(start_point, x_limit, z, bedrock, side)
  963.     else
  964.       for j=1, math.floor(z/z_limit) do
  965.         KOPALKA.clusterDigger(start_point, x_limit, z_limit, bedrock, side)
  966.         start_point.z = j*z_limit+1
  967.       end
  968.       if z%z_limit > 0 then
  969.         KOPALKA.clusterDigger(start_point, x_limit, z%z_limit, bedrock, side)
  970.       end
  971.       start_point.z = 0
  972.     end
  973.   end
  974.  
  975.   if x/x_limit < 1 then
  976.     local temp = x_limit
  977.     x_limit = x
  978.     z_glide()
  979.     x_limit = temp
  980.   else
  981.     for i=1, math.floor(x/x_limit) do
  982.       z_glide()
  983.       start_point.x = i*x_limit+1
  984.     end
  985.     if x%x_limit > 0 then
  986.       x_limit = x%x_limit
  987.       z_glide()
  988.     end
  989.   end
  990.   KOPALKA.home()
  991.   KOPALKA.rot(3)
  992.   sendSt("Итого руды добыто: "..ore_count)
  993.   sendSt("Всего блоков пройдено: "..way)
  994.   sendSt('Робот '..r.name()..' завершил работу.')
  995. end
  996.  
  997. function KOPALKA.check_components()
  998.   local function stop()
  999.     print('> ')
  1000.     if tonumber(io.read()) ~= 1 then
  1001.       os.exit()
  1002.     end
  1003.   end
  1004.   if comp.isAvailable("tunnel") then
  1005.     warp = true
  1006.     print("\t Связанная карта....доступна.")
  1007.   else
  1008.     print("\t Связанная карта не обнаружена. Начать работу? (0/1)")
  1009.     stop()
  1010.   end
  1011.   if comp.isAvailable("chunkloader") then
  1012.     comp.chunkloader.setActive(true)
  1013.     print("\t Чанклоадер....доступен.")
  1014.   else
  1015.     print("\t Чанклоадер не обнаружен, возможны проблемы и ошибки. Начать работу без чанклоадера? (0/1)")
  1016.     stop()
  1017.   end
  1018.   if comp.isAvailable("inventory_controller") then
  1019.     print("\t Контроллер инвентаря....доступен.")
  1020.   else
  1021.     print("\t Контроллер инвентаря не обнаружен, возможны проблемы и ошибки. Принудительная остановка программы.")
  1022.     os.exit()
  1023.   end
  1024.   if comp.isAvailable("generator") then
  1025.     print("\t Генератор....доступен.")
  1026.   else
  1027.     print("\t Генератор не обнаружен, возможны проблемы и ошибки. Начать работу без генератора? (0/1)")
  1028.     stop()
  1029.   end
  1030.   if comp.isAvailable("geolyzer") then
  1031.     print("\t Геосканер....доступен.")
  1032.   else
  1033.     print("\t Геосканер не обнаружен, возможны проблемы и ошибки. Принудительная остановка программы.")
  1034.     os.exit()
  1035.   end
  1036.   if pcall(r.select,KOPALKA.inv_scaner("Forestry:scoop", true)) then
  1037.     r.transferTo(inv_size)
  1038.     r.select(1)
  1039.     print("\t Сачок....доступен.")
  1040.   else
  1041.     print("\t Сачок не обнаружен, возможны проблемы и ошибки. Начать работу без сачка?")
  1042.     stop()
  1043.   end
  1044.   if r.durability() ~= nil then
  1045.     print("\t Инструмент....доступен.")
  1046.   else
  1047.     print("\t Инструмент не обнаружен, возможны проблемы и ошибки. Принудительная остановка программы.")
  1048.     os.exit()
  1049.   end
  1050.   print("\n Все компоненты в наличии.\n Программа может быть запущена.")
  1051. end
  1052.  
  1053. function KOPALKA.mine(x, z, bedrock, side, x_lim, z_lim)
  1054.   KOPALKA.check_components()
  1055.   lc.xMax = x
  1056.   lc.zMax = z
  1057.   way = 0
  1058.   term.clear()
  1059.   sendSt("Старт карьера: "..x.."x"..z.." блоков.")
  1060.   KOPALKA.check_state()
  1061.   local side = KOPALKA.whatsSide()
  1062.   local ok, err = pcall(KOPALKA.geoMiner, x, z, bedrock, side, x_lim, z_lim)
  1063.   if not ok then
  1064.     if type(err) ~= "table" then
  1065.       sendSt(err)
  1066.     end
  1067.     back_to_the_future_mode = true
  1068.     sendSt('Ошибка/препятствие. Возврат робота.')
  1069.     KOPALKA.mTo(lc.x, 0, lc.z)
  1070.     KOPALKA.home()
  1071.     KOPALKA.rot(3)
  1072.   end
  1073. end
  1074.  
  1075. function main(tArgs, options)
  1076.   local function argNumber(x)
  1077.     local v = tonumber(x)
  1078.     if type(v) ~= 'number' then
  1079.       io.write("Аргументы должны быть заданы в виде чисел.\n")
  1080.       os.exit(1)
  1081.     end
  1082.     return v
  1083.   end
  1084.  
  1085.   local function getNumberOption(name)
  1086.     local v = options[name]
  1087.     if v then
  1088.       v = argNumber(v)
  1089.     end
  1090.     return v
  1091.   end
  1092.  
  1093.   if #tArgs == 2 then
  1094.     bedrockWidth = getNumberOption("bedrock-width") or bedrockWidth
  1095.     minHardness = getNumberOption("min-hardness") or minHardness
  1096.     maxHardness = getNumberOption("max-hardness") or maxHardness
  1097.     local x = argNumber(tArgs[1])
  1098.     local z = argNumber(tArgs[2])
  1099.     KOPALKA.mine(x, z, getNumberOption("bedrock"))
  1100.   else
  1101.     io.write("Запуск: kopalka размер_вперёд размер_справа\n")
  1102.     io.write("Опции:\n")
  1103.     io.write("--min-hardness=<мин. плотность>\n")
  1104.     io.write("--max-hardness=<макс. плотность>\n")
  1105.     io.write("--bedrock=<нижний уровень бедрока относительно робота> ")
  1106.     io.write("= высота_нижнего_слоя_бедрока-высота_на_которой_стоит_робот> - \n")
  1107.     io.write("--bedrock-width=<ширина слоя бедрока>\n")
  1108.     io.write("Робот будет добывать блоки,\nплотность которых находится \nв интервале (<мин. плотность>, <макс. плотность>).\n")
  1109.     io.write("Значение по умолчанию: ("..minHardness..", "..maxHardness..").\n")
  1110.   end
  1111. end
  1112.  
  1113. main(shell.parse(...))
RAW Paste Data