Advertisement
Lyqyd

pocketgps

Mar 29th, 2014
3,815
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.35 KB | None | 0 0
  1. --[[
  2. The MIT License (MIT)
  3.  
  4. Copyright (c) 2014 Lyqyd
  5.  
  6. Permission is hereby granted, free of charge, to any person obtaining a copy
  7. of this software and associated documentation files (the "Software"), to deal
  8. in the Software without restriction, including without limitation the rights
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the Software is
  11. furnished to do so, subject to the following conditions:
  12.  
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  15.  
  16. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. THE SOFTWARE.
  23. --]]
  24.  
  25. local places = {}
  26. local destination, current, heading, distance
  27. local placesOffset = 1
  28. local screenHandler, screenDraw
  29. local newPlace, newPlaceFocus = {x = "", y = "", z = "", name = ""}, "name"
  30. local goto, gotoFocus = {x = "", y = "", z = ""}, "x"
  31. local tracing, traces = false, {}
  32. local openDoors = false
  33. local unpack = unpack or table.unpack
  34.  
  35. if fs.exists(".places") then
  36.     local handle = io.open(".places", "r")
  37.     if handle then
  38.         for line in handle:lines() do
  39.             local entry = {}
  40.             entry.x, entry.y, entry.z, entry.name = string.match(line, "(%-?%d+),(%-?%d+),(%-?%d+),(.*)")
  41.             if entry.x and entry.y and entry.z and entry.name then
  42.                 table.insert(places, entry)
  43.             end
  44.         end
  45.         handle:close()
  46.     end
  47. end
  48.  
  49. local function savePlaces()
  50.     local handle = io.open(".places", "w")
  51.     if handle then
  52.         for i = 1, #places do
  53.             handle:write(places[i].x..","..places[i].y..","..places[i].z..","..places[i].name.."\n")
  54.         end
  55.         handle:close()
  56.     else
  57.         error("Couldn't open file for writing!")
  58.     end
  59. end
  60.  
  61. local function saveTrace()
  62.     local name
  63.     if fs.exists("trace") then
  64.         local count = 1
  65.         repeat
  66.             count = count + 1
  67.         until not fs.exists("trace"..count)
  68.         name = "trace"..count
  69.     else
  70.         name = "trace"
  71.     end
  72.     local handle = io.open(name, "w")
  73.     if handle then
  74.         for i = 1, #traces do
  75.             handle:write(traces[i].x..","..traces[i].y..","..traces[i].z.."\n")
  76.         end
  77.         handle:close()
  78.     end
  79. end
  80.  
  81.  
  82. local function printCenter(text)
  83.     text = tostring(text)
  84.     local x, y = term.getSize()
  85.     local xCur, yCur = term.getCursorPos()
  86.     term.setCursorPos((x - #text) / 2 + 1, yCur)
  87.     term.write(text)
  88. end
  89.  
  90. local function menuBar()
  91.     term.setCursorPos(1,1)
  92.     term.setBackgroundColor(colors.gray)
  93.     term.setTextColor(colors.white)
  94.     term.write("  Places    Goto    Exit  ")
  95. end
  96.  
  97. local function clearState()
  98.     term.setCursorBlink(false)
  99.     placesOffset = 1
  100.     newPlace = {x = "", y = "", z = "", name = ""}
  101.     newPlaceFocus = "name"
  102. end
  103.  
  104. local function drawDestinationLine(index)
  105.     local x, y = term.getSize()
  106.     term.setBackgroundColor(colors.red)
  107.     term.setTextColor(colors.white)
  108.     term.write("x")
  109.     term.setBackgroundColor(index % 2 == 0 and colors.lightGray or colors.white)
  110.     term.setTextColor(colors.black)
  111.     local destCoords = tostring(places[index].x)..","..tostring(places[index].y)..","..tostring(places[index].z)
  112.     local nameLen = x - (#destCoords + 4) --4 for spacing and initial X and scrollbar
  113.     local nameStr = string.sub(places[index].name..string.rep(" ", x), 1, nameLen)
  114.     term.write(" "..nameStr.." "..destCoords)
  115. end
  116.  
  117.  
  118. local function mainScreen()
  119.     local x, y = term.getSize()
  120.     term.setBackgroundColor(colors.lightGray)
  121.     term.setTextColor(colors.black)
  122.     if heading then
  123.         term.setCursorPos(3, 4)
  124.         term.write("Heading: "..heading)
  125.     end
  126.     if current then
  127.         term.setCursorPos(3, 6)
  128.         term.write("Current Location:")
  129.         term.setCursorPos(1, 7)
  130.         printCenter(current)
  131.     end
  132.     if destination then
  133.         term.setCursorPos(3, 9)
  134.         term.write("Destination: ")
  135.         if destinationName then
  136.             term.write(destinationName)
  137.         end
  138.         term.setCursorPos(1, 10)
  139.         printCenter(destination)
  140.     end
  141.     if distance then
  142.         term.setCursorPos(3, 12)
  143.         term.write("Distance: "..distance.."m")
  144.     end
  145.     term.setCursorPos(3, y - 1)
  146.     term.setTextColor(tracing and colors.lime or colors.red)
  147.     term.write("Tracing    ")
  148.     if fs.exists("/.fingerprint") then
  149.         term.setTextColor(openDoors and colors.lime or colors.red)
  150.         term.write("Open Doors")
  151.     end
  152.     term.setTextColor(colors.black)
  153.     term.setCursorPos(1, y)
  154. end
  155.  
  156. local function handleMain(event)
  157.     local x, y = term.getSize()
  158.     if event[1] == "char" then
  159.         if event[2] == "t" then
  160.             tracing = not tracing
  161.             if not tracing then
  162.                 --toggled off, save traces.
  163.                 saveTrace()
  164.             end
  165.         elseif event[2] == "f" then
  166.             if not fs.exists("/.fingerprint") then
  167.                 local handle = io.open("/.fingerprint", "w")
  168.                 if handle then
  169.                     for i = 1, 256 do
  170.                         handle:write(string.char(math.random(32, 126)))
  171.                     end
  172.                     handle:close()
  173.                 end
  174.             end
  175.         end
  176.     elseif event[1] == "mouse_click" then
  177.         if event[4] == y - 1 and event[3] >= 3 and event[3] <= 9 then
  178.             tracing = not tracing
  179.             if not tracing then
  180.                 saveTrace()
  181.             end
  182.         elseif event[4] == y - 1 and event[3] >= 14 and event[3] <= 23 and fs.exists("/.fingerprint") then
  183.             openDoors = not openDoors
  184.         end
  185.     end
  186. end
  187.  
  188. local placesScreen, handlePlaces
  189.  
  190. local function newPlaceScreen()
  191.     local x, y = term.getSize()
  192.     local curX, curY
  193.     term.setBackgroundColor(colors.lightGray)
  194.     term.setTextColor(colors.black)
  195.     term.setCursorPos(3, 4)
  196.     term.write("Name: ")
  197.     if newPlace.name then
  198.         term.write(newPlace.name)
  199.     end
  200.     if newPlaceFocus == "name" then
  201.         curX, curY = term.getCursorPos()
  202.     end
  203.     term.setCursorPos(3, 6)
  204.     term.write("X: ")
  205.     if newPlace.x then
  206.         term.write(string.sub(tostring(newPlace.x), 0-(x - 7)))
  207.     end
  208.     if newPlaceFocus == "x" then
  209.         curX, curY = term.getCursorPos()
  210.     end
  211.     term.setCursorPos(3, 7)
  212.     term.write("Y: ")
  213.     if newPlace.y then
  214.         term.write(string.sub(tostring(newPlace.y), 0-(x - 7)))
  215.     end
  216.     if newPlaceFocus == "y" then
  217.         curX, curY = term.getCursorPos()
  218.     end
  219.     term.setCursorPos(3, 8)
  220.     term.write("Z: ")
  221.     if newPlace.z then
  222.         term.write(string.sub(tostring(newPlace.z), 0-(x - 7)))
  223.     end
  224.     if newPlaceFocus == "z" then
  225.         curX, curY = term.getCursorPos()
  226.     end
  227.     term.setCursorPos(x - 5, 10)
  228.     term.write("Done")
  229.     if curX and curY then
  230.         term.setCursorPos(curX, curY)
  231.         term.setCursorBlink(true)
  232.     end
  233. end
  234.  
  235. local function handleNewPlace(event)
  236.     local x, y = term.getSize()
  237.     if event[1] == "mouse_click" then
  238.         if event[4] == 4 then
  239.             newPlaceFocus = "name"
  240.         elseif event[4] == 6 then
  241.             newPlaceFocus = "x"
  242.         elseif event[4] == 7 then
  243.             newPlaceFocus = "y"
  244.         elseif event[4] == 8 then
  245.             newPlaceFocus = "z"
  246.         elseif event[4] == 10 and event[3] >= x - 5 and event[3] <= x - 1 then
  247.             --clicked Done
  248.             if tonumber(newPlace.x) and tonumber(newPlace.y) and tonumber(newPlace.z) and #newPlace.name > 0 then
  249.                 local entry = {x = newPlace.x, y = newPlace.y, z = newPlace.z, name = newPlace.name}
  250.                 table.insert(places, entry)
  251.                 savePlaces()
  252.                 clearState()
  253.                 screenHandler = handlePlaces
  254.                 screenDraw = placesScreen
  255.             end
  256.         end
  257.     elseif event[1] == "char" then
  258.         if event[2] == "-" and (newPlaceFocus == "x" or newPlaceFocus == "y" or newPlaceFocus == "z") then
  259.             if string.sub(newPlace[newPlaceFocus], 1, 1) == "-" then
  260.                 newPlace[newPlaceFocus] = string.sub(newPlace[newPlaceFocus], 2)
  261.             else
  262.                 newPlace[newPlaceFocus] = "-"..newPlace[newPlaceFocus]
  263.             end
  264.         else
  265.             newPlace[newPlaceFocus] = newPlace[newPlaceFocus]..event[2]
  266.         end
  267.     elseif event[1] == "key" and event[2] == 14 then
  268.         --backspace
  269.         newPlace[newPlaceFocus] = string.sub(newPlace[newPlaceFocus], 1, #newPlace[newPlaceFocus] - 1)
  270.     end
  271. end
  272.  
  273. function placesScreen()
  274.     term.setBackgroundColor(colors.lightGray)
  275.     term.setTextColor(colors.black)
  276.     term.setCursorPos(1, 3)
  277.     term.write("  New:   Manual  ")
  278.     if current and type(current) == "table" then
  279.         term.write("Current")
  280.     end
  281.     term.setCursorPos(1, 5)
  282.     local x, y = term.getSize()
  283.     for i = 1, math.min(#places, y - 4) do
  284.         term.setCursorPos(1, i + 4)
  285.         drawDestinationLine(i + placesOffset - 1)
  286.     end
  287.     term.setCursorPos(x, 5)
  288.     term.setBackgroundColor(colors.gray)
  289.     term.setTextColor(colors.white)
  290.     term.write("^")
  291.     term.setCursorPos(x, y)
  292.     term.write("v")
  293. end
  294.  
  295. function handlePlaces(event)
  296.     if event[1] == "mouse_click" then
  297.         local x, y = term.getSize()
  298.         if event[4] >= 5 and event[4] <= y then
  299.             --clicked somewhere in the places list
  300.             if event[3] == 1 then
  301.                 --removing a place from the list, clicked the x
  302.                 local index = placesOffset + event[4] - 5 --5 due to the starting y coord of the list
  303.                 if index <= #places then
  304.                     if event[2] == 1 then
  305.                         table.remove(places, index)
  306.                         savePlaces()
  307.                         placesScreen()
  308.                     elseif event[2] == 2 then
  309.                         --right-clicked, open place for editing!
  310.                         clearState()
  311.                         newPlace.x = tostring(places[index].x)
  312.                         newPlace.y = tostring(places[index].y)
  313.                         newPlace.z = tostring(places[index].z)
  314.                         newPlace.name = places[index].name
  315.                         table.remove(places, index)
  316.                         savePlaces()
  317.                         screenHandler = handleNewPlace
  318.                         screenDraw = newPlaceScreen
  319.                     end
  320.                 end
  321.             elseif event[3] == x then
  322.                 --clicked the scroll bar.
  323.                 if event[4] == 5 then
  324.                     --up
  325.                     if placesOffset > 1 then
  326.                         placesOffset = placesOffset - 1
  327.                     end
  328.                 elseif event[4] == y then
  329.                     if placesOffset + y - 5 < #places then
  330.                         placesOffset = placesOffset + 1
  331.                     end
  332.                 end
  333.             else
  334.                 --clicked on a place!
  335.                 local index = placesOffset + event[4] - 5
  336.                 if index <= #places then
  337.                     destination = vector.new(places[index].x, places[index].y, places[index].z)
  338.                     destinationName = places[index].name
  339.                     screenHandler = handleMain
  340.                     screenDraw = mainScreen
  341.                 end        
  342.             end
  343.         elseif event[4] == 3 then
  344.             --clicked one of our new places options
  345.             if event[3] >= 10 and event[3] <= 15 then
  346.                 --clicked manual
  347.                 clearState()
  348.                 screenHandler = handleNewPlace
  349.                 screenDraw = newPlaceScreen
  350.             elseif event[3] >= 18 and event[3] <= 24 then
  351.                 --clicked current
  352.                 if current and type(current) == "table" then
  353.                     clearState()
  354.                     newPlace.x = tostring(current.x)
  355.                     newPlace.y = tostring(current.y)
  356.                     newPlace.z = tostring(current.z)
  357.                     screenHandler = handleNewPlace
  358.                     screenDraw = newPlaceScreen
  359.                 end
  360.             end
  361.         end
  362.     end
  363. end
  364.  
  365. local function gotoScreen()
  366.     local x, y = term.getSize()
  367.     local curX, curY
  368.     term.setBackgroundColor(colors.lightGray)
  369.     term.setTextColor(colors.black)
  370.     term.setCursorPos(3, 4)
  371.     term.write("X: ")
  372.     if goto.x then
  373.         term.write(string.sub(tostring(goto.x), 0-(x - 7)))
  374.     end
  375.     if gotoFocus == "x" then
  376.         curX, curY = term.getCursorPos()
  377.     end
  378.     term.setCursorPos(3, 5)
  379.     term.write("Y: ")
  380.     if goto.y then
  381.         term.write(string.sub(tostring(goto.y), 0-(x - 7)))
  382.     end
  383.     if gotoFocus == "y" then
  384.         curX, curY = term.getCursorPos()
  385.     end
  386.     term.setCursorPos(3, 6)
  387.     term.write("Z: ")
  388.     if goto.z then
  389.         term.write(string.sub(tostring(goto.z), 0-(x - 7)))
  390.     end
  391.     if gotoFocus == "z" then
  392.         curX, curY = term.getCursorPos()
  393.     end
  394.     term.setCursorPos(x - 5, 8)
  395.     term.write("Done")
  396.     if curX and curY then
  397.         term.setCursorPos(curX, curY)
  398.         term.setCursorBlink(true)
  399.     end
  400. end
  401.  
  402. local function handleGoto(event)
  403.     local x, y = term.getSize()
  404.     if event[1] == "mouse_click" then
  405.         if event[4] == 4 then
  406.             gotoFocus = "x"
  407.         elseif event[4] == 5 then
  408.             gotoFocus = "y"
  409.         elseif event[4] == 6 then
  410.             gotoFocus = "z"
  411.         elseif event[4] == 8 and event[3] >= x - 5 and event[3] <= x - 1 then
  412.             --clicked Done
  413.             if tonumber(goto.x) and tonumber(goto.y) and tonumber(goto.z) then
  414.                 destinationName = nil
  415.                 destination = vector.new(tonumber(goto.x), tonumber(goto.y), tonumber(goto.z))
  416.                 clearState()
  417.                 screenHandler = handleMain
  418.                 screenDraw = mainScreen
  419.             end
  420.         end
  421.     elseif event[1] == "char" then
  422.         if event[2] == "-" and (gotoFocus == "x" or gotoFocus == "y" or gotoFocus == "z") then
  423.             if string.sub(goto[gotoFocus], 1, 1) == "-" then
  424.                 goto[gotoFocus] = string.sub(goto[gotoFocus], 2)
  425.             else
  426.                 goto[gotoFocus] = "-"..goto[gotoFocus]
  427.             end
  428.         else
  429.             goto[gotoFocus] = goto[gotoFocus]..event[2]
  430.         end
  431.     elseif event[1] == "key" and event[2] == 14 then
  432.         --backspace
  433.         goto[gotoFocus] = string.sub(goto[gotoFocus], 1, #goto[gotoFocus] - 1)
  434.     end
  435. end
  436.  
  437. local function handleEvents()
  438.     while true do
  439.         term.setBackgroundColor(colors.lightGray)
  440.         term.clear()
  441.         menuBar()
  442.         screenDraw()
  443.         local event = {os.pullEvent()}
  444.         if event[1] == "mouse_click" then
  445.             if event[4] == 1 then
  446.                 --clicked the menu bar at the top
  447.                 if event[3] >= 3 and event[3] <= 8 then
  448.                     --clicked places
  449.                     clearState()
  450.                     screenHandler = handlePlaces
  451.                     screenDraw = placesScreen
  452.                 elseif event[3] >= 13 and event[3] <= 16 then
  453.                     --clicked goto
  454.                     clearState()
  455.                     screenHandler = handleGoto
  456.                     screenDraw = gotoScreen
  457.                 elseif event[3] >= 21 and event[3] <= 24 then
  458.                     --clicked exit
  459.                     if screenHandler ~= handleMain then
  460.                         --not on main screen, return to main screen
  461.                         clearState()
  462.                         screenHandler = handleMain
  463.                         screenDraw = mainScreen
  464.                     else
  465.                         if tracing then
  466.                             saveTrace()
  467.                         end
  468.                         return
  469.                     end
  470.                 end
  471.             else
  472.                 screenHandler(event)
  473.             end
  474.         elseif event[1] == "key" or event[1] == "char" or event[1] == "mouse_scroll" or event[1] == "mouse_drag" then
  475.             screenHandler(event)
  476.         end
  477.     end
  478. end
  479.  
  480. local function doGPS()
  481.     local loc, oldLoc
  482.     while true do
  483.         oldLoc = loc
  484.         loc = nil
  485.         local result = {gps.locate()}
  486.         if #result == 3 then
  487.             loc = vector.new(unpack(result))
  488.         end
  489.         if loc then
  490.             current = loc
  491.             if destination then
  492.                 distance = math.sqrt((destination.x - current.x)^2 + (destination.y - current.y)^2 + (destination.z - current.z)^2)
  493.             end
  494.             if tracing then
  495.                 if not oldLoc or (oldLoc and (loc.x ~= oldLoc.x or loc.y ~= oldLoc.y or loc.z ~= oldLoc.z)) then
  496.                     table.insert(traces, loc)
  497.                 end
  498.             end
  499.         elseif current then
  500.             current = "GPS Signal Lost"
  501.         end
  502.         if loc and oldLoc then
  503.             local head = loc - oldLoc
  504.             if math.abs(head.z) > math.abs(head.x) and math.abs(head.z) > 1 then
  505.                 if head.z == math.abs(head.z) then
  506.                     --positive z, south
  507.                     heading = "South"
  508.                 else
  509.                     heading = "North"
  510.                 end
  511.             elseif math.abs(head.x) > 1 then
  512.                 if head.x == math.abs(head.x) then
  513.                     --positive x, east
  514.                     heading = "East"
  515.                 else
  516.                     heading = "West"
  517.                 end
  518.             end
  519.         end
  520.         sleep(1)
  521.     end
  522. end
  523.  
  524. local function openDoor()
  525.     local modem = peripheral.wrap("back")
  526.     modem.open(4210)
  527.     local handle = io.open("/.fingerprint")
  528.     local fingerprint
  529.     if handle then
  530.         fingerprint = handle:read("*a")
  531.         handle:close()
  532.     end
  533.     while true do
  534.         local event = {os.pullEvent()}
  535.         if openDoors then
  536.             if event[1] == "modem_message" and event[3] == 4210 then
  537.                 modem.transmit(4211, 4212, textutils.serialize({content = textutils.serialize(fingerprint), senderID = os.getComputerID(), senderName = os.getComputerLabel(), channel = 4211, replyChannel = 4212, messageID = messageID or math.random(10000), destinationID = event[5].senderID}))
  538.             end
  539.         end
  540.     end
  541. end
  542.                
  543.  
  544. screenHandler = handleMain
  545. screenDraw = mainScreen
  546. parallel.waitForAny(handleEvents, doGPS, openDoor)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement