LDDestroier

TPS (Turtle Positioning System) for ComputerCraft

Dec 8th, 2016
660
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.95 KB | None | 0 0
  1. --[[
  2.  Turtle Positioning System
  3.  Use two turtles as an expensive and crappy GPS server! Use ALL the fuel!
  4.  
  5.  pastebin get PsTiQ5eu startup
  6.  std PB PsTiQ5eu startup
  7. --]]
  8.  
  9. local chestX = 0 --fill this in!
  10. local chestY = 0 --fill this in!
  11. local chestZ = 0 --fill this in!
  12.  
  13. local startx,starty,startz --if there isn't a file storing them
  14. startx = 0
  15. starty = 64
  16. startz = 0
  17.  
  18. local chest = true
  19.  
  20. if not gps then --I love having comical error handling
  21.     return printError("GPS API wasn't found. Are you using an older version of ComputerCraft?")
  22. else
  23.     if type(gps) == "table" then
  24.         if not (gps.locate) then
  25.             return printError("gps.locate seems to be missing.")
  26.         else
  27.             if type(gps.locate) == "string" then
  28.                 return printError("Is this a joke? gps.locate is a string. This does knot make sense.")
  29.             elseif type(gps.locate) == "table" then
  30.                 return printError("What the... gps.locate is a table! Knock it off.")
  31.             elseif type(gps.locate) == "number" then
  32.                 return printError("Eh? gps.locate is a number! This doesn't ADD UP!")
  33.             end
  34.         end
  35.     end
  36. end
  37.  
  38. local cfilename = ".coords"
  39.  
  40. local tArg = {...}
  41. local modem = peripheral.find("modem")
  42. if not turtle then
  43.     if pocket then
  44.         return printError("Hey, what do you think you're doing!? Turtles only! No pocket computer servers!!")
  45.     else
  46.         return printError("Um? This is a turtle program, you know?")
  47.     end
  48. end
  49. if not modem then
  50.     local l = peripheral.wrap("right")
  51.     local r = peripheral.wrap("left")
  52.     if r and l then
  53.         return printError("Dangit, you messed up! Craft a WIRELESS turtle!")
  54.     else
  55.         return printError("You need a wireless modem.")
  56.     end
  57. end
  58. modem.open(gps.CHANNEL_GPS)
  59.  
  60. local tew,tps
  61. local requests = 0
  62. local scr_x, scr_y = term.getSize()
  63.  
  64. local fuels = {
  65.     ["minecraft:coal"] = 80,
  66.     ["minecraft:coal_block"] = 80*9,
  67. }
  68.  
  69. local dro = function(input)
  70.     return input % 4
  71. end
  72.  
  73. local fixNumber = function(num)
  74.     return math.floor(num+0.5)
  75. end
  76.  
  77. local getDist = function(x1,y1,z1,x2,y2,z2)
  78.     return math.abs(x2-x1)+math.abs(y2-y1)+math.abs(z2-z1)
  79. end
  80.  
  81. local directionNames = {
  82.     [0] = "South",
  83.     [1] = "West",
  84.     [2] = "North",
  85.     [3] = "East",
  86. }
  87.  
  88. local dudes = {}
  89.  
  90. local total
  91. --[[local sendRequests = function()
  92.     while true do
  93.         total = 0
  94.         getEvents("tew_move","tew_receive")
  95.         for k,v in pairs(dudes) do
  96.             if v > 0 then
  97.                 modem.transmit( k, gps.CHANNEL_GPS, { tew.x, tew.y, tew.z } )
  98.                 dudes[k] = dudes[k] - 1
  99.                 requests = requests + 1
  100.                 total = total + 1
  101.             end
  102.         end
  103.         tew.lock = (total == 0)
  104.     end
  105. end--]]
  106.  
  107. local sendRequest = function()
  108.     total = 0
  109.     for k,v in pairs(dudes) do
  110.         if v > 0 then
  111.             modem.transmit( k, gps.CHANNEL_GPS, { tew.x, tew.y, tew.z } )
  112.             dudes[k] = dudes[k] - 1
  113.             requests = requests + 1
  114.             total = total + 1
  115.         end
  116.     end
  117.     tew.lock = (total == 0)
  118. end
  119. local adjustCoords = function(dir, dist)
  120.     if dir == -1 then
  121.         tew.y = tew.y + 1
  122.     elseif dir == -2 then
  123.         tew.y = tew.y - 1
  124.     else
  125.         tew.x = fixNumber(tew.x - math.sin(math.rad(dir*90)))
  126.         tew.z = fixNumber(tew.z + math.cos(math.rad(dir*90)))
  127.     end
  128.     tps(true)
  129. end
  130.  
  131. local gotoCoords = function( gx, gy, gz )
  132.     if (gx == tew.x) and (gy == tew.y) and (gz == tew.z) then return end
  133.  
  134.     local cx,cy,cz = tew.x,tew.y,tew.z
  135.    
  136.     while (gx ~= tew.x) or (gy ~= tew.y) or (gz ~= tew.z) do
  137.        
  138.         for a = 1, math.abs(gy-cy) do
  139.             if tew.y == gy then break end
  140.             tew.lock = false
  141.             if gy > cy then
  142.                 tew.up()
  143.             else
  144.                 tew.down()
  145.             end
  146.         end
  147.         if tew.x ~= gx then
  148.             tew.lock = false
  149.             tew.turn(3)
  150.             for a = 1, math.abs(gx-cx) do
  151.                 if tew.x == gx then break end
  152.                 tew.lock = false
  153.                 if gx > cx then
  154.                     tew.forward()
  155.                 else
  156.                     tew.back()
  157.                 end
  158.             end
  159.         end
  160.         if tew.z ~= gz then
  161.             tew.lock = false
  162.             tew.turn(0)
  163.             for a = 1, math.abs(gz-cz) do
  164.                 if tew.z == gz then break end
  165.                 tew.lock = false
  166.                 if gz > cz then
  167.                     tew.forward()
  168.                 else
  169.                     tew.back()
  170.                 end
  171.             end
  172.         end
  173.        
  174.     end
  175. end
  176.  
  177. local saveTheWhales = function() --HOPEFULLY the path is unobstructed by blocks
  178.     local bC = {
  179.         x = tew.x,
  180.         y = tew.y,
  181.         z = tew.z,
  182.         direction = tew.direction,
  183.     }
  184.     gotoCoords(chestX,((chestY>bC.y) and (chestY-1) or (chestY+1)),chestZ)
  185.     for a = 1, 16 do
  186.         if turtle.inspectUp() then
  187.             turtle.suckUp()
  188.         elseif turtle.inspectDown() then
  189.             turtle.suckDown()
  190.         elseif turtle.inspect() then
  191.             turtle.suck()
  192.         end
  193.     end
  194.     gotoCoords(bC.x,bC.y,bC.z)
  195.     tew.lock = false
  196.     tew.turn(bC.direction)
  197. end
  198.  
  199. local checkIfCanFuel = function()
  200.     local currentSlot = turtle.getSelectedSlot()
  201.     for a = 1, 16 do
  202.         local item = turtle.getItemDetail(a)
  203.         if item then
  204.             if fuels[item.name] then
  205.                 return true
  206.             end
  207.         end
  208.     end
  209.     return false
  210. end
  211.  
  212. local doRefuel = function()
  213.     while true do
  214.         local currentSlot = turtle.getSelectedSlot()
  215.         for a = 1, 16 do
  216.             local item = turtle.getItemDetail(a)
  217.             if item then
  218.                 if fuels[item.name] then
  219.                     turtle.select(a)
  220.                     turtle.refuel(1)
  221.                     turtle.select(currentSlot)
  222.                     term.setCursorPos(1,scr_y)
  223.                     term.clearLine()
  224.                     return true
  225.                 end
  226.             end
  227.         end
  228.         sleep(0) --INSERT MORE FUEL!
  229.         term.setCursorPos(1,scr_y)
  230.         term.write("Insert more fuel!!")
  231.     end
  232.     return false
  233. end
  234.  
  235. local handleFuel = function(chest)
  236.     if type(turtle.getFuelLevel()) == "number" then
  237.         if chest and (not checkIfCanFuel()) then
  238.             local dist = getDist(tew.x,tew.y,tew.z,chestX,chestY,chestZ)
  239.             if dist+10 > turtle.getFuelLevel() then --gives me some leeway
  240.                 saveTheWhales() --PANIC
  241.                 doRefuel()
  242.             end
  243.         end
  244.         if turtle.getFuelLevel() == 0 then
  245.             doRefuel()
  246.         end
  247.     else
  248.         return true
  249.     end
  250. end
  251.  
  252. -- 'tew' is a reproduction of the turtle API, but tracked and written to a file located at cfilename (default: "/.coords")
  253.  
  254. tew = { --already localized
  255.     lock = false,
  256.     direction = 0,
  257.     x = startx,
  258.     y = starty,
  259.     z = startz,
  260.     forward = function(dist,doFuelThing)
  261.         local success, msg
  262.         for a = 1, dist or 1 do
  263.             if tew.lock then repeat sleep(0) until not tew.lock end
  264.             handleFuel(doFuelThing)
  265.             success, msg = turtle.forward()
  266.             if success then
  267.                 adjustCoords(dro(tew.direction),1)
  268.                 --os.queueEvent("tew_move")
  269.                 sendRequest()
  270.             else
  271.                 return success, msg
  272.             end
  273.         end
  274.         return true
  275.     end,
  276.     back = function(dist,doFuelThing)
  277.         local success, msg
  278.         for a = 1, dist or 1 do
  279.             if tew.lock then repeat sleep(0) until not tew.lock end
  280.             handleFuel(doFuelThing)
  281.             success, msg = turtle.back()
  282.             if success then
  283.                 adjustCoords(dro(tew.direction+2),1)
  284.                 --os.queueEvent("tew_move")
  285.                 sendRequest()
  286.             else
  287.                 return success, msg
  288.             end
  289.         end
  290.         return true
  291.     end,
  292.     up = function(dist,doFuelThing)
  293.         local success, msg
  294.         for a = 1, dist or 1 do
  295.             if tew.lock then repeat sleep(0) until not tew.lock end
  296.             handleFuel(doFuelThing)
  297.             success, msg = turtle.up()
  298.             if success then
  299.                 adjustCoords(-1,1)
  300.                 --os.queueEvent("tew_move")
  301.                 sendRequest()
  302.             else
  303.                 return success, msg
  304.             end
  305.         end
  306.         return true
  307.     end,
  308.     down = function(dist,doFuelThing)
  309.         local success, msg
  310.         for a = 1, dist or 1 do
  311.             if tew.lock then repeat sleep(0) until not tew.lock end
  312.             handleFuel(doFuelThing)
  313.             success, msg = turtle.down()
  314.             if success then
  315.                 adjustCoords(-2,1)
  316.                 --os.queueEvent("tew_move")
  317.                 sendRequest()
  318.             else
  319.                 return success, msg
  320.             end
  321.         end
  322.         return true
  323.     end,
  324.     turnRight = function(times,doFuelThing)
  325.         handleFuel(doFuelThing)
  326.         for a = 1, times or 1 do
  327.             if tew.lock then repeat sleep(0) until not tew.lock end
  328.             turtle.turnRight()
  329.             tew.direction = dro(tew.direction+1)
  330.             tps(true)
  331.         end
  332.         return true
  333.     end,
  334.     turnLeft = function(times,doFuelThing)
  335.         handleFuel(doFuelThing)
  336.         for a = 1, times or 1 do
  337.             if tew.lock then repeat sleep(0) until not tew.lock end
  338.             turtle.turnRight()
  339.             tew.direction = dro(tew.direction+1)
  340.             tps(true)
  341.         end
  342.         return true
  343.     end,
  344.     turn = function(dir)
  345.         if dir == tew.direction then return true end
  346.         repeat
  347.             tew.turnRight()
  348.         until tew.direction == dir
  349.         return true
  350.     end
  351. }
  352.  
  353. tps = function( doWrite )
  354.     if doWrite then
  355.         local file = fs.open(cfilename,"w")
  356.         file.write(tew.x.."\n"..tew.y.."\n"..tew.z.."\n"..tew.direction.."\n"..chestX.."\n"..chestY.."\n"..chestZ)
  357.         file.close()
  358.     else
  359.         if not fs.exists(cfilename) then tps(true) end
  360.         local file = fs.open(cfilename,"r")
  361.         tew.x = tonumber(file.readLine())
  362.         tew.y = tonumber(file.readLine())
  363.         tew.z = tonumber(file.readLine())
  364.         tew.direction = tonumber(file.readLine())
  365.         chestX = tonumber(file.readLine())
  366.         chestY = tonumber(file.readLine())
  367.         chestZ = tonumber(file.readLine())
  368.         file.close()
  369.     end
  370. end
  371.  
  372. tps(false)
  373. tew.lock = true
  374.  
  375. local doTurtleMove = function()
  376.     while true do
  377.         tew.forward(   1,true)
  378.         tew.turnRight( 1,true)
  379.         tew.forward(   1,true)
  380.         tew.up(        1,true)
  381.         tew.turnRight( 1,true)
  382.         tew.forward(   1,true)
  383.         tew.turnRight( 1,true)
  384.         tew.forward(   1,true)
  385.         tew.down(      1,true)
  386.         tew.turnRight( 1,true)
  387.     end
  388. end
  389.  
  390. local handleRequests = function() --also handles manual exit
  391.     local evt, side, chan, repchan, message, distance
  392.     while true do
  393.         evt, side, chan, repchan, message, distance = os.pullEvent()
  394.         if evt == "modem_message" then
  395.             if (chan == gps.CHANNEL_GPS) and (message == "PING") then
  396.                 dudes[repchan] = 4
  397.                 --os.queueEvent("tew_receive")
  398.                 sendRequest()
  399.             end
  400.         elseif evt == "key" then
  401.             if side == keys.x then
  402.                 return
  403.             end
  404.         end
  405.     end
  406. end
  407.  
  408. local getEvents = function(...)
  409.     local evt
  410.     while true do
  411.         evt = {os.pullEvent()}
  412.         for a = 1, #arg do
  413.             if arg[a] == evt[1] then
  414.                 return unpack(evt)
  415.             end
  416.         end
  417.     end
  418. end
  419.  
  420. local colClearLine = function(col,y,char)
  421.     local cbg,ctxt,cx,cy = term.getBackgroundColor(), term.getTextColor(), term.getCursorPos()
  422.     local scr_x,scr_y = term.getSize()
  423.     term.setCursorPos(1,y or cy)
  424.     term.setBackgroundColor(col or cbg)
  425.     term.write((char or " "):rep(scr_x))
  426.     term.setBackgroundColor(cbg)
  427.     term.setTextColor(ctxt)
  428.     term.setCursorPos(cx,cy)
  429. end
  430.  
  431. local prettyPrint = function(left,right)
  432.     local ctxt = term.getTextColor()
  433.     term.setTextColor(term.isColor() and colors.yellow or colors.lightGray)
  434.     write(left)
  435.     term.setTextColor(ctxt)
  436.     print(right)
  437. end
  438.  
  439. local displayData = function()
  440.     while true do
  441.         term.clear()
  442.         term.setCursorPos(1,1)
  443.         colClearLine(colors.gray)
  444.         prettyPrint("\nFuel: ",turtle.getFuelLevel())
  445.         prettyPrint("X/Y/Z: ",tew.x.."/"..tew.y.."/"..tew.z)
  446.         prettyPrint("Direction: ",tew.direction.." ("..directionNames[tew.direction]..")")
  447.         prettyPrint("Requests: ",requests)
  448.         colClearLine(colors.gray)
  449.         print("\nPress 'X' to exit.")
  450.         sleep(0)
  451.     end
  452. end
  453.  
  454. local displayHelp = function()
  455.     local data = [[
  456. Turtle GPS System (TPS)
  457. by LDDestroier/EldidiStroyrr
  458.  Place a chest down, and fill it with fuel.
  459.  Place the turtle down (you did), and specify its own coordinates ('1') and the chest coordinates ('2').
  460.  Start!]]
  461.     print(data)
  462.     sleep(0.1)
  463.     os.pullEvent("key")
  464. end
  465.  
  466. --[[local t = peripheral.find("turtle")  --this was for an easier setup with a specific pattern
  467. if t then
  468.     t.turnOn()
  469.     tew.turnRight()
  470.     tew.forward(2)
  471.     tew.turnRight()
  472. end--]]
  473.  
  474. local okaythen = false
  475. while not okaythen do
  476.     term.clear()
  477.     term.setCursorPos(1,1)
  478.     print()
  479.     print("Push '1' to change coordinates...")
  480.     print("Push '2' to change chest coordinates...")
  481.     print("Push 'X' to cancel...")
  482.     print("Push 'Spacebar' to start immediately...")
  483.     local _x,_y = term.getCursorPos()
  484.     local buttmode = 0
  485.     local res = parallel.waitForAny(function()
  486.         while true do
  487.             local _,char = os.pullEvent("char")
  488.             if char:lower() == "1" then
  489.                 buttmode = 1
  490.                 return
  491.             elseif char:lower() == "2" then
  492.                 buttmode = 2
  493.                 return
  494.             elseif char:lower() == " " then
  495.                 okaythen = true
  496.                 return
  497.             elseif char:lower() == "x" then
  498.                 buttmode = -1
  499.                 return
  500.             end
  501.         end
  502.     end,function()
  503.         for a = 1, 3*10 do
  504.             term.setCursorPos(_x,_y)
  505.             term.write("Starting in "..(3-(a/10)).." seconds...")
  506.             sleep(0.1)
  507.         end
  508.     end)
  509.    
  510.     if res == 1 then
  511.         term.clear()
  512.         term.setCursorPos(1,1)
  513.         if buttmode == 1 then
  514.             print("Turtle position input.")
  515.             colClearLine(colors.white)
  516.             write("\nX: ")
  517.             tew.x = tonumber(read()) or tew.x
  518.             write("Y: ")
  519.             tew.y = tonumber(read()) or tew.y
  520.             write("Z: ")
  521.             tew.z = tonumber(read()) or tew.z
  522.             print("Direction (F3 -> 'f'): ")
  523.             for k,v in pairs(directionNames) do
  524.                 print(" "..k.." = '"..v.."'")
  525.             end
  526.             write(">")
  527.             tew.direction = tonumber(read()) or tew.direction
  528.             tps(true)
  529.         elseif buttmode == 2 then
  530.             print("Refuel Chest input.")
  531.             colClearLine(colors.white)
  532.             write("\nChest X: ")
  533.             chestX = tonumber(read()) or chestX
  534.             write("Chest Y: ")
  535.             chestY = tonumber(read()) or chestY
  536.             write("Chest Z: ")
  537.             chestZ = tonumber(read()) or chestZ
  538.             tps(true)
  539.         elseif buttmode == -1 then
  540.             print("Cancelled.")
  541.             error()
  542.         end
  543.     else
  544.         okaythen = true
  545.     end
  546. end
  547.  
  548. parallel.waitForAny(handleRequests,doTurtleMove,displayData) --,sendRequests) --everything's okay, then
  549.  
  550. term.setCursorPos(1,scr_y-2)
  551. print("Thank you for using TPS!")
  552. sleep(0)
Add Comment
Please, Sign In to add comment