Krutoy242

KrutoyTurtle 2.0 preAlpha

Feb 24th, 2015
2,203
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --00_Readme.lua
  2.  
  3. -- ********************************************************************************** --
  4. -- **                                                                              ** --
  5. -- **   Krutoy Turtle 2.0  (debug version)                                         ** --
  6. -- **   http://pastebin.com/g2ZqawdP                                               ** --
  7. -- **   ----------------------------------------------------                       ** --
  8. -- **                                                                              ** --
  9. -- **   Run on turtle:                                                             ** --
  10. -- **   pastebin get g2ZqawdP startup                                              ** --
  11. -- **                                                                              ** --
  12. -- **   Developing page:                                                           ** --
  13. -- **   http://computercraft.ru/topic/48-stroitelnaia-sistema-krutoyturtle/        ** --
  14. -- **                                                                              ** --
  15. -- **   ----------------------------------------------------                       ** --
  16. -- **   Thanks for this peoples, i use theirs code:                                ** --
  17. -- **    - AustinKK (OreQuarry Turtle), NitrogenFingers (NPaintPro), ZeroGalaxy    ** --
  18. -- **                                                                              ** --
  19. -- ********************************************************************************** --
  20.  
  21.  
  22. ------------------------------------------------------
  23. -- Fun                                              --
  24. ------------------------------------------------------
  25.  
  26. --[[
  27.     ____
  28. \  /o o \  /
  29.  \|  ~   |/
  30.    \____/
  31.  
  32.  ,+---+  ,+---+  ,+---+
  33. +---+'| +---+'| +---+'|
  34. |^_^| + |^_^| + |^_^| +
  35. +---+'  +---+'  +---+'  
  36.  
  37. ]]--
  38.  
  39. K_VERSION = 2.0691 -- Version of program. Need for auto-update
  40.  
  41. --03_Utils.lua
  42.  
  43.  
  44.  
  45. -- Redefine global function for faster acces
  46. local floor = math.floor
  47. local ceil  = math.ceil
  48. local insert= table.insert
  49. local min   = math.min
  50. local max   = math.max
  51.  
  52.  
  53. --===========================================================
  54. -- Inline help functions
  55. --===========================================================
  56. local function clearScreen()     term.clear(); term.setCursorPos(1,1) end
  57. local function tblLen(tbl)       local n=0;       for _,_  in pairs(tbl) do n = n + 1 end return n end
  58. local function makeSet(list)     local set = {};  for _, v in pairs(list) do set[v] = true end return set end
  59. local function pressAnyKey()     local event, param1 = os.pullEvent ("key") end
  60. local function getChar(str, pos) return string.sub(str, pos, pos) end
  61.  
  62.  
  63. function shallowcopy(orig)
  64.     local orig_type = type(orig)
  65.     local copy
  66.     if orig_type == 'table' then
  67.         copy = {}
  68.         for orig_key, orig_value in pairs(orig) do
  69.             copy[orig_key] = orig_value
  70.         end
  71.     else -- number, string, boolean, etc
  72.         copy = orig
  73.     end
  74.     return copy
  75. end
  76.  
  77.  
  78. -- ********************************************************************************** --
  79. -- **   3D Vector                                                                  ** --
  80. -- **                                                                              ** --
  81. -- **   Modified version of 2d vector from                                         ** --
  82. -- **   https://github.com/vrld/hump/blob/master/vector.lua                        ** --
  83. -- **                                                                              ** --
  84. -- **   By Krutoy242                                                               ** --
  85. -- **                                                                              ** --
  86. -- ********************************************************************************** --
  87.  
  88. vec3 = (function()
  89.   local assert = assert
  90.   local sqrt, cos, sin, atan2 = math.sqrt, math.cos, math.sin, math.atan2
  91.  
  92.   local vector = {}
  93.   vector.__index = vector
  94.  
  95.   local function new(...)
  96.     local x,y,z = ...
  97.     if type(x) == "table" then x,y,z = x.x, x.y, x.z end
  98.     return setmetatable({x = x or 0, y = y or 0, z = z or 0}, vector)
  99.   end
  100.   local zero = new(0,0,0)
  101.  
  102.   local function isvector(v)
  103.     return type(v) == 'table' and type(v.x) == 'number' and type(v.y) == 'number' and type(v.z) == 'number'
  104.   end
  105.  
  106.   function vector:clone()
  107.     return new(self.x, self.y, self.z)
  108.   end
  109.  
  110.   function vector:unpack()
  111.     return self.x, self.y, self.z
  112.   end
  113.  
  114.   function vector:__tostring()
  115.     return "("..tonumber(self.x)..","..tonumber(self.y)..","..tonumber(self.z)..")"
  116.   end
  117.  
  118.   function vector.__unm(a)
  119.     return new(-a.x, -a.y, -a.z)
  120.   end
  121.  
  122.   function vector.__add(a,b)
  123.     assert(isvector(a) and isvector(b), "Add: wrong argument types (<vector> expected)")
  124.     return new(a.x+b.x, a.y+b.y, a.z+b.z)
  125.   end
  126.  
  127.   function vector.__sub(a,b)
  128.     assert(isvector(a) and isvector(b), "Sub: wrong argument types (<vector> expected)")
  129.     return new(a.x-b.x, a.y-b.y, a.z-b.z)
  130.   end
  131.  
  132.   function vector.__mul(a,b)
  133.     if type(a) == "number" then
  134.       return new(a*b.x, a*b.y, a*b.z)
  135.     elseif type(b) == "number" then
  136.       return new(b*a.x, b*a.y, b*a.z)
  137.     else
  138.       assert(isvector(a) and isvector(b), "Mul: wrong argument types (<vector> or <number> expected)")
  139.       return a.x*b.x + a.y*b.y + a.z*b.z
  140.     end
  141.   end
  142.  
  143.   function vector.__div(a,b)
  144.     assert(isvector(a) and type(b) == "number", "wrong argument types (expected <vector> / <number>)")
  145.     return new(a.x / b, a.y / b, a.z / b)
  146.   end
  147.  
  148.   function vector.__eq(a,b)
  149.     return a.x == b.x and a.y == b.y and a.z == b.z
  150.   end
  151.  
  152.   function vector.__lt(a,b)
  153.     return a.x < b.x and a.y < b.y and a.z < b.z
  154.   end
  155.  
  156.   function vector.__le(a,b)
  157.     return a.x <= b.x and a.y <= b.y and a.z <= b.z
  158.   end
  159.  
  160.   function vector.permul(a,b)
  161.     assert(isvector(a) and isvector(b), "permul: wrong argument types (<vector> expected)")
  162.     return new(a.x*b.x, a.y*b.y, a.z*b.z)
  163.   end
  164.  
  165.   function vector:len2()
  166.     return self.x * self.x + self.y * self.y + self.z * self.z
  167.   end
  168.  
  169.   function vector:len()
  170.     return sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
  171.   end
  172.  
  173.   function vector.dist(a, b)
  174.     assert(isvector(a) and isvector(b), "dist: wrong argument types (<vector> expected)")
  175.     local dx = a.x - b.x
  176.     local dy = a.y - b.y
  177.     local dz = a.z - b.z
  178.     return sqrt(dx * dx + dy * dy + dz * dz)
  179.   end
  180.  
  181.   function vector.dist2(a, b)
  182.     assert(isvector(a) and isvector(b), "dist: wrong argument types (<vector> expected)")
  183.     local dx = a.x - b.x
  184.     local dy = a.y - b.y
  185.     local dz = a.z - b.z
  186.     return (dx * dx + dy * dy + dz * dz)
  187.   end
  188.  
  189.   function vector:normalize_inplace()
  190.     local l = self:len()
  191.     if l > 0 then
  192.       self.x, self.y, self.z = self.x / l, self.y / l, self.z / l
  193.     end
  194.     return self
  195.   end
  196.  
  197.   function vector:normalized()
  198.     return self:clone():normalize_inplace()
  199.   end
  200.  
  201.   function vector:rotate_inplace_z(phi)
  202.     local c, s = cos(phi), sin(phi)
  203.     self.x, self.y = c * self.x - s * self.y, s * self.x + c * self.y
  204.     return self
  205.   end  
  206.   function vector:rotate_inplace_x(phi)
  207.     local c, s = cos(phi), sin(phi)
  208.     self.y, self.z = c * self.y - s * self.z, s * self.y + c * self.z
  209.     return self
  210.   end  
  211.   function vector:rotate_inplace_y(phi)
  212.     local c, s = cos(phi), sin(phi)
  213.     self.z, self.x = c * self.z - s * self.x, s * self.z + c * self.x
  214.     return self
  215.   end
  216.    
  217.   function vector:rotated_z(phi)
  218.     local c, s = cos(phi), sin(phi)
  219.     return new(c * self.x - s * self.y, s * self.x + c * self.y, self.z)
  220.   end  
  221.   function vector:rotated_x(phi)
  222.     local c, s = cos(phi), sin(phi)
  223.     return new(self.x, c * self.y - s * self.z, s * self.y + c * self.z)
  224.   end  
  225.   function vector:rotated_y(phi)
  226.     local c, s = cos(phi), sin(phi)
  227.     return new(s * self.z + c * self.x, self.y, c * self.z - s * self.x)
  228.   end
  229.  
  230.   function vector:cross(v)
  231.     assert(isvector(v), "cross: wrong argument types (<vector> expected)")
  232.     return new(self.Y * v.Z - self.Z * v.Y,
  233.                self.Z * v.X - self.X * v.Z,
  234.                self.X * v.Y - self.Y * v.X)
  235.   end
  236.  
  237.   function vector:trim_inplace(maxLen)
  238.     local s = maxLen * maxLen / self:len2()
  239.     s = (s > 1 and 1) or math.sqrt(s)
  240.     self.x, self.y, self.z = self.x * s, self.y * s, self.z * s
  241.     return self
  242.   end
  243.  
  244.   function vector:trimmed(maxLen)
  245.     return self:clone():trim_inplace(maxLen)
  246.   end
  247.  
  248.  
  249.   -- the module
  250.   return setmetatable({new = new, isvector = isvector, zero = zero},
  251.   {__call = function(_, ...) return new(...) end})
  252. end)()
  253.  
  254.  
  255. -- ********************************************************************************** --
  256. -- **   3D Array                                                                   ** --
  257. -- **                                                                              ** --
  258. -- **   By Krutoy242                                                               ** --
  259. -- **                                                                              ** --
  260. -- ********************************************************************************** --
  261. arr3d = function() return setmetatable({
  262.   set = function(t,x,y,z,v)
  263.     t[z]    = t[z]    or {}
  264.     t[z][y] = t[z][y] or {}
  265.     t[z][y][x] = v
  266.   end,
  267.   setVolume = function(t, x1,y1,z1,x2,y2,z2, v)
  268.     for z=z1, z2 do
  269.       for y=y1, y2 do
  270.         for x=x1, x2 do
  271.           t:set(x,y,z, v)
  272.         end
  273.       end
  274.     end  
  275.   end,
  276.   raw = function(t)
  277.     local raw = shallowcopy(t)
  278.     raw.set, raw.setVolume, raw.raw = nil,nil,nil
  279.     return raw
  280.   end
  281.   }, { __call = function(t, x, y, z)
  282.     if not t[z] or not t[z][y] then return nil end
  283.     return t[z][y][x]
  284.   end
  285. })end
  286.  
  287.  
  288.  
  289. --===========================================================
  290. -- Devide giving space to parts
  291. --===========================================================
  292. local function splitJob(cargo, ...)
  293.   local args = {...}
  294.   assert(#args ~= 0, "Wrong splitJob parameters")
  295.  
  296.   local cargoCount = #args
  297.   local arr = {}
  298.  
  299.   if type(cargo) == "number" and cargoCount==1 then
  300.     -- We havent weights, just count of slots
  301.     local slices = args[1]
  302.     local intPart = floor(cargo/slices)
  303.     local residue = cargo % slices
  304.     for i=1,slices do
  305.       insert(arr, intPart + (residue>=1 and 1 or 0))
  306.       residue = residue - 1
  307.     end
  308.   elseif type(cargo) == "number" then
  309.     -- We have weight array, devide by weight
  310.     local fullWeight=0
  311.     for i=1, #args do fullWeight = fullWeight+args[i] end
  312.     local residue = cargo
  313.     -- Give each slot weight 1
  314.     for i=1, #args do
  315.       insert(arr, 1)
  316.       residue = residue - 1
  317.     end
  318.     local tmpResidue = residue
  319.     -- Give each slot by weights
  320.     for i=1, #args do
  321.       local prtVal = floor(args[i]/fullWeight*tmpResidue)
  322.       arr[i] = arr[i] + prtVal
  323.       residue = residue - prtVal
  324.     end
  325.     -- Give last parts to most heavyes slots, if they will still not have enought
  326.     local overage = fullWeight/cargoCount
  327.     local optima = 1
  328.     while residue>0 do
  329.       for i=1,#args do
  330.         if args[i]/arr[i] > args[optima]/arr[optima] then
  331.           optima = i
  332.         end
  333.       end
  334.       arr[optima] = arr[optima] + 1
  335.       residue = residue - 1
  336.       optima = (optima % #args) + 1
  337.     end
  338.   elseif type(cargo) == "table" then
  339.     -- Each cargo have weight
  340.    
  341.     -- Make base 0 array
  342.     if cargo[0] == nil then
  343.       cargo[0] = cargo[1]
  344.       table.remove(cargo,1)
  345.     end
  346.    
  347.     local parts = args[1]
  348.     local len = tblLen(cargo)
  349.     local sum = {}
  350.     local avg
  351.     local T = {}; for i=1,len do T[i]={}end
  352.     local K = {}; for i=1,len do K[i]={}end
  353.    
  354.     local penalty = function(a,b)
  355.       local x = (sum[b]or 0) - (sum[a]or 0)
  356.       x = x-avg
  357.       return x*x
  358.     end
  359.    
  360.     sum[0]=0
  361.     for n=1, len do
  362.       sum[n] = (sum[n-1]or 0) + (cargo[n-1]or 0)
  363.     end
  364.     avg = (sum[len]or 0)/parts
  365.    
  366.     for n=0, len do
  367.       T[1][n] = penalty(0,n)
  368.       K[1][n] = n
  369.     end
  370.    
  371.     for m=2,parts do
  372.       for n=0,len do
  373.         T[m][n] = math.huge
  374.         K[m][n] = -1
  375.         for k=0,n do
  376.           if (T[m][n]or 0) > (T[m-1][k]or 0) + penalty(k,n) then
  377.             T[m][n] = (T[m-1][k]or 0) + penalty(k,n)
  378.             K[m][n] = k
  379.           end
  380.         end
  381.       end
  382.     end
  383.    
  384.    
  385.     for m=parts,2,-1 do
  386.       local sep = K[m][len]
  387.       arr[m] = len-sep
  388.       len = sep
  389.     end
  390.     arr[1] = K[1][len]
  391.   else
  392.     error("Wrong splitJob parameters: cargo")
  393.   end
  394.  
  395.   return arr
  396. end
  397.  
  398. --05_KrutoyTurtle.lua
  399.  
  400. -- ********************************************************************************** --
  401. -- **   Main file of KrutoyTurtle program                                          ** --
  402. -- **                                                                              ** --
  403. -- **   User interface, fill algirithm code.                                       ** --
  404. -- **                                                                              ** --
  405. -- ********************************************************************************** --
  406.  
  407.  
  408. ------------------------------------------------------
  409. -- Filling function variables                       --
  410. ------------------------------------------------------
  411.  
  412. -- Main patterns, using in jobs.fill() function
  413. --  Numbers tell what the count block will be placed
  414. --  Exists: fillPattern[name][z][y][x]
  415. --  [space]: here will no block
  416. --  0: remove block here
  417. fillPattern = {
  418.   ['Plain'] =
  419.   { {{1}} },
  420.   ['BoxGrid'] =
  421.   { {{3, 2, 2, 2},
  422.      {2, 1, 1, 1},
  423.      {2, 1, 1, 1},
  424.      {2, 1, 1, 1}},
  425.     {{2, 1, 1, 1},
  426.      {1},
  427.      {1},
  428.      {1}},
  429.     {{2, 1, 1, 1},
  430.      {1},
  431.      {1},
  432.      {1}},
  433.     {{2, 1, 1, 1},
  434.      {1},
  435.      {1},
  436.      {1}}},
  437. }
  438.  
  439.  
  440. -- List of avaliable flags
  441. local avaliableFlags = {
  442.   "hollow",         -- Only box without bulk
  443.   "sides",          -- Making boxes without corners
  444.   "corners",        -- Making frames
  445.   "mirror",         -- Pattern texture will mirrored
  446.   "mirror -1",      -- Each mirrored pattern indexes will shif by one block
  447.   "mirror -1x",
  448.   "mirror -1y",
  449.   "mirror -1z",
  450.   "x++", "x--",       -- Shift next coord. Userful for stairs
  451.   "y++", "y--",
  452.   "z++", "z--",
  453.   "wash",           -- Replaces all nil to 0
  454.   "skip",           -- Replaces all 0 to nil
  455.   "tunnel", "tube", -- tunnel without caps on start end end
  456.   "dense",          -- Chest for item every 1 block
  457.  
  458.   -- Flags changing fill iterator functions
  459.   "forth",          -- Build first x-z blocks, then go to next y layer
  460.   "printer",        -- Iterate block placing like printer
  461.   "down",           -- Place all blocks down. Works with "printer" or "forth"
  462.   "up",             -- Place all blocks up.   Works with "printer" or "forth"
  463.  
  464.   -- Flags for "plain" pattern
  465.   "clear",          -- Replaces all pattern indexes to -1
  466.   "greedy",         -- Save all items, putting them left ches
  467.   "mine",           -- Duplicate tags clear+greedy
  468.   "ore",            -- Duplicate "mine" but will crush only not cobble, dirt, gravel
  469.   "tidy",           -- When inventory is full drops all thrash
  470.   "lava",           -- Using bucket from first slot and refuels from it. Adds "clear"
  471. }
  472.  
  473.  
  474. ------------------------------------------------------
  475. -- Other variables                                  --
  476. ------------------------------------------------------
  477.  
  478. -- Enumeration to store names for the 6 directions
  479. local way = { FORWARD=0, RIGHT=1, BACK=2, LEFT=3, UP=4, DOWN=5 }
  480. local wayName = { [0]='Forward', ' Right', 'Back', 'Left', 'Up', 'Down'}
  481.  
  482. local MAXTURTLES = 128 -- Maximum amount of turtles in swarm
  483. local idle = false     -- Turtle is idle and will be moved when something ask get out
  484. local fillParamFile = "Krutoy/fillParams" -- Path to file with all fill parameters
  485. local scrW, scrH = term.getSize() -- Get screen params
  486. local serchOwnerThread, interfaceThread
  487. local KTurtle_source = "http://pastebin.com/raw.php?i=g2ZqawdP"
  488.  
  489. local args = { ... }
  490.  
  491. local surround = {
  492. [way.FORWARD] = vec3( 0, 1, 0),
  493. [way.RIGHT]   = vec3( 1, 0, 0),
  494. [way.BACK]    = vec3( 0,-1, 0),
  495. [way.LEFT]    = vec3(-1, 0, 0),
  496. [way.UP]      = vec3( 0, 0, 1),
  497. [way.DOWN]    = vec3( 0, 0,-1)
  498. }
  499.  
  500. local touch = {
  501. ["getout"] = 14,
  502. ["killMe"] = 13
  503. }
  504.  
  505. ------------------------------------------------------
  506. -- Debug in IDE                                     --
  507. ------------------------------------------------------
  508. IDE = (term==nil) and true or false
  509. --[[
  510. if IDE then
  511.   loadfile('CC_emulator.lua')()
  512. end
  513.  
  514. local function BREACKPOINT()
  515.   print("DEBUG")
  516.   while true do
  517.     local dbgFnc = setfenv(loadstring(read()), getfenv(1))
  518.     local status, err = pcall(dbgFnc)
  519.     if err then print(); print(err) else return end
  520.   end
  521. end]]
  522.  
  523.  
  524. -- ################################################################################## --
  525. -- ##                                Utilities                                     ## --
  526. -- ################################################################################## --
  527.  
  528. --===========================================================
  529. -- Read user input and separate into table
  530. --===========================================================
  531. local function readTable(separator)
  532.   local resultStr = read()
  533.   if resultStr ~= '' then
  534.     local result = {}
  535.     for v in string.gmatch(resultStr, separator) do
  536.       insert(result,v)
  537.     end
  538.     return result
  539.   end
  540.   return nil
  541. end
  542.  
  543. -- ################################################################################## --
  544. -- ##                            Startup functions                                 ## --
  545. -- ################################################################################## --
  546.  
  547. -- ==============================
  548. -- Auto-update
  549. -- Download and replace running file
  550. -- ==============================
  551. local function autoUpdate()
  552.   -- Get version of last
  553.   if not http then return end
  554.   local httpResponce = http.get(KTurtle_source)
  555.   local allText = httpResponce.readAll()
  556.   httpResponce.close()
  557.  
  558.   local newVersion = 0
  559.   local _,verPos = string.find(allText, 'K_VERSION *= *')
  560.   if verPos then
  561.     newVersion = tonumber(string.match(allText, '%d+[%.?%d*]*', verPos+1))
  562.   end
  563.  
  564.   -- Compare and replace
  565.   if K_VERSION < newVersion then
  566.     local sFile = shell.getRunningProgram()
  567.     local f = fs.open(sFile, "w")
  568.     f.write(allText)
  569.     f.close()
  570.     clearScreen()
  571.     print("New version downloaded!")
  572.     print("Rebooting to apply changes...")
  573.     sleep(0.1)
  574.     os.reboot()
  575.     sleep(10)
  576.   end
  577. end
  578.  
  579. local function radiateRedstine(val)
  580.   for k,v in pairs(redstone.getSides()) do
  581.     redstone.setOutput(v, val)
  582.   end
  583. end
  584.  
  585. local function waitingInHarbor()
  586.   -- Also, turn on nearest turtles
  587.   Turtle.turnRight()
  588.   -- Set redstone signal to nearest turtles
  589.   radiateRedstine(true)
  590.   pcall(peripheral.call,'front','turnOn')
  591.   pcall(peripheral.call,'back' ,'turnOn')
  592. end
  593.  
  594. local function leaveHarbor()
  595.   -- Clear redstone signals
  596.   radiateRedstine(false)
  597. end
  598.  
  599.  
  600. local function workInTeamSetup(leftShift)
  601.   local harborHeight = 2
  602.   local maxWidth = 256
  603.   Turtle.setBeacon("storageStart", leftShift, 0, 0)
  604.   Turtle.addForbiddenWayZone(way.LEFT,  way.UP,   leftShift+1,0,0, leftShift+maxWidth,0,0)
  605.   Turtle.addForbiddenWayZone(way.RIGHT, way.DOWN, leftShift  ,0,1, leftShift+maxWidth,0,1)
  606.  
  607.   Turtle.addAlterZone(way.UP,    leftShift+1,0,1, leftShift+maxWidth,0,harborHeight)
  608.   Turtle.addAlterZone(way.RIGHT, leftShift  ,0,0, leftShift+maxWidth,0,0)
  609.  
  610.   Turtle.addSafeZone(leftShift,0,0, leftShift+maxWidth+1,0,harborHeight)
  611.  
  612.   -- Block for path finding back wall and volume over harbor
  613.   Turtle.world:setVolume(leftShift-1, -1, 0, leftShift+maxWidth+1, 0, 128, true)
  614.   Turtle.world:setVolume(leftShift  ,  0, 0, leftShift+maxWidth  , 0, harborHeight, nil)
  615. end
  616.  
  617.  
  618.  
  619. local function setupCommunications()
  620.   -- Send message to neiborhoods to get out from way
  621.   Turtle.onMoveAttempt = function(attempt, newX, newY, newZ, direction)
  622.     if attempt > 2 and newY==0 then
  623.       local _,data = Turtle.inspect(direction)
  624.       if data and data.name and data.name:find("turtle") then
  625.         Turtle.touch(touch["getout"], direction)
  626.       end
  627.     end
  628.   end
  629.  
  630.   -- Get out
  631.   thread.create(function()
  632.     while true do
  633.       local strenght = Turtle.sense(-1) -- -1 means from all sides
  634.       if strenght == touch["getout"] and idle then
  635.         local oldPos = Turtle.pos:clone()
  636.         local oldOrient = Turtle.orient
  637.         Turtle.up()
  638.         sleep(1)
  639.         if idle then Turtle.goTo(oldPos); Turtle.setOrient(oldOrient) end
  640.       end
  641.     end
  642.   end)
  643. end
  644.  
  645.  
  646. -- ==============================
  647. -- Slave behavior
  648. -- Manage slave actions
  649. -- ==============================
  650. local slaveBehavior = function()
  651.   local distToOwner
  652.  
  653.   while true do
  654.     distToOwner = swarm.searchOwner()
  655.    
  656.     -- Kill other thread
  657.     thread.kill(interfaceThread)
  658.    
  659.     leaveHarbor()
  660.    
  661.     -- Owner is found. Show this on screen
  662.     KUI.setWindow({{ id='slaveLabel', type='textPanel', text='This turtle\nis slave.\n\nWaiting orders.',
  663.             x=8,y=scrH/2-3, w=scrW-16,h=6}})
  664.    
  665.     -- This turtle is slave. Waiting orders and run them
  666.     local fillParams
  667.     local firstShift = true
  668.  
  669.     -- loop for orders from master
  670.     while true do
  671.    
  672.       idle = true        
  673.       local orderFromOwner = swarm.waitOrders()
  674.       idle = false
  675.      
  676.       if not orderFromOwner then
  677.      
  678.       elseif orderFromOwner.name == 'disassemble' then
  679.         -- Just go home and spam request to be picked up
  680.         while true do
  681.           Turtle.goTo("storageStart")
  682.           Turtle.setOrient(way.BACK)
  683.           Turtle.touch(touch["killMe"])
  684.           sleep(0.5)
  685.         end
  686.        
  687.       elseif orderFromOwner.name == 'rightShift' then
  688.         -- If this turtle is fresh, suck fuel from down and refuel
  689.         while Turtle.isLowFuel() do
  690.           clearScreen()
  691.           print("Need Fuel! Please place in first slot or in chest under me.")
  692.           Turtle.selectEmptySlot()
  693.           turtle.suckDown()
  694.           turtle.refuel()
  695.         end
  696.        
  697.         if not firstShift then distToOwner = distToOwner+1 end
  698.         firstShift=false
  699.        
  700.         -- Correct the location
  701.         Turtle.setPos(-1,0,0)
  702.         Turtle.goTo(0,0,0)
  703.        
  704.       elseif orderFromOwner.name == 'fillOptions' then
  705.         fillParams = orderFromOwner
  706.        
  707.         if turtle.getFuelLevel() <= fillParams.stats.totalFuelNeeded then
  708.           -- Turtle have not anought fuel. It must send this to owner.
  709.           swarm.transmitToMaster({name='ERROR'})
  710.          
  711.           -- Run refuel loop till be fueled
  712.           while turtle.getFuelLevel() < fillParams.stats.totalFuelNeeded do
  713.             clearScreen()
  714.             print("Need Fuel! Please place fuel in turtle to consume...")
  715.             print()
  716.             for i=1,16 do
  717.               turtle.select(i)
  718.               turtle.refuel()
  719.             end
  720.           end
  721.         end
  722.        
  723.       elseif orderFromOwner.name == 'lash' then
  724.         -- IMPORTANT:
  725.         -- We changing self-position to turtle. It will think that we standing in negative coords
  726.         Turtle.setPos(-fillParams.shift.x + distToOwner, Turtle.pos.y, Turtle.pos.z)
  727.         workInTeamSetup(-fillParams.shift.x)
  728.        
  729.         -- Fill
  730.         jobs.fill(fillParams.volume,
  731.             vec3(fillParams.pos.x, fillParams.pos.y, fillParams.pos.z),
  732.             vec3(fillParams.size.x, fillParams.size.y, fillParams.size.z), fillParams.fillFlags, fillParams.stats)
  733.       end
  734.     end
  735.   end
  736. end
  737.  
  738.  
  739. -- ==============================
  740. -- Resume
  741. -- ==============================
  742. local function resume()
  743.   -- Check if resume required
  744.   if not Turtle.loadData() then return end
  745.  
  746.   -- Refstone signal means we dont need to comeback
  747.   for k,v in pairs(redstone.getSides()) do
  748.     if redstone.getInput(v) then
  749.       Turtle.removeData()
  750.       return
  751.     end
  752.   end
  753.  
  754.   local waitAbortThread, startResumeThread
  755.   local comebackBreack = true
  756.  
  757.   -- Wait if user press any key to abourt comeback
  758.   local waitAbortFnc = function()
  759.     clearScreen()
  760.     print("Seems like turtle is restarting!")
  761.     print("Press ANY KEY to abort.")
  762.     print()
  763.     pressAnyKey()
  764.    
  765.     thread.kill(startResumeThread)  
  766.    
  767.     Turtle.removeData()
  768.     comebackBreack = false
  769.   end
  770.  
  771.   -- Wait 10 seconds and go to start
  772.   local startResumeFnc = function()
  773.     sleep(2)
  774.     term.setCursorPos(scrW/2-7, scrH/2-1)
  775.     print("Come back in:")
  776.     for i=10,1 do
  777.       sleep(2)
  778.       term.setCursorPos(scrW/2-7, scrH/2-1)
  779.       print(i)
  780.     end
  781.     sleep(2)
  782.    
  783.     thread.kill(waitAbortThread)
  784.    
  785.     clearScreen()
  786.     print("Comebacking...")
  787.    
  788.     if Turtle.beacons and Turtle.beacons["storageStart"] and Turtle.beacons["startPos"] then
  789.       workInTeamSetup(Turtle.beacons["storageStart"].x)
  790.       if Turtle.pos.y > 0 then
  791.         Turtle.goTo(Turtle.pos.x, Turtle.pos.y, 0)
  792.         Turtle.goTo(0, 0, 0)
  793.       end
  794.       Turtle.goTo("startPos")
  795.     end
  796.     Turtle.setOrient(way.FORWARD)
  797.    
  798.     Turtle.removeData()
  799.     comebackBreack = false
  800.   end
  801.  
  802.   -- Lunch both threads and return only in case of resume solved
  803.   startResumeThread = thread.create(startResumeFnc)
  804.   waitAbortThread   = thread.create(waitAbortFnc)
  805.   while comebackBreack do sleep(0.1) end
  806. end
  807.  
  808. -- ################################################################################## --
  809. -- ##                                   Main                                       ## --
  810. -- ################################################################################## --
  811. function main()
  812.  
  813.   -- If we loaded from disk, copy startup file onboard
  814.   if fs.exists("disk/startup") and not fs.exists("startup") then
  815.     fs.copy("disk/startup", "startup")
  816.   end
  817.  
  818.   -- Update
  819.   autoUpdate()
  820.  
  821.   -- Not matter working this turtle alone or with others,
  822.   -- it should know how to communicate
  823.   setupCommunications()
  824.  
  825.   -- Check and resume if required
  826.   resume()
  827.  
  828.  
  829.   -- Seems like we are in line on harbor now
  830.   waitingInHarbor()
  831.  
  832.   -- ==============================
  833.   -- Main menu
  834.   -- Fill options
  835.   -- ==============================
  836.   local interfaceFnc = function()
  837.     idle = true
  838.  
  839.     while true do
  840.     local nextBtn = { id='btn_next', type='button',   text='Next>>',
  841.         x=scrW-10,y=scrH,w=8,h=1, borderStyle='none'}
  842.    
  843.     local fillOptionsWindow = {}
  844.     insert(fillOptionsWindow,{ id='optionsLabel', type='textPanel', text='Fill options',
  845.         x=0,y=0, w=scrW+2,h=3})
  846.     local inputSize = { id='btn_size', type='input',    text='',
  847.         x=3,y=6, w=scrW-13,h=1, borderStyle='none', align='left', padding={0,0,0,9}}
  848.        
  849.     insert(fillOptionsWindow,{ id='btn_pattern', type='button', text='Pattern: ""',
  850.         x=3,y=4, w=scrW-4,h=1, borderStyle='none', align='left'})
  851.     insert(fillOptionsWindow,{ id='txt_size', type='text',    text='   Size: ',
  852.         x=3,y=6, w=9,h=1, borderStyle='none', align='left'})
  853.     insert(fillOptionsWindow, inputSize)
  854.     insert(fillOptionsWindow,{ id='btn_flags', type='button',   text='  Flags: _',
  855.         x=3,y=8, w=scrW-4,h=1, borderStyle='none', align='left'})
  856.     insert(fillOptionsWindow,nextBtn)
  857.  
  858.  
  859.       local sizeX,sizeY,sizeZ
  860.       local pattern = nil
  861.       local pos = vec3(0,1,0)
  862.       local fillFlags = {}
  863.       local optionId, sender = 'btn_pattern', nil
  864.      
  865.      
  866.       if IDE then
  867.         sizeX,sizeY,sizeZ, pattern, pos, fillFlags = 2, 3, 3,'BoxGrid', pos, {}
  868.         optionId = 'btn_next'
  869.       end
  870.      
  871.       -- Size input
  872.       KUI.onKeyPressed = function(keyCode)
  873.         if KUI.selectedObj.id == 'btn_size' then
  874.           local inputText = KUI.selectedObj.text
  875.           if inputText ~= "" then
  876.             local result = {}
  877.             for s in string.gmatch(inputText, "%S+") do
  878.               if type(tonumber(s)) == "number" then
  879.                 insert(result,tonumber(s))
  880.               end
  881.             end
  882.             if #result == 3 then
  883.               sizeX,sizeY,sizeZ = result[1],result[2],result[3]
  884.             end
  885.           end
  886.         end
  887.       end
  888.      
  889.      
  890.       local helpTab = "btn_pattern"
  891.       while optionId ~= 'btn_next' or not pattern or not sizeX or not sizeY or not sizeZ do
  892.         KUI.setWindow(fillOptionsWindow, helpTab)
  893.         optionId, sender = KUI.navigate()
  894.        
  895.         if     optionId == 'btn_pattern' then
  896.           -- Fish all vox files in root
  897.           local tmpPatternList = {}
  898.           for k,_ in pairs(fillPattern) do insert(tmpPatternList, k) end
  899.           for _,v in pairs(fs.list('')) do
  900.             local fileExtension = string.sub(v,#v-3,#v)
  901.             if fileExtension == '.vox' or fileExtension == '.nfa' and not fillPattern[v] then
  902.               insert(tmpPatternList, v)
  903.             end
  904.           end
  905.          
  906.           -- Assemble string to show user and wait his choose
  907.           local currLine = ''
  908.           for k,v in pairs(tmpPatternList) do
  909.             currLine = currLine..' '..k..' - '..v..'\n'
  910.           end
  911.           clearScreen()
  912.           print(currLine)
  913.           local result
  914.           while true do
  915.             local event, n = os.pullEvent("char")
  916.             n = tonumber(n)
  917.             if type(n) == 'number' and n >= 1 and n <= #tmpPatternList then
  918.                 result = n
  919.               break
  920.             end
  921.           end
  922.          
  923.           -- Load needed files if we dont had them already
  924.           local pattLen = tblLen(fillPattern)
  925.           pattern = tmpPatternList[result]
  926.           if result > pattLen then -- This pattern is file. Load File
  927.             local fileExtension = string.sub(pattern,#pattern-3,#pattern)
  928.             if fileExtension == '.nfa' then
  929.               fillPattern[pattern],sizeX,sizeY,sizeZ = volumeLoader.load_nfa(pattern)
  930.               inputSize.text = sizeX..' '..sizeY..' '..sizeZ
  931.             end
  932.             if fileExtension == '.vox' then
  933.               fillPattern[pattern],sizeX,sizeY,sizeZ  = volumeLoader.load_vox(pattern)
  934.               inputSize.text = sizeX..' '..sizeY..' '..sizeZ
  935.             end
  936.           end
  937.          
  938.           -- Show pattern key to user
  939.           sender.text = 'Pattern: '..pattern
  940.         elseif optionId == 'btn_size' then
  941.        
  942.         elseif optionId == 'btn_flags' then
  943.           local oldWnd = KUI.currentWindow
  944.          
  945.           KUI.setWindow({{ id='flags_label', type='textPanel',
  946.             text='Add flags if need, separate\with commas, and press ENTER',
  947.             x=1,y=0, w=scrW,h=4}})
  948.           term.setCursorPos(5,7)
  949.           local result = readTable("[%a%d]+")
  950.           if result then
  951.             fillFlags = makeSet(result)
  952.             sender.text = '  Flags: '.. table.concat(result,", ")
  953.           end
  954.          
  955.           KUI.setWindow(oldWnd, optionId)
  956.         end
  957.        
  958.         if not pattern or not sizeX or not sizeY or not sizeZ then
  959.           inputSize.text = (sizeX or '0')..' '..(sizeY or '0')..' '..(sizeZ or '0')
  960.         end
  961.         KUI.nextTab()
  962.         helpTab = KUI.selectedObj.id
  963.       end
  964.       KUI.onKeyPressed = nil
  965.      
  966.       -- Kill searching thread
  967.       thread.kill(serchOwnerThread)
  968.      
  969.       -- Parse negative numbers
  970.       if sizeX < 0 then sizeX=math.abs(sizeX); pos.x=pos.x-sizeX end
  971.       if sizeY < 0 then sizeY=math.abs(sizeY); pos.y=pos.y-sizeY end
  972.       if sizeZ < 0 then sizeZ=math.abs(sizeZ); pos.z=pos.z-sizeZ end
  973.      
  974.       -- Volume of "owner" or "master" turtle
  975.       local masterVolume, masterStats
  976.       local gsize = vec3(sizeX,sizeY,sizeZ)
  977.       local masterSize = gsize
  978.       local wholeVlume, wholeStats = jobs.computeFillVolume(vec3(), gsize, gsize, fillPattern[pattern], fillFlags)
  979.            
  980.       -- ==============================
  981.       -- Find other turtles
  982.       -- ==============================
  983.       local errorsArray = {}
  984.       local slavesCount = 0
  985.      
  986.      
  987.       -- Loop while no errors sended from turtles
  988.       repeat
  989.      
  990.         -- If we have a dock, we need to place turtles one by one
  991.         local alreadyHaveDock = false
  992.         if fillFlags['dock'] then
  993.           if not alreadyHaveDock then slavesCount = jobs.createDock(sizeX) end
  994.           alreadyHaveDock = true
  995.         else
  996.           -- Show box that we waiting for slaves
  997.           KUI.setWindow({{ id='findSlaves', type='textPanel', text='Trying to find slaves\nWait a sec...', x=8,y=scrH/2-3, w=scrW-16,h=6}})
  998.          
  999.           -- Broadcast message and get all responses
  1000.           slavesCount = swarm.findSlaves(MAXTURTLES/200)   ;if IDE then slavesCount = 1 end
  1001.         end
  1002.        
  1003.         if(slavesCount > 0) then
  1004.           KUI.setWindow({{ id='slavesFound', type='textPanel', text='Slaves found!\nSending orders...', x=8,y=scrH/2-3, w=scrW-16,h=6}})
  1005.            
  1006.           -- Slice whole wolume to equal stacks
  1007.           local slices = splitJob(wholeStats.shelfX, slavesCount+1)
  1008.  
  1009.  
  1010.           local partCursor = 0          
  1011.           for i=0, slavesCount do
  1012.             local size      = vec3(slices[i+1], sizeY, sizeZ)
  1013.             local prt_shift = vec3(partCursor, 0, 0)
  1014.             partCursor = partCursor + slices[i+1]
  1015.            
  1016.             -- Get volume for this part
  1017.             local volumePart, statPart = jobs.computeFillVolume(prt_shift, size, gsize, fillPattern[pattern], fillFlags)
  1018.            
  1019.             if i==0 then
  1020.               -- This turtle is master and we have slaves
  1021.               masterSize = size
  1022.               masterVolume, masterStats = volumePart, statPart
  1023.               workInTeamSetup(0)
  1024.             else
  1025.               -- Prepare table with parameters for send
  1026.               local taskObj = {name='fillOptions', volume=volumePart, size={x=size.x,y=size.y,z=size.z},
  1027.                              shift={x=prt_shift.x,y=prt_shift.y,z=prt_shift.z}, pos={x=pos.x,y=pos.y,z=pos.z},
  1028.                              fillFlags=fillFlags, stats=statPart}
  1029.              
  1030.               swarm.transmitTask(i, taskObj)
  1031.             end
  1032.           end
  1033.          
  1034.           -- Show that we sended volumes and wait errors
  1035.           KUI.setWindow({{ id='waitingWhine', type='textPanel', text='Orders sended.\nWait problems if had...', x=8,y=scrH/2-3, w=scrW-16,h=6}})
  1036.          
  1037.           -- Make new array of errors
  1038.           errorsArray = {}
  1039.           local received = swarm.receiveFromSlave(slavesCount/100)
  1040.           while received do
  1041.             if received.name == "ERROR" then insert(errorsArray, received) end
  1042.             received = swarm.receiveFromSlave(slavesCount/100)
  1043.           end
  1044.                    
  1045.           -- Show errors
  1046.           if #errorsArray > 0 then
  1047.             local whineArrayStr = ""
  1048.             for k,v in pairs(errorsArray) do
  1049.               whineArrayStr = whineArrayStr .. 'Turt #' .. v.slaveId .. ': ' .. v.message
  1050.             end
  1051.             KUI.setWindow({{ id='showWhine', type='textPanel', text='Huston!\n We have a problems:\n' .. whineArrayStr .. '\nPress ENTER', x=8, y=scrH/2-2, w=scrW-10,h=10}})
  1052.             read()
  1053.           end
  1054.         else -- slavesCount == 0
  1055.           Turtle.setBeacon("storageStart", 0, 0, 0)
  1056.           masterVolume, masterStats = wholeVlume, wholeStats
  1057.         end
  1058.       until #errorsArray == 0
  1059.      
  1060.       local needUseApprove = not fillFlags['dock']
  1061.      
  1062.       -- ==============================
  1063.       -- Info screen
  1064.       -- ==============================
  1065.       local infoText = ' INFO \n' ..
  1066.                        'Fuel level:            ' .. (masterStats.totalFuelNeeded <= turtle.getFuelLevel() and 'OK' or 'NOT ENOUGHT!!') .. '\n' ..
  1067.                        'Blocks by type:\n'
  1068.  
  1069.       -- Print how much we need of blocks by each type
  1070.       for k,v in ipairs(wholeStats.totalBlockByIndex) do
  1071.         local stacks   = floor(v/64)
  1072.         local modStacks= v%64
  1073.         infoText = infoText .. ' #'..k..': '..((stacks>0) and stacks..'x64' or '')..
  1074.           ((stacks>0 and modStacks>0) and ' + ' or '')..
  1075.           ((modStacks>0) and modStacks or '') .. '\n'
  1076.       end
  1077.       infoText = infoText ..'Press ENTER\n'
  1078.                        
  1079.  
  1080.       KUI.setWindow({{ id='fillInfo', type='textPanel', text=infoText, x=1, y=1, w=scrW,h=scrH, align='left'}})
  1081.       if needUseApprove then read() end
  1082.       clearScreen()
  1083.      
  1084.       -- Lash slaves
  1085.       for i=1, slavesCount do
  1086.         swarm.transmitTask(i, {name='lash'})
  1087.       end
  1088.      
  1089.       leaveHarbor()
  1090.      
  1091.       idle = false
  1092.       jobs.fill(masterVolume, pos, masterSize, fillFlags, masterStats)
  1093.      
  1094.       -- Disassemble if we work with dock
  1095.       if fillFlags['dock'] then
  1096.         jobs.disassembleDock(slavesCount)
  1097.       end
  1098.      
  1099.       idle = true
  1100.     end
  1101.   end
  1102.  
  1103.    
  1104.   -- Do not show anything. Just wait if we had owner
  1105.   serchOwnerThread = thread.create(slaveBehavior)
  1106.   interfaceThread  = thread.create(interfaceFnc)
  1107.  
  1108.   -- Make look like we working.
  1109.   while true do sleep(999999) end
  1110.  
  1111. end
  1112.  
  1113. -- Function, called in start of all.
  1114. if IDE then main() end
  1115.  
  1116. --07_Jobs.lua
  1117.  
  1118.  
  1119.  
  1120. -- ################################################################################## --
  1121. -- ##                                PROGRAMS                                      ## --
  1122. -- ################################################################################## --
  1123.  
  1124.  
  1125.  
  1126. -- Looks like a class
  1127. jobs = {}
  1128. jobs.__index = jobs
  1129.  
  1130. --===========================================================
  1131. -- Computing volume by given pattern
  1132. -- pos is shift fo pattern
  1133. --===========================================================
  1134. function jobs.computeFillVolume(pos, size, gsize, pattern, fillFlags)
  1135.  
  1136.   -- ==============================
  1137.   -- Variables
  1138.   -- ==============================
  1139.  
  1140.   pos = pos  or vec3()
  1141.   size= size or vec3()
  1142.  
  1143.   local sizeX,sizeY,sizeZ    = size:unpack()
  1144.   local gsizeX,gsizeY,gsizeZ = gsize:unpack()
  1145.  
  1146.   local totalVolume = sizeX*sizeY*sizeZ -- Total volume of blocks
  1147.   local vol = arr3d() -- 3d array of whole volume filling territory
  1148.  
  1149.   -- Statistics
  1150.   local stats = {}
  1151.   stats.totalBlocksToPlace    = 0  -- Total count of blocks that must be placed
  1152.   stats.totalBlockByIndex = {} -- Blocks count by indexes
  1153.   stats.totalFuelNeeded       = 0
  1154.   stats.shelfX            = {} -- count of blocks on each X slice
  1155.   stats.shelfY            = {} -- count of blocks on each Y slice
  1156.   stats.shelfZ            = {} -- count of blocks on each Z slice
  1157.   stats.shelfZ_clear      = {} -- Determine if this Z level have something but 0
  1158.  
  1159.  
  1160.   -- Auto flags
  1161.   if fillFlags['hollow'] then fillFlags['sides'] = true; fillFlags['corners'] = true end
  1162.   if fillFlags['mine']   then fillFlags['clear'] = true; fillFlags['greedy']  = true end
  1163.   if fillFlags['ore']    then fillFlags['clear'] = true; fillFlags['greedy']  = true; fillFlags['mine']  = true end
  1164.   if fillFlags['lava']   then fillFlags['clear'] = true end
  1165.  
  1166.  
  1167.  
  1168.   -- ==============================
  1169.   -- Preparing
  1170.   -- ==============================
  1171.  
  1172.   -- Pattern sizes per axis
  1173.   local ptSzX, ptSzY, ptSzZ = 0,0,0
  1174.  
  1175.   -- Get sizes of pattern
  1176.   local rawPtrn = (pattern.raw and pattern:raw() or pattern)
  1177.   for z,vy in pairs(rawPtrn) do
  1178.     if ptSzZ < z then ptSzZ = z end
  1179.    
  1180.     for y,vx in pairs(vy) do
  1181.       if ptSzY < y then ptSzY = y end
  1182.      
  1183.       for x,v in pairs(vx) do
  1184.         if ptSzX < x then ptSzX = x end
  1185.       end
  1186.     end
  1187.   end
  1188.  
  1189.  
  1190.  
  1191.   -- We must make a large
  1192.   -- array of all blocks in volume
  1193.   for O=0, totalVolume-1 do
  1194.     local s_u, s_v, s_w
  1195.     s_u = floor(O/(sizeX*sizeY)) -- z
  1196.     s_v = floor(O/sizeX) % sizeY -- y
  1197.     s_w = floor(O%sizeX)         -- x
  1198.    
  1199.     local u,v,w = s_u+pos.z, s_v+pos.y, s_w+pos.x
  1200.    
  1201.  
  1202.     -- Pattern picker must think we are on this 'imagined' or 'fabled' positions
  1203.     local fabled_u, fabled_v, fabled_w = u, v, w
  1204.     if(fillFlags['mirror -1'] or fillFlags['mirror -1z']) then
  1205.       fabled_u = fabled_u + floor( (u+ptSzZ-1) / (ptSzZ*2-1) )
  1206.     end
  1207.     if(fillFlags['mirror -1'] or fillFlags['mirror -1y']) then
  1208.       fabled_v = fabled_v + floor( (v+ptSzY-1) / (ptSzY*2-1) )
  1209.     end
  1210.     if(fillFlags['mirror -1'] or fillFlags['mirror -1x']) then
  1211.       fabled_w = fabled_w + floor( (w+ptSzX-1) / (ptSzX*2-1) )
  1212.     end
  1213.  
  1214.     -- Compute pattern array indexes. Place on pattern that we want to take
  1215.     local ptX, ptY, ptZ = fabled_w%ptSzX, fabled_v%ptSzY, fabled_u%ptSzZ
  1216.    
  1217.     -- Flag "mirror" must mirrored all coordinates on even step
  1218.     if(fillFlags['mirror'] or fillFlags['mirror -1'] or fillFlags['mirror -1x'] or
  1219.        fillFlags['mirror -1y'] or fillFlags['mirror -1z']) then
  1220.       if (floor(fabled_w/ptSzX) % 2) == 1 then ptX = ptSzX-ptX-1 end
  1221.       if (floor(fabled_v/ptSzY) % 2) == 1 then ptY = ptSzY-ptY-1 end
  1222.       if (floor(fabled_u/ptSzZ) % 2) == 1 then ptZ = ptSzZ-ptZ-1 end
  1223.     end
  1224.  
  1225.  
  1226.     -- Get block index from pattern, demands on position of turtle
  1227.     local blockIndex = nil -- nil: avoid this block
  1228.     if pattern[ptZ+1] and pattern[ptZ+1][ptY+1] then
  1229.       blockIndex = pattern[ptZ+1][ptY+1][ptX+1]
  1230.     end
  1231.    
  1232.    
  1233.     -- When we use 'sides' or 'corners' flags, we avoid all blocks inside volume
  1234.     if fillFlags['sides'] or fillFlags['corners'] then
  1235.       if(u>0 and u<gsizeZ-1) and (v>0 and v<gsizeY-1) and (w>0 and w<gsizeX-1) then
  1236.         blockIndex = 0
  1237.       end
  1238.     end
  1239.    
  1240.     -- If only 'sides' flag enabled, clear all corners
  1241.     if fillFlags['sides'] and not fillFlags['corners'] then
  1242.       if not(((u>0 and u<gsizeZ-1) and (v>0 and v<gsizeY-1)) or
  1243.              ((u>0 and u<gsizeZ-1) and (w>0 and w<gsizeX-1)) or
  1244.              ((w>0 and w<gsizeX-1) and (v>0 and v<gsizeY-1))) then
  1245.         blockIndex = 0
  1246.       end
  1247.     end
  1248.    
  1249.     -- If only 'corners', clear all sides
  1250.     if fillFlags['corners'] and not fillFlags['sides'] then
  1251.       if not(((u==0 or u==gsizeZ-1) and (v==0 or v==gsizeY-1)) or
  1252.              ((u==0 or u==gsizeZ-1) and (w==0 or w==gsizeX-1)) or
  1253.              ((w==0 or w==gsizeX-1) and (v==0 or v==gsizeY-1))) then
  1254.         blockIndex = 0
  1255.       end
  1256.     end
  1257.     if fillFlags['tunnel'] and (w>0 and w<gsizeX-1) and (u>0 and u<gsizeZ-1) then
  1258.       blockIndex = 0
  1259.     end
  1260.     if fillFlags['tube']   and (w>0 and w<gsizeX-1) and (v>0 and v<gsizeY-1) then
  1261.       blockIndex = 0
  1262.     end
  1263.     if fillFlags['wash'] then if blockIndex== nil then blockIndex = 0 end end
  1264.     if fillFlags['skip']    then if blockIndex==   0 then blockIndex = nil end end
  1265.    
  1266.     -- Clear all blocks, ignoring any pattern
  1267.     if fillFlags['clear'] then blockIndex = 0 end
  1268.    
  1269.     -- Put block index in volume array
  1270.     vol:set(s_w,s_v,s_u,blockIndex)
  1271.    
  1272.     -- Statistics
  1273.     if blockIndex then
  1274.       stats.totalBlocksToPlace = stats.totalBlocksToPlace + 1
  1275.       stats.totalBlockByIndex[blockIndex] = (stats.totalBlockByIndex[blockIndex] or 0) + 1
  1276.      
  1277.       -- Shelfes
  1278.       stats.shelfX[s_w] = (stats.shelfX[s_w] or 0) + 1
  1279.       stats.shelfY[s_v] = (stats.shelfY[s_v] or 0) + 1
  1280.       stats.shelfZ[s_u] = (stats.shelfZ[s_u] or 0) + 1
  1281.      
  1282.       -- True if this level have other then 0
  1283.       if stats.shelfZ_clear[s_u] == nil then stats.shelfZ_clear[s_u] = true end
  1284.       stats.shelfZ_clear[s_u] = stats.shelfZ_clear[s_u] and (blockIndex == 0)
  1285.     end
  1286.   end
  1287.  
  1288.   -- More statistics
  1289.   stats.totalFuelNeeded = sizeX*sizeY*(2 + floor(sizeZ/3))
  1290.  
  1291.   -- Compute suggest pattern
  1292.   local suggestPattern = {}
  1293.   local blockList    = {}
  1294.   local blockIdxs    = {}
  1295.   local slotsToIndex = {}
  1296.   for i=1,16 do
  1297.     if stats.totalBlockByIndex[i] and stats.totalBlockByIndex[i] > 0 then
  1298.       insert(blockList, stats.totalBlockByIndex[i])
  1299.       insert(blockIdxs, i)
  1300.     end
  1301.   end
  1302.   if #blockList == 0 then
  1303.     slotsToIndex[0] = 16
  1304.     for j=1, 16 do insert(suggestPattern, 0) end
  1305.   elseif #blockList == 1 then
  1306.     slotsToIndex[1] = 16
  1307.     for j=1, 16 do insert(suggestPattern, blockIdxs[1]) end
  1308.   else
  1309.     local cargo = splitJob(16, unpack(blockList))
  1310.     for i=1,#cargo do
  1311.       slotsToIndex[blockIdxs[i]] = cargo[i]
  1312.       for j=1, cargo[i] do insert(suggestPattern,blockIdxs[i]) end
  1313.     end
  1314.   end
  1315.   stats.suggestPattern = suggestPattern
  1316.   stats.typesCont = #blockIdxs
  1317.   stats.slotsToIndex = slotsToIndex
  1318.  
  1319.  
  1320.  
  1321.   return vol, stats
  1322. end  
  1323.  
  1324.  
  1325. --===========================================================
  1326. -- Super-duper cool building program.
  1327. -- Using pre-made volume to fill it
  1328. --===========================================================
  1329. function jobs.fill(...)
  1330.   local vol, pos, size, fillFlags, stats = ...
  1331.  
  1332.   -- ==============================
  1333.   -- Preparing
  1334.   -- ==============================
  1335.   local sizeX, sizeY, sizeZ = size:unpack()
  1336.  
  1337.   -- Preparing world for path finding
  1338.   -- Note that world is only in filling volume and starts for [0,0,0]
  1339.   local p1,p2 = pos, size+pos
  1340.  
  1341.   -- Block some cells to prevent gouing on forbidden places
  1342.   -- Bottom and Top
  1343.   Turtle.world:setVolume(p1.x, p1.y, p1.z-1, p2.x, p2.y, p1.z-1, true)
  1344.   Turtle.world:setVolume(p1.x, p1.y, p2.z+1, p2.x, p2.y, p2.z+1, true)
  1345.   -- Left and right
  1346.   Turtle.world:setVolume(p1.x-1, p1.y, p1.z, p1.x-1, p2.y, p2.z, true)
  1347.   Turtle.world:setVolume(p2.x+1, p1.y, p1.z, p2.x+1, p2.y, p2.z, true)
  1348.   -- Forth
  1349.   Turtle.world:setVolume(p1.x, p2.y+1, p1.z, p2.x, p2.y+1, p2.z, true)
  1350.   -- Inter point
  1351.   Turtle.world:set(0,1,0, nil)
  1352.  
  1353.    
  1354.   -- There we will storage what slots was deplited, out of building blocks
  1355.   -- 0: slot in use, have blocks.
  1356.   -- 1: slot deplited, haven't blocks or have thrash
  1357.   local blacklistPattern = {}
  1358.  
  1359.   local isGoBackAfterFill = true
  1360.   local slotsPattern
  1361.   local armedByIndex = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  1362.   Turtle.setBeacon("startPos", Turtle.pos:clone())
  1363.  
  1364.   -- Make array representing how much blocks each type we need to place
  1365.   -- Each time block placed value will be decremented
  1366.   local totalBlockByIndexLeft = {}
  1367.   for k,v in ipairs(stats.totalBlockByIndex) do totalBlockByIndexLeft[k] = v end
  1368.  
  1369.   -- We need to create array with cells where we already was, and then not need to dig
  1370.   -- in case we clearing then volume
  1371.   local clearedPionts = arr3d()
  1372.   if stats.totalBlockByIndex[0] then
  1373.     Turtle.onMove = function (attempt, newX, newY, newZ, direction)
  1374.       clearedPionts:set(Turtle.pos.x,Turtle.pos.y,Turtle.pos.z,true)
  1375.     end
  1376.   end
  1377.  
  1378.   --[[ Saving fill parameters
  1379.   do
  1380.     local f = fs.open(fillParamFile, "w")
  1381.     f.write(table.toString({...}))
  1382.     f.close()
  1383.   end]]--
  1384.  
  1385.  
  1386.   -- ==============================
  1387.   -- Functions
  1388.   -- ==============================
  1389.  
  1390.   local goThruGangway = function(...)
  1391.     if Turtle.pos.y ~= 0 or Turtle.pos.z~= 0 then
  1392.       Turtle.pathTo(0,1,0)
  1393.       Turtle.goTo(0,0,0)
  1394.     end
  1395.     Turtle.goTo(...)
  1396.   end
  1397.  
  1398.   local fillGetPos = function(x,y,z)
  1399.     -- Shift next coord with flags
  1400.     -- Userful for stairs and diagonals
  1401.     local shift = vec3()
  1402.     if y then shift.x = y*(fillFlags['x++'] and 1 or (fillFlags['x--'] and -1 or 0)) end
  1403.     if x then shift.y = x*(fillFlags['y++'] and 1 or (fillFlags['y--'] and -1 or 0)) end
  1404.     if y then shift.z = y*(fillFlags['z++'] and 1 or (fillFlags['z--'] and -1 or 0)) end
  1405.    
  1406.     local changeVec = pos + shift
  1407.    
  1408.     -- nil means we dont need change current position
  1409.     if not x then x = Turtle.pos.x-changeVec.x end
  1410.     if not y then y = Turtle.pos.y-changeVec.y end
  1411.     if not z then z = Turtle.pos.z-changeVec.z end
  1412.  
  1413.     local targetPos = vec3(x,y,z) + changeVec
  1414.     return targetPos
  1415.   end
  1416.  
  1417.   -- Function same as GoTo, but consider position of building and incremental shifting
  1418.   local _fillGoToFnc = function(x,y,z)
  1419.     Turtle.goTo(fillGetPos(x,y,z))
  1420.   end
  1421.   local _fillPathToFnc = function(x,y,z)
  1422.     Turtle.pathTo(fillGetPos(x,y,z))
  1423.   end
  1424.  
  1425.   -- Sometimes we need using safe way to go, so we will need to
  1426.   -- switch this handle to _fillPathToFnc
  1427.   local fillGoToFnc = _fillGoToFnc
  1428.  
  1429.  
  1430.   -- If we handle some unsolutionabled error, we can hope only on user.
  1431.   -- Going to start and waiting until he fix all
  1432.   local backToStartFnc = function(msg)
  1433.     print()
  1434.     print(msg)
  1435.    
  1436.     goThruGangway("startPos")
  1437.     Turtle.setOrient(way.FORWARD)
  1438.    
  1439.     idle = true
  1440.     pressAnyKey()
  1441.     idle = false
  1442.   end
  1443.  
  1444.   local dropIfTidy = function()
  1445.     local itemsDropped = 0
  1446.     if fillFlags['tidy'] then
  1447.       for i=1,16 do
  1448.         turtle.select(i)
  1449.         local data = turtle.getItemDetail()
  1450.         if data and Turtle.isThrash(data.name) then
  1451.           itemsDropped = itemsDropped + turtle.getItemCount(i)
  1452.           turtle.dropDown()
  1453.         end
  1454.       end
  1455.     end
  1456.     return itemsDropped
  1457.   end
  1458.  
  1459.   -- Go to start and wait user help for fuel
  1460.   local alreadyWaitFuel = false
  1461.   Turtle.onLowFuel = function(newX, newY, newZ, direction)
  1462.     if alreadyWaitFuel == false then
  1463.       alreadyWaitFuel = true
  1464.       local oldFuelLevel = turtle.getFuelLevel()
  1465.       while turtle.getFuelLevel() <= oldFuelLevel do
  1466.         backToStartFnc('Low fuel! Place something to refuel and press ANY KEY')
  1467.         shell.run("refuel all")
  1468.       end
  1469.       alreadyWaitFuel = false
  1470.     end
  1471.   end
  1472.  
  1473.   --[[
  1474.   -- Show moving status on screen
  1475.   Turtle.onMoveAttempt = function(attempt, newX, newY, newZ, attDir)
  1476.     local scrW, scrH = term.getSize()
  1477.     term.setCursorPos (1,scrH-2)
  1478.     print(string.format('fill()   size:%i,%i,%i pos:%i,%i,%i',sizeX, sizeY, sizeZ, pos.x, pos.y, pos.z))
  1479.     print(string.format('[Turtle] pos:%i,%i,%i orient:%i',Turtle.pos.x, Turtle.pos.y, Turtle.pos.z,Turtle.orient))
  1480.     write(string.format('[WantTo] pos:%i,%i,%i dir:%i att:%i',newX, newY, newZ, attDir, attempt))
  1481.   end
  1482.   ]]--
  1483.  
  1484.  
  1485.   -- Go to the storage and suck needed blocks. Storage must be defined
  1486.   local reloadForFilling = function()    
  1487.     -- First, unload blacklisted slotls
  1488.     -- This is blocks that we dont using for building
  1489.     local strgPos = Turtle.beacons["storageStart"]
  1490.      
  1491.     for i=1, 16 do
  1492.       if blacklistPattern[i] and turtle.getItemCount(i) > 0 then
  1493.         goThruGangway(strgPos)
  1494.         Turtle.setOrient(way.LEFT)
  1495.        
  1496.         turtle.select(i)
  1497.         turtle.drop()
  1498.         blacklistPattern[i] = nil
  1499.       end
  1500.     end
  1501.    
  1502.     -- Then move to storages and take blocks
  1503.     for i=1, 16 do
  1504.       local texelIndex = slotsPattern[i]
  1505.       local hungryForCount = (stats.totalBlockByIndex[texelIndex] or 0) - (armedByIndex[texelIndex] or 0)
  1506.       local itemSpace = turtle.getItemSpace(i)
  1507.       local already   = turtle.getItemCount(i)
  1508.       local needToSuck= math.min(itemSpace, hungryForCount)
  1509.       if( needToSuck > 0  and texelIndex > 0) then
  1510.         local chestStep = (fillFlags['dense'] and 1 or 2)
  1511.         goThruGangway((texelIndex-1)*chestStep +strgPos.x, strgPos.y, strgPos.z)
  1512.         Turtle.setOrient(way.BACK)
  1513.         turtle.select(i)
  1514.         if turtle.suck(needToSuck) then
  1515.           local sucked = turtle.getItemCount(i) - already
  1516.          
  1517.           -- Show how much items we already have on board
  1518.           armedByIndex[texelIndex] = armedByIndex[texelIndex] + sucked
  1519.         end
  1520.       end
  1521.     end
  1522.   end
  1523.  
  1524.   -- Go to start and try reload while accomplished
  1525.   local reloadFnc = function()
  1526.     -- Collect how much items we armed in reload session
  1527.     armedByIndex = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  1528.  
  1529.     local isReloaded = false
  1530.    
  1531.     while not isReloaded do
  1532.       reloadForFilling()
  1533.      
  1534.       -- Check if we reloaded all blocks
  1535.       local lastIndex = 0
  1536.       isReloaded = true
  1537.       for i=1, 16 do
  1538.         if slotsPattern[i] ~= lastIndex then
  1539.           lastIndex = slotsPattern[i]
  1540.           if totalBlockByIndexLeft[lastIndex] > 0 and armedByIndex[lastIndex] == 0 then
  1541.             -- Seems like this index isn't reloaded
  1542.             isReloaded = false
  1543.           end
  1544.         end
  1545.       end
  1546.      
  1547.       if not isReloaded then
  1548.         backToStartFnc('Error: Reloading failed. Please make storage and press any key')
  1549.       end
  1550.     end
  1551.   end
  1552.  
  1553.   -- Get slot pattern.
  1554.   do  
  1555.     -- Search if turtle have anought tipes is inventory
  1556.     local typesExist = 0
  1557.     local ptrn = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} -- Standart pattern. All slots empty
  1558.     local lastUnemptySlot = 0
  1559.     local lastEnum = 1
  1560.    
  1561.     for i=1, 16 do
  1562.       turtle.select(i)
  1563.       if( turtle.getItemCount(i) > 0) then
  1564.         if (lastUnemptySlot == 0) then
  1565.           lastUnemptySlot = i
  1566.         elseif (i>1) and (turtle.compareTo(lastUnemptySlot) == false) then
  1567.           lastEnum = lastEnum + 1
  1568.           lastUnemptySlot = i
  1569.         end
  1570.        
  1571.         typesExist = typesExist + 1
  1572.         ptrn[i] = lastEnum
  1573.       end
  1574.     end
  1575.    
  1576.     if stats.typesCont > typesExist then
  1577.       -- We have not anought items in inventory and need to use suggested pattern
  1578.       -- So we need to reload
  1579.       slotsPattern = stats.suggestPattern
  1580.       reloadFnc()
  1581.     else
  1582.       -- we should use pattern that we get ourself.
  1583.       -- But if we clearing, pattern mus be clear
  1584.       if fillFlags['clear'] then
  1585.         slotsPattern = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  1586.       else
  1587.         -- Just work with items we have inside
  1588.         slotsPattern = ptrn
  1589.       end
  1590.     end
  1591.   end
  1592.  
  1593.   -- Searching if wee have needed item in inventory
  1594.   local findInSlotsArrayByPattern = function (arr, n, blacklist)
  1595.     for i=1, 16 do
  1596.       if not blacklist[i] and arr[i] == n and (turtle.getItemCount(i) > 0) then
  1597.         return i
  1598.       end
  1599.     end
  1600.     return 0
  1601.   end
  1602.  
  1603.  
  1604.  
  1605.  
  1606.   -- The main function of placing blocks with parameters
  1607.   local fillFnc = function(x,y,z,direct,orient, blockIndex)
  1608.     -- nil means skipping
  1609.     if blockIndex == nil then return nil end
  1610.  
  1611.     -- Error text only for fatals, where program cant do nothing
  1612.     local fillError
  1613.    
  1614.     repeat -- Repeat until no fillErrors
  1615.       fillError = nil
  1616.  
  1617.       if blockIndex > 0 then
  1618.         local slotWithBlock = findInSlotsArrayByPattern(slotsPattern, blockIndex, blacklistPattern)
  1619.         if slotWithBlock ~= 0  then
  1620.           fillGoToFnc(x,y,z)
  1621.           if orient then Turtle.setOrient(orient) end -- Can be nil - orientation don't matter
  1622.          
  1623.           -- We have block and can put it on place
  1624.           local placeSucces = Turtle.place(slotWithBlock, direct)
  1625.          
  1626.           if(placeSucces == true)then
  1627.             -- Block this cell in world, make it unable to go throught
  1628.             local blockPos = Turtle.getRelativeCoord(direct)
  1629.             Turtle.world:set(blockPos.x, blockPos.y, blockPos.z, true)
  1630.            
  1631.             -- Decrement block for placing
  1632.             totalBlockByIndexLeft[blockIndex] = totalBlockByIndexLeft[blockIndex] - 1
  1633.           end
  1634.          
  1635.           -- If slot was emptyed, we must note, that now there will be thrash
  1636.           -- Each next time when turtle dig, empty slot will filling
  1637.           if(turtle.getItemCount(slotWithBlock) == 0) then
  1638.             blacklistPattern[slotWithBlock] = true
  1639.            
  1640.             -- Check again if we have another slot with item
  1641.             if findInSlotsArrayByPattern(slotsPattern, blockIndex, blacklistPattern) == 0 and
  1642.               totalBlockByIndexLeft[blockIndex] > 0  then
  1643.               -- No avaliable blocks to build!
  1644.               -- Save coords, reload and return
  1645.               local stopPos = Turtle.pos:clone()
  1646.              
  1647.               reloadFnc()
  1648.              
  1649.               -- Go back to work
  1650.               Turtle.pathTo(stopPos)
  1651.             end
  1652.           end
  1653.         else
  1654.           -- Fatal fillError. We are probably reloaded, but still havent blocks to place
  1655.           -- This can happend only with bug in code
  1656.           fillError = 'Fatal Fill Error: No blocks to place on {'..x..','..y..','..z..'}. I dont know what went wrong. '
  1657.           backToStartFnc(fillError)
  1658.         end
  1659.       else -- blockIndex == 0
  1660.         -- Remove block here and do nothing
  1661.         local blockPos = fillGetPos(x,y,z) + (orient and surround[orient] or surround[direct])
  1662.         if not clearedPionts(blockPos:unpack()) then
  1663.           fillGoToFnc(x,y,z)
  1664.           if orient then Turtle.setOrient(orient) end -- Can be nil - orientation don't matter
  1665.          
  1666.           -- Choose action method
  1667.           if fillFlags['ore'] then
  1668.             Turtle.mine(direct)
  1669.           elseif fillFlags['lava'] then
  1670.             Turtle.place(1, direct, true)
  1671.             turtle.select(1)
  1672.             turtle.refuel()
  1673.             -- TODO: Fully refueled event
  1674.             --if turtle.getFuelLevel()>= turtle.getFuelLimit() then
  1675.             --  backToStartFnc("Turtle is complitely refueled!")
  1676.             --  os.reboot()
  1677.             --end
  1678.           else
  1679.             Turtle.dig(direct)
  1680.           end
  1681.          
  1682.           -- We cleared this point, so add to list
  1683.           clearedPionts:set(blockPos.x,blockPos.y,blockPos.z, true)
  1684.              
  1685.           -- If we should be greedy, chech we have free slots. And, free cargo if we havent
  1686.           if fillFlags['greedy'] then
  1687.             local noFreeSlots = true
  1688.             for i=1,16 do
  1689.               if turtle.getItemCount(i) < 1 then
  1690.                 noFreeSlots = false
  1691.                 break
  1692.               end
  1693.             end
  1694.            
  1695.             -- We have no free slots! Need to drop some items.
  1696.             if noFreeSlots then            
  1697.               -- If we dropped nothing or dropped only 1 block, go to start and drop there
  1698.               if dropIfTidy() <= 1 then
  1699.                 -- Save coords, reload and return
  1700.                 local stopPos = Turtle.pos:clone()
  1701.                
  1702.                 -- Honestly, we not really reloading. Just clearing items in black list
  1703.                 for i=1,16 do
  1704.                   blacklistPattern[i] = (slotsPattern[i]>0 and blacklistPattern[i] or 1)
  1705.                 end
  1706.                 reloadFnc()
  1707.                  
  1708.                 -- Go back to work
  1709.                 Turtle.pathTo(stopPos)
  1710.               end
  1711.             end
  1712.           end
  1713.         end
  1714.       end
  1715.     until not fillError
  1716.    
  1717.     return nil
  1718.   end -- fillFnc()
  1719.  
  1720.  
  1721.  
  1722.   -- Check bucked if we are refueling from lava
  1723.   if fillFlags['lava'] then
  1724.     while true do
  1725.       turtle.select(1)
  1726.       local data = turtle.getItemDetail()
  1727.       if not data or not (data.name == "minecraft:bucket" or data.name == "minecraft:lava_bucket") then
  1728.         backToStartFnc("Place a bucket in first slot and press ANY KEY")
  1729.       else
  1730.         break
  1731.       end
  1732.     end
  1733.    
  1734.     -- And try to suck firs bucket from down
  1735.     Turtle.place(1, way.DOWN, true)
  1736.     turtle.refuel()
  1737.   end
  1738.  
  1739.  
  1740.  
  1741.   -- ==============================
  1742.   -- Iterators
  1743.   -- ==============================
  1744.  
  1745.   -- move to start position
  1746.   fillGoToFnc(0, 0, ((sizeZ>1) and 1 or 0))
  1747.  
  1748.   -- forth is printing method, when we fill from us to forward
  1749.   if     fillFlags['forth'] then
  1750.     for _y=0, sizeY-1 do
  1751.       for _z=0, sizeZ-1 do
  1752.         for _x=0, sizeX-1 do
  1753.           local x,y,z = _x,_y,_z
  1754.           local placeWay = way.DOWN
  1755.           local shift = 1
  1756.          
  1757.           -- Ping-pong
  1758.           if not fillFlags['up'] and not fillFlags['down'] then
  1759.             if(y%2==1) then z = sizeZ-z-1; x = sizeX-x-1; placeWay=way.UP; shift=-1 end
  1760.           end
  1761.           if(z%2==1) then x = sizeX-x-1 end
  1762.          
  1763.           if fillFlags['up'] then
  1764.             fillFnc(x,y,z-1, way.UP, nil, vol[z][y][x])
  1765.           elseif fillFlags['down'] then
  1766.             fillFnc(x,y,z+1, way.DOWN, nil, vol[z][y][x])
  1767.           else
  1768.             fillFnc(x,y,z+shift, placeWay, nil, vol[z][y][x])
  1769.           end
  1770.         end
  1771.       end
  1772.     end
  1773.    
  1774.   -- Printer working as usual building programs
  1775.   elseif fillFlags['printer'] then
  1776.     for _z=0, sizeZ-1 do
  1777.       for _y=0, sizeY-1 do
  1778.         for _x=0, sizeX-1 do
  1779.           local x,y,z = _x,_y,_z
  1780.           if(z%2==1) then y = sizeY-y-1; x = sizeX-x-1 end -- Ping-pong
  1781.           if(y%2==1) then x = sizeX-x-1 end                -- Ping-pong
  1782.          
  1783.           if  fillFlags['up'] then
  1784.             fillFnc(x,y,z-1, way.UP, nil, vol[z][y][x])
  1785.           else
  1786.             fillFnc(x,y,z+1, way.DOWN, nil, vol[z][y][x])
  1787.           end
  1788.         end
  1789.       end
  1790.     end
  1791.    
  1792.   -- And most awesome and fast filling method
  1793.   -- It filling 3 blocks per move
  1794.   else
  1795.     local zStepsCount    = math.ceil(sizeZ/3)-1 -- Count of levels, where robot moves horisontally
  1796.     local lastZStepIsCap = (sizeZ%3 == 1) -- The top level of volume is last level where turtle moves hor-ly
  1797.     local zLastStepLevel = zStepsCount*3+(lastZStepIsCap and 0 or 1) -- Z level where turtle will move last
  1798.     local boostMode = stats.totalBlockByIndex[0] == stats.totalBlocksToPlace -- clear all
  1799.     local yFirst = (sizeY > sizeX) -- We will go to Y coords first, then to next X
  1800.     local yBoost = boostMode and yFirst
  1801.     local size_v, size_w = sizeY-1, sizeX-1
  1802.     fillGoToFnc = _fillPathToFnc
  1803.    
  1804.    
  1805.     if yBoost then
  1806.       size_v, size_w = size_w, size_v
  1807.     end
  1808.    
  1809.    
  1810.     for _z=0, zStepsCount do
  1811.       for v=0, size_v do
  1812.         for w=0, size_w do
  1813.           local z = _z*3+1
  1814.           local currZStepIsLast = (_z==zStepsCount)
  1815.           if currZStepIsLast then z = zLastStepLevel end -- Cap of volume
  1816.          
  1817.          
  1818.           -- Ping-pong
  1819.           local currZIsEven = (_z%2==0)
  1820.           local horisontDirect = way.BACK -- Specific orientation, when we move to next Y pos
  1821.           local horisontShift  = -1       -- Y direction, when we move to next Y pos
  1822.           local x,y = w,v
  1823.          
  1824.           if boostMode then
  1825.             if yFirst then
  1826.               x,y = v, w
  1827.               if(_z%2==1) then y = sizeY-y-1; x = sizeX-x-1 end
  1828.               if(x%2==1)  then y = sizeY-y-1 end
  1829.             else
  1830.               if(_z%2==1) then y = sizeY-y-1; x = sizeX-x-1 end
  1831.               if(y%2==1)  then x = sizeX-x-1 end
  1832.             end
  1833.            
  1834.             -- Fill down
  1835.             if z>0 then
  1836.               fillFnc(x,y,z, way.DOWN, nil, vol[z-1][y][x])
  1837.             end
  1838.             -- Fill UP
  1839.             if z<sizeZ-1 then
  1840.               fillFnc(x,y,z, way.UP, nil, vol[z+1][y][x])
  1841.             end
  1842.           else
  1843.             if not currZIsEven then
  1844.               y = sizeY - y - 1
  1845.               horisontDirect = way.FORWARD
  1846.               horisontShift = 1
  1847.             end
  1848.             x = sizeX - x - 1 -- Revert X coordinates. Filling will be from right to left
  1849.            
  1850.             local escapeShaftHere = (x==0 and y==0)
  1851.             local hereWeWillGoUp = ((x==0 and ((_z%2==0 and y==sizeY-1) or (_z%2==1 and y==0))) and _z < zStepsCount)
  1852.            
  1853.  
  1854.             -- Fill down
  1855.             if z>0 and not (lastZStepIsCap and currZStepIsLast) and not escapeShaftHere then
  1856.               fillFnc(x,y,z, way.DOWN, nil, vol[z-1][y][x])
  1857.             end
  1858.            
  1859.             -- Fill forward
  1860.             if x < sizeX-1 then
  1861.               fillFnc(x,y,z, way.FORWARD, way.RIGHT, vol[z][y][x+1])
  1862.             end
  1863.            
  1864.             -- Fill back previous line when we starting new x line
  1865.             if not currZStepIsLast or (not currZIsEven and currZStepIsLast) then
  1866.               if x==0 and ((currZIsEven and y>0) or ((not currZIsEven) and y<sizeY-1)) and
  1867.                not (x==0 and y==1 and currZIsEven) then
  1868.                 fillFnc(x,y,z, way.FORWARD, horisontDirect, vol[z][y+horisontShift][x])
  1869.               end
  1870.             end
  1871.            
  1872.             -- Fill UP
  1873.             if z<sizeZ-1 and not hereWeWillGoUp and (not escapeShaftHere or currZStepIsLast) then
  1874.               fillFnc(x,y,z, way.UP, nil, vol[z+1][y][x])
  1875.             end
  1876.            
  1877.             -- Move up and fill bocks down, if we advance to next Z level
  1878.             if hereWeWillGoUp then
  1879.               local nextZLevel = (_z+1)*3 + 1
  1880.               if lastZStepIsCap and (_z+1==zStepsCount) then nextZLevel = nextZLevel-1 end -- Cap of volume
  1881.               if not escapeShaftHere then
  1882.                 for zAdvance=z+1, nextZLevel do
  1883.                   fillFnc(x,y,zAdvance, way.DOWN, nil, vol[zAdvance-1][y][x])
  1884.                 end
  1885.               end
  1886.             end
  1887.           end
  1888.          
  1889.         end
  1890.       end
  1891.     end
  1892.    
  1893.    
  1894.     -- We use our shaft to go back to x=0, y=0
  1895.     if not (zStepsCount%2==1) then
  1896.       for y=sizeY-2, 0, -1 do
  1897.         fillFnc(0, y, zLastStepLevel, way.FORWARD, way.FORWARD, vol[zLastStepLevel][y+1][0])
  1898.       end
  1899.     end
  1900.    
  1901.     -- And then go down to z 0
  1902.     for z=zLastStepLevel-1, 0, -1 do
  1903.       fillFnc(0, 0, z, way.UP, nil, vol[z+1][0][0])
  1904.     end
  1905.    
  1906.     -- And last block
  1907.     fillFnc(0, -1, 0, way.FORWARD, way.FORWARD, vol[0][0][0])
  1908.   end
  1909.  
  1910.   -- Drop thrash if need
  1911.   dropIfTidy()
  1912.  
  1913.   -- Drop all mined items
  1914.   if fillFlags['greedy'] then
  1915.     -- Honestly, we not really reloading. Just clearing items in black list
  1916.     blacklistPattern = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
  1917.     reloadFnc()
  1918.   end
  1919.  
  1920.   -- ==============================
  1921.   -- Finishing
  1922.   -- ==============================
  1923.  
  1924.   -- Now we finished filling territory. Just go home
  1925.   if isGoBackAfterFill == true then
  1926.     -- Spread message then we want die
  1927.     if fillFlags['dock'] then Turtle.touch(touch["killMe"], -1) end
  1928.    
  1929.     -- And go to start pos to not interrupt others
  1930.     goThruGangway("startPos")
  1931.     Turtle.setOrient(way.FORWARD)
  1932.   end
  1933.  
  1934.   return true
  1935. end
  1936.  
  1937.  
  1938. --===========================================================
  1939. -- Dock building
  1940. --===========================================================
  1941. function jobs.createDock(maxSize)
  1942.   -- Select turtle from inventory, or suck from down
  1943.   local selectTurtleFnc = function()
  1944.     if not Turtle.select("turtle", true) then
  1945.       if not turtle.suckUp() then return false end
  1946.       return Turtle.select("turtle", true)
  1947.     end
  1948.     return true
  1949.   end
  1950.  
  1951.   -- Show box that we placing turtles
  1952.   KUI.setWindow({{ id='makeDock', type='textPanel', text='Placing turtles\nPlease click on\neach placed turtle', x=8,y=scrH/2-3, w=scrW-16,h=6}})
  1953.  
  1954.   -- Set redstone signal to avoid comebacking
  1955.   Turtle.setOrient(way.FORWARD)
  1956.   redstone.setOutput('front', true)
  1957.  
  1958.   -- Place turtles in front till all will be placed
  1959.   -- Loop untill we have turtles sucked from chest
  1960.   local slavesCount = 0
  1961.   while slavesCount < maxSize-1 and selectTurtleFnc() do
  1962.     -- Place turtle in front
  1963.     KUI.setWindow({{ id='placeTrtl', type='textPanel', text='Placing one turtle...', x=8,y=scrH/2-3, w=scrW-16,h=6}})
  1964.     while not Turtle.place(nil, nil, true) do sleep(1) end
  1965.    
  1966.     -- Turn on this slave
  1967.     while not pcall(peripheral.call,'front','turnOn') do sleep(0.5) end
  1968.    
  1969.     -- Add this turtle in slave list
  1970.     -- Loop until turtle will be activated and send message
  1971.     KUI.setWindow({{ id='placeTrtl', type='textPanel', text='Adding turtle\nto list...', x=8,y=scrH/2-3, w=scrW-16,h=6}})
  1972.     swarm.addSlave()
  1973.    
  1974.     slavesCount = slavesCount + 1
  1975.    
  1976.     -- Transmit location correction to older turtles
  1977.     KUI.setWindow({{ id='placeTrtl', type='textPanel', text='Send shift task to all', x=8,y=scrH/2-3, w=scrW-16,h=6}})
  1978.     swarm.transmitTask(nil, {name='rightShift'}, true)
  1979.   end
  1980.  
  1981.   -- Put turtles back
  1982.   -- TODO: Working with more chests sides
  1983.   while Turtle.selectNonEmptySlot() do turtle.dropUp() end
  1984.  
  1985.   redstone.setOutput('front', false)
  1986.  
  1987.   -- Move like we are the boss
  1988.   Turtle.setPos(0,-1,0)
  1989.   Turtle.goTo(0,0,0)
  1990.  
  1991.   return slavesCount
  1992. end
  1993.  
  1994.  
  1995. --===========================================================
  1996. -- Dock disassembling
  1997. --===========================================================
  1998. function jobs.disassembleDock(slavesCount)  
  1999.   KUI.setWindow({{ id='destroyDock', type='textPanel', text='Waiting all\nturtles go home...', x=8,y=scrH/2-3, w=scrW-16,h=6}})
  2000.  
  2001.   if Turtle.pos ~= vec3() then Turtle.goTo(0,0,0) end
  2002.   Turtle.goTo(0,-1,0)
  2003.   Turtle.setOrient(way.FORWARD)
  2004.  
  2005.   local slavesPicked = 0
  2006.   while slavesPicked < slavesCount do
  2007.     for i=1, slavesCount do
  2008.       swarm.transmitTask(i, {name='disassemble'})
  2009.     end
  2010.    
  2011.     -- Wait before someone throw kill request
  2012.     local strenght = Turtle.sense(way.FORWARD, 1)
  2013.     --local receivedObj = swarm.receiveFromSlave(1)
  2014.    
  2015.     --if receivedObj and receivedObj.name == "PleaseKillMe" then
  2016.     if strenght == touch["killMe"] then
  2017.       Turtle.dig()
  2018.       if Turtle.select("turtle", true) then
  2019.         if not turtle.dropUp() then turtle.dropDown() end
  2020.        
  2021.         slavesPicked = slavesPicked + 1
  2022.       end
  2023.     end
  2024.   end
  2025. end
  2026.  
  2027.  
  2028. --10_KTurtle.lua
  2029.  
  2030. -- ********************************************************************************** --
  2031. -- **   Krutoy Turtle Wrapper                                                      ** --
  2032. -- **   ----------------------------------------------------                       ** --
  2033. -- **                                                                              ** --
  2034. -- **   Wrap standart turtle functions but monitoring position and orientation     ** --
  2035. -- **   To get turtle pos and orient use Turtle.pos and Turtle.orient              ** --
  2036. -- **                                                                              ** --
  2037. -- ********************************************************************************** --
  2038.  
  2039. -- Enumeration to store names for the 6 directions
  2040. local way = {
  2041.   FORWARD=0,
  2042.   RIGHT  =1,
  2043.   BACK   =2,
  2044.   LEFT   =3,
  2045.   UP     =4,
  2046.   DOWN   =5
  2047. }
  2048.  
  2049.  
  2050.  
  2051. local oppositeWay = {[0]=2,3,0,1,5,4}
  2052.  
  2053. local attemptsToAlternative = 5
  2054. local attemptsToFailure = 7
  2055. local attemptsToIndicate = 15
  2056.  
  2057. local dataFilePath = "Krutoy/location"
  2058.  
  2059. -- Global Turtle variable
  2060. Turtle = {}
  2061. Turtle.__index = Turtle
  2062. math.randomseed(os.time())
  2063.  
  2064. -- Variables to store the current location and orientation of the turtle. x is right, left, z is up, down and
  2065. -- y is forward, back with relation to the starting orientation.
  2066. Turtle.orient = way.FORWARD
  2067.  
  2068. -- If turtle start moving in some direction, store it here
  2069. Turtle.moving = nil
  2070.  
  2071. Turtle.pos = vec3()        -- Start Pos is 0,0,0
  2072. Turtle.beacons  = {}       -- User-made points to route
  2073. Turtle.safe     = true     -- In this mode turtle will newer crush forbidden blocks
  2074. Turtle.oneWay   = arr3d()  -- An 3d array of points where we cant move some special ways
  2075. Turtle.safeZone = arr3d()  -- An 3d array of "safe" places, where we cant go with pickaxe
  2076. Turtle.alterZone= arr3d()  --
  2077. Turtle.world    = arr3d()  -- World of blocked positions for path finding
  2078.  
  2079. Turtle.lowFuelLevel = 300  -- Call onLowFuel function if above this
  2080.  
  2081. local surround = {
  2082. [way.FORWARD] = vec3( 0, 1, 0),
  2083. [way.RIGHT]   = vec3( 1, 0, 0),
  2084. [way.BACK]    = vec3( 0,-1, 0),
  2085. [way.LEFT]    = vec3(-1, 0, 0),
  2086. [way.UP]      = vec3( 0, 0, 1),
  2087. [way.DOWN]    = vec3( 0, 0,-1)
  2088. }
  2089.  
  2090. local cc_sides = {
  2091. [way.FORWARD] = "front",
  2092. [way.RIGHT]   = "right",
  2093. [way.BACK]    = "back",
  2094. [way.LEFT]    = "left",
  2095. [way.UP]      = "top",
  2096. [way.DOWN]    = "bottom"
  2097. }
  2098.  
  2099. local trtlOperationBySide = {
  2100. [way.FORWARD] = {turtle.forward, turtle.detect,     turtle.dig,     turtle.attack,     turtle.compare,     turtle.suck,     turtle.place,     turtle.inspect},
  2101. [way.UP]      = {turtle.up,      turtle.detectUp,   turtle.digUp,   turtle.attackUp,   turtle.compareUp,   turtle.suckUp,   turtle.placeUp,   turtle.inspectUp},
  2102. [way.DOWN]    = {turtle.down,    turtle.detectDown, turtle.digDown, turtle.attackDown, turtle.compareDown, turtle.suckDown, turtle.placeDown, turtle.inspectDown}
  2103. }
  2104.  
  2105. local thrash = {"minecraft:stone","minecraft:cobblestone","minecraft:dirt","minecraft:gravel","minecraft:grass","minecraft:sand"}
  2106.  
  2107. -- Call function only if it is function
  2108. local function safeCall(fnc, ...)
  2109.   if type(fnc)=='function' then fnc(...) end
  2110. end
  2111.  
  2112. -- Help function
  2113. local function addZoneInArray(arr, val, ...)
  2114.   local args = {...}
  2115.   local x1,y1,z1,x2,y2,z2
  2116.   -- Overload to working with vectors
  2117.   if type(args[1]) == 'table' and type(args[2]) == 'table' then
  2118.     x1,y1,z1,x2,y2,z2 = args[1]:unpack(), args[2]:unpack()
  2119.   else
  2120.     x1,y1,z1,x2,y2,z2 = ...
  2121.   end
  2122.   assert(x1 and y1 and z1 and x2 and y2 and z2, 'Wrong Turtle.addZone params')
  2123.  
  2124.  
  2125.   local sortFnc = function(n1,n2) if n2<n1 then return n2,n1 else return n1,n2 end end  
  2126.   x1,x2=sortFnc(x1,x2); y1,y2=sortFnc(y1,y2); z1,z2=sortFnc(z1,z2);
  2127.  
  2128.   for _z=0, z2-z1 do
  2129.     for _y=0, y2-y1 do
  2130.       for _x=0, x2-x1 do
  2131.         arr:set(x1+_x,y1+_y,z1+_z,val)
  2132.       end
  2133.     end
  2134.   end
  2135. end
  2136.  
  2137.  
  2138. -- Saving location and stats to file
  2139. function Turtle.removeData()
  2140.   fs.delete(dataFilePath)
  2141.  
  2142.   Turtle.pos    = vec3()
  2143.   Turtle.orient = way.FORWARD
  2144.   Turtle.moving = way.FORWARD
  2145.   Turtle.beacons= {}
  2146. end
  2147.  
  2148.  
  2149. -- Saving location and stats to file
  2150. function Turtle.saveData(movingDir)
  2151.   if movingDir then Turtle.moving = movingDir end
  2152.  
  2153.   local saveData = {
  2154.     x=Turtle.pos.x,
  2155.     y=Turtle.pos.y,
  2156.     z=Turtle.pos.z,
  2157.     orient=Turtle.orient,
  2158.     fuel=turtle.getFuelLevel(),
  2159.     moving=Turtle.moving,
  2160.     beacons=Turtle.beacons}
  2161.   local f = fs.open(dataFilePath, "w")
  2162.   f.write(table.toString(saveData))
  2163.   f.close()
  2164. end
  2165.  
  2166. -- Taken from
  2167. -- http://www.computercraft.info/forums2/index.php?/topic/19939
  2168. -- By Signify
  2169. function Turtle.loadData()
  2170.   --Checking for previous config...
  2171.   if fs.exists(dataFilePath) then
  2172.     local f = fs.open(dataFilePath, "r")
  2173.     local data = table.fromString(f.readAll())
  2174.     f.close()
  2175.  
  2176.     --Config found. Loading data
  2177.     --Checks to make sure turtle didn't move or do anything wonky after reboot
  2178.     local currentFuel = turtle.getFuelLevel()
  2179.     if data.fuel == currentFuel or data.fuel == currentFuel+1 then
  2180.       local oldState = {pos=Turtle.pos, orient=Turtle.orient}
  2181.       --Loading in the data since nothig bad happened
  2182.       Turtle.pos    = vec3(data.x, data.y, data.z)
  2183.       Turtle.orient = data.orient
  2184.       Turtle.moving = data.moving
  2185.      
  2186.       if data.fuel == currentFuel+1 then
  2187.         --Here, we've gotta fix a few things since the turtle did in fact, move
  2188.         Turtle.setPos(Turtle.getRelativeCoord(Turtle.moving))
  2189.       end
  2190.      
  2191.       -- Indicate that we are resuming
  2192.       if oldState.pos == Turtle.pos and Turtle.orient == oldState.orient then
  2193.         return false
  2194.       else
  2195.         Turtle.beacons = data.beacons
  2196.         for k,v in pairs(Turtle.beacons) do
  2197.           Turtle.beacons[k] = vec3(v)
  2198.         end
  2199.        
  2200.         return true
  2201.       end
  2202.     else
  2203.       --Looks like the fuel level changed by more than one. Wiping location knowledge
  2204.       Turtle.removeData()
  2205.     end
  2206.   end
  2207.   return false
  2208. end
  2209.  
  2210. -- ********************************************************************************** --
  2211. -- Add sector when we cant move in determined way
  2212. -- ********************************************************************************** --
  2213. function Turtle.addForbiddenWayZone(_way, _alter, ...)
  2214.   addZoneInArray(Turtle.oneWay, {_way, _alter}, ...)
  2215. end
  2216.  
  2217. -- ********************************************************************************** --
  2218. -- Add sector when we cant crushing blocks with pickaxe
  2219. -- ********************************************************************************** --
  2220. function Turtle.addSafeZone(...)
  2221.   addZoneInArray(Turtle.safeZone, true, ...)
  2222. end
  2223.  
  2224. -- ********************************************************************************** --
  2225. --
  2226. -- ********************************************************************************** --
  2227. function Turtle.addAlterZone(_alter, ...)
  2228.   addZoneInArray(Turtle.alterZone, _alter, ...)
  2229. end
  2230.  
  2231.  
  2232. -- ********************************************************************************** --
  2233. -- Sets the turtle coordinates
  2234. -- ********************************************************************************** --
  2235. function Turtle.setPos(...)
  2236.   local args = {...}
  2237.   local x,y,z
  2238.  
  2239.   -- Overload to working with vectors
  2240.   if type(args[1]) == 'table' then
  2241.     x,y,z = args[1]:unpack()
  2242.   else
  2243.     x,y,z = ...
  2244.   end
  2245.   assert(x and y and z, 'Wrong Turtle.setPos() params')
  2246.  
  2247.   Turtle.pos = vec3(x,y,z)
  2248.   Turtle.saveData()
  2249. end
  2250.  
  2251. -- ********************************************************************************** --
  2252. -- Sets the turtle to a specific orientation, irrespective of its current orientation
  2253. -- ********************************************************************************** --
  2254. function Turtle.setOrient(newOrient)
  2255.  
  2256.   -- Already turned
  2257.   if (Turtle.orient == newOrient) then return true end
  2258.  
  2259.  
  2260.   -- Wrong parameters - we cant turn up or down
  2261.   if newOrient < 0 or newOrient > way.LEFT then
  2262.     error("Invalid newOrient in Turtle.setOrient function")
  2263.     return false
  2264.   end
  2265.  
  2266.   local turn = Turtle.orient - newOrient
  2267.   local turnFnc
  2268.  
  2269.   if turn==1 or turn==-3 then
  2270.     turnFnc = Turtle.turnLeft
  2271.   else
  2272.     turnFnc = Turtle.turnRight
  2273.   end
  2274.  
  2275.   turn = math.abs(turn)
  2276.   if(turn==3) then turn=1 end
  2277.  
  2278.   for i=1, turn do turnFnc() end
  2279.  
  2280.   return true
  2281. end
  2282.  
  2283. -- ********************************************************************************** --
  2284. --
  2285. -- ********************************************************************************** --
  2286. function Turtle.turnRight()
  2287.   turtle.turnRight()
  2288.   Turtle.orient = (Turtle.orient + 1)%4
  2289.   Turtle.saveData()
  2290.   return true
  2291. end
  2292. function Turtle.turnLeft()
  2293.   turtle.turnLeft()
  2294.   Turtle.orient = (Turtle.orient + 3)%4
  2295.   Turtle.saveData()
  2296.   return true
  2297. end
  2298.  
  2299. --===========================================================
  2300. -- Test name for thrashed ore
  2301. --===========================================================
  2302. function Turtle.isThrash(name)
  2303.   if type(name) == "string" then
  2304.     for i=1,#thrash do
  2305.       if thrash[i] == name then return true end
  2306.     end
  2307.   end
  2308.   return false
  2309. end
  2310.  
  2311.  
  2312. --===========================================================
  2313. -- Determine when turtle have very low fuel
  2314. --===========================================================
  2315. function Turtle.isLowFuel()
  2316.   return  turtle.getFuelLevel() <= Turtle.lowFuelLevel
  2317. end
  2318.  
  2319. --===========================================================
  2320. -- Dig, depending on direction
  2321. --===========================================================
  2322. local digFncArr = {[way.FORWARD]=turtle.dig, [way.DOWN]=turtle.digDown, [way.UP]=turtle.digUp}
  2323. function Turtle.dig(direction)
  2324.   direction = direction or way.FORWARD -- Optional param
  2325.   assert(direction == way.DOWN or direction == way.UP or direction == way.FORWARD, 'Wrong params in Turtle.dig()')
  2326.    
  2327.   return digFncArr[direction]()
  2328. end
  2329.  
  2330. --===========================================================
  2331. -- Dig only ore
  2332. --===========================================================
  2333. function Turtle.mine(direction)
  2334.   direction = direction or way.FORWARD -- Optional param
  2335.   assert(direction == way.DOWN or direction == way.UP or direction == way.FORWARD, 'Wrong params in Turtle.mine()')
  2336.  
  2337.   local inspectFc = trtlOperationBySide[direction][8]
  2338.   local _,blockData = inspectFc()
  2339.   local blockName = blockData and blockData.name
  2340.   if Turtle.isThrash(blockName) then
  2341.     return false
  2342.   else
  2343.     return digFncArr[direction]()
  2344.   end
  2345. end
  2346.  
  2347. -- ********************************************************************************** --
  2348. -- Generic function to move the Turtle (pushing through any gravel or other
  2349. -- things such as mobs that might get in the way).
  2350. --
  2351. -- The only thing that should stop the turtle moving is bedrock. Where this is
  2352. -- found, the function will return after 15 seconds returning false
  2353. -- ********************************************************************************** --
  2354. function Turtle.move(direction, doNotTurnBack)
  2355.   local straightDirection = (direction == way.FORWARD or direction == way.UP or direction == way.DOWN)
  2356.  
  2357.   local isReceding = (direction == way.BACK)
  2358.   local tmpDir = straightDirection and direction or way.FORWARD
  2359.   local moveFn, detectFn, digFn, attackFn,_,_,_, inspectFn = unpack(trtlOperationBySide[tmpDir])
  2360.  
  2361.  
  2362.   local destination = Turtle.getRelativeCoord(direction)
  2363.   local newX, newY, newZ = destination:unpack()
  2364.  
  2365.   -- Low fuel event
  2366.   if Turtle.isLowFuel() then
  2367.     safeCall(Turtle.onLowFuel, newX, newY, newZ, direction)
  2368.   end
  2369.  
  2370.   -- Flag to determine whether digging has been tried yet. If it has
  2371.   -- then pause briefly before digging again to allow sand or gravel to drop
  2372.   local attempt = 0
  2373.  
  2374.   -- Raise event if we try to move
  2375.   safeCall(Turtle.onMove, attempt, newX, newY, newZ, direction)
  2376.   safeCall(Turtle.onMoveAttempt, attempt, newX, newY, newZ, direction)
  2377.  
  2378.   -- Check if this move is forbidden. In this case change move to other way
  2379.   local forbid = Turtle.oneWay(Turtle.pos:unpack())
  2380.   if forbid ~= nil and forbid[1] == Turtle.getIrrespectiveOrient(direction) then
  2381.     return Turtle.move(Turtle.getRelativeOrient(forbid[2]), doNotTurnBack)
  2382.   end
  2383.  
  2384.   -- Speciall kind of sides
  2385.   local oldOrient= Turtle.orient
  2386.   if not straightDirection then
  2387.     if direction == way.RIGHT then Turtle.turnRight() end
  2388.     if direction == way.LEFT  then Turtle.turnLeft()  end
  2389.     direction = way.FORWARD
  2390.   end
  2391.  
  2392.  
  2393.   local moveWithSave = function(mFn)
  2394.     Turtle.saveData(direction)
  2395.     return mFn()
  2396.   end
  2397.  
  2398.  
  2399.   local moveSuccess = false
  2400.   if isReceding then
  2401.     moveSuccess = moveWithSave(turtle.back)
  2402.   else
  2403.     moveSuccess = moveWithSave(moveFn)
  2404.   end
  2405.  
  2406.  
  2407.   -- Check if we want to move into safe zone. In this case dig will be turned off
  2408.   local safe = Turtle.safe or Turtle.safeZone(destination:unpack())
  2409.  
  2410.   -- Loop until we've successfully moved
  2411.   while not moveSuccess do
  2412.  
  2413.     -- We had too many attempts. Now we can only make error
  2414.     if attempt >= attemptsToFailure then
  2415.       safeCall(Turtle.onMoveFailure, newX, newY, newZ, direction)
  2416.     end
  2417.    
  2418.     -- Check if this move is forbidden. In this case change move to other way
  2419.     if attempt >= attemptsToAlternative then
  2420.       local alternative = Turtle.alterZone(Turtle.pos:unpack())
  2421.       local irrOrient = Turtle.getIrrespectiveOrient(direction)
  2422.       if alternative ~= nil and
  2423.          alternative ~= irrOrient and
  2424.          alternative ~= oppositeWay[irrOrient] then
  2425.         return Turtle.move(Turtle.getRelativeOrient(alternative), doNotTurnBack)
  2426.       end
  2427.     end
  2428.    
  2429.     -- Show that we are stuked a bit. Turn 360*
  2430.     if attempt>1 and attempt % attemptsToIndicate == 0 then
  2431.       for i=1,4 do Turtle.turnRight() end
  2432.     end
  2433.    
  2434.     -- Turn face to distraction to dig it if we are go backwards
  2435.     if isReceding then
  2436.       Turtle.turnRight(); Turtle.turnRight(); direction = way.FORWARD
  2437.       isReceding = false
  2438.     end
  2439.  
  2440.     -- If there is a block in front, dig it
  2441.     if detectFn() == true then
  2442.       if safe then
  2443.         -- If this is safe zone, we can dig anything except turtles
  2444.         local _, data = inspectFn()
  2445.         if data and data.name and not data.name:find("turtle") then
  2446.           digFn()
  2447.         end
  2448.       else
  2449.         digFn()
  2450.       end
  2451.     else
  2452.       -- Am being stopped from moving by a mob, attack it
  2453.       attackFn()
  2454.     end
  2455.  
  2456.     -- Raise event if we try to move
  2457.     safeCall(Turtle.onMoveAttempt, attempt, newX, newY, newZ, direction)
  2458.      
  2459.     -- Try the move again
  2460.     moveSuccess = moveWithSave(moveFn)
  2461.    
  2462.     attempt = attempt + 1
  2463.    
  2464.     -- Random sleep between attempts
  2465.     if not moveSuccess then sleep(math.random()/10+0.1) end
  2466.   end
  2467.  
  2468.   Turtle.setPos(destination)
  2469.  
  2470.   -- Turn turtle back on origin orient
  2471.   if not straightDirection and doNotTurnBack ~= true then
  2472.     Turtle.setOrient(oldOrient)
  2473.   end
  2474.  
  2475.   -- Return the move success
  2476.   return moveSuccess
  2477. end
  2478.  
  2479. function Turtle.forward() return Turtle.move(way.FORWARD) end
  2480. function Turtle.up()      return Turtle.move(way.UP) end
  2481. function Turtle.down()    return Turtle.move(way.DOWN) end
  2482. function Turtle.back(doNotTurnBack)  return Turtle.move(way.BACK,  doNotTurnBack) end
  2483. function Turtle.left(doNotTurnBack)  return Turtle.move(way.LEFT,  doNotTurnBack) end
  2484. function Turtle.right(doNotTurnBack) return Turtle.move(way.RIGHT, doNotTurnBack) end
  2485.  
  2486. -- ********************************************************************************** --
  2487. -- Get relativety position from direction of turtle
  2488. -- ********************************************************************************** --
  2489. function Turtle.getRelativeCoord(direct)
  2490.   -- Return direction with displace
  2491.   return Turtle.pos + surround[Turtle.getIrrespectiveOrient(direct)]
  2492. end
  2493.  
  2494. -- ********************************************************************************** --
  2495. -- Get relativety position from direction of turtle
  2496. -- ********************************************************************************** --
  2497. function Turtle.getIrrespectiveOrient(direct)
  2498.   if direct == way.UP or direct == way.DOWN then
  2499.     return direct
  2500.   else
  2501.     return (Turtle.orient + direct)%4
  2502.   end
  2503. end
  2504.  
  2505. function Turtle.getRelativeOrient(direct)
  2506.   if direct == way.UP or direct == way.DOWN then
  2507.     return direct
  2508.   else
  2509.     return math.abs(Turtle.orient - direct)%4
  2510.   end
  2511. end
  2512.  
  2513.  
  2514.  
  2515. --===========================================================
  2516. -- Find path to coordinates, avoid block listed cells
  2517. -- Using A* algorithm http://pastebin.com/CHCB8nDz
  2518. --===========================================================
  2519. function Turtle.pathTo(...)
  2520.   local args = {...}
  2521.   local x,y,z
  2522.  
  2523.   -- Overload to working with vectors
  2524.   if type(args[1]) == 'string' then
  2525.     if Turtle.beacons[args[1]] then
  2526.       x,y,z = Turtle.beacons[args[1]]:unpack()
  2527.     else
  2528.       return false
  2529.     end
  2530.   elseif type(args[1]) == 'table' then
  2531.     x,y,z = args[1]:unpack()
  2532.   else
  2533.     x,y,z = ...
  2534.   end
  2535.   assert(x and y and z, 'Wrong Turtle.pathTo() params')
  2536.  
  2537.   -- Already here!
  2538.   if Turtle.pos.x==x and Turtle.pos.y==y and Turtle.pos.z==z then return true end
  2539.  
  2540.   -- Get first crumb of path
  2541.   local crumb = AStarFindPath(Turtle.world, Turtle.pos, vec3(x,y,z))
  2542.  
  2543.   if crumb then
  2544.     -- Run over all crumbs
  2545.     while crumb.next ~= nil do
  2546.       crumb = crumb.next
  2547.       Turtle.goTo(crumb.pos.x,crumb.pos.y,crumb.pos.z)
  2548.     end
  2549.   else
  2550.     -- Path cant be found. Move straight
  2551.     error("Path cant be found! From:".. tostring(vec3(Turtle.pos.x,Turtle.pos.y,Turtle.pos.z)) .." To:" ..tostring(vec3(x,y,z)))
  2552.   end
  2553.  
  2554. end
  2555.  
  2556. --===========================================================
  2557. -- Move turtle on needed position
  2558. -- Simple move by x, then y, then z
  2559. -- args can be vector or three parameters x,y,z
  2560. --===========================================================
  2561. function Turtle.goTo(...)
  2562.   local args = {...}
  2563.   local x,y,z
  2564.  
  2565.   -- Overload to working with vectors
  2566.   if type(args[1]) == 'string' then
  2567.     if Turtle.beacons[args[1]] then
  2568.       x,y,z = Turtle.beacons[args[1]]:unpack()
  2569.     else
  2570.       return false
  2571.     end
  2572.   elseif type(args[1]) == 'table' then
  2573.     x,y,z = args[1]:unpack()
  2574.   else
  2575.     x,y,z = ...
  2576.   end
  2577.   assert(x and y and z, 'Wrong Turtle.goTo() params')
  2578.  
  2579.   local targetPos = vec3(x,y,z)
  2580.   local targetVec = targetPos - Turtle.pos
  2581.  
  2582.   -- We need additional loop for cases of one way roads
  2583.   while not (targetPos == Turtle.pos) do
  2584.  
  2585.     -- X
  2586.     while Turtle.pos.x ~= x do
  2587.       if (targetVec.x<0 and Turtle.orient==way.RIGHT)   or
  2588.          (targetVec.x>0 and Turtle.orient==way.LEFT)    then
  2589.         Turtle.back(true)
  2590.       elseif (x<Turtle.pos.x) then
  2591.         Turtle.setOrient(way.LEFT)
  2592.         Turtle.forward()
  2593.       elseif (x>Turtle.pos.x) then
  2594.         Turtle.setOrient(way.RIGHT)
  2595.         Turtle.forward()
  2596.       end
  2597.     end
  2598.    
  2599.    
  2600.    
  2601.     -- Y
  2602.     while Turtle.pos.y ~= y do
  2603.       if(targetVec.y<0 and Turtle.orient==way.FORWARD) or
  2604.         (targetVec.y>0 and Turtle.orient==way.BACK)    then
  2605.         Turtle.back(true)
  2606.       elseif (y<Turtle.pos.y) then
  2607.         Turtle.setOrient(way.BACK)
  2608.         Turtle.forward()
  2609.       elseif (y>Turtle.pos.y) then
  2610.         Turtle.setOrient(way.FORWARD)
  2611.         Turtle.forward()
  2612.       end
  2613.     end
  2614.    
  2615.    
  2616.     -- Z
  2617.     while (z<Turtle.pos.z) do
  2618.       Turtle.down()
  2619.     end
  2620.     while (z>Turtle.pos.z) do
  2621.       Turtle.up()
  2622.     end
  2623.   end
  2624.  
  2625.   return true
  2626. end
  2627.  
  2628. -- ********************************************************************************** --
  2629. -- Add point for easy acces
  2630. -- ********************************************************************************** --
  2631. function Turtle.setBeacon(beaconName, _x,_y,_z)
  2632.   Turtle.beacons[beaconName] = vec3(_x,_y,_z)
  2633.   Turtle.saveData()
  2634. end
  2635.  
  2636.  
  2637. -- ********************************************************************************** --
  2638. -- Select non-empty slot
  2639. -- ********************************************************************************** --
  2640. function Turtle.selectNonEmptySlot()
  2641.   for i=1, 16 do
  2642.     if( turtle.getItemCount(i) > 0) then
  2643.       turtle.select(i)
  2644.       return true
  2645.     end
  2646.   end
  2647.   return false
  2648. end
  2649.  
  2650.  
  2651. -- ********************************************************************************** --
  2652. -- Select empty slot
  2653. -- ********************************************************************************** --
  2654. function Turtle.selectEmptySlot()
  2655.   for i=1, 16 do
  2656.     if( turtle.getItemCount(i) == 0) then
  2657.       turtle.select(i)
  2658.       return true
  2659.     end
  2660.   end
  2661.   return false
  2662. end
  2663.  
  2664. -- ********************************************************************************** --
  2665. -- Select slot with data name as pattern
  2666. -- ********************************************************************************** --
  2667. function Turtle.select(str, isPattern)
  2668.   for i=1, 16 do
  2669.     if turtle.getItemCount(i) > 0 then
  2670.       local data = turtle.getItemDetail(i)
  2671.       if data and data.name then
  2672.         if isPattern then
  2673.           if data.name:find(str) then turtle.select(i); return i end
  2674.         else
  2675.           if data.name == str then turtle.select(i); return i end
  2676.         end
  2677.       end
  2678.     end
  2679.   end
  2680.   return nil
  2681. end
  2682.  
  2683.  
  2684. -- ********************************************************************************** --
  2685. -- Inspect item using direction
  2686. -- ********************************************************************************** --
  2687. function Turtle.inspect(direction)
  2688.   assert(direction==way.FORWARD or direction==way.UP or direction==way.DOWN, 'Wrong Turtle.inspect() params')
  2689.   return trtlOperationBySide[direction][8]()
  2690. end
  2691.  
  2692. -- ********************************************************************************** --
  2693. -- Place item. Check if item already placed.
  2694. -- ********************************************************************************** --
  2695. function Turtle.place(itemSlot, direction, noChecks)
  2696.   direction = direction or way.FORWARD
  2697.   assert(direction==way.FORWARD or direction==way.UP or direction==way.DOWN, 'Wrong Turtle.place() params')
  2698.  
  2699.   local _, detectFnc, _, attackFnc, compareFnc, _, placeFnc = unpack(trtlOperationBySide[direction])
  2700.   noChecks = noChecks or false
  2701.  
  2702.   -- slotsPattern is array of 16 nubbers that represent
  2703.   -- what kind of blocks lying in what kind of
  2704.   if itemSlot then
  2705.     turtle.select(itemSlot)
  2706.   end
  2707.  
  2708.   local placeSucces = false
  2709.   local digCount = 0
  2710.   local maxDigCount = 20
  2711.   local attempt = 0
  2712.  
  2713.  
  2714.   -- Check if there is already item  then try to place
  2715.   placeSucces = placeFnc()
  2716.  
  2717.   if noChecks then return placeSucces end
  2718.  
  2719.   if (not placeSucces) and detectFnc()  then
  2720.     if(compareFnc()) then
  2721.       -- Item that we must set already here
  2722.       return true
  2723.     else
  2724.       -- There is something else. Dig/Attack and place item
  2725.       Turtle.dig(direction)
  2726.       digCount = digCount + 1
  2727.     end
  2728.   end
  2729.  
  2730.   -- Now try to place item until item will placed
  2731.   while ((placeSucces == false) and (digCount < maxDigCount)) and attempt < attemptsToFailure do
  2732.     if (detectFnc()) then
  2733.       if(digCount > 0) then
  2734.         sleep(0.4)
  2735.       end
  2736.       Turtle.dig(direction)
  2737.       digCount = digCount + 1
  2738.     else
  2739.        -- Am being stopped from moving by a mob, attack it
  2740.        attackFnc()
  2741.     end
  2742.     -- Try the place again
  2743.     placeSucces = placeFnc()
  2744.    
  2745.     attempt = attempt + 1
  2746.   end
  2747.  
  2748.   return placeSucces
  2749. end
  2750.  
  2751.  
  2752. --===========================================================
  2753. -- Touching is way to communicate with other turtles
  2754. -- using redstone signals 0-15
  2755. --===========================================================
  2756. local sidesList = {"top", "bottom", "left", "right", "front", "back"}
  2757. function Turtle.touch(strenght, direction, sleepTime)
  2758.   direction = direction or way.FORWARD -- Optional param
  2759.   sleepTime = sleepTime or 0.1
  2760.  
  2761.  
  2762.   if direction == -1 then
  2763.     local oldOut = {}
  2764.     for i=1, #sidesList do
  2765.       insert(oldOut, rs.getAnalogOutput(sidesList[i]))
  2766.       rs.setAnalogOutput(sidesList[i], strenght)
  2767.     end
  2768.     sleep(sleepTime)
  2769.     for i=1, #sidesList do
  2770.       rs.setAnalogOutput(sidesList[i], oldOut[i])
  2771.     end
  2772.   else
  2773.     local oldOutput = rs.getAnalogOutput(cc_sides[direction])
  2774.     rs.setAnalogOutput(cc_sides[direction], strenght)
  2775.     sleep(sleepTime)
  2776.     rs.setAnalogOutput(cc_sides[direction], oldOutput)
  2777.   end
  2778. end
  2779.  
  2780. --===========================================================
  2781. -- Feel the touches
  2782. --===========================================================
  2783. function Turtle.sense(direction, timeout)
  2784.   direction = direction or way.FORWARD -- Optional param
  2785.  
  2786.   -- Start the timer
  2787.   local timer, sFilter
  2788.   if nTimeout then
  2789.     timer = os.startTimer( timeout )
  2790.   else
  2791.     sFilter = "redstone"
  2792.   end
  2793.  
  2794.   while true do
  2795.     local sEvent, p1, p2, p3, p4, p5 = os.pullEvent( sFilter )
  2796.    
  2797.     if sEvent == "redstone" then
  2798.       if direction == -1 then
  2799.         for i=1, #sidesList do
  2800.           local strenght = rs.getAnalogInput(sidesList[i])
  2801.           if strenght > 0 then return strenght, sidesList[i] end
  2802.         end
  2803.       else
  2804.         local strenght = rs.getAnalogInput(cc_sides[direction])
  2805.         if strenght > 0 then return strenght end
  2806.       end
  2807.     elseif sEvent == "timer" then
  2808.       -- Return nil if we timeout
  2809.       if p1 == timer then
  2810.         return nil
  2811.       end
  2812.     end
  2813.   end
  2814. end
  2815.  
  2816. --20_KUI.lua
  2817.  
  2818. -- ********************************************************************************** --
  2819. -- **   UI class for program "KrutoyTurtle"                                        ** --
  2820. -- **                                                                              ** --
  2821. -- ********************************************************************************** --
  2822.  
  2823. --[[
  2824. ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2825. ░_____________Final info______________░
  2826. ░-Slaves:      64                     ░
  2827. ░-Total Volume:30000                  ░
  2828. ░-Est. time:   90 min                 ░
  2829. ░-More info:   bla bla                ░
  2830. ░___________Blocks by type____________░
  2831. ░#1 : 99s+50  #2 : 99s+50  #3 : 99s+50░
  2832. ░#4 : 99s+50  #5 : 99s+50  #6 : 99s+50░
  2833. ░#7 : 99s+50  #8 : 99s+50  #9 : 99s+50░
  2834. ░#10: 99s+50  #11: 99s+50  #12: 99s+50░
  2835. ░#13: 99s+50  #14: 99s+50  #15: 99s+50░
  2836. ░#16: 99s+50  #16: 99s+50  #16: 99s+50░
  2837. ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2838.  
  2839. ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2840. ░                                     ░
  2841. ░           KRUTOY TURTLE             ░
  2842. ░_____________________________________░
  2843. ░ Fill options:                       ░
  2844. ░                                     ░
  2845. ░  Pattern: Plain                     ░
  2846. ░     Size: 5 5 6                     ░
  2847. ░    Flags: mine, tidy, dock          ░
  2848. ░                                     ░
  2849. ░Help:                                ░
  2850. ░ Navigate - TAB, arrows              ░
  2851. ░ Refuel - R, Console - ~     [Next>>]░
  2852. ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2853.  
  2854. ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2855. ░__________Select pattern:____________░
  2856. ░ 1 - Plain                           ░
  2857. ░ 2 - BoxGrid                         ░
  2858. ░ 3 - MyFirstTample.vox               ░
  2859. ░                                     ░
  2860. ░                                     ░
  2861. ░                                     ░
  2862. ░                                     ░
  2863. ░                                     ░
  2864. ░                                     ░
  2865. ░                                     ░
  2866. ░                                     ░
  2867. ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2868.  
  2869.  
  2870. ]]
  2871.  
  2872. KUI = {}
  2873. KUI.__index = KUI
  2874.  
  2875. local sub = string.sub
  2876.  
  2877. local borderStylesStr = {
  2878.   ['selectedBtn']= '/\\/\\  ||',
  2879.   ['standart']   = '++++--||',
  2880.   ['none']       = '        ',
  2881.   ['inlineBtn']  = '[]][    '
  2882. }
  2883. -- Transform string to array
  2884. local borderStyles = {}
  2885. for k,v in pairs(borderStylesStr) do
  2886.   borderStyles[k] = {}
  2887.   local styleStr = v
  2888.   for i = 1, #styleStr do
  2889.     borderStyles[k][i] = (styleStr:sub(i,i))
  2890.   end
  2891. end
  2892.  
  2893.  
  2894. local alignTypes = {'left', 'right', 'center'}
  2895.  
  2896. KUI.items = {} -- Array of UI elements
  2897. KUI.selectedObj = nil -- Currently selected item
  2898. KUI.currentWindow = nil -- Current drawing window
  2899.  
  2900.  
  2901.  
  2902. -- Repeat char many as need times to make string
  2903. local function repeatChar(char, count)
  2904.   local returnString = ''
  2905.   for _=0, count-1 do
  2906.     returnString = returnString..char
  2907.   end
  2908.   return returnString
  2909. end
  2910.  
  2911.  
  2912. function KUI.drawText(text, x,y, w,h, align)
  2913.   align = align or 'center'
  2914.  
  2915.   -- String params
  2916.   local textLinesCount = 1 + select(2, text:gsub('\n', '\n'))
  2917.  
  2918.   -- Top spaces
  2919.   local vertSpace = (h-textLinesCount)/2
  2920.   local clearLine = repeatChar(' ', w)
  2921.   for _=1, math.floor(vertSpace) do
  2922.     term.setCursorPos(x, y)
  2923.     term.write(clearLine)
  2924.   end
  2925.  
  2926.   -- Bottom spaces
  2927.   for _=1, math.ceil (vertSpace) do
  2928.     term.setCursorPos(x, y+h-1)
  2929.     term.write(clearLine)
  2930.   end  
  2931.  
  2932.   -- Write lines
  2933.   local currLine = 0
  2934.   for l in text:gmatch('[^\r\n]+') do
  2935.     local margin = {0,0} -- Spaces from left and right
  2936.     local horisSpace = (w - #l)
  2937.    
  2938.     -- Align styles
  2939.     if    (align == 'left') then
  2940.       margin = {0, horisSpace}
  2941.     elseif(align == 'right')then
  2942.       margin = {horisSpace, 0}
  2943.     elseif(align == 'center')then
  2944.       margin = {math.floor(horisSpace/2), math.ceil(horisSpace/2)}
  2945.     end
  2946.    
  2947.     term.setCursorPos(x, y+currLine)
  2948.     term.write( repeatChar(' ',margin[1])..l..repeatChar(' ',margin[2]))
  2949.     currLine = currLine+1
  2950.   end
  2951. end
  2952.  
  2953. -- Draw simple panel with borders
  2954. function KUI.drawPanel(x,y, w,h, borderStyle)
  2955.   borderStyle = borderStyle or 'standart'
  2956.   local styleArr = borderStyles[borderStyle]
  2957.  
  2958.   -- Horisontal lines
  2959.   if(h > 1) then
  2960.     term.setCursorPos(x, y)
  2961.     term.write(styleArr[1]..repeatChar(styleArr[5], w-2)..styleArr[2])
  2962.     term.setCursorPos(x, y+h-1)
  2963.     term.write(styleArr[4]..repeatChar(styleArr[6], w-2)..styleArr[3])
  2964.   elseif h==1 then
  2965.     term.setCursorPos(x, y);     term.write(styleArr[1])
  2966.     term.setCursorPos(x+w-1, y); term.write(styleArr[2])
  2967.   end
  2968.  
  2969.   -- Vertical lines
  2970.   for i=0,h-3 do
  2971.     term.setCursorPos(x, y+i+1)
  2972.     term.write(styleArr[7])
  2973.     term.setCursorPos(x+w-1, y+i+1)
  2974.     term.write(styleArr[8])
  2975.   end
  2976.  
  2977. end
  2978.  
  2979. -- Draw panel with text
  2980. function KUI.drawTextPanel(text, x,y, w,h, borderStyle, align)
  2981.   KUI.drawPanel(x,y, w,h, borderStyle)
  2982.  
  2983.   if borderStyle == 'none' then
  2984.     KUI.drawText(text, x,y+((h>1) and 1 or 0), w,h, align)
  2985.   else
  2986.     KUI.drawText(text, x+1,y+((h>1) and 1 or 0), w-2,h, align)
  2987.   end
  2988. end
  2989.  
  2990. -- ********************************************************************************** --
  2991. -- Add gui element to current window
  2992. -- ********************************************************************************** --
  2993. function KUI.add(obj)
  2994.   -- Standart values
  2995.   obj.borderStyle = obj.borderStyle or 'standart'
  2996.   obj.align       = obj.align       or 'center'
  2997.   obj.padding     = obj.padding     or {0,0,0,0}
  2998.  
  2999.   -- Add additional info
  3000.   obj.center = {x=obj.x+obj.w/2, y=obj.y+obj.h/2}
  3001.  
  3002.   obj.nextTab = KUI.items[1] or obj
  3003.   if(#KUI.items >= 1) then
  3004.   KUI.items[#KUI.items].nextTab = obj
  3005.   end
  3006.  
  3007.   if obj.type == 'button' or obj.type == 'input' then
  3008.     obj.selectable = true
  3009.   end
  3010.  
  3011.   table.insert(KUI.items, obj)
  3012. end
  3013.  
  3014. -- ********************************************************************************** --
  3015. -- Set new window. Add all objects in list to screen
  3016. -- ********************************************************************************** --
  3017. function KUI.setWindow(window, selectedId)
  3018.   KUI.items = {}
  3019.   KUI.selectedObj = nil
  3020.   KUI.currentWindow = window
  3021.   for _,obj in pairs(window) do
  3022.     KUI.add(obj)
  3023.    
  3024.     if obj.id == selectedId then KUI.selectedObj = obj end
  3025.   end
  3026.   KUI.selectedObj = KUI.selectedObj or KUI.items[1]
  3027.   KUI.draw()
  3028. end
  3029.  
  3030. -- ********************************************************************************** --
  3031. -- Clears screen and write message in center
  3032. -- ********************************************************************************** --
  3033. function KUI.msgBox(str)
  3034.  
  3035. end
  3036.  
  3037. -- ********************************************************************************** --
  3038. -- Draw all objects in list
  3039. -- ********************************************************************************** --
  3040. function KUI.draw()
  3041.   term.clear()
  3042.   for _,obj in pairs(KUI.items) do
  3043.    
  3044.     -- Switch type
  3045.     if     obj.type == 'panel' then
  3046.       KUI.drawPanel(obj.x,obj.y, obj.w,obj.h, obj.borderStyle)
  3047.     elseif obj.type == 'text' then
  3048.       KUI.drawText(obj.text,
  3049.         obj.x+obj.padding[4],
  3050.         obj.y+obj.padding[1],
  3051.         obj.w-obj.padding[2]-obj.padding[4],
  3052.         obj.h-obj.padding[1]-obj.padding[3],
  3053.         obj.align)
  3054.     elseif obj.type == 'textPanel' or obj.type == 'button' or obj.type == 'input' then
  3055.       KUI.drawTextPanel(obj.text,
  3056.         obj.x+obj.padding[4],
  3057.         obj.y+obj.padding[1],
  3058.         obj.w-obj.padding[2]-obj.padding[4],
  3059.         obj.h-obj.padding[1]-obj.padding[3],
  3060.         obj.borderStyle, obj.align)
  3061.     else
  3062.      
  3063.     end
  3064.    
  3065.     -- This object is selected and selectable
  3066.     if KUI.selectedObj == obj and obj.selectable == true then
  3067.       KUI.drawPanel(obj.x-1,
  3068.                     obj.y,
  3069.                     obj.w+2+obj.padding[2]+obj.padding[4],
  3070.                     obj.h  +obj.padding[1]+obj.padding[3], 'inlineBtn')
  3071.     end
  3072.    
  3073.   end
  3074.  
  3075.   -- Set Cursor
  3076.   local selObj = KUI.selectedObj
  3077.   if selObj.type == 'input' then
  3078.     term.setCursorPos(selObj.x+selObj.padding[4]+#selObj.text, selObj.y+selObj.padding[1])
  3079.     term.setCursorBlink(true)
  3080.   else
  3081.     term.setCursorBlink(false)
  3082.   end
  3083.  
  3084.   sleep(0)
  3085. end
  3086.  
  3087. function KUI.navigate()
  3088.   while true do
  3089.     local e, keyCode = os.pullEvent('key')
  3090.    
  3091.     -- Call user-defined event
  3092.     if KUI.onKeyPressed then KUI.onKeyPressed(keyCode) end
  3093.    
  3094.     -- Input line
  3095.     local selObj = KUI.selectedObj
  3096.     if selObj ~= nil and selObj.type == 'input' then
  3097.       local keyMap = {"",1,2,3,4,5,6,7,8,9,0,"-",[57]=" "}
  3098.       if keyMap[keyCode] ~= nil then
  3099.         selObj.text = selObj.text .. keyMap[keyCode]
  3100.         KUI.draw()
  3101.       elseif keyCode == 14 then -- BACKSPACE
  3102.         selObj.text = selObj.text:sub(1,#selObj.text-1)
  3103.         KUI.draw()
  3104.       end
  3105.     end
  3106.    
  3107.     if     keyCode == 200 then --UP
  3108.       KUI.prevTab()
  3109.     elseif keyCode == 203 then --LEFT
  3110.      
  3111.     elseif keyCode == 205 then --RIGHT
  3112.      
  3113.     elseif keyCode == 15 or keyCode == 208 then --TAB --DOWN
  3114.       KUI.nextTab()
  3115.     elseif keyCode == 28  then --ENTER
  3116.       if selObj ~= nil then
  3117.         return selObj.id, selObj
  3118.       end
  3119.     end
  3120.   end
  3121. end
  3122.  
  3123. function KUI.nextTab()
  3124.   local oldSelectedObj = KUI.selectedObj
  3125.   KUI.selectedObj = KUI.selectedObj.nextTab
  3126.   while KUI.selectedObj.selectable ~= true and oldSelectedObj ~= KUI.selectedObj do
  3127.     KUI.selectedObj = KUI.selectedObj.nextTab
  3128.   end
  3129.   KUI.draw()
  3130. end
  3131.  
  3132. function KUI.prevTab()
  3133.   local oldSelectedObj = KUI.selectedObj
  3134.   local nextTab = KUI.selectedObj.nextTab
  3135.   local lastSelectable = (nextTab.selectable == true) and nextTab or oldSelectedObj
  3136.   while oldSelectedObj ~= nextTab.nextTab do
  3137.     nextTab = nextTab.nextTab
  3138.     if nextTab.selectable == true then lastSelectable = nextTab end
  3139.   end
  3140.   KUI.selectedObj = lastSelectable
  3141.   KUI.draw()
  3142. end
  3143.  
  3144. --30_Swarm.lua
  3145.  
  3146. -- ********************************************************************************** --
  3147. -- **   ZeroSwarm                                                                  ** --
  3148. -- **   with help from ZeroGalaxy                                                  ** --
  3149. -- **   ----------------------------------------------------                       ** --
  3150. -- **                                                                              ** --
  3151. -- **   Swapping messages with turtles to make band                                ** --
  3152. -- **   for KrutoyTurtle                                                           ** --
  3153. -- **                                                                              ** --
  3154. -- ********************************************************************************** --
  3155.  
  3156. -- Looks like a class
  3157. swarm = {}
  3158. swarm.__index = swarm
  3159.  
  3160. -- Locals
  3161. local CHANNEL_BROADCAST = 65535
  3162. local CHANNEL_REPEAT = 65533
  3163. local modemOpened = false
  3164. local MASTERMESSAGE = 'I AM YOUR MASTER. OBEY!'
  3165. local GETOUTMESSAGE = 'GET OUT!'
  3166. local masterId
  3167. local slaves = {}
  3168. local modem
  3169. local uniqueID = math.floor(os.time()*1000) % 65530 -- SIC!
  3170. if not os.getComputerLabel() then os.setComputerLabel("KT"..uniqueID) end
  3171. local hashes = {} -- Set of all hashes that had been received
  3172.  
  3173. -- Required to open channels before working with modem
  3174. local function openModem()
  3175.   if modemOpened then return true end
  3176.    
  3177.   for n,sSide in ipairs( rs.getSides() ) do
  3178.     if rednet.isOpen( sSide ) then
  3179.       modemOpened = true
  3180.       return true
  3181.     end
  3182.   end
  3183.   for n,sSide in ipairs( rs.getSides() ) do
  3184.     if peripheral.getType( sSide )=='modem' then
  3185.       peripheral.call( sSide, "open", uniqueID )
  3186.       peripheral.call( sSide, "open", CHANNEL_BROADCAST )
  3187.       modem = peripheral.wrap(sSide)
  3188.       modemOpened = true
  3189.       return true
  3190.     end
  3191.   end
  3192.   return false
  3193. end
  3194. openModem()
  3195.  
  3196. -- Searching value in table by keys
  3197. local function tblContainsVal(table, key, val)
  3198.   for k, v in pairs(table) do
  3199.     if v[key] == val then
  3200.       return k
  3201.     end
  3202.   end
  3203.   return nil
  3204. end
  3205.  
  3206. -- Receive message with timeout
  3207. local function receive(nTimeout)
  3208.   -- Start the timer
  3209.     local timer, sFilter
  3210.     if nTimeout then
  3211.         timer = os.startTimer( nTimeout )
  3212.     else
  3213.         sFilter = "modem_message"
  3214.     end
  3215.  
  3216.     -- Wait for events
  3217.     while true do
  3218.         local sEvent, p1, p2, p3, p4, p5 = os.pullEvent( sFilter )
  3219.         if sEvent == "modem_message" then
  3220.       -- senderId, msg, channel
  3221.         return p3, p4, p5
  3222.         elseif sEvent == "timer" then
  3223.       -- Return nil if we timeout
  3224.       if p1 == timer then
  3225.         return nil
  3226.       end
  3227.         end
  3228.     end
  3229. end
  3230.  
  3231.  
  3232. ------------------------------
  3233. -- Functions called from turtles
  3234. ------------------------------
  3235.  
  3236. -- Looking for broadcast from master. If so, sending answer with distance
  3237. function swarm.searchOwner()
  3238.  
  3239.   local senderId, msg, distance
  3240.   while msg~=MASTERMESSAGE do
  3241.     _,_,_,senderId, msg,distance = os.pullEvent("modem_message")
  3242.     if msg==MASTERMESSAGE then    
  3243.       -- We gained first message from master.
  3244.       -- Send back a distance
  3245.       masterId = senderId
  3246.       modem.transmit(senderId, uniqueID, distance)
  3247.     end
  3248.   end
  3249.  
  3250.   return distance
  3251. end
  3252.  
  3253.  
  3254. -- Waiting for order message till find
  3255. function swarm.waitOrders()
  3256.  
  3257.   local senderId, message, channel
  3258.   while true do
  3259.     _,_,channel,senderId, message = os.pullEvent("modem_message")
  3260.    
  3261.     if senderId == masterId or channel == CHANNEL_BROADCAST then
  3262.       local obj = table.fromString(message)
  3263.      
  3264.       if not (obj and obj.messageHash and hashes[obj.messageHash]) then
  3265.        
  3266.         -- Send confirm
  3267.         swarm.transmitToMaster(message)
  3268.        
  3269.         -- Add this hash to hash table
  3270.         if obj and obj.messageHash then hashes[obj.messageHash] = true end
  3271.        
  3272.         return obj
  3273.       end
  3274.     end
  3275.   end
  3276. end
  3277.  
  3278.  
  3279. -- Call broadcast and waiting for responces, collecting them to array
  3280. function swarm.findSlaves(waitingResponceTime)
  3281.   if not modemOpened then return 0 end
  3282.  
  3283.   -- Broadcast
  3284.   modem.transmit(CHANNEL_BROADCAST, uniqueID, MASTERMESSAGE)
  3285.  
  3286.   local received={}
  3287.   local senderId, message = receive(waitingResponceTime); if IDE then senderId, message = "slave1", 1 end
  3288.   while senderId do
  3289.     if(type(tonumber(message)) == 'number') then
  3290.       table.insert(received, {id=senderId, dist=tonumber(message)})
  3291.     end
  3292.     senderId, message = receive(waitingResponceTime)
  3293.   end
  3294.   table.sort(received,function(s1,s2) return s1.dist < s2.dist end)
  3295.  
  3296.   slaves = {}
  3297.   local k=1
  3298.   for _,v in pairs(received) do
  3299.     if(v.dist == k) then
  3300.       k = k+1
  3301.       table.insert(slaves, v)
  3302.     else
  3303.       break
  3304.     end
  3305.   end
  3306.  
  3307.   return k-1
  3308. end
  3309.  
  3310. -- Call broadcast and waiting for responces, and add only nearest
  3311. function swarm.addSlave()
  3312.   if not modemOpened then return nil end
  3313.  
  3314.   while true do
  3315.  
  3316.     -- Broadcast
  3317.     modem.transmit(CHANNEL_BROADCAST, uniqueID, MASTERMESSAGE)
  3318.    
  3319.     local senderId, message = receive(0.5)
  3320.     while senderId do
  3321.       local n = tonumber(message)
  3322.       if type(n) == 'number' and n == 1 then
  3323.         table.insert(slaves, 1, {id=senderId, dist=nil})
  3324.         return true
  3325.       end
  3326.       senderId, message = receive(0.5)
  3327.     end
  3328.   end
  3329.   return nil
  3330. end
  3331.  
  3332.  
  3333. -- Send message from owner to slave
  3334. function swarm.transmitTask(turtleNumber, taskObj, needConfirm)
  3335.   local messageHash = math.floor(math.random()*(2^20))
  3336.   taskObj.messageHash = messageHash
  3337.   local slaveId
  3338.   local received = {} -- Set of all confirms
  3339.   local taskString = table.toString(taskObj)
  3340.  
  3341.  
  3342.   while true do
  3343.     -- Transmit message to all turtles or to one
  3344.     if turtleNumber == nil then
  3345.       for k,v in pairs(slaves) do
  3346.         slaveId = v.id
  3347.         modem.transmit(slaveId, uniqueID, taskString)
  3348.       end
  3349.     else
  3350.       slaveId = slaves[turtleNumber].id
  3351.       modem.transmit(slaveId, uniqueID, taskString)
  3352.     end
  3353.    
  3354.     -- Instant leave function if not need to wait responce
  3355.     if not needConfirm then return true end
  3356.    
  3357.     -- Receive loop
  3358.     local senderId, msg, channel = receive(0.5)
  3359.     while senderId do
  3360.       local receivedObj = table.fromString(msg)
  3361.      
  3362.       if turtleNumber == nil then
  3363.         -- Check if we have this turtle in our list
  3364.         -- And if so, add to receive
  3365.         local n = tblContainsVal(slaves, 'id', senderId)
  3366.         if n~= nil and channel ~= CHANNEL_BROADCAST then
  3367.           received[senderId] = true
  3368.         end
  3369.        
  3370.         -- If we received confirms from all turtles, return
  3371.         if tblLen(received) == tblLen(slaves) then return true end
  3372.       else
  3373.         if senderId == slaveId and receivedObj and receivedObj.messageHash == messageHash then
  3374.           return true
  3375.         end
  3376.       end
  3377.      
  3378.       senderId, msg, channel = receive(0.5)
  3379.     end
  3380.   end
  3381. end
  3382.  
  3383. -- If we have something
  3384. function swarm.transmitToMaster(obj)
  3385.   if type(obj) == 'table' then obj = table.toString(obj) end
  3386.   modem.transmit(masterId, uniqueID, obj)
  3387. end
  3388.  
  3389.  
  3390. -- Receive troubles
  3391. function swarm.receiveFromSlave(waitingResponceTime)
  3392.   local senderId, msg, channel = receive(waitingResponceTime)
  3393.  
  3394.   if not senderId then return end
  3395.  
  3396.   local n = tblContainsVal(slaves, 'id', senderId)
  3397.   if n~= nil and channel ~= CHANNEL_BROADCAST then
  3398.     local receivedObj = table.fromString(msg)
  3399.     if not receivedObj then return end
  3400.     receivedObj.slaveId = n
  3401.     return receivedObj
  3402.   end
  3403. end
  3404.  
  3405.  
  3406. -- Waiting broadcast that means i
  3407. function swarm.waitGetout()
  3408.   local senderId, msg, distance
  3409.   while true do
  3410.     _,_,_,senderId, msg,distance = os.pullEvent("modem_message")
  3411.     if msg==GETOUTMESSAGE and distance == 1 then
  3412.       return true
  3413.     end
  3414.   end
  3415. end
  3416.  
  3417. -- Waiting broadcast that means i
  3418. function swarm.sendGetout()
  3419.   -- Broadcast
  3420.   modem.transmit(CHANNEL_BROADCAST, uniqueID, GETOUTMESSAGE)
  3421. end
  3422.  
  3423. --40_AStar.lua
  3424.  
  3425. -- ********************************************************************************** --
  3426. -- **                                                                              ** --
  3427. -- **   A-Star algorithm for 3d dimensional volume                                 ** --
  3428. -- **                                                                              ** --
  3429. -- **   http://en.wikipedia.org/wiki/A*_search_algorithm                           ** --
  3430. -- **   ----------------------------------------------------                       ** --
  3431. -- **                                                                              ** --
  3432. -- **   Developed to use in program "KrutoyTurtle"                                 ** --
  3433. -- **   http://computercraft.ru/topic/48-stroitelnaia-sistema-krutoyturtle/        ** --
  3434. -- **                                                                              ** --
  3435. -- ********************************************************************************** --
  3436.  
  3437. -- Redefine global function for faster acces
  3438. local abs,pairs,floor,time,insert,remove = math.abs,pairs,math.floor,os.time,table.insert,table.remove
  3439.  
  3440. -- Heuristic estimate.
  3441. local function heuristic_cost_estimate(p1,p2)
  3442.   return abs(p1.x-p2.x) + abs(p1.y-p2.y) + abs(p1.z-p2.z)
  3443. end
  3444.  
  3445. -- ********************************************************************************** --
  3446. -- **                         Utils                                                ** --
  3447. -- ********************************************************************************** --
  3448.  
  3449. -- 3d array metatable
  3450. -- Use arr3d() as constructor, arr(x,y,z) as acces and arr:set(x,y,z,v) as set value
  3451. if not arr3d then arr3d = function() return setmetatable({  
  3452.   set = function(t,x,y,z,v)
  3453.     t[z]    = t[z]    or {}
  3454.     t[z][y] = t[z][y] or {}
  3455.     t[z][y][x] = v
  3456.   end,
  3457.   setVolume = function(t, x1,y1,z1,x2,y2,z2, v)
  3458.     for z=z1, z2 do
  3459.       for y=y1, y2 do
  3460.         for x=x1, x2 do
  3461.           t:set(x,y,z, v)
  3462.         end
  3463.       end
  3464.     end  
  3465.   end
  3466.   }, { __call = function(t, x, y, z)
  3467.     if not t[z] or not t[z][y] then return nil end
  3468.     return t[z][y][x]
  3469.   end
  3470. })end end
  3471.  
  3472.  
  3473. -- Checking time for avoid yeld exception
  3474. local chtime
  3475. local function checktime()
  3476.   -- os.queueEvent("")
  3477.   -- coroutine.yield()
  3478.  
  3479.   if not chtime then chtime=time() end
  3480.   local ntime=time()
  3481.   if ntime-chtime>0.05 or ntime-chtime<0  then
  3482.     sleep(0)
  3483.     chtime=ntime
  3484.   end
  3485. end
  3486.  
  3487. -- ********************************************************************************** --
  3488. -- **                            BreadCrumb                                        ** --
  3489. -- ********************************************************************************** --
  3490.  
  3491. local BreadCrumb = {}
  3492. BreadCrumb.__index = BreadCrumb
  3493.  
  3494. function BreadCrumb.new(x,y,z, parent)
  3495.   local self = setmetatable({}, BreadCrumb)
  3496.   self.pos = {x=x,y=y,z=z}
  3497.   self.next = parent
  3498.   self.cost = math.huge
  3499.   self.onClosedList = false
  3500.   self.onOpenList = false
  3501.   return self
  3502. end
  3503.  
  3504. function BreadCrumb:Equals(b)
  3505.     return b.pos.x == self.pos.x and b.pos.y == self.pos.y and b.pos.z == self.pos.z
  3506. end
  3507.  
  3508. -- ********************************************************************************** --
  3509. -- **                          Path Finder                                         ** --
  3510. -- ********************************************************************************** --
  3511.  
  3512. -- Neigtbours of current point
  3513. local surrounding = {
  3514.   {x=0,y=0,z=-1}, {x=0,y=0,z= 1}, {x=0,y=-1,z=0}, {x=0,y= 1,z=0}, {x=-1,y=0,z=0}, {x=1, y=0,z=0},
  3515. }
  3516.  
  3517.  
  3518. -- Method that switfly finds the best path from p_start to end.
  3519. -- The starting breadcrumb traversable via .next to the end or nil if there is no path
  3520. -- Method that switfly finds the best path from p_start to end. Doesn't reverse outcome
  3521. -- The p_end breadcrump where each .next is a step back
  3522. function AStarFindPath(world, p_start, p_end)
  3523.     -- note we just flip p_start and end here so you don't have to.            
  3524.    p_end, p_start = p_start, p_end
  3525.  
  3526.   -- Destination point is bloked
  3527.   if world(p_start.x, p_start.y, p_start.z) then return end
  3528.  
  3529.   local openList = {}
  3530.   local brWorld  = arr3d()
  3531.  
  3532.  
  3533.   local current= BreadCrumb.new(p_start.x,p_start.y,p_start.z)
  3534.   current.cost = heuristic_cost_estimate(current.pos,p_end)
  3535.  
  3536.   local finish = BreadCrumb.new(p_end.x,p_end.y,p_end.z)
  3537.   brWorld:set(current.pos.x,current.pos.y,current.pos.z,current)
  3538.   insert(openList,current)
  3539.  
  3540.   --while openList.count > 0 do
  3541.   while #openList > 0 do
  3542.     --Find best item and switch it to the 'closedList'
  3543.     current = remove(openList)
  3544.     current.onClosedList = true
  3545.  
  3546.     --Find neighbours
  3547.     for k,v in pairs(surrounding) do
  3548.       local tmpX,tmpY,tmpZ = current.pos.x + v.x, current.pos.y + v.y, current.pos.z + v.z
  3549.       if not world(tmpX,tmpY,tmpZ) then
  3550.         --Check if we've already examined a neighbour, if not create a new node for it.
  3551.         local node
  3552.         if brWorld(tmpX,tmpY,tmpZ) == nil then
  3553.           node = BreadCrumb.new(tmpX,tmpY,tmpZ)
  3554.           brWorld:set(tmpX,tmpY,tmpZ,node)
  3555.         else
  3556.           node = brWorld(tmpX,tmpY,tmpZ)
  3557.         end
  3558.        
  3559.         --If the node is not on the 'closedList' check it's new score, keep the best
  3560.         if node.onClosedList == false then
  3561.           local cost = --[[current.cost +]] heuristic_cost_estimate(node.pos,p_end)
  3562.           --print(string.format("current.pos:%i,%i,%i nodePos:%i,%i,%i cost:%i current.cost:%i node.cost:%i", current.pos.x, current.pos.y, current.pos.z, tmpX,tmpY,tmpZ, cost, current.cost, node.cost))
  3563.          
  3564.           if cost < node.cost then
  3565.             node.cost = cost
  3566.             node.next = current
  3567.           end
  3568.  
  3569.           --If the node wasn't on the openList yet, add it
  3570.           if node.onOpenList == false then
  3571.             --Check to see if we're done
  3572.             if node:Equals(finish) == true then
  3573.               node.next = current
  3574.               return node
  3575.             end
  3576.             node.onOpenList = true
  3577.            
  3578.             -- Sort and add to open list
  3579.             local pos = #openList
  3580.             while pos > 0 and openList[pos].cost <= node.cost do
  3581.                 pos = pos - 1
  3582.             end
  3583.             insert(openList,pos+1,node)
  3584.             --for k,v in pairs(openList) do io.write(v.cost .." ") end
  3585.             --print()
  3586.           end        
  3587.         end
  3588.       end
  3589.     end
  3590.     --print()
  3591.     checktime() -- Check yelding time for computerCraft
  3592.   end
  3593.  
  3594.   return nil --no path found
  3595. end
  3596.  
  3597.  
  3598. -- ********************************************************************************** --
  3599. -- **                              Usage                                           ** --
  3600. -- ********************************************************************************** --
  3601.  
  3602.  
  3603. --[[
  3604. -- Create new world as 3d array
  3605. local world = arr3d()
  3606.  
  3607. -- Block a cell, make it impassable. Indexes from [0]
  3608. -- Indexes is [x][y][z]
  3609. --world:setVolume(0,0,0,9,9,0,true)
  3610. --world:setVolume(0,0,9,9,9,9,true)
  3611.  
  3612. --world:setVolume(0,0,0,9,0,9,true)
  3613. --world:setVolume(0,9,0,9,9,9,true)
  3614.  
  3615. --world:setVolume(0,0,0,0,9,9,true)
  3616. --world:setVolume(9,0,0,9,9,9,true)
  3617. world:set(1,3,1,true)
  3618. world:set(1,7,1,true)
  3619. world:setVolume(-1,5,-1,3,5,3,true)
  3620. world:set(1,5,1,nil)
  3621.  
  3622.  
  3623. local p_start = {x=1,y=9,z=1} -- Start point.
  3624. local p_end   = {x=1,y=1,z=1} -- End point
  3625.  
  3626. -- Main path find function
  3627. -- Return the first bread crumb of path
  3628. local crumb = AStarFindPath(world, p_start, p_end)
  3629.  
  3630. if crumb == nil then
  3631.   print('Path not found')
  3632. else
  3633.   io.write('['.. crumb.pos.x..","..crumb.pos.y..","..crumb.pos.z.."]->")
  3634.  
  3635.   -- BreadCrumbs is connected list. To get next point in path use crumb.next
  3636.   while crumb.next ~= nil do
  3637.     crumb = crumb.next
  3638.     io.write('['.. crumb.pos.x..","..crumb.pos.y..","..crumb.pos.z..(crumb.next and "]->" or "]"))
  3639.   end
  3640. end
  3641. --]]
  3642.  
  3643.  
  3644. --50_TableToString.lua
  3645.  
  3646. -- ********************************************************************************** --
  3647. -- **   Serialize table to string                                                  ** --
  3648. -- **                                                                              ** --
  3649. -- ********************************************************************************** --
  3650.  
  3651. -- declare local variables
  3652. --// exportstring( string )
  3653. --// returns a "Lua" portable version of the string
  3654. local function exportstring( s )
  3655.   return string.format("%q", s)
  3656. end
  3657.  
  3658. local insert  = table.insert
  3659. local tostring= tostring
  3660. local ipairs  = ipairs
  3661. local pairs   = pairs
  3662. local type    = type
  3663.  
  3664. --// The Save Function
  3665. function table.toString(tbl)
  3666.   if type(tbl) ~= 'table' then return "" end
  3667.  
  3668.   local charS,charE = "   ","\n"
  3669.   local s_tbl = {}
  3670.  
  3671.   -- initiate variables for save procedure
  3672.   local tables,lookup = { tbl },{ [tbl] = 1 }
  3673.   insert(s_tbl, "return {"..charE )
  3674.  
  3675.   for idx,t in ipairs( tables ) do
  3676.     insert(s_tbl, "-- Table: {"..idx.."}"..charE )
  3677.     insert(s_tbl, "{"..charE )
  3678.     local thandled = {}
  3679.  
  3680.     for i,v in ipairs( t ) do
  3681.       thandled[i] = true
  3682.       local stype = type( v )
  3683.       -- only handle value
  3684.       if stype == "table" then
  3685.         if not lookup[v] then
  3686.           insert( tables, v )
  3687.           lookup[v] = #tables
  3688.         end
  3689.         insert(s_tbl, charS.."{"..lookup[v].."},"..charE )
  3690.       elseif stype == "string" then
  3691.         insert(s_tbl,  charS..exportstring( v )..","..charE )
  3692.       elseif stype == "number" or stype == "boolean" then
  3693.         insert(s_tbl,  charS..tostring( v )..","..charE )
  3694.       end
  3695.     end
  3696.  
  3697.     for i,v in pairs( t ) do
  3698.       -- escape handled values
  3699.       if (not thandled[i]) then
  3700.  
  3701.         local str = ""
  3702.         local stype = type( i )
  3703.         -- handle index
  3704.         if stype == "table" then
  3705.           if not lookup[i] then
  3706.             insert( tables,i )
  3707.             lookup[i] = #tables
  3708.           end
  3709.           str = charS.."[{"..lookup[i].."}]="
  3710.         elseif stype == "string" then
  3711.           str = charS.."["..exportstring( i ).."]="
  3712.         elseif stype == "number" or stype == "boolean" then
  3713.           str = charS.."["..tostring( i ).."]="
  3714.         end
  3715.  
  3716.         if str ~= "" then
  3717.           stype = type( v )
  3718.           -- handle value
  3719.           if stype == "table" then
  3720.             if not lookup[v] then
  3721.               insert( tables,v )
  3722.               lookup[v] = #tables
  3723.             end
  3724.             insert(s_tbl, str.."{"..lookup[v].."},"..charE )
  3725.           elseif stype == "string" then
  3726.             insert(s_tbl, str..exportstring( v )..","..charE )
  3727.           elseif stype == "number" or stype == "boolean" then
  3728.             insert(s_tbl, str..tostring( v )..","..charE )
  3729.           end
  3730.         end
  3731.       end
  3732.     end
  3733.     insert(s_tbl, "},"..charE )
  3734.   end
  3735.   insert(s_tbl, "}" )
  3736.  
  3737.   return table.concat(s_tbl)
  3738. end
  3739.  
  3740. --// The Load Function
  3741. function table.fromString(s)
  3742.   if not s then return end
  3743.   local ftables = loadstring(s)
  3744.   if not ftables then return end
  3745.   local tables = ftables()
  3746.   for idx = 1,#tables do
  3747.     local tolinki = {}
  3748.     for i,v in pairs( tables[idx] ) do
  3749.       if type( v ) == "table" then
  3750.         tables[idx][i] = tables[v[1]]
  3751.       end
  3752.       if type( i ) == "table" and tables[i[1]] then
  3753.         insert( tolinki,{ i,tables[i[1]] } )
  3754.       end
  3755.     end
  3756.     -- link indices
  3757.     for _,v in ipairs( tolinki ) do
  3758.       tables[idx][v[2]],tables[idx][v[1]] =  tables[idx][v[1]],nil
  3759.     end
  3760.   end
  3761.   return tables[1]
  3762. end
  3763.  
  3764.  
  3765. --60_Thread.lua
  3766.  
  3767. -- ********************************************************************************** --
  3768. -- **   Thread                                                                     ** --
  3769. -- **   by ZeroGalaxy                                                              ** --
  3770. -- **   ----------------------------------------------------                       ** --
  3771. -- **                                                                              ** --
  3772. -- **   Easy acces to parralel process in ComputerCraft                            ** --
  3773. -- **   http://computercraft.ru/topic/393                                          ** --
  3774. -- **                                                                              ** --
  3775. -- ********************************************************************************** --
  3776.  
  3777. thread = {}
  3778. thread.__index = thread
  3779.  
  3780. local mainThread=coroutine.running()
  3781. local filter={}
  3782.  
  3783. local function SingleThread( _sFilter )
  3784.   return coroutine.yield( _sFilter )
  3785. end
  3786.  
  3787. local function MultiThread( _sFilter )
  3788.   if coroutine.running()==mainThread then
  3789.     local event,co
  3790.     repeat
  3791.       event={coroutine.yield()}
  3792.       co=next(filter)
  3793.       if not co then os.pullEventRaw=SingleThread end
  3794.       while co do
  3795.         if coroutine.status( co ) == "dead" then
  3796.           filter[co],co=nil,next(filter,co)
  3797.         else
  3798.           if filter[co] == '' or filter[co] == event[1] or event[1] == "terminate" then
  3799.         local ok, param = coroutine.resume( co, unpack(event) )
  3800.         if not ok then filter={} error( param )
  3801.         else filter[co] = param or '' end
  3802.           end
  3803.           co=next(filter,co)
  3804.         end
  3805.       end
  3806.     until _sFilter == nil or _sFilter == event[1] or event[1] == "terminate"
  3807.     return unpack(event)
  3808.   else
  3809.   return coroutine.yield( _sFilter )
  3810.   end
  3811. end
  3812.  
  3813. function thread.create(f,...)
  3814.   os.pullEventRaw=MultiThread
  3815.   local co=coroutine.create(f)
  3816.   filter[co]=''
  3817.   local ok, param = coroutine.resume( co, ... )
  3818.   if not ok then filter={} error( param )
  3819.   else filter[co] = param or '' end
  3820.   return co
  3821. end
  3822.  
  3823. function thread.kill(co)
  3824.   filter[co]=nil
  3825. end
  3826.  
  3827. function thread.killAll()
  3828.   filter={}
  3829.   os.pullEventRaw=SingleThread
  3830. end
  3831.  
  3832. --70_VolumeLoaders.lua
  3833.  
  3834. -- ********************************************************************************** --
  3835. -- **   Loader of .vox files from MagivaVoxels editor and .nfa files from NPaintPRO** --
  3836. -- **   https://voxel.codeplex.com                                                 ** --
  3837. -- **                                                                              ** --
  3838. -- ********************************************************************************** --
  3839.  
  3840. volumeLoader = {}
  3841. volumeLoader.__index = volumeLoader
  3842.  
  3843.  
  3844. --===========================================================
  3845. -- Read string from binary file with
  3846. --===========================================================
  3847. local function readBString(file, len)
  3848.   local s = ''
  3849.   for i=1,len do
  3850.     s = s .. string.char(file.read())
  3851.   end
  3852.   return s
  3853. end
  3854.  
  3855. --===========================================================
  3856. -- Read 4 bites and convert them to integer
  3857. --===========================================================
  3858. local function readBInt(file)
  3859.   local t = {}
  3860.   for i=1,4 do table.insert(t, file.read()) end
  3861.   local n=0
  3862.   for k=1,#t do
  3863.       n=n+t[k]*2^((k-1)*8)
  3864.   end
  3865.   return n
  3866. end
  3867.  
  3868. --===========================================================
  3869. -- Locad voxel files from program MagcaVoxels
  3870. --===========================================================
  3871. function volumeLoader.load_vox(path)
  3872.   local bFile = fs.open(path, "rb")
  3873.  
  3874.   local magic = readBString(bFile, 4)
  3875.   assert(magic=="VOX ")
  3876.  
  3877.   local version = readBString(bFile, 4)
  3878.  
  3879.   local mainChunkID = readBString(bFile, 4)
  3880.   assert(mainChunkID=="MAIN")
  3881.  
  3882.   local mainChunkSize   = readBInt(bFile)
  3883.   local mainchildChunks = readBInt(bFile)
  3884.   readBString(bFile, mainChunkSize)
  3885.  
  3886.   local sizeID = readBString(bFile, 4)
  3887.   assert(sizeID=="SIZE")
  3888.   readBString(bFile, 8) -- Dont know what this two numbers means.
  3889.  
  3890.   local sizeX = readBInt(bFile)
  3891.   local sizeY = readBInt(bFile)
  3892.   local sizeZ = readBInt(bFile)
  3893.  
  3894.   local voxelID = readBString(bFile, 4)
  3895.   assert(voxelID=="XYZI")
  3896.   readBString(bFile, 8) -- Dont know what this two numbers means.
  3897.   local numVoxels= readBInt(bFile)
  3898.  
  3899.   local vol = arr3d()
  3900.   for j=1, numVoxels do
  3901.     local x,y,z,i = bFile.read(),bFile.read(),bFile.read(),bFile.read()
  3902.    
  3903.     vol:set(x+1,y+1,z+1, i)
  3904.   end
  3905.   bFile.close()
  3906.  
  3907.   return vol, sizeX, sizeY, sizeZ
  3908. end
  3909.  
  3910.  
  3911.  
  3912. --===========================================================
  3913. -- Load files from NPaintPro
  3914. --===========================================================
  3915. function volumeLoader.load_nfa(path)
  3916.   if fs.exists(path) == false then
  3917.     return nil
  3918.   end
  3919.  
  3920.   local vol = arr3d()
  3921.  
  3922.   local sizeX,sizeY,sizeZ = 1,1,1
  3923.  
  3924.   local file = io.open(path, "r" )
  3925.   local sLine = file:read()
  3926.   local z = 1
  3927.   local y = 1
  3928.   while sLine do
  3929.     if sLine == "~" then
  3930.       z = z + 1
  3931.       sizeZ = math.max(sizeZ, z)
  3932.       y = 1
  3933.     else
  3934.       local x=1
  3935.       for i=1,#sLine do
  3936.         vol:set(x,y,z, tonumber(string.sub(sLine,i,i), 16))
  3937.         sizeX = math.max(sizeX, x)
  3938.         x=x+1
  3939.       end
  3940.       sizeY = math.max(sizeY, y)
  3941.       y = y+1
  3942.     end
  3943.     sLine = file:read()
  3944.   end
  3945.   file:close()
  3946.  
  3947.   return vol, sizeX, sizeY, sizeZ
  3948. end
  3949.  
  3950. --99_main.lua
  3951.  
  3952. main()
RAW Paste Data