-- Totoro SpiderEye Terminal -- v.3 -- serial = require('serialization') fs = require('filesystem') event = require('event') sides = require('sides') term = require('term') com = require('component') gpu = com.gpu red = com.redstone -- Parameters -- owner = "Totoro" monsterlist = {"Spider", "Zombie", "Creeper", "Skeleton", "Enderman", "Sheep", "Cow", "Chicken"} howlerside = sides.back cooldown = 100 -- Colors -- backcolor = 0x000000 forecolor = 0xFFFFFF infocolor = 0x0066FF errorcolor = 0xFF0000 truecolor = 0x00FF00 -- **** -- -- vars monsters = false whitelist = {owner} sensors = {} log = {} -- init graphics oldw, oldh = gpu.getResolution() width, height = gpu.maxResolution() gpu.setResolution(width, height) gpu.setForeground(forecolor) gpu.setBackground(backcolor) loglen = height-4 -- create folder for logs if not fs.exists("logs") then fs.makeDirectory("logs") end function clear(x, y, w, h) gpu.fill(x, y, w, h, " ") end local strLine = "+" for i=1, width do strLine = strLine..'-' end function line(x1, x2, y) gpu.set(x1,y,string.sub(strLine, 1, x2-x1)) gpu.set(x2,y,'+') end function frame(x1, y1, x2, y2, caption) line(x1, x2, y1) line(x1, x2, y2) if caption ~= nil then gpu.set(x1+(x2-x1)/2-#caption/2, y1, caption) end end function center(y, text) gpu.set(width/2-#text/2, y, text) end -- screens function drawLog() for y=1, #log do gpu.set(6, y+2, log[y]) end end function drawlist() for y=3, height-3 do if y-2>#sensors then break end local xx = 6+math.floor(y/loglen)*(width/2-8) local yy = y-math.floor(y/loglen)*(loglen-1) -- color indication if sensors[y-2].time > 5 then gpu.setBackground(0xFF0000) gpu.set(xx, yy, sensors[y-2].name..': '..sensors[y-2].entity) gpu.setBackground(0x000000) elseif sensors[y-2].time >0 then gpu.setBackground(0xFFFF00) gpu.set(xx, yy, sensors[y-2].name..': '..sensors[y-2].entity) gpu.setBackground(0x000000) else gpu.set(xx, yy, sensors[y-2].name) end end end function drawWhitelist() for y=1, #whitelist do gpu.set(6+math.floor(y/loglen)*(width/3), y+2-math.floor(y/loglen)*(loglen-1), whitelist[y]) end end function mainframe() term.clear() frame(2,1, width-1, height, "{ SpiderEye Terminal }") drawlist() if monsters then gpu.set(2, height-1, "M") end gpu.set(4, height-1, "[Info] Press 'H' for help, 'Q' for exit") end function logframe() term.clear() frame(2,1, width-1, height, "{ SpiderEye Log }") drawLog() if monsters then gpu.set(2, height-1, "M") end gpu.set(4, height-1, "[Info] Press 'H' for help, 'Q' for exit") end function helpframe() term.clear() frame(2,1, width-1, height, "{ SpiderEye Help }") center(3, "Controls") gpu.set(8, 5, "'H' - Show/hide help") gpu.set(8, 6, "'L' - Show/hide log") gpu.set(8, 7, "'W' - Show/hide whitelist") gpu.set(8, 8, "'A' - Add new motion sensor/whitelist user") gpu.set(8, 9, "'D' - Delete sensor/whitelist user") gpu.set(8, 10, "'R' - Refresh sensors list") gpu.set(8, 11, "'M' - Allow monsters detection") gpu.set(8, 12, "'Q' - Exit SpiderEye") center(height-6, "About") center(height-4, "Programmer: Totoro") center(height-3, "9/8/2014, MIT license") center(height-2, "moonlightowl@creep.im") if monsters then gpu.set(2, height-1, "M") end end function whiteframe() term.clear() frame(2,1, width-1, height, "{ SpiderEye WhiteList }") drawWhitelist() if monsters then gpu.set(2, height-1, "M") end gpu.set(4, height-1, "[Info] Press 'H' for help, 'Q' for exit") end function getBox(title) clear(1, height/2-2, width, 5) line(2, width-1, height/2-2) line(2, width-1, height/2+2) gpu.set(6, height/2-2, title) term.setCursor(5, height/2) return string.sub(term.read(), 1, -2) end function addSensor() local new = {} new.address = getBox("[ Enter address: ]") if new.address == nil or new.address == '' then return end -- check address test = com.get(new.address) if test == nil then message("Address "..new.address.." not found!", errorcolor) return else new.address = test end new.name = getBox("[ Enter codename: ]") if new.name == nil or new.name == '' then return end -- add new sensor new.entity = "None" new.time = 0 table.insert(sensors, new) message("New sensor in table!", infocolor) end function addWhitelist() name = getBox("[ Enter nickname: ]") if name == nil or name == '' then return end table.insert(whitelist, name) message("User "..name.." in whitelist!", infocolor) end function removeSensor() code = getBox("[ Deletion. Enter name or address: ]") if code == nil or code == '' then return end for i=1, #sensors do if string.sub(sensors[i].address, 1, #code) == code or sensors[i].name == code then table.remove(sensors, i) message("Sensor "..code.." deleted!", infocolor) return end end message("No "..code.." sensor found!", errorcolor) end function removeWhitelist() code = getBox("[ Deletion. Enter nickname: ]") if code == nil or code == '' then return end for i=1, #whitelist do if whitelist[i] == code then table.remove(whitelist, i) message("User "..code.." deleted!", infocolor) return end end message("No "..code.." in whitelist found!", errorcolor) end function message(text, color) local off = width/2-#text/2 gpu.setBackground(color) clear(off-2, height/2-1, #text+4, 3) frame(off-2, height/2-1, off+#text+1, height/2+1) gpu.set(off, height/2, text) gpu.setBackground(backcolor) message_visible = true end function redraw() if state == 0 then mainframe() elseif state == 1 then helpframe() elseif state == 3 then logframe() elseif state == 4 then whiteframe() end end -- processing function getName(add) for i=1, #sensors do if add == sensors[i].address then return sensors[i].name end end return 'Unknown' end function intruder(add, name) for i=1, #sensors do if add == sensors[i].address then if sensors[i].entity ~= name or sensors[i].time == 0 then toLog(os.date().." / Motion in "..sensors[i].name..": "..name) end sensors[i].entity = name sensors[i].time = cooldown break end end end function update() local calm = true for i=1, #sensors do if sensors[i].time>0 then sensors[i].time = sensors[i].time-1 calm = false end end if calm and howling then howl(false) end end function refresh() local all_right = true if sensors ~= nil then for i=#sensors, 1, -1 do if com.get(sensors[i].address) == nil then message("Sensor '"..sensors[i].address.."' not found!", errorcolor) table.remove(sensors, i) all_right = false end end end if all_right then message("All is right!", truecolor) end end function toLog(message) if #log < loglen then table.insert(log, message) else for c=1, loglen-1 do log[c] = log[c+1] end log[loglen] = message end local name = 'logs/'..string.gsub(os.date('%x'), '/', '_')..'.log' local file = nil if fs.exists(name) then file = io.open(name, 'a') else file = io.open(name, 'w') end file:write(message..'\n') file:close() end function whitelisted(name) if not monsters then for i=1, #monsterlist do if name == monsterlist[i] then return true end end end for i=1, #whitelist do if name == whitelist[i] then return true end end return false end function howl(active) -- any redstone controller? if red ~= nil then -- then emit! if active then if not howling then red.setOutput(howlerside, 15) howling = true end elseif howling then red.setOutput(howlerside, 0) howling = false end end end -- load and save data function loadSensorlist() if fs.exists("senslist.txt") then local file = io.open("senslist.txt", "r") local data = file:read("*a") sensors = serial.unserialize(data) file:close() if sensors == nil then sensors = {} end refresh() end end function saveSensorlist() local file = io.open("senslist.txt", "w") local data = serial.serialize(sensors) file:write(data) file:close() end function loadWhitelist() if fs.exists("whitelist.txt") then local file = io.open("whitelist.txt", "r") local data = file:read("*a") whitelist = serial.unserialize(data) file:close() if whitelist == nil then whitelist = {owner} end end end function saveWhitelist() local file = io.open("whitelist.txt", "w") local data = serial.serialize(whitelist) file:write(data) file:close() end -- init loadSensorlist() loadWhitelist() mainframe() state = 0 -- 0-main; 1-help; 3-log; 4-whitelist message_visible = false howling = false while true do name, add, a, b, c, d = event.pull(0.1) if b~=nil then --print(a, b, c) end if name == 'key_down' then if message_visible then -- hide message redraw() message_visible = false elseif b == 35 then -- 'H' - help if state~=1 then helpframe() state = 1 else mainframe() state = 0 end elseif b == 38 then -- 'L' - log if state~=3 then logframe() state = 3 else mainframe() state = 0 end elseif b == 17 then -- 'W' - whitelist if state~=4 then whiteframe() state = 4 else mainframe() state = 0 end elseif b == 30 then -- 'A' - add new sensor/user if state ~= 4 then addSensor() else addWhitelist() end if not message_visible then redraw() end elseif b == 32 then -- 'D' - delete sensor/user from list if state ~= 4 then removeSensor() else removeWhitelist() end if not message_visible then redraw() end elseif b == 19 then -- 'R' - refresh sensors list refresh() elseif b == 50 then -- 'M' - allow monster detection monsters = not monsters -- draw indicator if monsters then gpu.set(2, height-1, "M") else gpu.set(2, height-1, " ") end elseif b == 16 then break -- 'Q' - exit SpiderEye end elseif name == 'motion' then if not whitelisted(d) then intruder(add, d) howl(true) end if d ~= owner then message("Motion in "..getName(add)..": "..d, errorcolor) end end update() end -- end gpu.setResolution(oldw, oldh) term.clear() saveSensorlist() saveWhitelist()