pocketgps - waypoints, heading and distance!
Description
Here's a quick script I whipped up tonight to take advantage of the wireless pocket computers. Its features include a waypoint system, the users's last heading, and the coordinates of and distance to ...
Installation
Copy one of these commands into your ComputerCraft terminal:
Pastebin:
pastebin get wQaGzaK7 pocketgps_-_waypoints,_heading_and_distance!wget:
wget https://pastebin.com/raw/wQaGzaK7 pocketgps_-_waypoints,_heading_and_distance!Archive:
wget https://cc.shobie.xyz/cc/get/pb-wQaGzaK7 pocketgps_-_waypoints,_heading_and_distance!
Quick Install:
wget https://cc.shobie.xyz/cc/get/pb-wQaGzaK7 pocketgps - waypoints, heading and distance!
Usage
Run the program after downloading
Tags
Source
View Original SourceCode Preview
--[[
The MIT License (MIT)
Copyright (c) 2014 Lyqyd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
--]]
local places = {}
local destination, current, heading, distance
local placesOffset = 1
local screenHandler, screenDraw
local newPlace, newPlaceFocus = {x = "", y = "", z = "", name = ""}, "name"
local goto, gotoFocus = {x = "", y = "", z = ""}, "x"
local tracing, traces = false, {}
local openDoors = false
local unpack = unpack or table.unpack
if fs.exists(".places") then
local handle = io.open(".places", "r")
if handle then
for line in handle:lines() do
local entry = {}
entry.x, entry.y, entry.z, entry.name = string.match(line, "(%-?%d+),(%-?%d+),(%-?%d+),(.*)")
if entry.x and entry.y and entry.z and entry.name then
table.insert(places, entry)
end
end
handle:close()
end
end
local function savePlaces()
local handle = io.open(".places", "w")
if handle then
for i = 1, #places do
handle:write(places[i].x..","..places[i].y..","..places[i].z..","..places[i].name.."\n")
end
handle:close()
else
error("Couldn't open file for writing!")
end
end
local function saveTrace()
local name
if fs.exists("trace") then
local count = 1
repeat
count = count + 1
until not fs.exists("trace"..count)
name = "trace"..count
else
name = "trace"
end
local handle = io.open(name, "w")
if handle then
for i = 1, #traces do
handle:write(traces[i].x..","..traces[i].y..","..traces[i].z.."\n")
end
handle:close()
end
end
local function printCenter(text)
text = tostring(text)
local x, y = term.getSize()
local xCur, yCur = term.getCursorPos()
term.setCursorPos((x - #text) / 2 + 1, yCur)
term.write(text)
end
local function menuBar()
term.setCursorPos(1,1)
term.setBackgroundColor(colors.gray)
term.setTextColor(colors.white)
term.write(" Places Goto Exit ")
end
local function clearState()
term.setCursorBlink(false)
placesOffset = 1
newPlace = {x = "", y = "", z = "", name = ""}
newPlaceFocus = "name"
end
local function drawDestinationLine(index)
local x, y = term.getSize()
term.setBackgroundColor(colors.red)
term.setTextColor(colors.white)
term.write("x")
term.setBackgroundColor(index % 2 == 0 and colors.lightGray or colors.white)
term.setTextColor(colors.black)
local destCoords = tostring(places[index].x)..","..tostring(places[index].y)..","..tostring(places[index].z)
local nameLen = x - (#destCoords + 4) --4 for spacing and initial X and scrollbar
local nameStr = string.sub(places[index].name..string.rep(" ", x), 1, nameLen)
term.write(" "..nameStr.." "..destCoords)
end
local function mainScreen()
local x, y = term.getSize()
term.setBackgroundColor(colors.lightGray)
term.setTextColor(colors.black)
if heading then
term.setCursorPos(3, 4)
term.write("Heading: "..heading)
end
if current then
term.setCursorPos(3, 6)
term.write("Current Location:")
term.setCursorPos(1, 7)
printCenter(current)
end
if destination then
term.setCursorPos(3, 9)
term.write("Destination: ")
if destinationName then
term.write(destinationName)
end
term.setCursorPos(1, 10)
printCenter(destination)
end
if distance then
term.setCursorPos(3, 12)
term.write("Distance: "..distance.."m")
end
term.setCursorPos(3, y - 1)
term.setTextColor(tracing and colors.lime or colors.red)
term.write("Tracing ")
if fs.exists("/.fingerprint") then
term.setTextColor(openDoors and colors.lime or colors.red)
term.write("Open Doors")
end
term.setTextColor(colors.black)
term.setCursorPos(1, y)
end
local function handleMain(event)
local x, y = term.getSize()
if event[1] == "char" then
if event[2] == "t" then
tracing = not tracing
if not tracing then
--toggled off, save traces.
saveTrace()
end
elseif event[2] == "f" then
if not fs.exists("/.fingerprint") then
local handle = io.open("/.fingerprint", "w")
if handle then
for i = 1, 256 do
handle:write(string.char(math.random(32, 126)))
end
handle:close()
end
end
end
elseif event[1] == "mouse_click" then
if event[4] == y - 1 and event[3] >= 3 and event[3] <= 9 then
tracing = not tracing
if not tracing then
saveTrace()
end
elseif event[4] == y - 1 and event[3] >= 14 and event[3] <= 23 and fs.exists("/.fingerprint") then
openDoors = not openDoors
end
end
end
local placesScreen, handlePlaces
local function newPlaceScreen()
local x, y = term.getSize()
local curX, curY
term.setBackgroundColor(colors.lightGray)
term.setTextColor(colors.black)
term.setCursorPos(3, 4)
term.write("Name: ")
if newPlace.name then
term.write(newPlace.name)
end
if newPlaceFocus == "name" then
curX, curY = term.getCursorPos()
end
term.setCursorPos(3, 6)
term.write("X: ")
if newPlace.x then
term.write(string.sub(tostring(newPlace.x), 0-(x - 7)))
end
if newPlaceFocus == "x" then
curX, curY = term.getCursorPos()
end
term.setCursorPos(3, 7)
term.write("Y: ")
if newPlace.y then
term.write(string.sub(tostring(newPlace.y), 0-(x - 7)))
end
if newPlaceFocus == "y" then
curX, curY = term.getCursorPos()
end
term.setCursorPos(3, 8)
term.write("Z: ")
if newPlace.z then
term.write(string.sub(tostring(newPlace.z), 0-(x - 7)))
end
if newPlaceFocus == "z" then
curX, curY = term.getCursorPos()
end
term.setCursorPos(x - 5, 10)
term.write("Done")
if curX and curY then
term.setCursorPos(curX, curY)
term.setCursorBlink(true)
end
end
local function handleNewPlace(event)
local x, y = term.getSize()
if event[1] == "mouse_click" then
if event[4] == 4 then
newPlaceFocus = "name"
elseif event[4] == 6 then
newPlaceFocus = "x"
elseif event[4] == 7 then
newPlaceFocus = "y"
elseif event[4] == 8 then
newPlaceFocus = "z"
elseif event[4] == 10 and event[3] >= x - 5 and event[3] <= x - 1 then
--clicked Done
if tonumber(newPlace.x) and tonumber(newPlace.y) and tonumber(newPlace.z) and #newPlace.name > 0 then
local entry = {x = newPlace.x, y = newPlace.y, z = newPlace.z, name = newPlace.name}
table.insert(places, entry)
savePlaces()
clearState()
screenHandler = handlePlaces
screenDraw = placesScreen
end
end
elseif event[1] == "char" then
if event[2] == "-" and (newPlaceFocus == "x" or newPlaceFocus == "y" or newPlaceFocus == "z") then
if string.sub(newPlace[newPlaceFocus], 1, 1) == "-" then
newPlace[newPlaceFocus] = string.sub(newPlace[newPlaceFocus], 2)
else
newPlace[newPlaceFocus] = "-"..newPlace[newPlaceFocus]
end
else
newPlace[newPlaceFocus] = newPlace[newPlaceFocus]..event[2]
end
elseif event[1] == "key" and event[2] == 14 then
--backspace
newPlace[newPlaceFocus] = string.sub(newPlace[newPlaceFocus], 1, #newPlace[newPlaceFocus] - 1)
end
end
function placesScreen()
term.setBackgroundColor(colors.lightGray)
term.setTextColor(colors.black)
term.setCursorPos(1, 3)
term.write(" New: Manual ")
if current and type(current) == "table" then
term.write("Current")
end
term.setCursorPos(1, 5)
local x, y = term.getSize()
for i = 1, math.min(#places, y - 4) do
term.setCursorPos(1, i + 4)
drawDestinationLine(i + placesOffset - 1)
end
term.setCursorPos(x, 5)
term.setBackgroundColor(colors.gray)
term.setTextColor(colors.white)
term.write("^")
term.setCursorPos(x, y)
term.write("v")
end
function handlePlaces(event)
if event[1] == "mouse_click" then
local x, y = term.getSize()
if event[4] >= 5 and event[4] <= y then
--clicked somewhere in the places list
if event[3] == 1 then
--removing a place from the list, clicked the x
local index = placesOffset + event[4] - 5 --5 due to the starting y coord of the list
if index <= #places then
if event[2] == 1 then
table.remove(places, index)
savePlaces()
placesScreen()
elseif event[2] == 2 then
--right-clicked, open place for editing!
clearState()
newPlace.x = tostring(places[index].x)
newPlace.y = tostring(places[index].y)
newPlace.z = tostring(places[index].z)
newPlace.name = places[index].name
table.remove(places, index)
savePlaces()
screenHandler = handleNewPlace
screenDraw = newPlaceScreen
end
end
elseif event[3] == x then
--clicked the scroll bar.
if event[4] == 5 then
--up
if placesOffset > 1 then
placesOffset = placesOffset - 1
end
elseif event[4] == y then
if placesOffset + y - 5 < #places then
placesOffset = placesOffset + 1
end
end
else
--clicked on a place!
local index = placesOffset + event[4] - 5
if index <= #places then
destination = vector.new(places[index].x, places[index].y, places[index].z)
destinationName = places[index].name
screenHandler = handleMain
screenDraw = mainScreen
end
end
elseif event[4] == 3 then
--clicked one of our new places options
if event[3] >= 10 and event[3] <= 15 then
--clicked manual
clearState()
screenHandler = handleNewPlace
screenDraw = newPlaceScreen
elseif event[3] >= 18 and event[3] <= 24 then
--clicked current
if current and type(current) == "table" then
clearState()
newPlace.x = tostring(current.x)
newPlace.y = tostring(current.y)
newPlace.z = tostring(current.z)
screenHandler = handleNewPlace
screenDraw = newPlaceScreen
end
end
end
end
end
local function gotoScreen()
local x, y = term.getSize()
local curX, curY
term.setBackgroundColor(colors.lightGray)
term.setTextColor(colors.black)
term.setCursorPos(3, 4)
term.write("X: ")
if goto.x then
term.write(string.sub(tostring(goto.x), 0-(x - 7)))
end
if gotoFocus == "x" then
curX, curY = term.getCursorPos()
end
term.setCursorPos(3, 5)
term.write("Y: ")
if goto.y then
term.write(string.sub(tostring(goto.y), 0-(x - 7)))
end
if gotoFocus == "y" then
curX, curY = term.getCursorPos()
end
term.setCursorPos(3, 6)
term.write("Z: ")
if goto.z then
term.write(string.sub(tostring(goto.z), 0-(x - 7)))
end
if gotoFocus == "z" then
curX, curY = term.getCursorPos()
end
term.setCursorPos(x - 5, 8)
term.write("Done")
if curX and curY then
term.setCursorPos(curX, curY)
term.setCursorBlink(true)
end
end
local function handleGoto(event)
local x, y = term.getSize()
if event[1] == "mouse_click" then
if event[4] == 4 then
gotoFocus = "x"
elseif event[4] == 5 then
gotoFocus = "y"
elseif event[4] == 6 then
gotoFocus = "z"
elseif event[4] == 8 and event[3] >= x - 5 and event[3] <= x - 1 then
--clicked Done
if tonumber(goto.x) and tonumber(goto.y) and tonumber(goto.z) then
destinationName = nil
destination = vector.new(tonumber(goto.x), tonumber(goto.y), tonumber(goto.z))
clearState()
screenHandler = handleMain
screenDraw = mainScreen
end
end
elseif event[1] == "char" then
if event[2] == "-" and (gotoFocus == "x" or gotoFocus == "y" or gotoFocus == "z") then
if string.sub(goto[gotoFocus], 1, 1) == "-" then
goto[gotoFocus] = string.sub(goto[gotoFocus], 2)
else
goto[gotoFocus] = "-"..goto[gotoFocus]
end
else
goto[gotoFocus] = goto[gotoFocus]..event[2]
end
elseif event[1] == "key" and event[2] == 14 then
--backspace
goto[gotoFocus] = string.sub(goto[gotoFocus], 1, #goto[gotoFocus] - 1)
end
end
local function handleEvents()
while true do
term.setBackgroundColor(colors.lightGray)
term.clear()
menuBar()
screenDraw()
local event = {os.pullEvent()}
if event[1] == "mouse_click" then
if event[4] == 1 then
--clicked the menu bar at the top
if event[3] >= 3 and event[3] <= 8 then
--clicked places
clearState()
screenHandler = handlePlaces
screenDraw = placesScreen
elseif event[3] >= 13 and event[3] <= 16 then
--clicked goto
clearState()
screenHandler = handleGoto
screenDraw = gotoScreen
elseif event[3] >= 21 and event[3] <= 24 then
--clicked exit
if screenHandler ~= handleMain then
--not on main screen, return to main screen
clearState()
screenHandler = handleMain
screenDraw = mainScreen
else
if tracing then
saveTrace()
end
return
end
end
else
screenHandler(event)
end
elseif event[1] == "key" or event[1] == "char" or event[1] == "mouse_scroll" or event[1] == "mouse_drag" then
screenHandler(event)
end
end
end
local function doGPS()
local loc, oldLoc
while true do
oldLoc = loc
loc = nil
local result = {gps.locate()}
if #result == 3 then
loc = vector.new(unpack(result))
end
if loc then
current = loc
if destination then
distance = math.sqrt((destination.x - current.x)^2 + (destination.y - current.y)^2 + (destination.z - current.z)^2)
end
if tracing then
if not oldLoc or (oldLoc and (loc.x ~= oldLoc.x or loc.y ~= oldLoc.y or loc.z ~= oldLoc.z)) then
table.insert(traces, loc)
end
end
elseif current then
current = "GPS Signal Lost"
end
if loc and oldLoc then
local head = loc - oldLoc
if math.abs(head.z) > math.abs(head.x) and math.abs(head.z) > 1 then
if head.z == math.abs(head.z) then
--positive z, south
heading = "South"
else
heading = "North"
end
elseif math.abs(head.x) > 1 then
if head.x == math.abs(head.x) then
--positive x, east
heading = "East"
else
heading = "West"
end
end
end
sleep(1)
end
end
local function openDoor()
local modem = peripheral.wrap("back")
modem.open(4210)
local handle = io.open("/.fingerprint")
local fingerprint
if handle then
fingerprint = handle:read("*a")
handle:close()
end
while true do
local event = {os.pullEvent()}
if openDoors then
if event[1] == "modem_message" and event[3] == 4210 then
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}))
end
end
end
end
screenHandler = handleMain
screenDraw = mainScreen
parallel.waitForAny(handleEvents, doGPS, openDoor)