scottbot95

ComputerCraft Turtle APIv2

May 30th, 2013
135
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.21 KB | None | 0 0
  1. logFile=fs.open("/usr/apis/turtle2/turtle2.log","a")
  2. if logFile then
  3.    oldPrint=print
  4.    oldError=error
  5.    print = function(...)
  6.       oldPrint(...)
  7.       logFile.writeLine(...)
  8.    end
  9.    error = function(...)
  10.       logFile.writeLine(...)
  11.       oldError(...)
  12.    end
  13. else
  14.    print("Warning: couldn't open log file")
  15. end
  16.  
  17. if not turtle then
  18.    error( "Cannot load turtle API on computer" )
  19. end
  20.  
  21. native = turtle.native or turtle
  22.  
  23. local function waitForResponse( _id )
  24.    local event, responseID, success
  25.    while event ~= "turtle_response" or responseID ~= _id do
  26.       event, responseID, success = os.pullEvent( "turtle_response" )
  27.    end
  28.    return success
  29. end
  30.  
  31. local function wrap( _sCommand )
  32.    return function(...)
  33.       local id = native[_sCommand]( ... )
  34.       if id == -1 then
  35.          return false
  36.       end
  37.       return waitForResponse ( id )
  38.    end
  39. end
  40.  
  41. -- Wrap standard commands
  42. local turtle, turtle2 = {}, {}
  43. turtle["getItemCount"], turtle2["getItemCount"] = native.getItemCount, native.getItemCount
  44. turtle["getItemSpace"], turtle2["getItemSpace"] = native.getItemSpace, native.getItemSpace
  45. turtle["getFuelLevel"], turtle2["getFuelLevel"] = native.getFuelLevel, native.getFuelLevel
  46.  
  47. for k,v in pairs( native ) do
  48.    if type( k ) == "string" and type( v ) == "function" then
  49.       if turtle[k] == nil then
  50.          turtle[k], turtle2[k] = wrap( k ), wrap ( k )
  51.       end
  52.    end
  53. end
  54.  
  55. -- Wrap peripheral commands
  56. if peripheral.getType("left") == "workbench" then
  57.    turtle["craft"]= function(...)
  58.       local id = peripheral.call( "left", "craft", ...)
  59.       return waitForResponse( id )
  60.    end
  61.    turtle2["craft"] = turtle["craft"]
  62. elseif peripheral.getType("right") == "workbench" then
  63.    turtle["craft"] = function(...)
  64.       local id = peripheral.call( "right", "craft", ...)
  65.       return waitForResponse( id )
  66.    end
  67.    turtle2["craft"] = turtle["craft"]
  68. end
  69.  
  70. -- Turtle Function overloading
  71.  
  72. -- Random variable inits to default values
  73. --print("Initializing turtle...")
  74. turtle2.fuelSafety, turtle2.inventorySafety = true, true
  75. turtle2.fuelSafetyNet = 15
  76. turtle2.warned = false
  77. turtle2.returned = false
  78. turtle2.deltas = { [1] =  vector.new(0,0,0) }
  79. turtle2.sumDeltas = { [1] =  vector.new(0,0,0) }
  80. turtle2.distance = 0
  81. turtle2.currMoveDist = 0
  82. turtle2.heading = 0
  83. turtle2.blugdeon = false
  84. turtle2.turning = false
  85.  
  86. -- for the following two options, a chest must be placed in slot 1
  87. -- and there must be a chest adjecent to the turtle at start of program
  88. -- Note: vertcially adjecent counts, but diagonally does not
  89. turtle2.autoRefuel = false -- will automatically try to refuel from slot 16
  90.                            -- if enabled, fuel must be first item in chest
  91. turtle2.greedyRefuel = false -- will attempt to refuel whenever possible
  92.                             -- and will try to drain chest of fuel
  93. turtle2.lastRunDistance = 0
  94. turtle2.autoDump = true
  95. turtle2.skipDump = { [1]=true, [16]=true }
  96.  
  97. function turtle2:reloadConfigs(cPath)
  98.    cPath = cPath or "/usr/apis/turtle2/turtle2.conf"
  99.    if fs.exists(cPath) then
  100.       h = fs.open(cPath,"r")
  101.       while true do
  102.          line = h.readLine()
  103.          if not line then break end
  104.          if line:match("warned") or line:match("deltas") or line:match("sumDeltas")
  105.                or line:match("distance") or line:match("turning") then
  106.             print("Warning: ", line, " is not a permitted configuration")
  107.          else
  108.             cString = "turtle2." .. line
  109.             assert(loadstring(cString))()
  110.             print("Config loaded: ", cString)
  111.          end
  112.       end
  113.    end
  114. end
  115.  
  116. function turtle2:saveConfigs(cPath)
  117.    error("Function not yet implemented")
  118. end
  119.  
  120. function turtle2:printDeltas()
  121.    for k,v in pairs(self.deltas) do print(k,":",v) end
  122. end
  123.  
  124. function turtle2:printSumDeltas()
  125.    for k,v in pairs(self.sumDeltas) do print(k,":",v) end
  126. end
  127.  
  128. -- Clear some old function just to be safe
  129. turtle2["forward"], turtle2["back"], turtle2["up"], turtle2["down"], turtle2["turnLeft"], turtle2["turnRight"] = nil, nil, nil, nil, nil, nil
  130.  
  131. local function newMovement(newVector)
  132.    turtle2.deltas[#turtle2.deltas+1] = newVector
  133.    turtle2.distance = turtle2.distance + math.abs(turtle2.currMoveDist)
  134. end
  135.  
  136. function turtle2:hasReturned()
  137.    return self.returned
  138. end
  139.  
  140. local function undoMoveVector(movement,self)
  141.    --print("undoing vector <",movement,">")
  142.    prevLength = 0
  143.    tmpBlugdeon = false
  144.    while movement:length() ~= 0 do
  145.       if (not self.blugdeon) and (movement:length() == prevLength) then tmpBlugdeon,self.blugdeon = true, true
  146.       elseif tmpBlugdeon and self.blugdeon then tmpBlugdeon, self.blugdeon = false, false end
  147.      
  148.       if movement.y > 0 then
  149.          --print("going down")
  150.          if self.blugdeon then turtle.digDown() end
  151.          if turtle.down() then movement.y = movement.y - 1 end
  152.       elseif movement.y < 0 then
  153.          --print("going up")
  154.          if self.blugdeon then turlte.digUp() end
  155.          if turtle.up() then movement.y = movement.y + 1 end
  156.       end
  157.       --print(self.heading)
  158.       if movement.x > 0 then
  159.          --print("going -x")
  160.          if self.heading == 0 then
  161.             self:turnRight()
  162.             self:turnRight()
  163.          elseif self.heading == 1 then
  164.             self:turnRight()
  165.          elseif self.heading == 3 then
  166.             self:turnLeft()
  167.          end
  168.          
  169.          if self.blugdeon then turtle.dig() end
  170.          if turtle.forward() then movement.x = movement.x - 1 end
  171.       elseif movement.x < 0 then
  172.          --print("going +x")
  173.          if self.heading == 2 then
  174.             self:turnRight()
  175.             self:turnRight()
  176.          elseif self.heading == 3 then
  177.             self:turnRight()
  178.          elseif self.heading == 1 then
  179.             self:turnLeft()
  180.          end
  181.          
  182.          if self.blugdeon then turtle.dig() end
  183.          if turtle.forward() then movement.x = movement.x + 1 end
  184.       end
  185.      
  186.       if movement.z < 0 then
  187.          --print("going +z")
  188.          if self.heading == 3 then
  189.             self:turnRight()
  190.             self:turnRight()
  191.          elseif self.heading == 0 then
  192.             self:turnRight()
  193.          elseif self.heading == 2 then
  194.             self:turnLeft()
  195.          end
  196.          
  197.          if self.blugdeon then turtle.dig() end
  198.          if turtle.forward() then movement.z = movement.z - 1 end
  199.       elseif movement.z > 0 then
  200.          --print("going -z")
  201.          if self.heading == 1 then
  202.             self:turnRight()
  203.             self:turnRight()
  204.          elseif self.heading == 2 then
  205.             self:turnRight()
  206.          elseif self.heading == 0 then
  207.             self:turnLeft()
  208.          end
  209.          
  210.          if self.blugdeon then turtle.dig() end
  211.          if turtle.forward() then movement.z = movement.z + 1 end
  212.       end
  213.    end
  214. end
  215.  
  216. local function addUpDeltas(force,self)
  217.    --print("gothere1")
  218.    if force or (#self.sumDeltas ~= #self.deltas) then self.sumDeltas = {} end
  219.    --print("gothere2")
  220.    
  221.    self.sumDeltas[1] = self.deltas[1]
  222.    --print(#self.deltas)
  223.    for i=2,#self.deltas do
  224.       --print(i)
  225.       if self.sumDeltas[i] == nil then
  226.          --print(self.sumDeltas[i-1])
  227.          self.sumDeltas[i] = self.sumDeltas[i-1]:add(self.deltas[i])
  228.       end
  229.    end
  230. end
  231.  
  232.  
  233. local function optimizePath(self)
  234.    print("Checking to see if I can optimize my path back home")
  235.    addUpDeltas(false,self)
  236.    local i,j
  237.    for i = 1,#self.sumDeltas/2 do
  238.       --print("i=",i)
  239.       for j = #self.sumDeltas, i+1, -1 do
  240.          --print("j=",j)
  241.          --print(self.sumDeltas[i]:sub(self.sumDeltas[j]):length())
  242.          if self.sumDeltas[i]:sub(self.sumDeltas[j]):length() == 0 then
  243.             print("Found matching positions...")
  244.             print("Shortening route home")
  245.             for k = 1, (j-i) do
  246.                --print("Removing deltas[",i+k,"]")
  247.                --print(self.deltas[i+1])
  248.                table.remove(self.deltas, i+1)
  249.             end
  250.             return true
  251.          end
  252.       end
  253.    end
  254.    return false
  255. end
  256.  
  257. local findChest
  258.  
  259. if peripheral.getType("right") == "idetect" then
  260.    findChest = function()
  261.       returnFunc = returnFunc or "dump"
  262.      
  263.       for i=0,2 do
  264.                                         --vvv Chest id vvv
  265.         if peripheral.call("right","IDetect") == 54 then return returnFunc:find("suck") and turtle2.suck or turlte2.dump end
  266.         turtle2:turnRight()
  267.       end
  268.      
  269.       -- check top and bottom
  270.       if peripheral.call("right","IDetectUp") == 54 then return returnFunc:find("suck") and turtle2.suckUp or turtle2.dumpUp end
  271.       if peripheral.call("right","IDetectDown") == 54 then return returnFunc:find("suck") and turtle2.suckDown or turtle2.dumpDown end
  272.    
  273.       -- Bummer. No chest :(
  274.       return nil
  275.    end
  276. else
  277.    findChest = function()
  278.       returnFunc = returnFunc or "dump"
  279.       -- must assume chest is in slot 1
  280.       turtle2.select(1)
  281.       -- will search all sides then up and down
  282.       for i=0,2 do
  283.         if turtle.compare() then return returnFunc:find("suck") and turtle2.suck or turtle2.dump end
  284.         turtle2:turnRight()
  285.       end
  286.       -- not any of the sides :( let's turn back the way we were
  287.       turtle2:turnRight()
  288.    
  289.       -- check top and bottom
  290.       if turtle2:compareUp() then return returnFunc:find("suck") and turtle2.suckUp or turtle2.dumpUp end
  291.       if turtle2:compareDown() then return returnFunc:find("suck") and turtle2.suckDown or turtle2.dumpDown end
  292.    
  293.       -- Bummer. No chest :(
  294.       return nil
  295.    end
  296. end
  297.  
  298. function turtle2:autoDumpFunc()
  299.    if not self.autoDump then return false end
  300.    dumpFunc = findChest("dump")
  301.    if not dumpFunc then
  302.       print("Could not find a chest next to me...")
  303.       return false
  304.    end
  305.    
  306.    print("Dumping all inventory...")
  307.    for i = 1, 16 do
  308.       if ((not turtle2.skipDump[i]) and (turtle2.getItemCount(i) ~=0 )) then
  309.          --print("Dropping slot ",i)
  310.          turtle2.select(i)
  311.          dumpFunc()
  312.       else
  313.          --print("Skiping slot ",i)
  314.       end
  315.    end
  316.    
  317.    return true
  318. end
  319.  
  320. function turtle2:autoRefuelFunc()
  321.    if not self.autoRefuel then return false end
  322.    suckFunc = findChest("suck")
  323.    if not suckFunc then
  324.       error("Could not find a chest next to me")
  325.    end
  326.    
  327.    self.select(16)
  328.    itemCount = self.getItemCount(16)
  329.    while itemCount > 1 and self.refuel(itemCount-1) and self.greedyRefuel  do
  330.       suckFunc()
  331.       itemCount = self.getItemCount(16)
  332.    end
  333.    
  334.    return true
  335. end
  336.  
  337. function turtle2:getPosition()
  338.    addUpDeltas(true, self)
  339.    return self.sumDeltas[#self.sumDeltas]
  340. end
  341.  
  342. function turtle2:returnHome()
  343.    print("Returning Home...")
  344.    optimizePath(self)
  345.    if self.blugdeon then
  346.       undoMoveVector(self.sumDeltas[#self.sumDeltas],self)
  347.    else
  348.       for i = #self.deltas, 1, -1 do
  349.          --sleep(1)
  350.          undoMoveVector(self.deltas[i],self)
  351.       end
  352.    end
  353.    self.deltas = {}
  354.    self.lastRunDistance = self.distance
  355.    self.distance = 0
  356.    newMovement(vector.new(0,0,0))
  357.    self.returned = true
  358.    self:autoDumpFunc()
  359.    self:autoRefuelFunc()
  360.    return true
  361. end
  362.  
  363. function turtle2:checkFuel()
  364.    local reqFuel = self.distance + math.abs(self.currMoveDist) + self.fuelSafetyNet -- safety net
  365.    --print(reqFuel)
  366.    if turtle2.getFuelLevel() <= reqFuel then
  367.       turtle2.select(16)
  368.       if optimizePath(self) or turtle2.refuel() then self:checkFuel() end
  369.       if self.warned == false then print("I appear to be low on Fuel...") end
  370.       if self.fuelSafety then return self:returnHome()
  371.       elseif self.warned == false then
  372.          print("Warning!! Fuel Safety not engaged. Turtle will eventually run out of fuel");
  373.          self.warned = true
  374.       end
  375.    end
  376.    return false
  377. end
  378.  
  379. function turtle2:checkInv()
  380.    for slotNum = 1,16 do
  381.       if turtle.getItemSpace(slotNum) > 0 then return false end
  382.    end
  383.    
  384.    if self.warned == false then print("Inventory Full...") end
  385.    if self.inventorySafety == true then return self:returnHome()
  386.    elseif self.warned == false then
  387.       print("Warning!! Inventory Safety not engaged. Turtle will eventually run out of fuel");
  388.       self.warned = true
  389.    end
  390.    return false
  391. end
  392.  
  393. local function horizMove(self,units)
  394.    if self:checkFuel() or self:checkInv() then return end
  395.    self.returned = false
  396.    if units > 0 then move = turtle.forward
  397.    elseif units < 0 then move = turtle.back
  398.    else return true end
  399.    if move() then
  400.       --print(self.turning)
  401.       --print(#self.deltas)
  402.       --print(self.deltas[#self.deltas])
  403.       if self.turning or self.deltas[#self.deltas].y ~= 0 then
  404.          newMovement(vector.new(0,0,0))
  405.          self.turning = false
  406.       end
  407.       self.currMoveDist = self.currMoveDist + units
  408.       local tmpVector
  409.       if self.heading == 0 then
  410.          tmpVector = vector.new(units,0,0)
  411.       elseif self.heading == 1 then
  412.          tmpVector = vector.new(0,0,units)
  413.       elseif self.heading == 2 then
  414.          tmpVector = vector.new(-1*units, 0,0)
  415.       elseif self.heading == 3 then
  416.          tmpVector = vector.new(0,0,-1*units)
  417.       end
  418.      
  419.       self.deltas[#self.deltas] = self.deltas[#self.deltas]:add(tmpVector)
  420.       return true
  421.    else
  422.       return false
  423.    end
  424. end
  425.  
  426. function turtle2:forward(units)
  427.    return horizMove(self,units or 1)
  428. end
  429.  
  430. function turtle2:back(units)
  431.    return horizMove(self,units and units*-1 or -1)
  432. end
  433.  
  434. function turtle2:turnLeft()
  435.    --read()
  436.    if self.heading == 0 then
  437.       self.heading = 3
  438.    else
  439.       self.heading = self.heading - 1
  440.    end
  441.    if turtle.turnLeft() then
  442.       self.turning = true
  443.    else
  444.       return false
  445.    end
  446. end
  447.  
  448. function turtle2:turnRight()
  449.    --read()
  450.    if self.heading == 3 then
  451.       self.heading = 0
  452.    else
  453.       self.heading = self.heading + 1
  454.    end
  455.    if turtle.turnRight() then
  456.       self.turning = true
  457.       return true
  458.    else
  459.       return false
  460.    end
  461. end
  462.  
  463. local function vertMove(self,units)
  464.    --print(#self.deltas)
  465.    --read()
  466.    if self:checkFuel() or self:checkInv() then return end
  467.    if units > 0 then move = turtle.up
  468.    elseif units < 0 then move = turtle.down
  469.    else return true end
  470.    if move() then
  471.       lastMove = self.deltas[#self.deltas]
  472.       --[[print(lastMove)
  473.       print(#self.deltas)
  474.       print(self)
  475.       print(self.deltas)
  476.       print(self.deltas[#self.deltas])
  477.       print(self.turning)]]
  478.       if self.turning or (lastMove.y == 0 and (lastMove.x ~= 0 or lastMove.z ~= 0)) then
  479.          newMovement(vector.new(0,units,0))
  480.       else
  481.          self.deltas[#self.deltas].y = self.deltas[#self.deltas].y + units
  482.       end
  483.       self.currMoveDist = self.currMoveDist + units
  484.       turning = false
  485.       return true
  486.    else
  487.       return false
  488.    end
  489. end
  490.  
  491. function turtle2:up(units)
  492.    return vertMove(self,units or 1)
  493. end
  494.  
  495. function turtle2:down(units)
  496.    return vertMove(self,units and units*-1 or -1)
  497. end
  498.  
  499. -- All commands defined
  500. -- One last thing to do because reasons
  501. newMovement(vector.new(0,0,0))
  502. if turtle2.autoRefuel then
  503.   turtle2.select(16)
  504.   if not (turtle2.getItemCount(16) ~= 0 and turtle2.refuel()) then
  505.      print("Hey! Punk! You didn't put fuel in slot 16!")
  506.   end
  507. end
  508.  
  509.  
  510. -- Put Commands into environment table
  511. local env = getfenv()
  512. for k,v in pairs( turtle2 ) do
  513.    env[k] = v
  514. end
  515.  
  516. --turtle2:reloadConfigs()
Advertisement
Add Comment
Please, Sign In to add comment