Asioron

Untitled

May 26th, 2019
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 40.70 KB | None | 0 0
  1. -- FORKED FROM http://pastebin.com/gqZ1Qdqi
  2. -- http://computercraft.ru/topic/1031-geokopatel-ili-stan-millionerom/
  3. -- v0.7.6
  4.  
  5. ---------------------------------------------------------
  6. local energyGenPercent = 50
  7. local energyReturnPercent = 20
  8. local energyStartPercent = 99
  9. local minHardness = 2.05
  10. local maxHardness = 40
  11. local scanRadius = 5
  12. local bedrockWidth = 3
  13. local maxTry = 255
  14. local chkPeriod = 30
  15.  
  16. local scrap = {
  17. "minecraft:stone",
  18. "minecraft:cobblestone",
  19. "minecraft:dirt",
  20. "minecraft:gravel",
  21. "minecraft:sand",
  22. "minecraft:grass",
  23. "minecraft:sandstone",
  24. "minecraft:mossy_cobblestone",
  25. "minecraft:stonebrick",
  26. "minecraft:brown_mushroom",
  27. "minecraft:red_mushroom",
  28. "minecraft:netherrack"
  29. }
  30.  
  31. local fuel_list = {
  32. "minecraft:fence",
  33. "minecraft:planks",
  34. "minecraft:log",
  35. "minecraft:coal_block",
  36. "minecraft:coal"
  37. }
  38.  
  39. local mining_tools_list = {
  40. "minecraft:iron_pickaxe",
  41. "minecraft:golden_pickaxe",
  42. "appliedenergistics2:item.ToolCertusQuartzPickaxe",
  43. "appliedenergistics2:item.ToolNetherQuartzPickaxe",
  44. "IC2:itemToolBronzePickaxe",
  45. "Forestry:bronzePickaxe",
  46. "minecraft:diamond_pickaxe",
  47. "IC2:itemToolDrill",
  48. "IC2:itemToolDDrill",
  49. "IC2:itemToolIridiumDrill",
  50. "GraviSuite:advDDrill"
  51. }
  52. ---------------------------------------------------------
  53.  
  54. local shell = require "shell"
  55. local sides = require("sides")
  56. local term = require("term")
  57. local r = require("robot")
  58. local comp = require("component")
  59. local event = require("event")
  60. local computer = require("computer")
  61. local inv = comp.inventory_controller
  62. local geolyzer
  63. local mod
  64. local KOPALKA = {}
  65. local inv_size = r.inventorySize()
  66. local inv_side = sides.back
  67. local charge_side = sides.left
  68. local temp_state = {x=0, y=0, z=0, dr=3}
  69. local lc = {x=0, y=0, z=0, dr=3, xMax = 0, zMax = 0}
  70. local way = 0
  71. local warp = false
  72. local warpMod = false
  73. local warpTun = false
  74. local port = 1
  75. local id = 'MINER'
  76. local key = false
  77. local MINE, BACK_TO_BASE, BACK_TO_MINE, EMERGENCY = 0, 1, 2, 3
  78. local mode = MINE
  79. local directives = {
  80. pause = false,
  81. home = false,
  82. report = false,
  83. move = false
  84. }
  85. local progress
  86.  
  87. --RoboCraft-server
  88. if computer.maxEnergy() >= 1000000 then
  89. print("RoboCraft server detected")
  90. energyStartPercent = 20
  91. energyGenPercent = 10
  92. energyReturnPercent = 2
  93. end
  94.  
  95. local clusterHeight --вычисляется при запуске
  96. local worldHeight = 256
  97.  
  98. local function sprintf(s, ...)
  99. return s:format(...)
  100. end
  101.  
  102. function pause()
  103. os.sleep(0)
  104. end
  105.  
  106. local function sendSt(message) -- ОТПРАВКА СТАТУСНОГО СООБЩЕНИЯ ЧЕРЕЗ ТУННЕЛЬ
  107. if warp then
  108. if warpMod then
  109. pcall(mod.broadcast(port, id, message))
  110. elseif warpTun then
  111. pcall(comp.tunnel.send(id, message))
  112. end
  113. end
  114. end
  115.  
  116. local function printSt(message) -- ОТПРАВКА СТАТУСНОГО СООБЩЕНИЯ ЧЕРЕЗ ТУННЕЛЬ
  117. print(message)
  118. sendSt(message)
  119. end
  120.  
  121. local actionCnt = 0
  122. local function incActionCnt(energyOnly)
  123. -- не проверяем состояние в режимах возврата на базу
  124. if (mode == EMERGENCY) or (mode == BACK_TO_BASE) then
  125. return
  126. end
  127. if actionCnt%chkPeriod == 0 then
  128. if energyOnly then
  129. KOPALKA.check_state(false, false, true)
  130. else
  131. KOPALKA.check_state(true, true, true)
  132. end
  133. end
  134. actionCnt = actionCnt + 1
  135. end
  136.  
  137. function KOPALKA.charge_tool(chargerSide, slot)
  138. local side = 3
  139. local tool = nil
  140.  
  141. if chargerSide == 1 then
  142. side=1
  143. elseif chargerSide == 0 then
  144. side=0
  145. end
  146.  
  147. if r.durability() == nil then
  148. return false
  149. end
  150.  
  151. if r.durability() < 0.1 then
  152. r.select(slot)
  153. inv.equip()
  154. tool = inv.getStackInInternalSlot(slot)
  155. inv.equip()
  156. if not(lc.x == 0 and lc.y == 0 and lc.z == 0) then
  157. return true
  158. end
  159. else
  160. return false
  161. end
  162.  
  163. local function isElectric(device)
  164. if device.maxCharge ~= nil then
  165. return true
  166. else
  167. return false
  168. end
  169. end
  170.  
  171. local function find_new_tool()
  172. KOPALKA.rot(inv_side)
  173. local temp = KOPALKA.inv_scaner(mining_tools_list, false, start_slot)
  174. printSt("Поиск замены инструменту в сундуке.")
  175. while temp ~= 0 do
  176. local temp_device = inv.getStackInSlot(3, temp)
  177. if isElectric(temp_device) then
  178. if temp_device.charge/temp_device.maxCharge > 0.3 then
  179. break
  180. else
  181. temp = KOPALKA.inv_scaner(mining_tools_list, false, temp+1)
  182. end
  183. else
  184. if temp_device.damage/temp_device.maxDamage < 0.2 then
  185. break
  186. else
  187. temp = KOPALKA.inv_scaner(mining_tools_list, false, temp+1)
  188. end
  189. end
  190. end
  191. return temp
  192. end
  193.  
  194. local function service(device)
  195. if isElectric(device) then
  196. KOPALKA.rot(chargerSide)
  197. if (inv.getInventorySize(3) or 0) == 0 then
  198. printSt("Зарядник не найден. Установите зарядник.")
  199. while (inv.getInventorySize(3) or 0) == 0 do
  200. os.sleep(5)
  201. end
  202. end
  203. r.select(slot)
  204. inv.equip()
  205. inv.dropIntoSlot(3,1)
  206. printSt("Зарядка инструмента.")
  207. while inv.getStackInSlot(3,1).charge < device.maxCharge do
  208. os.sleep(10)
  209. end
  210. inv.suckFromSlot(3,1)
  211. inv.equip()
  212. else
  213. printSt("Поиск инструмента в сундуке.")
  214. KOPALKA.rot(inv_side)
  215. while true do
  216. local temp = find_new_tool()
  217. if temp ~= 0 then
  218. r.select(slot)
  219. inv.equip()
  220. if not r.drop() then
  221. printSt("Нет места в сундуке. Освободите место.")
  222. while not r.drop() do
  223. os.sleep(10)
  224. end
  225. end
  226. inv.suckFromSlot(3, temp)
  227. inv.equip()
  228. r.select(1)
  229. break
  230. end
  231. end
  232. end
  233. end
  234.  
  235. if lc.x == 0 and lc.y == 0 and lc.z == 0 then
  236. printSt("Сервис инструмента.")
  237. service(tool)
  238. else
  239. return false
  240. end
  241. end
  242.  
  243. function KOPALKA.drop() --функция дропа всего инвентаря в сундук, если таковой стоит перед носом
  244. while true do
  245. if r.detect() then
  246. if inv.getInventorySize(3) ~= nil then
  247. for i=1,inv_size-1 do
  248. if inv.getStackInInternalSlot(i) ~= nil then
  249. r.select(i)
  250. if not r.drop() then
  251. printSt("Сундук переполнен. Освободите место под складирование.")
  252. while not r.drop() do
  253. os.sleep(5)
  254. end
  255. end
  256. end
  257. end
  258. break
  259. else
  260. printSt("Блок не является сундуком.")
  261. os.sleep(5)
  262. end
  263. else
  264. printSt("Установите сундук!")
  265. os.sleep(5)
  266. end
  267. end
  268. end
  269.  
  270. function KOPALKA.isScrap(name) -- ПРОВЕРКА ПРЕДМЕТА, ЯВЛЯЕТСЯ ЛИ ОН МУСОРОМ
  271. for i, nm in pairs(scrap) do
  272. if name == nm then
  273. return true
  274. end
  275. end
  276. return false
  277. end
  278.  
  279. local dont_drop_scrap
  280. function KOPALKA.drop_scrap()
  281. if dont_drop_scrap then
  282. return
  283. end
  284. for i=1, inv_size do
  285. local slot = inv.getStackInInternalSlot(i)
  286. if slot ~= nil then
  287. if KOPALKA.isScrap(slot.name) then
  288. r.select(i)
  289. r.dropDown()
  290. end
  291. end
  292. end
  293. return KOPALKA.inv_sorting()
  294. end
  295.  
  296. -----------------------------------ДВИЖЕНИЕ СКВОЗЬ ПОРОДУ [BEGIN]
  297. local compR = comp.robot
  298. if (maxTry or 0 ) < 1 then
  299. maxTry = 255
  300. end
  301.  
  302. local function hiver(direction) --ДОБЫЧА УЛЬЯ
  303. if geolyzer and geolyzer.analyze(direction).name == "ExtraBees:hive" then
  304. if pcall(r.select, KOPALKA.inv_scaner("Forestry:scoop", true)) then
  305. inv.equip()
  306. compR.swing(direction)
  307. inv.equip()
  308. r.select(1)
  309. end
  310. return true
  311. end
  312. end
  313.  
  314. local function move(direction)
  315. while true do
  316. local ok, err = compR.move(direction)
  317. if not ok and err == "already moving" then
  318. os.sleep(0.5)
  319. else
  320. return ok, err
  321. end
  322. end
  323. end
  324.  
  325. function KOPALKA.swingmove(direction, doMove, action, arg)
  326. if action ~= nil then
  327. action(arg)
  328. end
  329. local detected, detectInf, moveOk, moveInf, rSwing, tSwing
  330. local chkHiver = true
  331. for try = 1, maxTry do
  332. detected, detectInf = compR.detect(direction)
  333. if detected then
  334. incActionCnt()
  335. rSwing, tSwing = compR.swing(direction) --air, block, entity
  336. if not rSwing and (tSwing ~= "air") then
  337. local skipErr
  338. if tSwing == "block" and chkHiver then
  339. if hiver(direction) then
  340. chkHiver = false
  341. skipErr = true
  342. end
  343. end
  344. if not skipErr then
  345. return false, detectInf, "Неустранимое препятствие ("..tostring(tSwing)..")"
  346. end
  347. end
  348. else
  349. if doMove then
  350. incActionCnt()
  351. moveOk, moveInf = move(direction)
  352. if moveOk then
  353. way = way + 1
  354. return true
  355. elseif moveInf == "impossible move" then -- or moveInf == "not enough energy"
  356. return false, detectInf, "Ошибка перемещения ("..tostring(moveInf)..")"
  357. end
  358. else
  359. return true
  360. end
  361. end
  362. end
  363. return false, detectInf, "Лимит попыток передвижения исчерпан"
  364. end
  365.  
  366. local function makeMoveErrMsg(direction, detect, msg)
  367. local directionText
  368. local s = msg.." у точки: x="..lc.x.." z="..lc.z.." y="..lc.y
  369. if direction == sides.front then
  370. directionText = "спереди"
  371. elseif direction == sides.top then
  372. directionText = "сверху"
  373. elseif direction == sides.bottom then
  374. directionText = "снизу"
  375. else
  376. directionText = "("..direction..")"
  377. end
  378. if geolyzer then
  379. detect = detect.." ["..geolyzer.analyze(3).name.."]"
  380. end
  381. return s.." Направление Dr="..lc.dr.." "..detect.." "..directionText
  382. end
  383.  
  384. function KOPALKA.mUp(action, arg)
  385. local ok, detect, msg = KOPALKA.swingmove(sides.up, true, action, arg)
  386. if ok then
  387. lc.y = lc.y + 1
  388. else
  389. printSt(makeMoveErrMsg(sides.down, detect, msg))
  390. -- KOPALKA.mTo(lc.x+2,lc.y,lc.z) --?? Нужно ли? Совместимость с ЧЛ DA?
  391. if mode ~= EMERGENCY then -- в режиме аварийного возврата долбимся до упора
  392. os.exit(1)
  393. else
  394. os.sleep(1)
  395. end
  396. end
  397. end
  398.  
  399. function KOPALKA.mDown(action, arg)
  400. local ok, detect, msg = KOPALKA.swingmove(sides.down, true, action, arg)
  401. if ok then
  402. lc.y = lc.y - 1
  403. else
  404. printSt(makeMoveErrMsg(sides.down, detect, msg))
  405. if mode ~= EMERGENCY then -- в режиме аварийного возврата долбимся до упора
  406. os.exit(1)
  407. else
  408. os.sleep(1)
  409. end
  410. end
  411. end
  412.  
  413. function KOPALKA.mForw(action, arg)
  414. local ok, detect, msg = KOPALKA.swingmove(sides.front, true, action, arg)
  415. if ok then
  416. if lc.dr==2 then
  417. lc.x = lc.x - 1
  418. elseif lc.dr==3 then
  419. lc.x = lc.x + 1
  420. elseif lc.dr==4 then
  421. lc.z = lc.z + 1
  422. elseif lc.dr==5 then
  423. lc.z = lc.z - 1
  424. end
  425. else
  426. printSt(makeMoveErrMsg(sides.front, detect, msg))
  427. if mode ~= EMERGENCY then -- в режиме аварийного возврата долбимся до упора
  428. os.exit(1)
  429. else
  430. os.sleep(1)
  431. end
  432. end
  433. end
  434. -----------------------------------ДВИЖЕНИЕ СКВОЗЬ ПОРОДУ [END]
  435.  
  436.  
  437. -----------------------------------ВРАЩЕНИЕ К ПРОГРАММНОЙ НАВИГАЦИИ [BEGIN]
  438. function KOPALKA.turnLeft()
  439. r.turnLeft()
  440. if lc.dr == 3 then
  441. lc.dr = 5
  442. elseif lc.dr == 4 then
  443. lc.dr = 3
  444. elseif lc.dr == 2 then
  445. lc.dr = 4
  446. elseif lc.dr == 5 then
  447. lc.dr = 2
  448. end
  449. end
  450.  
  451. function KOPALKA.turnRight()
  452. r.turnRight()
  453. if lc.dr == 3 then
  454. lc.dr = 4
  455. elseif lc.dr == 4 then
  456. lc.dr = 2
  457. elseif lc.dr == 2 then
  458. lc.dr = 5
  459. elseif lc.dr == 5 then
  460. lc.dr = 3
  461. end
  462. end
  463.  
  464. function KOPALKA.turnAround()
  465. r.turnAround()
  466. if lc.dr == 3 then
  467. lc.dr = 2
  468. elseif lc.dr == 4 then
  469. lc.dr = 5
  470. elseif lc.dr == 2 then
  471. lc.dr = 3
  472. elseif lc.dr == 5 then
  473. lc.dr = 4
  474. end
  475. end
  476.  
  477. function KOPALKA.rot(side) -- ВРАЩЕНИЕ С ЗАПОМИНАНИЕМ НАПРАВЛЕНИЯ
  478. if (side ~= 1) and (side ~= 0) and lc.dr-side ~=0 then
  479. if lc.dr == 3 then
  480. if side == 4 then
  481. KOPALKA.turnRight()
  482. elseif side == 2 then
  483. KOPALKA.turnAround()
  484. elseif side == 5 then
  485. KOPALKA.turnLeft()
  486. end
  487. elseif lc.dr == 4 then
  488. if side == 2 then
  489. KOPALKA.turnRight()
  490. elseif side == 5 then
  491. KOPALKA.turnAround()
  492. elseif side == 3 then
  493. KOPALKA.turnLeft()
  494. end
  495. elseif lc.dr == 2 then
  496. if side == 5 then
  497. KOPALKA.turnRight()
  498. elseif side == 3 then
  499. KOPALKA.turnAround()
  500. elseif side == 4 then
  501. KOPALKA.turnLeft()
  502. end
  503. else
  504. if side == 3 then
  505. KOPALKA.turnRight()
  506. elseif side == 4 then
  507. KOPALKA.turnAround()
  508. elseif side == 2 then
  509. KOPALKA.turnLeft()
  510. end
  511. end
  512. end
  513. end
  514. -----------------------------------ВРАЩЕНИЕ К ПРОГРАММНОЙ НАВИГАЦИИ [END]
  515.  
  516.  
  517. -----------------------------------ДВИЖЕНИЕ С ПРОГРАММНОЙ НАВИГАЦИЕЙ [BEGIN]
  518. function KOPALKA.mTo(x, y, z, action, arg)
  519. if directives.pause then
  520. KOPALKA.execDirective()
  521. end
  522. if lc.x > x then
  523. KOPALKA.rot(sides.back)
  524. while lc.x > x do
  525. KOPALKA.mForw(action,arg)
  526. end
  527. end
  528. if lc.x < x then
  529. KOPALKA.rot(sides.forward)
  530. while lc.x < x do
  531. KOPALKA.mForw(action,arg)
  532. end
  533. end
  534. if lc.z > z then
  535. KOPALKA.rot(sides.left)
  536. while lc.z > z do
  537. KOPALKA.mForw(action,arg)
  538. end
  539. end
  540. if lc.z < z then
  541. KOPALKA.rot(sides.right)
  542. while lc.z < z do
  543. KOPALKA.mForw(action,arg)
  544. end
  545. end
  546. while lc.y > y do
  547. KOPALKA.mDown(action,arg)
  548. end
  549. while lc.y < y do
  550. KOPALKA.mUp(action,arg)
  551. end
  552. end
  553.  
  554. function KOPALKA.home(service, emergency)
  555. if (mode == BACK_TO_BASE) or (mode == EMERGENCY) then
  556. return
  557. end
  558. if emergency then
  559. mode = EMERGENCY
  560. KOPALKA.mTo(lc.x, 0, lc.z)
  561. else
  562. if mode == BACK_TO_MINE then
  563. printSt("Не могу добраться до точки возобновления работы. Вероятно карьер слишком большой")
  564. os.exit(1)
  565. end
  566. mode = BACK_TO_BASE
  567. end
  568. sendSt("Возвращаюсь на базу.")
  569. temp_state.x = lc.x
  570. temp_state.y = lc.y
  571. temp_state.z = lc.z
  572. temp_state.dr = lc.dr
  573. KOPALKA.mTo(0, 0, 0)
  574. KOPALKA.rot(2)
  575. KOPALKA.drop_scrap()
  576. KOPALKA.drop()
  577. --KOPALKA.rot(3)
  578. if service then
  579. service()
  580. end
  581. end
  582.  
  583. function KOPALKA.back_to_mine(action, arg)
  584. printSt("Продолжаю работу.")
  585. mode = BACK_TO_MINE
  586. KOPALKA.mTo(0, temp_state.y, 0, action, arg)
  587. KOPALKA.mTo(temp_state.x, temp_state.y, temp_state.z, action, arg)
  588. KOPALKA.rot(temp_state.dr)
  589. temp_state.x = 0
  590. temp_state.y = 0
  591. temp_state.z = 0
  592. temp_state.dr = 3
  593. mode = MINE
  594. end
  595.  
  596. -----------------------------------ДВИЖЕНИЕ С ПРОГРАММНОЙ НАВИГАЦИЕЙ [END]
  597.  
  598.  
  599. function KOPALKA.check_inv()
  600. return r.inventorySize()
  601. end
  602.  
  603. function KOPALKA.inv_sorting()
  604. local items_stored = 0
  605.  
  606. for i=1, inv_size-1 do
  607. if r.count(i) == 0 then
  608. for j=inv_size-1, 1, -1 do
  609. if r.count(j) > 0 then
  610. if j<i then
  611. break
  612. end
  613. r.select(j)
  614. r.transferTo(i)
  615. break
  616. end
  617. end
  618. end
  619. end
  620. for i=1,inv_size do
  621. if r.count(i) > 0 then
  622. items_stored = items_stored + 1
  623. end
  624. end
  625. r.select(1)
  626. return items_stored/inv_size
  627. end
  628.  
  629. function KOPALKA.check_state(chkInventory, chkTool, chkEnergy)
  630. chkInventory = chkInventory or true
  631. chkTool = chkTool or true
  632. chkEnergy = chkEnergy or true
  633. local function inventory()
  634. local need_to_home = false
  635. if (r.count(inv_size-2) > 0) then
  636. if KOPALKA.drop_scrap() > 0.9 then
  637. need_to_home = true
  638. else
  639. need_to_home = false
  640. end
  641. end
  642. if need_to_home then
  643. sendSt("Инвентарь заполнен.")
  644. end
  645. return need_to_home
  646. end
  647.  
  648. local function wayChargeService()
  649. local need_energy = computer.energy() < (computer.maxEnergy()*energyGenPercent/100)
  650. local need_to_home = computer.energy() < (computer.maxEnergy()*energyReturnPercent/100)
  651. if need_energy and comp.isAvailable("generator") and comp.generator.count() == 0 then
  652. local slt = KOPALKA.inv_scaner(fuel_list, true)
  653. if slt ~= 0 then
  654. r.select(slt)
  655. sendSt("Запускаю генератор.")
  656. comp.generator.insert()
  657. r.select(1)
  658. end
  659. end
  660. if need_to_home then
  661. sendSt("Недостаточно энергии.")
  662. end
  663. return need_to_home
  664. end
  665.  
  666. local function chargeService()
  667. while computer.energy() < (computer.maxEnergy()*energyStartPercent/100) do
  668. printSt("Недостаточно энергии.")
  669. if comp.isAvailable("generator") and comp.generator.count() == 0 then
  670. local slt = KOPALKA.inv_scaner(fuel_list, false)
  671. if slt ~= 0 then
  672. r.select(inv_size-2)
  673. inv.suckFromSlot(3, slt)
  674. printSt("Запускаю генератор.")
  675. comp.generator.insert()
  676. r.select(1)
  677. end
  678. end
  679. os.sleep(15)
  680. end
  681. printSt("Аккумулятор заряжен.")
  682. end
  683.  
  684. local function homeService()
  685. KOPALKA.charge_tool(charge_side, inv_size-2)
  686. chargeService()
  687. end
  688.  
  689. if (chkInventory and inventory()) or (chkEnergy and wayChargeService()) or
  690. (chkTool and KOPALKA.charge_tool(charge_side, inv_size-2)) then
  691. KOPALKA.home(homeService)
  692. KOPALKA.back_to_mine()
  693. end
  694. end
  695.  
  696. function KOPALKA.inv_scaner(filter, internal, start_slot) --автопоисковик заданного итема в своем инвентаре по системному имени. возвращает номер ячейки итема, первого найденного от начала ивентаря.
  697. ins = inv.getInventorySize(3)
  698. if start_slot == nil then
  699. start_slot = 1
  700. end
  701. if filter == "empty" then
  702. if internal then
  703. for i=start_slot, inv_size do
  704. if inv.getStackInInternalSlot(i) == nil then
  705. return i
  706. end
  707. end
  708. else
  709. for i=start_slot, inv.getInventorySize(3) do
  710. if inv.getStackInSlot(3, i) == nil then
  711. return i
  712. end
  713. end
  714. end
  715. end
  716. if internal then
  717. for i=start_slot, inv_size do
  718. if inv.getStackInInternalSlot(i) ~= nil then
  719. if pcall(pairs, filter) then
  720. for j, name in pairs(filter) do
  721. if inv.getStackInInternalSlot(i).name == name then
  722. return i
  723. end
  724. end
  725. else
  726. if inv.getStackInInternalSlot(i).name == filter then
  727. return i
  728. end
  729. end
  730. end
  731. end
  732. return 0
  733. else
  734. if ins ~= nil then
  735. for i=start_slot, ins do
  736. if inv.getStackInSlot(3, i) ~= nil then
  737. if pcall(pairs, filter) then
  738. for j, name in pairs(filter) do
  739. if inv.getStackInSlot(3, i).name == name then
  740. return i
  741. end
  742. end
  743. else
  744. if inv.getStackInSlot(3, i).name == filter then
  745. return i
  746. end
  747. end
  748. end
  749. end
  750. return 0
  751. else
  752. return 0
  753. end
  754. end
  755. end
  756.  
  757. function KOPALKA.distance(blockA, blockB)
  758. local dist = math.sqrt(math.pow(blockA.x - blockB.x,2) +
  759. math.pow(blockA.z - blockB.z,2) + math.pow(blockA.y - blockB.y,2))
  760. return dist
  761. end
  762.  
  763. function KOPALKA.closest_point(point, points)
  764. local cl_num = 1
  765. local length = KOPALKA.distance(point, points[1])
  766. for i=1, #points do
  767. local l = KOPALKA.distance(point, points[i])
  768. if l < length then
  769. cl_num = i
  770. length = l
  771. end
  772. end
  773. return cl_num
  774. end
  775.  
  776. function KOPALKA.waypoints(ores_table, last)
  777. local yeildGuard = 0
  778. local way_table = {}
  779. local count = #ores_table
  780. table.insert(way_table, {x=lc.x, z=lc.z, y=lc.y})
  781. while count ~= #way_table - 1 do
  782. yeildGuard = yeildGuard + 1
  783. if yeildGuard == 100 then
  784. yeildGuard = 0
  785. pause()
  786. end
  787. local j = KOPALKA.closest_point(way_table[#way_table], ores_table)
  788. table.insert(way_table, ores_table[j])
  789. table.remove(ores_table, j)
  790. end
  791. return way_table, last
  792. end
  793.  
  794. function KOPALKA.scanVolume(xn, zn, side, hiLayer, loLayer) --сканирование карьерного "этажа" заданного радиуса -10 блоков вниз+сканер+10 блоков вверх; bedrock - верхний уровень бедрока
  795. local geo = geolyzer
  796. local ores_table = {}
  797. local last = false
  798. local x_limit = 0
  799. local z_limit = 0
  800. local x_increment = 1
  801. local z_increment = 1
  802. if side == "north" or side == "север" then
  803. x_limit = zn
  804. x_increment = 1
  805. z_limit = -xn
  806. z_increment = -1
  807. elseif side == "west" or side == "запад" then
  808. x_limit = -xn
  809. x_increment = -1
  810. z_limit = -zn
  811. z_increment = -1
  812. elseif side == "south" or side == "юг" then
  813. x_limit = -zn
  814. x_increment = -1
  815. z_limit = xn
  816. z_increment = 1
  817. elseif side == "east" or side == "восток" or side == nil then
  818. x_limit = xn
  819. x_increment = 1
  820. z_limit = zn
  821. z_increment = 1
  822. end
  823.  
  824. for xt=0,x_limit,x_increment do
  825. for zt=0,z_limit,z_increment do
  826. local scan = KOPALKA.scanPilar(xt, zt)
  827. for yt = hiLayer, loLayer, -1 do
  828. local y = lc.y + yt
  829. local hardness = scan[33 + yt]
  830. if hardness > minHardness and hardness < maxHardness and not (yt == 0 and zt == 0 and xt == 0) then
  831. if side == "north" or side == "север" then
  832. table.insert(ores_table, {x=math.abs(zt)+lc.x, z=math.abs(xt)+lc.z, y = y})
  833. elseif side == "west" or side == "запад" then
  834. table.insert(ores_table, {x=math.abs(xt)+lc.x, z=math.abs(zt)+lc.z, y = y})
  835. elseif side == "south" or side == "юг" then
  836. table.insert(ores_table, {x=math.abs(zt)+lc.x, z=math.abs(xt)+lc.z, y = y})
  837. elseif side == "east" or side == "восток" or side == nil then
  838. table.insert(ores_table, {x=math.abs(xt)+lc.x, z=math.abs(zt)+lc.z, y = y})
  839. end
  840. end
  841. end
  842. end
  843. end
  844. return ores_table
  845. end
  846.  
  847. function KOPALKA.whatsSide()
  848. printSt("Ориентирование в пространстве.")
  849. local function isBlock(dens)
  850. if dens ~= nil and dens ~= 0 then
  851. return 1
  852. elseif dens == 0 then
  853. return 0
  854. end
  855. end
  856.  
  857. local function check(fig, front)
  858. local figure1 = {
  859. east = isBlock(KOPALKA.scanPilar(1,0)[33]),
  860. south = isBlock(KOPALKA.scanPilar(0,1)[33]),
  861. west = isBlock(KOPALKA.scanPilar(-1,0)[33]),
  862. north = isBlock(KOPALKA.scanPilar(0,-1)[33])
  863. }
  864. if front then
  865. if fig.east > figure1.east then
  866. return "east"
  867. elseif fig.south > figure1.south then
  868. return "south"
  869. elseif fig.west > figure1.west then
  870. return "west"
  871. elseif fig.north > figure1.north then
  872. return "north"
  873. end
  874. elseif not front then
  875. if fig.east < figure1.east then
  876. return "east"
  877. elseif fig.south < figure1.south then
  878. return "south"
  879. elseif fig.west < figure1.west then
  880. return "west"
  881. elseif fig.north < figure1.north then
  882. return "north"
  883. end
  884. end
  885. end
  886. local figure = {
  887. east = isBlock(KOPALKA.scanPilar(1,0)[33]),
  888. south = isBlock(KOPALKA.scanPilar(0,1)[33]),
  889. west = isBlock(KOPALKA.scanPilar(-1,0)[33]),
  890. north = isBlock(KOPALKA.scanPilar(0,-1)[33])
  891. }
  892. KOPALKA.rot(3)
  893. while true do
  894. if r.detect() then
  895. r.swing()
  896. local direction = check(figure, true)
  897. r.place()
  898. return direction
  899. elseif r.detectDown() then
  900. r.swingDown()
  901. r.place()
  902. local direction = check(figure, false)
  903. r.swing()
  904. r.placeDown()
  905. return direction
  906. end
  907. printSt("Для ориентирования в пространстве недостаточно данных.")
  908. printSt("Пожалуйста установите любой блок перед или под роботом и повторите попытку")
  909. os.exit(1)
  910. end
  911. end
  912.  
  913. function KOPALKA.scanPilar(x, z)
  914. local scan = geolyzer.scan(x, z, true)
  915. incActionCnt()
  916. return scan, bedrock
  917. end
  918.  
  919. local testBedrock
  920. local flatBedrock
  921. function KOPALKA.findoutBedrockLevel()
  922. printSt("Проверка уровня бедрока. Вертикальная шахта до дна и обратно.")
  923. for i = lc.y, -worldHeight + 1, -scanRadius do
  924. local tempr = KOPALKA.scanPilar(0, 0)
  925. for i = 1, scanRadius do
  926. if tempr[33 - i] < -0.3 then
  927. local bedrockHi = lc.y - i
  928. if testBedrock then
  929. printSt("Бедрок обнаружен на уровне "..bedrockHi)
  930. end
  931. KOPALKA.mTo(lc.x, bedrockHi + 1, lc.z)
  932. local tempr = KOPALKA.scanPilar(0, 0)
  933. local bedrockLo = bedrockHi
  934. for i = 5, 1, -1 do
  935. if tempr[33 - i] < -0.3 then
  936. bedrockLo = lc.y - i
  937. if testBedrock then
  938. printSt("Нижний уровень бедрока "..bedrockLo)
  939. end
  940. break
  941. end
  942. end
  943. local scannedBedrockWidth = bedrockHi - bedrockLo + 1
  944. local bedrock
  945. if flatBedrock then
  946. bedrock = bedrockHi
  947. else
  948. bedrock = bedrockLo + (bedrockWidth - 1)
  949. end
  950. if testBedrock then
  951. printSt("Толщина бедрока в точке старта "..scannedBedrockWidth)
  952. printSt("Уровень бедрока установлен "..bedrock)
  953. end
  954. return bedrock
  955. end
  956. end
  957. KOPALKA.mTo(lc.x, i, lc.z)
  958. end
  959. printSt("Бедрок не обнаружен")
  960. os.exit(1)
  961. end
  962.  
  963. function KOPALKA.quarry(quarryLength, quarryWidth, quarryHeight, side)
  964. if side == nil then
  965. side = sides.front
  966. end
  967. function dig(h)
  968. local try = 0
  969. if h >= 3 then
  970. KOPALKA.swingmove(sides.up, false)
  971. end
  972. if h >=2 then
  973. KOPALKA.swingmove(sides.down, false)
  974. end
  975. end
  976. if not quarryHeight then
  977. quarryHeight = 255
  978. end
  979. local doTurnRight = true
  980. for yy = 0, math.ceil(quarryHeight / 3) * 3 - 1, 3 do
  981. local h = quarryHeight - yy
  982. if yy > 0 then
  983. if h >= 3 then
  984. n = 3
  985. else
  986. n = 2
  987. end
  988. for n = n, 1, -1 do
  989. KOPALKA.mDown()
  990. end
  991. KOPALKA.turnAround()
  992. elseif h >= 3 then
  993. KOPALKA.mDown()
  994. end
  995. for zz = 1, quarryWidth do
  996. for xx = 1, quarryLength - 1 do
  997. KOPALKA.mForw(dig, h)
  998. end
  999. if zz < quarryWidth then
  1000. if doTurnRight then
  1001. KOPALKA.turnRight()
  1002. else
  1003. KOPALKA.turnLeft()
  1004. end
  1005. KOPALKA.mForw(dig, h)
  1006. if doTurnRight then
  1007. KOPALKA.turnRight()
  1008. else
  1009. KOPALKA.turnLeft()
  1010. end
  1011. doTurnRight = not doTurnRight
  1012. end
  1013. end
  1014. dig(h)
  1015. end
  1016. KOPALKA.home()
  1017. KOPALKA.rot(3)
  1018. printSt("Всего блоков пройдено: "..way)
  1019. printSt('Робот '..r.name()..' завершил работу.')
  1020. end
  1021.  
  1022. function KOPALKA.geoMiner(mineLength, mineWidth, mineHeight, side, clusterLength, clusterWidth)
  1023. progress = { oreCount = 0 }
  1024. if side == nil then
  1025. side = KOPALKA.whatsSide()
  1026. end
  1027. mineHeight = mineHeight or -KOPALKA.findoutBedrockLevel()
  1028. progress.mineLength = mineLength
  1029. progress.mineWidth = mineWidth
  1030. progress.mineHeight = mineHeight
  1031. progress.numClusters = math.ceil(mineLength / clusterLength)
  1032. * math.ceil(mineWidth / clusterWidth)
  1033. * math.ceil(mineHeight / clusterHeight)
  1034. progress.currentCluster = 0
  1035. for x = 0, mineLength - 1, clusterLength do
  1036. l = clusterLength
  1037. if x + clusterLength > mineLength then
  1038. l = mineLength - x
  1039. end
  1040. for z = 0, mineWidth - 1, clusterWidth do
  1041. w = clusterWidth
  1042. if z + clusterWidth > mineWidth then
  1043. w = mineWidth - z
  1044. end
  1045. local bottomLayer = mineHeight - 1
  1046. for y = scanRadius, math.ceil(mineHeight / clusterHeight) * clusterHeight, clusterHeight do
  1047. local loLayer = -math.min(scanRadius, bottomLayer - y)
  1048. local hiLayer = scanRadius
  1049. if y >= mineHeight then
  1050. hiLayer = 0
  1051. loLayer = -math.min(scanRadius, scanRadius - (y - bottomLayer))
  1052. y = mineHeight - mineHeight%clusterHeight
  1053. end
  1054. progress.currentCluster = progress.currentCluster + 1
  1055. progress.clusterStartPoint = {x = x, y = -y, z = z}
  1056. progress.clusterOreCount = 0
  1057. progress.clusterNumOres = 0
  1058. KOPALKA.clusterDigger(progress.clusterStartPoint, l, w, side, hiLayer, loLayer)
  1059. end
  1060. end
  1061. end
  1062. KOPALKA.home()
  1063. KOPALKA.rot(3)
  1064. printSt("Итого руды добыто: "..progress.oreCount)
  1065. printSt("Всего блоков пройдено: "..way)
  1066. printSt('Робот '..r.name()..' завершил работу.')
  1067. end
  1068.  
  1069. function KOPALKA.clusterDigger(start_point, l, w, side, hiLayer, loLayer)
  1070. sendSt(sprintf("Кластер: (%d, %d) размером (%d, %d) на уровне %d (%d->%d)",
  1071. start_point.x, start_point.z, l, w, start_point.y, loLayer, hiLayer))
  1072. KOPALKA.mTo(start_point.x, start_point.y, start_point.z)
  1073. sendSt("Сканирование...")
  1074. local arr = KOPALKA.scanVolume(l-1, w-1, side, hiLayer, loLayer)
  1075. progress.clusterNumOres = #arr
  1076. if progress.clusterNumOres > 0 then
  1077. sendSt("Найдено "..tostring(progress.clusterNumOres).." блока(ов)...")
  1078. sendSt("Оптимизация пути...")
  1079. arr = KOPALKA.waypoints(arr)
  1080. sendSt("Добыча...")
  1081. local n = #arr
  1082. for i = 2, n do
  1083. KOPALKA.mTo(arr[i].x, arr[i].y, arr[i].z)
  1084. progress.clusterOreCount = progress.clusterOreCount + 1
  1085. progress.oreCount = progress.oreCount + 1
  1086. if (i % 10 == 1 or i == n) then
  1087. sendSt(sprintf("%d из %d", progress.clusterOreCount, progress.clusterNumOres))
  1088. end
  1089. end
  1090. end
  1091. sendSt(sprintf("Кластер: (%d, %d) на уровне %d (%d->%d) обработан",
  1092. start_point.x, start_point.z, start_point.y, loLayer, hiLayer))
  1093. end
  1094.  
  1095. function KOPALKA.check_components(ignoreCheck)
  1096. ignoreCheck = ignoreCheck or { }
  1097. if comp.isAvailable("keyboard") then
  1098. key = false --true
  1099. else
  1100. print('Отсутствует клавиатура, включен режим игнорирования ошибок')
  1101. end
  1102. local function stop()
  1103. print('> ')
  1104. if key then
  1105. if tonumber(io.read()) ~= 1 then
  1106. os.exit()
  1107. end
  1108. else
  1109. print('> Игнорируем')
  1110. end
  1111. end
  1112. if comp.isAvailable("modem") then
  1113. warp = true
  1114. warpMod = true
  1115. mod = comp.modem
  1116. print("\t wifi карта....доступна.")
  1117. else
  1118. print("\t wifi карта не обнаружена. Начать работу? (0/1)")
  1119. stop()
  1120. end
  1121. if comp.isAvailable("tunnel") then
  1122. warp = true
  1123. warpTun = true
  1124. print("\t Связанная карта....доступна.")
  1125. else
  1126. print("\t Связанная карта не обнаружена. Начать работу? (0/1)")
  1127. stop()
  1128. end
  1129. if comp.isAvailable("chunkloader") then
  1130. comp.chunkloader.setActive(true)
  1131. print("\t Чанклоадер....доступен.")
  1132. else
  1133. print("\t Чанклоадер не обнаружен, возможны проблемы и ошибки. Начать работу без чанклоадера? (0/1)")
  1134. stop()
  1135. end
  1136. if comp.isAvailable("inventory_controller") then
  1137. print("\t Контроллер инвентаря....доступен.")
  1138. else
  1139. print("\t Контроллер инвентаря не обнаружен, возможны проблемы и ошибки. Принудительная остановка программы.")
  1140. os.exit()
  1141. end
  1142. if comp.isAvailable("generator") then
  1143. print("\t Генератор....доступен.")
  1144. else
  1145. print("\t Генератор не обнаружен, возможны проблемы и ошибки. Начать работу без генератора? (0/1)")
  1146. stop()
  1147. end
  1148. if comp.isAvailable("geolyzer") then
  1149. print("\t Геосканер....доступен.")
  1150. geolyzer = comp.geolyzer
  1151. else
  1152. if not ignoreCheck.geolyzer then
  1153. print("\t Геосканер не обнаружен, возможны проблемы и ошибки. Принудительная остановка программы.")
  1154. os.exit()
  1155. end
  1156. end
  1157. if pcall(r.select,KOPALKA.inv_scaner("Forestry:scoop", true)) then
  1158. r.transferTo(inv_size)
  1159. r.select(1)
  1160. print("\t Сачок....доступен.")
  1161. else
  1162. if not ignoreCheck.scoop then
  1163. print("\t Сачок не обнаружен, возможны проблемы и ошибки. Начать работу без сачка?")
  1164. stop()
  1165. end
  1166. end
  1167. if r.durability() ~= nil then
  1168. print("\t Инструмент....доступен.")
  1169. else
  1170. print("\t Инструмент не обнаружен, возможны проблемы и ошибки. Принудительная остановка программы.")
  1171. os.exit()
  1172. end
  1173. print("\n Все компоненты в наличии.\n Программа может быть запущена.")
  1174. end
  1175.  
  1176. local function control(start)
  1177. if warp then
  1178. local mess = {}
  1179. print('Засуск синхорнизации с главным ПК')
  1180. if warpMod then
  1181. print('Произвожу подключение через модем ...')
  1182. mod.open(1)
  1183. mod.broadcast(1, id, 'Setting')
  1184. mess = {event.pull(10, 'modem_message')}
  1185. if mess[1] == nil then
  1186. print('Главный ПК не отвечает, базовый старт')
  1187. computer.shutdown() --это убрать! сделано чтобы робота не ловить по всей карте
  1188. end
  1189. id = mess[6]
  1190. port = mess[7]
  1191. os.sleep(1)
  1192. mod.broadcast(1, id, 'Setting_action')
  1193. mod.close(1)
  1194. mod.open(port)
  1195. os.sleep(1)
  1196. mod.broadcast(port, id, 'Status_On')
  1197. mess = {event.pull(5, 'modem_message')}
  1198. if mess[1] == nil then
  1199. print('Главный ПК не отвечает, базовый старт')
  1200. computer.shutdown()
  1201. end
  1202. elseif warpTun then
  1203. print('Произвожу подключение через связанную карту ...')
  1204. comp.tunnel.send(id, 'Setting')
  1205. mess = {event.pull(5, 'modem_message')}
  1206. if mess[1] == nil then
  1207. print('Главный ПК не отвечает, базовый старт')
  1208. settingControl(true)
  1209. computer.shutdown()
  1210. end
  1211. id = mess[6]
  1212. comp.tunnel.send(id, 'Setting_action')
  1213. comp.tunnel.send(id, 'Status_On')
  1214. mess = {event.pull(5, 'modem_message')}
  1215. if mess[1] == nil then
  1216. print('Главный ПК не отвечает, базовый старт')
  1217. settingControl(true)
  1218. computer.shutdown()
  1219. end
  1220. end
  1221. for i=1,6 do
  1222. table.remove(mess, 1)
  1223. end
  1224. return mess
  1225. end
  1226. end
  1227.  
  1228. function KOPALKA.mine(x, z, mineHeight, side, x_lim, z_lim, quarry, ignoreCheck)
  1229. if quarry then
  1230. ignoreCheck = { geolyzer = true }
  1231. end
  1232. KOPALKA.check_components(ignoreCheck)
  1233. local kod = control()
  1234. if kod then
  1235. x = kod[1]
  1236. z = kod[2]
  1237. end
  1238. lc.xMax = x
  1239. lc.zMax = z
  1240. way = 0
  1241. term.clear()
  1242. printSt("Старт карьера: "..x.."x"..z.." блоков.")
  1243. local worker = KOPALKA.geoMiner
  1244. if quarry then
  1245. worker = KOPALKA.quarry
  1246. end
  1247. local ok, err = pcall(worker, x, z, mineHeight, side, x_lim, z_lim)
  1248. if not ok then
  1249. if type(err) ~= "table" then
  1250. printSt(err)
  1251. end
  1252. printSt('Ошибка/препятствие. Возврат робота.')
  1253. KOPALKA.home(nil, true)
  1254. KOPALKA.rot(3)
  1255. end
  1256. printSt("Работа карьера завершена.")
  1257. printSt("Stop")
  1258. computer.shutdown()
  1259. end
  1260.  
  1261. function main(tArgs, options)
  1262. local function argNumber(x)
  1263. local v = tonumber(x)
  1264. if type(v) ~= 'number' then
  1265. io.write("Аргументы должны быть заданы в виде чисел.\n")
  1266. os.exit(1)
  1267. end
  1268. return v
  1269. end
  1270.  
  1271. local function getNumberOption(name)
  1272. local v = options[name]
  1273. if v then
  1274. v = argNumber(v)
  1275. end
  1276. return v
  1277. end
  1278. if options.help then
  1279. io.write("Установите робота в левом верхнем углу карьера. \n")
  1280. io.write("За спиной робота — сундук. Слева — зарядник IC2/ \n")
  1281. io.write("OC. Если размер_вниз не указан робот будет копать\n")
  1282. io.write("до бедрока. В этом случае укажите ширину бедрока \n")
  1283. io.write("опцией --bedrock-width. Или добавте опцию -f, ес-\n")
  1284. io.write("ли бедрок плоский. Робот будет добывать блоки, \n")
  1285. io.write("плотность которых находится в интервале (a, b). \n")
  1286. io.write("a - мин. плотность, b - макс. плотность. \n")
  1287. io.write("Опция --scan-radius устанавливает радиус сканиро-\n")
  1288. io.write("вания по вертикали. Для ванильного конфига OC ре-\n")
  1289. io.write("комендуется значение 5. Также можно указать его \n")
  1290. io.write("в 11 строке программы. Опция --estart - заряд \n")
  1291. io.write("акк.(%), необходимый для старта. При заряде акк. \n")
  1292. io.write("ниже --egen - вкл. ген-р; --ereturn - возврат. \n")
  1293. io.write("Для выкапывания карьера, укажите опцию --quarry \n")
  1294. return
  1295. end
  1296. if #tArgs == 2 or #tArgs == 3 then
  1297. bedrockWidth = getNumberOption("bedrock-width") or bedrockWidth
  1298. minHardness = getNumberOption("min-hardness") or minHardness
  1299. maxHardness = getNumberOption("max-hardness") or maxHardness
  1300. scanRadius = getNumberOption("scan-radius") or scanRadius
  1301. clusterHeight = scanRadius * 2 + 1
  1302. local clusterSize = getNumberOption("cluster-size") or 32
  1303. local bedrockWidth = getNumberOption("bedrock-width") or bedrockWidth
  1304. testBedrock = options["test-bedrock"]
  1305. flatBedrock = options["flat-bedrock"] or options.f
  1306. local x = argNumber(tArgs[1])
  1307. local z = argNumber(tArgs[2])
  1308. local mineHeight = tArgs[3] and argNumber(tArgs[3])
  1309. dont_drop_scrap = options["dont-drop-scrap"]
  1310. KOPALKA.mine(x, z, mineHeight, nil, clusterSize, clusterSize, options.quarry or options.q)
  1311. else
  1312. io.write("Запуск:\nkopalka размер_вперёд размер_справа [размер_вниз]\n")
  1313. io.write("Опции:\n")
  1314. io.write("--help — информация о программе\n")
  1315. io.write("--flat-bedrock, -f — если бедрок плоский \n")
  1316. io.write(sprintf("--bedrock-width=<ширина слоя бедрока> [%d]\n", bedrockWidth))
  1317. io.write(sprintf("--scan-radius=<радиус сканирования по верт.> [%d]\n", scanRadius))
  1318. io.write(sprintf("--cluster-size=<размер кластера> [32]\n"))
  1319. io.write(sprintf("--min-hardness=<мин. плотность> [%s]\n", minHardness))
  1320. io.write(sprintf("--max-hardness=<макс. плотность> [%s]\n", maxHardness))
  1321. io.write(sprintf("--estart=<уровень заряда для старта> [%s%%]\n", energyStartPercent))
  1322. io.write(sprintf("--egen=<уровень заряда вкл. генератора> [%s%%]\n", energyGenPercent))
  1323. io.write(sprintf("--ereturn=<уровень заряда для возврата> [%s%%]\n", energyReturnPercent))
  1324. io.write("--quarry, -q — карьер\n")
  1325. end
  1326. end
  1327.  
  1328. main(shell.parse(...))
Advertisement
Add Comment
Please, Sign In to add comment