MoonlightOwl

SmartLock 0.4 by Totoro

Oct 11th, 2014
505
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --                SmartLock 0.4               --
  2. -- advances lock system by Totoro; 10/10/2014 --
  3.  
  4. local event = require('event')
  5. local serial = require('serialization')
  6. local sides = require('sides')
  7. local term = require('term')
  8. local fs = require('filesystem')
  9. local com = require('component')
  10. local comp = require('computer')
  11.  
  12. -- Таблица констант --
  13. OWNER = 'Totoro'
  14. --
  15. OPEN_TIME = 1
  16. ALARM_TIME = 5
  17. RED_STRENGTH = 1
  18. REALTIME = true
  19. TIMEZONE = 0
  20. COOLDOWN = 2
  21. PORT = 27
  22. --
  23. ALLOW = "。◕‿◕。"
  24. WAIT  = "(⊙_◎)"
  25. DENY  = "(¬_¬)"
  26. --
  27. DEFAULT_USER = 'Noname'
  28. DEFAULT_DOOR = 'Door X'
  29. DEFAULT_LEVEL = 1
  30. --
  31. GLASSX = 240
  32. GLASSY = 55
  33. GLASS_TIME = 2
  34.  
  35. -- Таблица цветов --
  36. forecolor  = 0xFFFFFF
  37. backcolor  = 0x000000
  38. allowcolor = 0x00FF00
  39. errorcolor = 0xFF0000
  40. warncolor = 0xCCCC00
  41. infocolor = 0x398eb5
  42. --
  43.  
  44. function trytofind(name)
  45.   if com.isAvailable(name) then
  46.     return com.getPrimary(name)
  47.   else
  48.     return nil
  49.   end
  50. end
  51.  
  52. local modem = trytofind('modem')
  53. local glass = trytofind('openperipheral_glassesbridge')
  54. local mgpu  = trytofind('gpu')
  55.  
  56. term.clear()
  57. function errout(message)
  58.   mgpu.setForeground(errorcolor)
  59.   print('[ERROR] '..message)
  60.   mgpu.setForeground(forecolor)
  61. end
  62. function warnout(message)
  63.   mgpu.setForeground(warncolor)
  64.   print('[WARNING] '..message)
  65.   mgpu.setForeground(forecolor)
  66. end
  67. function infout(message)
  68.   mgpu.setForeground(infocolor)
  69.   print('[INFO] '..message)
  70.   mgpu.setForeground(forecolor)
  71. end
  72. function helpout(message)
  73.   mgpu.setForeground(allowcolor)
  74.   print(message)
  75.   mgpu.setForeground(forecolor)
  76. end
  77.  
  78. local agpu = nil
  79. for a,b in com.list('gpu') do
  80.   if a ~= mgpu.address then agpu = com.proxy(a); break end
  81. end
  82. if agpu == nil then
  83.   errout("Не обнаружена вторая видеокарта!")
  84.   return
  85. end
  86.  
  87. if modem ~= nil then infout("Обнаружен модем. Активирован сетевой интерфейс.") end
  88. if glass ~= nil then infout("Вы можете использовать удаленный интерфейс через очки.")
  89. else warnout("Очки не обнаружены. Удаленный интерфейс недоступен.") end
  90.  
  91. width, height = mgpu.getResolution()
  92.  
  93. -- создаем папку для логов
  94. if not fs.exists("logs") then
  95.   fs.makeDirectory("logs")
  96. end
  97.  
  98. -- ======================================== L I S T   M A N A G E R S ======================================== --
  99. function readList(filename)
  100.   if fs.exists(filename) then
  101.     local file = io.open(filename, "r")
  102.     local data = file:read("*a")
  103.     local list = serial.unserialize(data)
  104.     file:close()
  105.     return list
  106.   else
  107.     errout("Файл "..filename.." не найден, создан пустой список!")
  108.     return {}
  109.   end
  110. end
  111. function saveList(list, filename)
  112.   local file = io.open(filename, "w")
  113.   data = serial.serialize(list)
  114.   file:write(data)
  115.   file:close()
  116. end
  117. function toList(list, name, data)
  118.   if data == nil then data = true end
  119.   list[name] = data
  120.   return true
  121. end
  122. function fromList(list, name)
  123.   if list[name] then
  124.     list[name] = nil
  125.     return true
  126.   end
  127.   return false
  128. end
  129. function contains(list, name)
  130.   return list[name] ~= nil
  131. end
  132. function printlist(list)
  133.   if next(list) == nil then print("Таблица пуста.")
  134.   else
  135.     c = 1
  136.     for a,b in pairs(list) do
  137.       print(a, serial.serialize(b))
  138.       c = c + 1
  139.       if c > height-3 then
  140.         print("Любая клавиша для продолжения...")
  141.         event.pull('key_down')
  142.         c = 1
  143.       end
  144.     end
  145.   end
  146. end
  147.  
  148. -- ================================================= L O G S ================================================= --
  149. log = {}
  150. log_new = 1
  151. time_offset = TIMEZONE * 60 * 60
  152.  
  153. function toLog(message)
  154.   -- записываем в файл
  155.   local name = 'logs/total.log'
  156.   local file = nil
  157.   if fs.exists(name) then
  158.     file = io.open(name, 'a')
  159.   else
  160.     file = io.open(name, 'w')
  161.   end
  162.   if REALTIME then
  163.     lm = string.sub(fs.lastModified(name), 1, -4)
  164.     nm = tonumber(lm) + time_offset
  165.     dt = os.date("*t", nm)
  166.     date = dt.day..'.'..dt.month..'.'..dt.year..'/'..dt.hour..':'..dt.min
  167.   else
  168.     date = os.date()
  169.   end
  170.   message = date..' | '..message
  171.   file:write(message..'\n')
  172.   file:close()
  173.   -- сохраняем в локальный лог
  174.   table.insert(log, message)
  175.   last_date = date
  176. end
  177. function printlog(index)
  178.   if index == nil then
  179.     infout(" Лог событий (полностью):")
  180.   else
  181.     infout(" Лог событий (новое):")
  182.   end
  183.   c = 0
  184.   for i=index or 1, #log do
  185.     print(log[i])
  186.       c = c + 1
  187.       if c > height-3 then
  188.         print("Любая клавиша для продолжения...")
  189.         event.pull('key_down')
  190.         c = 1
  191.       end
  192.   end
  193.   if c == 0 then print("Лог пуст.") end
  194.   log_new = #log + 1
  195. end
  196.  
  197. -- =========================================== P R O C E S S I N G =========================================== --
  198. function change(id, open)
  199.   door = findDoor(id)
  200.   if door == nil then
  201.     errout("Неверное название/ID двери ('"..tostring(id).."').")
  202.     return false
  203.   end
  204.  
  205.   -- если дверь открывается - показываем смайлик и записываем время
  206.   if open then
  207.     for a,b in pairs(doorlist[door].screen) do
  208.       show(a, ALLOW)
  209.     end
  210.     doorlist[door].time = comp.uptime()
  211.   end
  212.  
  213.   -- изменяем сигнал редстоуна
  214.   if doorlist[door].inverted then open = not open end
  215.   for a, b in pairs(doorlist[door].red) do
  216.     local red = com.proxy(a)
  217.     if red == nil then
  218.       errout("Неверный адрес контроллера: "..a.." ("..doorlist[door].name..")")
  219.     else
  220.       for i=1, #b do
  221.         if open then
  222.           red.setOutput(sides[b[i]], RED_STRENGTH)
  223.         else
  224.           red.setOutput(sides[b[i]], 0)
  225.         end
  226.       end
  227.     end
  228.   end
  229.  
  230.   return true
  231. end
  232.  
  233. function changeAll(open)
  234.   for a,b in pairs(doorlist) do
  235.     change(a, open)
  236.   end
  237. end
  238.  
  239. function trytoopen(door, output)
  240.   door = findDoor(door)
  241.   if door == nil then door = last_door end
  242.   if change(door, true) then
  243.     if output then ginfout("Открыто: "..doorlist[door].name) end
  244.   else
  245.     if output then gerrout("Неверное название/ID двери ('"..tostring(door).."').") end
  246.   end
  247. end
  248. function findDoor(id)
  249.   if id == nil then return nil end
  250.   if contains(doorlist, tonumber(id)) then return tonumber(id) end
  251.   for a,b in pairs(doorlist) do
  252.     if b.name == id then return a end
  253.   end
  254.   return nil
  255. end
  256. function findDoorByAddress(address)
  257.   for a,b in pairs(doorlist) do
  258.     if contains(b.screen, address) then
  259.       return a
  260.     end
  261.   end
  262.   return nil
  263. end
  264. function getDoor(id, glasses)
  265.   door = findDoor(id)
  266.   if door == nil then
  267.     gerrout("Неверное название/ID двери ('"..tostring(id).."').")
  268.     return false
  269.   end
  270.   local t = doorlist[door]
  271.   print('ID: '..door, 'Название: '..t.name..' (Уровень: '..t.level..')')
  272.   io.write('Контроллеры: ')
  273.   for a,b in pairs(t.red) do
  274.     io.write(a..' (')
  275.     for i=1, #b do
  276.       io.write(b[i]..' ')
  277.     end
  278.     io.write(') ')
  279.   end
  280.   io.write('\nМониторы: ')
  281.   for a,b in pairs(t.screen) do
  282.     io.write(a..' ')
  283.   end
  284.   if t.inverted then
  285.     print("Инверсный режим редстоуна.")
  286.   end
  287.   print()
  288.   -- вывод на очки
  289.   if glasses then
  290.     glassSplash('ID: '..door, 'Название: '..t.name..' (Уровень: '..t.level..')', 0)
  291.   end
  292. end
  293. function setScreens(id, output)
  294.   door = findDoor(id)
  295.   if door == nil then
  296.     errout("Неверное название/ID двери ('"..tostring(id).."').")
  297.     return false
  298.   end
  299.  
  300.   print("Введите адреса экранов (через пробел): ")
  301.   local data = split(term.read())
  302.   for i=1, #data do
  303.     local screen = com.get(data[i], 'screen')
  304.     if screen == nil then
  305.       errout("Экран "..data[i].." не найден.")
  306.     else
  307.       toList(doorlist[door].screen, screen)
  308.     end
  309.   end
  310.   if output then
  311.     ginfout("Установлены новые мониторы ("..doorlist[door].name..")")
  312.   end
  313.   return true
  314. end
  315. function setRedControllers(id, output)
  316.   door = findDoor(id)
  317.   if door == nil then
  318.     errout("Неверное название/ID двери ('"..tostring(id).."').")
  319.     return false
  320.   end
  321.  
  322.   print("Введите адрес контроллера и стороны (через пробел): ")
  323.   local data = split(term.read())
  324.   local controller = com.get(data[1], 'redstone')
  325.   if controller == nil then
  326.     errout("Неверный адрес контроллера.")
  327.     return false
  328.   end
  329.   if doorlist[door].red[controller] == nil then
  330.     toList(doorlist[door].red, controller, {})
  331.   end
  332.   for i=2, #data do
  333.     if sides[data[i]] == nil then
  334.       errout("Неверная сторона: "..data[i])
  335.     else
  336.       table.insert(doorlist[door].red[controller], data[i])
  337.     end
  338.   end
  339.   if output then
  340.     ginfout("Установлены новые контроллеры ("..doorlist[door].name..")")
  341.   end
  342.   return true
  343. end
  344. function setLevel(id, output)
  345.   door = findDoor(id)
  346.   if door == nil then
  347.     errout("Неверное название/ID двери ('"..tostring(id).."').")
  348.     return false
  349.   end
  350.  
  351.   io.write("Введите уровень двери: ")
  352.   level = tonumber(term.read())
  353.   if level ~= nil then
  354.     doorlist[door].level = level
  355.     if output then
  356.       ginfout(doorlist[door].name..": новый уровень ("..level..")")
  357.     end
  358.     return true
  359.   else
  360.     errout("Неверное значение.")
  361.   end
  362.   return false
  363. end
  364. function setInverted(id, output)
  365.   door = findDoor(id)
  366.   if door == nil then
  367.     errout("Неверное название/ID двери.")
  368.     return false
  369.   end
  370.   doorlist[door].inverted = not doorlist[door].inverted
  371.   if output then
  372.     if doorlist[door].inverted then
  373.       ginfout("Установлен инверсный редстоун-режим ("..doorlist[door].name..")")
  374.     else
  375.       ginfout("Установлен обычный редстоун-режим ("..doorlist[door].name..")")
  376.     end
  377.   end
  378.   change(door, false)
  379.   return true
  380. end
  381. function addDoor(name)
  382.   if name == nil then
  383.     errout("Неверное название двери.")
  384.     return false
  385.   end
  386.   door = findDoor(name)
  387.   if door then
  388.     warnout("Такая дверь уже есть в базе.")
  389.     return false
  390.   end
  391.   table.insert(doorlist, {name = name, level = DEFAULT_LEVEL, screen = {}, red = {}})
  392.   id = findDoor(name)
  393.   setLevel(id)
  394.   setScreens(id)
  395.   setRedControllers(id)
  396.   change(id, false)
  397.  
  398.   infout("Новая дверь успешно добавлена.")
  399.   getDoor(id)
  400.   return true
  401. end
  402.  
  403. function addAlarm(data)
  404.   if data[2] == nil then
  405.     errout("Неверное название триггера.")
  406.     return false
  407.   end
  408.   local n = tonumber(data[3])
  409.   if n == nil then
  410.     errout("Неверное условие.")
  411.     return false
  412.   end
  413.   local red = com.get(data[4], 'redstone')
  414.   if red == nil then
  415.     errout("Неверный адрес красного контроллера.")
  416.     return false
  417.   end
  418.   local side = sides[data[5]]
  419.   if red == nil then
  420.     errout("Неверно задана сторона контроллера.")
  421.     return false
  422.   end
  423.   toList(alarmlist, data[2], {condition = n, red = red, side = side})
  424.   infout("Новый триггер успешно создан.")
  425. end
  426. function offAlarms(current_time)
  427.   for a,b in pairs(alarmlist) do
  428.     if b.time ~= nil then
  429.       if (current_time-b.time) > ALARM_TIME then
  430.         changeAlarm(a, false)
  431.       end
  432.     end
  433.   end
  434. end
  435. function checkAlarms(value)
  436.   for a,b in pairs(alarmlist) do
  437.     if value >= b.condition then
  438.       changeAlarm(a, true)
  439.     end
  440.   end
  441. end
  442. function changeAlarm(name, on)
  443.   if alarmlist[name] ~= nil then
  444.     if on then alarmlist[name].time = comp.uptime()
  445.     else alarmlist[name].time = nil end
  446.  
  447.     local red = com.proxy(alarmlist[name].red)
  448.     if red ~= nil then
  449.       if on then
  450.         red.setOutput(alarmlist[name].side, 15)
  451.       else
  452.         red.setOutput(alarmlist[name].side, 0)
  453.       end
  454.     else
  455.       gerrout("Неверный адрес контроллера тревоги. ("..a..")")
  456.     end
  457.   end
  458. end
  459.  
  460. function help()
  461.   helpout("Краткая справка:")
  462.   helpout("open    - открывает дверь")
  463.   helpout("user    - задает уровень пользователя")
  464.   helpout("door    - создает новую дверь")
  465.   helpout("alarm   - создает новый триггер тевоги")
  466.   helpout("set     - редактирует параметр двери")
  467.   helpout("list    - выводит список пользователей, триггеров или дверей")
  468.   helpout("get     - информация об одной двери/пользователе")
  469.   helpout("delete  - удаляет дверь, триггер или пользователя")
  470.   helpout("log     - показывает лог событий (или очищает его)")
  471.   helpout("checkup - проверяет наличие проблем")
  472.   helpout("exit    - безопасный выход из программы")
  473.   helpout("Введите '<команда> ?' чтобы узнать синтаксис.")
  474. end
  475.  
  476.  
  477. function split(str)
  478.   local result = {}
  479.   for i in string.gmatch(str, "%S+") do
  480.     table.insert(result, i)
  481.   end
  482.   return result
  483. end
  484. function process(command, console)
  485.   -- разбивка строки-команды
  486.   local data = split(command)
  487.  
  488.   -- команда на открытие двери
  489.   if data[1] == 'help' or data[1] == '?' or data[1] == 'man' then
  490.     help()
  491.   elseif data[1] == 'open' then
  492.     if data[2] == '?' then
  493.       ghelpout("Синтаксис: open [name/ID]")
  494.     else
  495.       name = string.sub(command, 6, -2)
  496.       trytoopen(name, true)
  497.     end
  498.   -- добавление нового игрока в таблицу / изменение существующего
  499.   elseif data[1] == 'user' then
  500.     if data[2] == nil or data[2] == '?' or data[3] == nil then
  501.       ghelpout("Синтаксис: user <name> <level>")
  502.     end
  503.     local name = data[2] or DEFAULT_USER
  504.     local level = tonumber(data[3]) or DEFAULT_LEVEL
  505.     toList(userlist, name, level)
  506.     ginfout("Новый уровень доступа "..name..": "..level)
  507.   -- добавление новой двери в список
  508.   elseif data[1] == 'door' then
  509.     if data[2] == nil or data[2] == '?' then
  510.       ghelpout("Синтаксис: door <name>")
  511.     else
  512.       name = string.sub(command, 6, -2)
  513.       addDoor(name)
  514.     end
  515.   -- создание нового триггера тревоги
  516.   elseif data[1] == 'alarm' then
  517.     if data[2] == '?' then
  518.       ghelpout("Синтаксис: alarm <name> <value> <address> <side>")
  519.     else
  520.       addAlarm(data)
  521.     end
  522.   -- установка параметров
  523.   elseif data[1] == 'set' then
  524.     if data[2] == 'level' then
  525.       name = string.sub(command, 11, -2)
  526.       setLevel(name, true)
  527.     elseif data[2] == 'redstone' then
  528.       name = string.sub(command, 14, -2)
  529.       setRedControllers(name, true)
  530.     elseif data[2] == 'screen' then
  531.       name = string.sub(command, 12, -2)
  532.       setScreens(name, true)
  533.     elseif data[2] == 'inverted' then
  534.       name = string.sub(command, 14, -2)
  535.       setInverted(name, true)
  536.     else
  537.       ghelpout("Синтаксис: set <level/screen/redstone/inverted> <id/name>")
  538.     end
  539.   -- вывод на экран/очки списков
  540.   elseif data[1] == 'list' then
  541.     if data[2] == '?' then
  542.       ghelpout("Синтаксис: list [doors/users/alarms]")
  543.     elseif data[2] == 'door' or data[2] == 'doors' then
  544.       if next(doorlist) == nil then ginfout("Таблица пуста.")
  545.       else
  546.         ginfout(" Таблица дверей:")
  547.         local c = 1
  548.         for a,b in pairs(doorlist) do
  549.           getDoor(a)
  550.           c = c+5
  551.           if c > height-3 then
  552.             print("Любая клавиша для продолжения...")
  553.             event.pull('key_down')
  554.             c = 1
  555.           end
  556.         end
  557.       end
  558.     elseif data[2] == 'alarms' or data[2] == 'triggers' then
  559.       ginfout(" Таблица триггеров тревоги:")
  560.       printlist(alarmlist)
  561.     else
  562.       ginfout(" Таблица пользователей:")
  563.       printlist(userlist)
  564.     end
  565.   -- вывод информации об одной двери/юзере
  566.   elseif data[1] == 'get' then
  567.     if data[2] == nil or data[2] == '?' then
  568.       ghelpout("Синтаксис: get <username/doorname/doorID>")
  569.     end
  570.     if contains(userlist, data[2]) then
  571.       ginfout("Пользователь "..data[2]..", уровень доступа "..userlist[data[2]])
  572.     else
  573.       name = string.sub(command, 5, -2)
  574.       getDoor(name, not console)
  575.     end
  576.   -- удаление двери или игрока из списка
  577.   elseif data[1] == 'delete' or data[1] == 'remove' or data[1] == 'rm' then
  578.     if data[2] == nil or data[2] == '?' then
  579.       ghelpout("Синтаксис: rm <name/id>")
  580.     end
  581.     local name = data[2]
  582.     for i=3, #data do name = name..data[i] end
  583.     door = findDoor(name)
  584.     if door == nil then
  585.       if contains(userlist, data[2]) then
  586.         fromList(userlist, data[2])
  587.         ginfout("Игрок "..data[2].." успешно удален из списка.")
  588.       else
  589.         if contains(alarmlist, data[2]) then
  590.           fromList(alarmlist, data[2])
  591.           ginfout("Триггер "..data[2].." успешно удален.")
  592.         else
  593.           gerrout("Неверное имя/адрес.")
  594.         end
  595.       end
  596.     else
  597.       fromList(doorlist, door)
  598.       ginfout("Дверь '"..name.."' успешно удалена.")
  599.     end
  600.   -- вывод лога
  601.   elseif data[1] == 'log' then
  602.     if data[2] == '?' then
  603.       ghelpout("Синтаксис: log [all/clear]")
  604.     elseif data[2] == 'clear' then
  605.       log = {}
  606.       log_new = 1
  607.       ginfout("Лог очищен.")
  608.     elseif data[2] == 'all' then
  609.       printlog()
  610.     else
  611.       printlog(log_new)
  612.     end
  613.   -- проверка правильности данных
  614.   elseif data[1] == 'checkup' then
  615.     if data[2] == '?' then
  616.       ghelpout("Синтаксис: checkup")
  617.     else
  618.       local errors = 0
  619.       for a,b in pairs(doorlist) do
  620.         for k,v in pairs(b.screen) do
  621.           local screen = com.get(k, 'screen')
  622.           if screen == nil then
  623.             gwarnout("Не найден монитор "..screen.." ("..b.name..")")
  624.             errors = errors + 1
  625.           end
  626.         end
  627.         for k,v in pairs(b.red) do
  628.           local red = com.get(k, 'redstone')
  629.           if red == nil then
  630.             gwarnout("Не найден контроллер "..red.." ("..b.name..")")
  631.             errors = errors + 1
  632.           end
  633.         end
  634.       end
  635.       if errors == 0 then
  636.         ginfout("Проблем не обнаружено.")
  637.       else
  638.         gerrout("Найдены проблемы ("..errors..").")
  639.       end
  640.     end
  641.   -- выход из программы
  642.   elseif data[1] == 'exit' or data[1] == 'quit' or data[1] == 'q' then return false
  643.   else gerrout("Команда не знакома.") end
  644.   -- успешное выполнение
  645.   return true
  646. end
  647.  
  648. -- ============================================ E M O T I C O N S ============================================ --
  649. function show(address, str)
  650.   agpu.bind(address)
  651.   agpu.setResolution(5,1)
  652.   if str == ALLOW then
  653.     agpu.setForeground(allowcolor)
  654.   elseif str == WAIT then
  655.     agpu.setForeground(warncolor)
  656.   else
  657.     agpu.setForeground(errorcolor)
  658.   end
  659.   agpu.set(1, 1, str)
  660. end
  661.  
  662. -- ============================================== G L A S S E S ============================================== --
  663. glass_uptime = 0
  664.  
  665. function glassClear()
  666.   if glass ~= nil then
  667.     glass.clear()
  668.   end
  669. end
  670. function glassAddText(x, y, text, color)
  671.   if glass ~= nil then
  672.     obj = {}
  673.     obj[0] = glass.addText(x+1, y+1, text, 0x000000)
  674.     obj[1] = glass.addText(x, y, text, color)
  675.     return obj
  676.   end
  677. end
  678. function glassSplash(message, app)
  679.   if glass ~= nil then
  680.     glassClear()
  681.  
  682.     local width = #message*5.3; title = '[ Message ]'; color = 0xFFFFFF
  683.     x = GLASSX - width/2; y = GLASSY-10
  684.     if app == 0 then
  685.       color = infocolor
  686.       title = '[ INFO ]'
  687.     elseif app == 1 then
  688.       color = warncolor
  689.       title = '[ WARNING ]'
  690.     elseif app == 2 then
  691.       color = errorcolor
  692.       title = '[ ERROR ]'
  693.     else
  694.       color = allowcolor
  695.       title = '[ HELP ]'
  696.     end
  697.     glass.addBox(x, y, width, 20, color, 0.5)
  698.     glassAddText(GLASSX - 17, GLASSY-11, title, 0xFFFFFF)
  699.     glassAddText(x+10, GLASSY, message, 0xFFFFFF)
  700.     glass_uptime = comp.uptime()
  701.   end
  702. end
  703. function ginfout(message)
  704.   infout(message)
  705.   glassSplash(message, 0)
  706. end
  707. function gwarnout(message)
  708.   warnout(message)
  709.   glassSplash(message, 1)
  710. end
  711. function gerrout(message)
  712.   errout(message)
  713.   glassSplash(message, 2)
  714. end
  715. function ghelpout(message)
  716.   helpout(message)
  717.   glassSplash(message, 3)
  718. end
  719.  
  720. -- ======================================== N E T   I N T E R F A C E ======================================== --
  721. function sendPackage(message)
  722.   if modem ~= nil then
  723.     modem.broadcast(PORT, message)
  724.   end
  725. end
  726.  
  727. -- ================================================= M A I N ================================================= --
  728. if glass ~= nil then glass.clear() end
  729. if modem ~= nil then modem.open(PORT) end
  730.  
  731. userlist = readList('userlist.txt')
  732. doorlist = readList('doorlist.txt')
  733. alarmlist = readList('alarlist.txt')
  734.  
  735. -- добавляем OWNER'а в суперюзеры, если список только что создан
  736. if next(userlist) == nil then
  737.   toList(userlist, OWNER, 9000)
  738. end
  739. -- все двери - в исходное положение
  740. print("Закрываю все двери...")
  741. changeAll(false)
  742.  
  743. last_date = 'nil'
  744. last_call = {address = '', time = 0, user = DEFAULT_USER, pause = COOLDOWN}
  745. history = {}
  746. infout("Нажмите любую кнопку, чтобы перейти в режим ввода команд.")
  747.  
  748. -- Главный цикл - обновление/обработка --
  749. while true do
  750.   -- ждем событие
  751.   name, add, a, b, c, d = event.pull(1.0)
  752.  
  753.   local current_time = comp.uptime()
  754.   -- чистим очки
  755.   if glass_uptime ~= 0 then
  756.     if (current_time - glass_uptime) > GLASS_TIME then
  757.       glassClear()
  758.       glass_uptime = 0
  759.     end
  760.   end
  761.  
  762.   -- закрываем двери
  763.   for a,b in pairs(doorlist) do
  764.     if b.time ~= nil then
  765.       if (current_time - b.time) > OPEN_TIME then
  766.         change(a, false)
  767.         b.time = nil
  768.       end
  769.     end
  770.   end
  771.  
  772.   -- выключаем тревогу
  773.   offAlarms(current_time)
  774.  
  775.   -- обработка пользовательских команд с терминала и очков
  776.   if name == 'key_down' then
  777.     term.write("\n>> ")
  778.     command = term.read(history)
  779.     if not process(command, true) then break end
  780.   elseif name == 'chat_command' then
  781.     if not process(add, false) then break end
  782.  
  783.   -- обработка "звонков в двери"
  784.   elseif name == 'touch' then
  785.     -- защита от спама
  786.     if (d~=OWNER) and (last_call.address == add and
  787.         last_call.user == d and
  788.         (comp.uptime()-last_call.time)<last_call.pause) then
  789.       last_call.pause = last_call.pause + 1
  790.       warnout('Задержка от спама: '..last_call.pause)
  791.     else
  792.       -- обновляем антиспам-таблицу
  793.       last_call.address = add
  794.       last_call.user = d
  795.       last_call.time = comp.uptime()
  796.       last_call.pause = COOLDOWN
  797.  
  798.       -- проверяем звонок (один адрес может принадлежать нескольким дверям)
  799.       for door, value in pairs(doorlist) do
  800.         if contains(value.screen, add) then
  801.           -- выводим информацию
  802.           print("\n"..d.." у "..value.name.." (ID: "..door..")!")
  803.           -- отчет для лога
  804.           log_message = d..' | '..value.name.." (ID: "..door..") | "
  805.           net_message = {player = d, doorname = value.name, id = door}
  806.           -- проверка по списку
  807.           if not contains(userlist, d) then
  808.             show(add, WAIT)
  809.             last_door = door
  810.  
  811.             warnout("В списке его нет. Что делать?")
  812.             toLog(log_message..'?')
  813.             glassSplash(log_message..'?', 1)
  814.            
  815.             net_message.message = '?'
  816.           else
  817.             -- проверяем триггеры тревоги
  818.             checkAlarms(value.level - userlist[d])
  819.             -- выбираем реакцию
  820.             if value.level > userlist[d] then
  821.               show(add, DENY)
  822.  
  823.               print("В доступе отказано!")
  824.               toLog(log_message..'X')
  825.               glassSplash(log_message..'X', 2)
  826.              
  827.               net_message.message = 'X'
  828.             else
  829.               change(door, true)
  830.  
  831.               print("Доступ разрешен.")
  832.               toLog(log_message..'Y')
  833.               glassSplash(log_message..'Y', 0)
  834.  
  835.               net_message.message = 'Y'
  836.             end
  837.           end
  838.           -- отсылаем отчет по сети
  839.           net_message.date = last_date
  840.           sendPackage(serial.serialize(net_message))
  841.         end
  842.       end
  843.     end
  844.  
  845.   -- обрабатывает сообщения по сети
  846.   elseif name == 'modem_message' then
  847.     local data = serial.unserialize(d)
  848.     if data.command == 'open' then
  849.       trytoopen(door.id)
  850.     end
  851.   end
  852. end
  853.  
  854. -- завершение (сохраняем списки, чистим экран)
  855. if modem ~= nil then modem.close(PORT) end
  856. saveList(userlist, 'userlist.txt')
  857. saveList(doorlist, 'doorlist.txt')
  858. saveList(alarmlist, 'alarlist.txt')
  859. term.clear()
RAW Paste Data