Advertisement
ogrezem

frashBot.lua

Jun 29th, 2017
171
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 62.38 KB | None | 0 0
  1. -- Max K. 26.06.2017 mcskill.ru
  2. local component = require("component")
  3. local computer = require("computer")
  4. local term = require("term")
  5. local event = require("event")
  6. local gpu = component.gpu
  7. local serialization = require("serialization")
  8. local unicode = require("unicode")
  9. local chat = component.chat_box
  10. local debug = component.debug
  11. local fs = require("filesystem")
  12. local shell = require("shell")
  13.  
  14. function sayLocal(msg)
  15.     chat.say("local: " .. tostring(msg),40)
  16. end
  17.  
  18. chat.setName("§6G§7")
  19. setFG = gpu.setForeground
  20. setBG = gpu.setBackground
  21. gpu.setResolution(160,28)
  22. term.clear()
  23. color1 = "§3" -- дефолтное значение, переписывается в _config
  24. color2 = "§d" -- дефолтное значение, переписывается в _config
  25.  
  26. local LIVE = true -- true если стоит в рабочем состоянии на сервере - меняет поведение isGlobal(),cmd(),say()
  27.  
  28.  
  29. local c = {
  30.     download_main = "https://pastebin.com/raw/2duc9dh0", -- ссылка на код бота, для самоапдейта
  31.     download_q = "https://pastebin.com/raw/0tsR4MRP", -- ссылка на список вопросов
  32.     download_rules = "https://pastebin.com/raw/sSe7sUzK", -- ссылка на список правил
  33.     persiki = true, -- ответы в стиле "не флуди, персик"
  34.     history_borderUp = 1,
  35.     history_borderDown = 1,
  36.     history_borderLeft = 1,
  37.     history_borderRight = 1,
  38.     history_rows = nil,
  39.     history_highglight_color = 0xff0000,
  40.     history_tabs_y = 1,
  41.     screenWidth = nil,
  42.     screenHeight = nil,
  43.     frame_main_color = 0xff00ff,
  44.     frame_tabs_name_color = 0xffffff,
  45.     white = 0xffffff,
  46.     --color1 = "§3",
  47.     --color2 = "§d",
  48.     server_reboot_period = 10800, -- нужно указать как часто сервер делает рестарты
  49.     timeout_question = 60, -- кд на повторный ответ на тот же самый вопрос в чате
  50.     timeout_greeting = 60, -- кд на приветствие в чате
  51.     timeout_bye = 60, -- кд на прощание в чате
  52.     command_help = "-help",
  53.     command_help2 = "-help2",
  54.     command_inf = "-inf",
  55.     command_mods = "-mods",
  56.     command_yes = "-yes",
  57.     command_no = "-no",
  58.     command_server = "-server",
  59.     command_votestats = "-votestats",
  60.     command_votestop = "-votestop",
  61.     command_is_player_muted = "-ismuted",
  62.     command_is_player_warned = "-iswarned",
  63.     command_unmute = "-unmute",
  64.     command_unwarn = "-unwarn",
  65.     command_toggle_detect = "-toggledetect", -- стать невидимым для -mods
  66.     command_memory_used = "-memory",
  67.     command_retranslate = "==", -- говорить от имени бота
  68.     command_reboot = "=restart", -- перезагрузка бота (обновляется код бота)
  69.     command_reboot_2 = "=restart2", -- перезагрузка бота (обновляется список вопросов, правила)
  70.     command_load_config = "=loadconfig", -- скачать _config по ссылке в чат
  71.     command_stop = "=stop", -- остановить бота, сохранив только историю
  72.     server_command_personal_cooldown = 5, -- личный кулдаун на команду -server
  73.     warn_decay = 3600, -- период в секундах, на который бот запоминает свои варны. повторное нарушение дает мут вместо варна
  74.     double_warn_mute_duration = 1800, -- длительность мута в случае двойного варна за censoredWords
  75.     vote_easy_yes_to_pass = 2, -- во сколько голосов должен быть перевес для того, чтоб isEasy голосование прошло
  76.     duration_mute_caps = 600, -- длительность мута за капс
  77.     duration_mute_symbol_flood = 600, -- длительность мута за флуд символами
  78.     duration_mute_flood = 900, -- длительность мута за флуд, в т.ч. торговыми сообщениями
  79.     ratio_flood_symbol = 0.8, -- процент символов в сообщении для получения мута
  80.     ratio_caps_symbol = 0.85, -- процент капса в сообщении для получения мута (также используется в isUsernameBad())
  81.     flood_timeout = 45, -- таймаут для одинаковых сообщений
  82.     flood_normal_messages_trigger = 3, -- сколько одинаковых сообщений подряд для мута
  83.     flood_identical_trade_messages_trigger = 2, -- сколько одинаковых торговых сообщений подряд для мута
  84.     flood_any_trade_messages_trigger = 3, -- сколько любых торговых сообщений ЗА flood_any_trade_messages_period СЕКУНД для получения мута
  85.     flood_any_trade_messages_period = 180, -- период, за который учитываются торговые сообщения игрока для получения мута
  86.  
  87. }
  88.  
  89. --[[local masters = {
  90.     Shyvana = {
  91.         --undetectable = false, -- не видно в списке -mods (это значение меняется командой c.command_toggle_detect)
  92.         infiniteVote = true, -- может голосовать бесконечно
  93.         canAccessVoteStats = true, -- может юзать votestats (инфа о текущем голосовании)
  94.         canSkipVoteStartCondition = true, -- может начать голосование, даже если startCondition для голосования не соблюдено
  95.         canSkipVoteGlobalCooldown = true, -- может игнорировать глобальный кулдаун на голосование
  96.         canSkipVotePersonalCooldown = true, -- может игнорировать личный кулдаун на голосование
  97.         canSkipQuestionsCooldown = true, -- может игнорировать кулдаун на вопросы c.timeout_question
  98.         canSkipServerCommandCooldown = true, -- может игнорировать кулдаун команды -server
  99.         canCancelIssuedMutes = true, -- может отменять муты, выданные ботом
  100.         canNOTGetIgnoredByBot = true, -- если true то не может быть проигнорирован ботом (для команд глобального чата) после получения мута от него
  101.         canCurse = false, -- может ли материться в чат (если true, бот будет игнорировать мат)
  102.         canIgnoreModeratorCheckForCW = false, -- может ли игнорировать проверку на модератора если сматерится/зафлудит/закапсит в чат. true - будет получать муты, false - реплику в чат
  103.         canStopVotes = true, -- может отменять голосование
  104.         canHideFromModsCommand = true, -- может использовать команду для скрытия себя из списка -mods
  105.         canUseRetranslate = true, -- может говорить от имени бота
  106.         canReboot = true, -- может перезагружать бота
  107.     },
  108.     lLuffy = {
  109.         undetectable = true,
  110.         canAccessVoteStats = true,
  111.         canCancelIssuedMutes = true,
  112.         canStopVotes = true,
  113.         canHideFromModsCommand = true,
  114.         canUseRetranslate = true,
  115.     },
  116.     Astro = {
  117.         canAccessVoteStats = true,
  118.         canCancelIssuedMutes = true,
  119.         canStopVotes = true,
  120.         canUseRetranslate = true,
  121.     },
  122.     Makcu = {
  123.         canAccessVoteStats = true,
  124.         canCancelIssuedMutes = true,
  125.         canStopVotes = true,
  126.         canUseRetranslate = true,
  127.     },
  128. }
  129.  
  130. local mods = {
  131.     { group = "Тех.Админ", prefixColor = "§4", nameColor = "§7", list = {"lLuffy",}},
  132.     { group = "Дизайнер", prefixColor = "§9", nameColor = "§3", list = {"Shyvana",}},
  133.     { group = "Гл.модератор", prefixColor = "§9", nameColor = "§3", list = {}},
  134.     { group = "Ст.модератор", prefixColor = "§3", nameColor = "§b", list = {"Makcu",}},
  135.     { group = "Строитель", prefixColor = "§d", nameColor = "§d", list = {"Stanislav",}},
  136.     { group = "Модератор", prefixColor = "§4", nameColor = "§6", list = {"SilverGamers",}},
  137.     { group = "Помощник", prefixColor = "§2", nameColor = "§a", list = {"DanilValiev1",}},
  138.     { group = "Стажёр", prefixColor = "§a", nameColor = "§a", list = {"Hammerschmidt","Jordan","RobinzonCruzo","Jane","V1taliy_"}},
  139. }]]
  140.  
  141. local historyTabs = {
  142.     [1] = {name = "Questions", start = 2, width = 37, prefix = "[Q]", prefix2 = "%[Q%]", prefixColor = 0x00ff00}, -- 2 45
  143.     [2] = {name = "Warned/Muted", start = 41, width = 93,prefix = "[M]", prefix2 = "%[M%]", prefixColor = 0xcd8700}, --49 91
  144.     [3] = {name = "Commands", start = 136, width = 23,prefix = "[C]", prefix2 = "%[C%]", prefixColor = 0x00ff00},
  145. }
  146.  
  147. local censoredWords = {
  148.     [1] = {list = {"пидор", "пидар", "ебать", "ёбаный", "ёбанный", "ёбырь", "ебырь", "ебнутый", "ёбнутый", "хер ", "хуй ","хуйл", "нихуя", "хуя ", "ебись", "ебать", "пидр", "хуйня", "хуи ", "хуила", "нахуй", "похуй", "хуев", "хуёв", "хуес", "хуег", "отъебись", "отьебись", "отебись", "долбаеб", "долбаёб", "долбоеб", "долбоёб", "хуета", "хуита", "пизд", "ебан", "ёбан", "ебал", "наеб", "наёб", "ебу", "ебло", "уебок", "уёбо", "уебан", "уебки", "уёбки", "ахуеть", "ахуительно", "ахуенно", "охуенно", "охуительно", "заебись", "заебал", "ебет", "ебёт", "ебаца", "ебацца", "нехуя", "ебацо", "ибаца", "ибацца", "ебанат", "уебище", "уёбище", "выеб", "блядь", "блядин", "хуйня", "выбляд", "еблищ", "пиздяч", "впиздяч", "выблядова", "blyad", "blyat", "ebal", "pidor", "pidar", "hui", "huesos", "ueban", "uebok", "xyi", "xui", "пидрила", "мразь", "залуп", "гандон"}, duration = 1800},
  149.     [2] = {list = {}, duration = 1200},
  150.     [3] = {list = {"бля", "сука", "чмо", "педик", "хули ", "мудак", "мудила", "мудень", "мудозвон", "курва", "cyka", "suka",}, duration = "warn"},
  151. }
  152.  
  153. local helloWords = {"прив","q","ку","здаров","здоров","доброе утро","добрый день","добрый вечер","хай"}
  154. local byeWords = {"bb","бб","пока","свидания","досвид","спокойной"}
  155. local helloPhrases = {"Привет, persik :*","Как дела, persik :*","Давно не виделись, persik :*"}
  156. local byePhrases = {"Спокойной ночи, persik :*","Я буду скучать, persik :*","Не уходи, persik :(","до завтра, persik :*"}
  157. local ignoredCaps = {"ЭХПФ", "МФЭХ", "МФЭ",}
  158. local persiki = {"солнышко", "зайчик", "пупсик", "котик", "сладкий", "милый", "медвежонок", "ангелочек", "одуванчик", "малыш", "кисик", "любимый", "родной", "симпотяжка", "львеночек", "тигреночек", "пушистик", "персик", "пончик", "котенок","апельсинчик","арбузик","бельчонок","лапочка","лисёнок","очаровашка",}
  159.  
  160. c.screenWidth, c.screenHeight = gpu.getResolution()
  161. c.history_rows = c.screenHeight - c.history_borderUp - c.history_borderDown
  162.  
  163. local messages = {}
  164. -- инициализируются в initialization()
  165. --local history = {}
  166. --local mutes = {} -- mutes["Shyvana"] = 29111 - содержит computer.uptime() момента, когда мут истечет
  167. --local warns = {} -- warns["Shyvana"] = 29111 - содержит computer.uptime() момента, когда варн истечет
  168.  
  169. function initialization()
  170.     -- считывает файлы _q, _rules, _config и не стартует без них. потом загружает __history, __messages, __mutes, __warns чтобы продолжить работу там где закончил до рестарта. иначе начинает с нуля
  171.     local currentTime = computer.uptime()
  172.     local exit = false
  173.     local files = {
  174.     "/home/_q",
  175.     "/home/_rules",
  176.     "/home/_config",
  177.     }
  178.    
  179.     sayLocal(color2 .. "Запуск ...")
  180.     for _,file in ipairs(files) do
  181.         if fs.exists(file) then
  182.             loadfile(file)()
  183.             print(file .. " - OK")
  184.             sayLocal(color1 .. file .. "§2 - ok")
  185.         else
  186.             sayLocal(color1 .. file .. "§c - !не найден!")
  187.             print(" !!!   не найден файл " .. file)
  188.             exit = true
  189.         end
  190.     end
  191.     if exit then
  192.         sayLocal("§4 запуск невозможен")
  193.         os.exit()
  194.     end
  195.     function historyInitialize()
  196.         for i = 1,#historyTabs do
  197.             history[i] = {}
  198.             for ii = 1,c.history_rows do
  199.                 history[i][ii] = {text = "", highlight = nil}
  200.             end
  201.         end
  202.     end
  203.     function restoreTable(file)
  204.         if fs.exists(file) then
  205.             local f,err = io.open(file,"r")
  206.             if err then
  207.                 print(err)
  208.                 exit = true
  209.             else
  210.                 local res = f:read()
  211.                 f:close()
  212.                 res = serialization.unserialize(res)
  213.                 sayLocal(color1 .. file .. "§2 - возобновлен")
  214.                 fs.remove(file)
  215.                 return res
  216.             end
  217.         else
  218.             sayLocal(color1 .. file .. "§c не возобновлен")
  219.         end
  220.     end
  221.  
  222.     function fixMutesAndWarns(table) -- фиксит mutes и warns (в файле записано оставшееся время мута, а ф-я меняет его на computer.uptime() момента, когда мут истечет минус пару сек для компенсации времени рестарта)
  223.         for k,v in pairs(table) do
  224.             table[k] = table[k] + currentTime - 5
  225.         end
  226.     end
  227.     -- продублировать все в saveAllStates()
  228.     history = restoreTable("/home/__history")
  229.     if history == nil then
  230.         history = {}
  231.         historyInitialize()
  232.     end
  233.     --messages = restoreTable("/home/__messages") or {}
  234.     mutes = restoreTable("/home/__mutes") or {}
  235.     warns = restoreTable("/home/__warns") or {}
  236.  
  237.     fixMutesAndWarns(mutes)
  238.     fixMutesAndWarns(warns)
  239.  
  240.     if exit then
  241.         os.exit()
  242.     else
  243.         sayLocal(color2 .. "Бот запущен")
  244.         term.clear()
  245.     end
  246. end
  247.  
  248. initialization()
  249.  
  250. local coloring = {"&0","&1","&2","&3","&4","&5","&6","&7","&8","&9","&a","&b","&c","&d","&e","&f",}
  251.  
  252. --local mainWorld = 0 -- id главного мира, через component.debug.getWorld().getDimensionId() например
  253. local activeVote = false -- "=votesun"
  254. local activeVoteTimerId
  255. local hasUserVoted = {}
  256. local currentVoteResults = {
  257.     yes = 0,
  258.     no = 0,
  259. }
  260. local questionLastTriggered = {}
  261. local serverCommandCooldowns = {} -- serverCommandCooldowns["Shyvana"] = 29111 - содержит computer.uptime() момента, когда кд на команду -server истечет
  262. local greetingCooldown = 0 -- содержит computer.uptime() момента, когда глобальный кд на приветствие истечет
  263. local byeCooldown = 0 -- содержит computer.uptime() момента, когда глобальный кд на прощание истечет
  264. function isRaining()
  265.     return debug.getWorld(mainWorld).isRaining()
  266. end
  267. function turnOffRain()
  268.     debug.getWorld(mainWorld).setRaining(false)
  269. end
  270. function setMorning()
  271.     debug.getWorld(mainWorld).setTime(0)
  272. end
  273. function none()
  274.     return true
  275. end
  276. local votes = {
  277.     ["-votesun"] = {
  278.         lastActivatedByPlayer = {}, -- не трогать
  279.         lastActivated = 0, -- не трогать
  280.         StaticGlobalCooldown = 300, -- глобальный кулдаун для всех игроков на использование именно этого голосования
  281.         StaticPersonalCooldown = 1200, -- личный кулдаун каждого игрока на использование именно этого голосования
  282.         text = "отключение дождя", -- "игрок начал голосование за" ..
  283.         duration = 25, -- время в секундах, которое дается на голосование
  284.         isEasy = true, -- легко проголосовать "да" (не юзать в votemute). перевес определяется в c.vote_easy_yes_to_pass
  285.         startCondition = isRaining, -- возможно начать голосование только если эта функция вернет true. ВСЕ ФУНКЦИИ ДОЛЖНЫ СТОЯТЬ ВЫШЕ ЭТОЙ ТАБЛИЦЫ. указать none если условие не нужно
  286.         denyMsg = "в данный момент дождя нет", -- что получит пользователь в ответ если startCondition == false
  287.         passFunction = turnOffRain, -- функция, которая вызовется если голосование пройдет
  288.         passMessage = "дождь отключен", -- отчет в глобал чат если голосование пройдет
  289.         failFunction = none, -- функция, которая вызовется, если голосование провалится
  290.         failMessage = "дождь не отключен", -- отчет в глобал чат если голосование не пройдет
  291.         },
  292.     ["-voteday"] = {
  293.         lastActivatedByPlayer = {},
  294.         lastActivated = 0,
  295.         StaticGlobalCooldown = 300,
  296.         StaticPersonalCooldown = 1200,
  297.         text = "смену времени суток на утро",
  298.         duration = 25,
  299.         isEasy = true,
  300.         startCondition = none,
  301.         denyMsg = " ",
  302.         passFunction = setMorning,
  303.         passMessage = "утро включено",
  304.         failFunction = none,
  305.         failMessage = "время суток не изменено",
  306.         },
  307. }
  308.  
  309. function say(msg0,shouldIgnore) -- shouldIgnore - будет ли ф-я будет игнорировать uppercaseGlobal (true - не будет менять первую букву на заглавную)
  310.     local msg = tostring(msg0)
  311.     if uppercaseGlobal and not shouldIgnore then
  312.         if string.find(msg,"§") == 1 then -- если вдруг первая буква - установка цвета
  313.             msg = unicode.sub(msg,0,2) .. unicode.upper(unicode.sub(msg,3,3)) .. unicode.sub(msg,4)
  314.         else
  315.             msg = unicode.upper(unicode.sub(msg,0,1)) .. unicode.sub(msg,2)
  316.         end
  317.     end
  318.     if LIVE then
  319.         chat.say(CHATNAME .. msg)
  320.     else
  321.         chat.say(CHATNAME .. msg,40)
  322.     end
  323. end
  324.  
  325. function cmdReal(command)
  326.     component.opencb.execute(tostring(command))
  327. end
  328. function cmd(command)
  329.     if LIVE then
  330.         component.opencb.execute(tostring(command))
  331.     else
  332.         say("CMD: " .. command)
  333.     end
  334. end
  335. function whisper(player,text0)
  336.     local text = tostring(text0)
  337.     if uppercaseWhisper then
  338.         if string.find(text,"§") == 1 then -- если вдруг первая буква - установка цвета
  339.             text = unicode.sub(text,0,2) .. unicode.upper(unicode.sub(text,3,3)) .. unicode.sub(text,4)
  340.         else
  341.             text = unicode.upper(unicode.sub(text,0,1)) .. unicode.sub(text,2)
  342.         end
  343.     end
  344.     component.opencb.execute("m " .. player .. " " .. text)
  345. end
  346. function drawMainFrame()
  347.     setFG(c.frame_main_color)
  348.     gpu.set(1,1,string.rep("─",c.screenWidth)) -- ═
  349.     gpu.set(1,c.screenHeight,string.rep("─",c.screenWidth)) -- ═
  350.     gpu.set(1,1,string.rep("│",c.screenHeight),true) -- ║
  351.     gpu.set(c.screenWidth,1,string.rep("│",c.screenHeight),true)
  352.     gpu.set(1,1,"┌") --╔
  353.     gpu.set(c.screenWidth,1,"┐")
  354.     gpu.set(1,c.screenHeight,"└")
  355.     gpu.set(c.screenWidth,c.screenHeight,"┘")
  356.     for i = 1,#historyTabs do
  357.         drawCenteredText(historyTabs[i].start,c.history_tabs_y,historyTabs[i].width,"┤ " .. historyTabs[i].name .. " ├")
  358.         setFG(c.frame_tabs_name_color)
  359.         drawCenteredText(historyTabs[i].start,c.history_tabs_y,historyTabs[i].width,historyTabs[i].name )
  360.         setFG(c.frame_main_color)
  361.     end
  362.     for ii = 1,#historyTabs-1 do
  363.         gpu.set(historyTabs[ii].start+historyTabs[ii].width+1,c.history_tabs_y,string.rep("│",c.history_rows+2),true)
  364.         gpu.set(historyTabs[ii].start+historyTabs[ii].width+1,c.history_tabs_y,"┬")
  365.         gpu.set(historyTabs[ii].start+historyTabs[ii].width+1,c.history_tabs_y+c.history_rows+1,"┴")
  366.     end
  367.     setFG(c.white)
  368. end
  369.  
  370. function drawCenteredText(x,y,width,text)
  371.     gpu.set(x+math.floor(width/2)-math.floor(unicode.len(text)/2),y,text)
  372. end
  373. function log(index,text,highlightedText)
  374.     local text = historyTabs[index].prefix .. text
  375.     local extra = unicode.len(text) - historyTabs[index].width
  376.     if extra <= 0 then
  377.         table.insert(history[index],{text = text .. string.rep(" ",-extra), highlight = highlightedText})
  378.         table.remove(history[index],1)
  379.     else
  380.         local text1
  381.         local text2
  382.         if highlightedText then
  383.             local a,b = string.find(text,highlightedText)
  384.             if a then
  385.                 if a <= historyTabs[index].width and b > historyTabs[index].width then
  386.                     text1 = unicode.sub(text,0,a-1)
  387.                     text2 = unicode.sub(text,a,a+historyTabs[index].width)
  388.                 else
  389.                     text1 = unicode.sub(text,0,historyTabs[index].width)
  390.                     text2 = unicode.sub(text,historyTabs[index].width+1,historyTabs[index].width*2)
  391.                 end
  392.             else
  393.                 text1 = unicode.sub(text,0,historyTabs[index].width)
  394.                 text2 = unicode.sub(text,historyTabs[index].width+1,historyTabs[index].width*2)
  395.             end
  396.         else
  397.             text1 = unicode.sub(text,0,historyTabs[index].width)
  398.             text2 = unicode.sub(text,historyTabs[index].width+1,historyTabs[index].width*2)
  399.         end
  400.         table.insert(history[index],{text = text1 .. string.rep(" ",historyTabs[index].width-unicode.len(text1)), highlight = highlightedText})
  401.         table.insert(history[index],{text = text2 .. string.rep(" ",historyTabs[index].width-unicode.len(text2)), highlight = highlightedText})
  402.         table.remove(history[index],1)
  403.         table.remove(history[index],2)
  404.     end
  405.     historyDraw()
  406. end
  407. function historyDraw()
  408.     for column = 1,#historyTabs do
  409.         for row = c.history_rows,1,-1 do
  410.             drawStringWithHighlight(historyTabs[column].start,c.history_borderUp+row,history[column][row].text,history[column][row].highlight,column)
  411.         end
  412.     end
  413. end
  414. function drawStringWithHighlight(x,y,string,highlight,index)
  415.     if index and string.find(string,historyTabs[index].prefix2) == 1 then
  416.         gpu.set(x,y,string.sub(historyTabs[index].prefix,1,1))
  417.         setFG(historyTabs[index].prefixColor)
  418.         gpu.set(x+1,y,string.sub(historyTabs[index].prefix,2,2))
  419.         setFG(c.white)
  420.         gpu.set(x+2,y,string.sub(historyTabs[index].prefix,3,3))
  421.         local newstring = string.sub(string,string.len(historyTabs[index].prefix)+1)
  422.         drawStringWithHighlight(x+string.len(historyTabs[index].prefix),y,newstring,highlight)
  423.     else
  424.         if highlight ~= nil then
  425.             local a,b = string.find(unicode.lower(string),highlight)
  426.             if a == nil then
  427.                 gpu.set(x,y,string)
  428.             elseif a > 1 then
  429.                 local newstring0 = string.sub(string,0,a-1)
  430.                 gpu.set(x,y,newstring0)
  431.                 local newstring = string.sub(string,a)
  432.                 drawStringWithHighlight(x+unicode.len(newstring0),y,newstring,highlight)
  433.             elseif a == 1 then
  434.                 setFG(c.history_highglight_color)
  435.                 local newstring0 = string.sub(string,0,b)
  436.                 gpu.set(x,y,newstring0)
  437.                 setFG(0xffffff)
  438.                 local newstring = string.sub(string,b+1)
  439.                 drawStringWithHighlight(x+unicode.len(newstring0),y,newstring,highlight)
  440.             end
  441.         else
  442.             gpu.set(x,y,string)
  443.         end
  444.     end
  445. end
  446. function getIndex(table,ind)
  447.     --say("getindex")
  448.     local ind = unicode.lower(ind)
  449.     for k,_ in pairs(table) do
  450.         if unicode.lower(k) == ind then
  451.             return k
  452.         end
  453.     end
  454. end
  455. function isModerator(name)
  456.     for _,group in ipairs(mods) do
  457.         for _,nick in ipairs(group.list) do
  458.             if nick == name then
  459.                 return true
  460.             end
  461.         end
  462.     end
  463.     return false
  464. end
  465. function isPlayerMuted(name0,specificCase) -- если specificCase = true то будет проверять ник только по заданному регистру, а не по всем
  466.     local currentTime = computer.uptime()
  467.     local name = name0
  468.     if not specificCase then
  469.         name = getIndex(mutes,name)
  470.     end
  471.     if mutes[name] and (mutes[name] > currentTime) then
  472.         return true, math.floor(mutes[name] - currentTime), name
  473.     else
  474.         return false
  475.     end
  476. end
  477. function isPlayerWarned(name) -- имеет ли активный варн
  478.     local currentTime = computer.uptime()
  479.     name = getIndex(warns,name)
  480.     if warns[name] and (warns[name] > currentTime) then
  481.         return true, math.floor(warns[name] - currentTime), name
  482.     else
  483.         return false
  484.     end
  485. end
  486. function canPlayerUseServerCommand(name)
  487.     local currentTime = computer.uptime()
  488.     if serverCommandCooldowns[name] and (serverCommandCooldowns[name] > currentTime) then
  489.         return false, math.floor(serverCommandCooldowns[name] - currentTime)
  490.     else
  491.         return true
  492.     end
  493. end
  494. function tempMute(name,duration,reason)
  495.     mutes[name] = computer.uptime() + duration
  496.     cmd("tempmute " .. name .. " " .. duration .. " sec " .. reason)
  497. end
  498. function isGlobal(msg)
  499.     if LIVE == true then
  500.         if string.find(msg,"!") == 1 then
  501.             return true
  502.         else
  503.             return false
  504.         end
  505.     else
  506.         if string.find(msg,"%.") == 1 or string.find(msg,"!") == 1 then
  507.             return true
  508.         else
  509.             return false
  510.         end
  511.     end
  512. end
  513. function isOnline(player)
  514.     if debug.getPlayer(player).getGameType() == nil then
  515.         return false
  516.     else
  517.         return true
  518.     end
  519. end
  520. function isOnlineFaster(table,name) -- получает таблицу debug.getPlayers()
  521.     for k,v in ipairs(table) do
  522.         if v == name then
  523.             return true
  524.         end
  525.     end
  526.     return false
  527. end
  528. function deColor(string)
  529.     local text = string
  530.     for _,v in pairs(coloring) do
  531.         text = string.gsub(text,v,"")
  532.     end
  533.     return text
  534. end
  535. function processMods(msg0,player)
  536.     local msg = unicode.lower(msg0)
  537.     if msg == c.command_mods then
  538.         local strings = {}
  539.         log(3,player .. ": " .. msg0)
  540.         local t = debug.getPlayers()
  541.         for index,this in ipairs(mods) do
  542.             for _,name in ipairs(this.list) do
  543.                 if isOnlineFaster(t,name) then
  544.            
  545.                     if (not masters[name]) or (not masters[name].undetectable) then
  546.                         table.insert(strings,"m " .. player .. " §aonline §8> [" .. this.prefixColor .. this.group .. "§8] " .. this.nameColor .. name)
  547.                     end
  548.                 end
  549.             end
  550.         end
  551.         for k,v in ipairs(strings) do
  552.             cmdReal(v)
  553.         end
  554.     end
  555. end
  556. function processQuestions(msg0,name)
  557.     local msg = unicode.lower(msg0)
  558.     local currentTime = computer.uptime()
  559.     function checkWordBlock(wordblock)
  560.         for _,word in ipairs(wordblock) do
  561.             if string.find(msg,word) then
  562.                 return true
  563.             end
  564.         end
  565.         return false
  566.     end
  567.     function canTriggerQuestion(ind)
  568.         if questionLastTriggered[ind] then
  569.             if (questionLastTriggered[ind] + c.timeout_question) > currentTime then
  570.                 return false
  571.             else
  572.                 return true
  573.             end
  574.         else
  575.             return true
  576.         end
  577.     end
  578.    
  579.     for ind,question in ipairs(Q) do
  580.         local shouldAnswer = true
  581.         for _,wordblock in ipairs(question) do
  582.             if checkWordBlock(wordblock) == false then
  583.                 shouldAnswer = false
  584.                 break
  585.             end
  586.         end
  587.         if shouldAnswer then
  588.             if canTriggerQuestion(ind) or (masters[name] and masters[name].canSkipQuestionsCooldown) then
  589.                 local answer = Q[ind].response
  590.                 answer = string.gsub(string.gsub(answer,"#c1",color1),"#c2",color2)
  591.                 say(answer)
  592.                 questionLastTriggered[ind] = currentTime
  593.                 log(1,name .. ": " .. msg0)
  594.                 return true
  595.             end
  596.         end
  597.     end
  598. end
  599. function processCensoredWords(msg0,name)
  600.     local msg = unicode.lower(msg0)
  601.     if not (masters[name] and masters[name].canCurse) then
  602.         for _,wordSet in ipairs(censoredWords) do
  603.             for _,word in pairs(wordSet.list) do
  604.                 if string.find(msg,word) then
  605.                     if not string.find(msg,"%S" .. word) then
  606.                         if isModerator(name) == false or (masters[name] and masters[name].canIgnoreModeratorCheckForCW) then
  607.                             if wordSet.duration == "warn" then
  608.                                 if not isPlayerWarned(name) then
  609.                                     cmd("warn " .. name .. " autowarn 3.1 (ругательства)")
  610.                                     persikAnswer(5,name)
  611.                                     warns[name] = computer.uptime() + c.warn_decay
  612.                                     log(2,"(3.1) warn " .. name .. ": " .. msg0,word)
  613.                                 else
  614.                                     tempMute(name,c.double_warn_mute_duration,"automute 3.1 (ругательства)+")
  615.                                     persikAnswer(2,name)
  616.                                     log(2,"(3.1) " .. name .. ": " .. msg0,word)
  617.                                     warns[name] = nil
  618.                                 end
  619.                                 return true
  620.                             else
  621.                                 tempMute(name,wordSet.duration,"automute 3.1 (ругательства)")
  622.                                 persikAnswer(2,name)
  623.                                 log(2,"(3.1) " .. name .. ": " .. msg0,word)
  624.                                 return true
  625.                             end
  626.                         else
  627.                             say(color1 .. name .. ", ты же модератор, не ругайся :*")
  628.                             log(2," mod? " .. name .. ": " .. msg0,word)
  629.                             return true
  630.                         end
  631.                     end
  632.                 end
  633.             end
  634.         end
  635.     end
  636. end
  637. function processInf(msg0,name)
  638.     local msg = unicode.lower(msg0)
  639.     if msg == c.command_inf then
  640.         whisper(name,color1 .. "необходимо указать пункт правил, например, " .. color2 .. c.command_inf .. " 3.1")
  641.     else
  642.         if string.find(msg,c.command_inf .. " ") == 1 then
  643.             local rule = rules[string.sub(msg,string.len(c.command_inf)+2)] or rules[string.gsub(string.sub(msg,string.len(c.command_inf)+2),",",".")]
  644.             if rule then
  645.                 whisper(name,color2 .. string.gsub(string.sub(msg,string.len(c.command_inf)+2),",",".") ..  ": " .. color1 .. rule.text)
  646.                 if rule.punishment then
  647.                     whisper(name,string.gsub(rule.punishment,"Наказание:",color2 .. "Наказание:" .. color1))
  648.                     whisper(name,string.gsub(rule.punishment,"За нарушение правил:",color2 .. "За нарушение правил:" .. color1))
  649.                 end
  650.                 log(3,name .. ": " .. msg0)
  651.             else
  652.                 whisper(name,color1 .. "пункт правил указан неверно")
  653.             end
  654.         end
  655.     end
  656. end
  657. function processCaps(msg,name)
  658.     local newmsg
  659.     function isUsernameBad(username)
  660.         local username = string.gsub(username,"%d","")
  661.         local username = string.gsub(username,"%p","")
  662.         local total = unicode.len(username)
  663.         if total > 5 then
  664.             local bad = 0
  665.             for i = 1,total do
  666.                 local char = unicode.sub(username,i,i)
  667.                 if char ~= unicode.lower(char) then
  668.                     bad = bad + 1
  669.                 end
  670.             end
  671.             if bad/total > c.ratio_caps_symbol then
  672.                 return true
  673.             else
  674.                 return false
  675.             end
  676.         else
  677.             return false
  678.         end
  679.     end
  680.     function getBadUsernames()
  681.         local t = debug.getPlayers()
  682.         local res = {}
  683.         for _,player in ipairs(t) do
  684.             if isUsernameBad(player) then
  685.                 table.insert(res,player)
  686.             end
  687.         end
  688.         return res
  689.     end
  690.  
  691.     for _,word in ipairs(ignoredCaps) do
  692.         newmsg = string.gsub(msg,word,"")
  693.     end
  694.     local newmsg = string.gsub(newmsg,"%d","")
  695.     local newmsg = string.gsub(newmsg,"%p","")
  696.     local newmsg = string.gsub(newmsg," ","")
  697.     if unicode.len(newmsg) > 7 then
  698.         local total = unicode.len(newmsg)
  699.         local bad = 0
  700.         for i = 1,total do
  701.             local char = unicode.sub(newmsg,i,i)
  702.             if char ~= unicode.lower(char) then
  703.                 bad = bad + 1
  704.             end
  705.         end
  706.         if bad/total > c.ratio_caps_symbol then
  707.             for k,player in ipairs(getBadUsernames()) do
  708.                 if string.find(msg,player) then
  709.                     return true
  710.                 end
  711.             end
  712.             if isModerator(name) == false or (masters[name] and masters[name].canIgnoreModeratorCheckForCW) then
  713.                 tempMute(name,c.duration_mute_caps,"automute 3.1 (капс)")
  714.                 persikAnswer(1,name)
  715.                 log(2,"(3.1 caps)" .. name .. ": " .. msg)
  716.             else
  717.                 say(color1 .. name .. ", ты же модератор, не капси :*")
  718.             end
  719.         end
  720.     end
  721. end
  722. function processSymbolFlood(msg,name)
  723.     local len1 = unicode.len(msg)
  724.     if len1 >= 8 then
  725.         local _,len2 = string.gsub(msg,"%p","")
  726.         if (len2/len1) > c.ratio_flood_symbol then
  727.             if isModerator(name) == false or (masters[name] and masters[name].canIgnoreModeratorCheckForCW) then
  728.                 tempMute(name,c.duration_mute_symbol_flood,"automute 3.1 (флуд символами)")
  729.                 persikAnswer(3,name)
  730.                 log(2,"3.1 (symbol flood)" .. name .. ": " .. msg)
  731.             else
  732.                 say(color1 .. name .. ", ты же модератор, не флуди :*")
  733.             end
  734.         end
  735.     end
  736. end
  737. function processFlood(msg0,name)
  738.     local msg = unicode.lower(msg0)
  739.     local function isTradeMsg(msg)
  740.         local len = unicode.len(msg)
  741.         local tradeFilter = {"купл","продам","кто продаст","продаю"}
  742.         local tradeFilter2 = {"warp"}
  743.         for _,word in ipairs(tradeFilter) do
  744.             if string.find(msg,word) and len > 12 then
  745.                 return true
  746.             end
  747.         end
  748.         for _,word in ipairs(tradeFilter2) do
  749.             if string.find(msg,word) and len > 30 then
  750.                 return true
  751.             end
  752.         end
  753.         return false
  754.     end
  755.     local isTrade = isTradeMsg(msg)
  756.     local currentTime = computer.uptime()
  757.     if not messages[name] then
  758.         messages[name] = {}
  759.     end
  760.     if not messages[name].previous then
  761.         messages[name].anyTradeTimers = {}
  762.         for i = 1,c.flood_any_trade_messages_trigger do
  763.             messages[name].anyTradeTimers[i] = 0
  764.         end
  765.     end
  766.     if not messages[name].previous or messages[name].previous ~= msg or messages[name].time <= currentTime - c.flood_timeout then
  767.         messages[name].previous = msg
  768.         messages[name].time = currentTime
  769.         messages[name].subsequents = 1
  770.     else
  771.         messages[name].subsequents = messages[name].subsequents + 1
  772.     end
  773.     if isTrade then
  774.         table.insert(messages[name].anyTradeTimers,currentTime)
  775.         table.remove(messages[name].anyTradeTimers,1)
  776.     end
  777.     if isTrade and messages[name].subsequents >= c.flood_identical_trade_messages_trigger then
  778.         if isModerator(name) == false or (masters[name] and masters[name].canIgnoreModeratorCheckForCW) then
  779.             tempMute(name,c.duration_mute_flood,"automute 3.6 (частая реклама)")
  780.             persikAnswer(4,name)
  781.             messages[name].previous = nil
  782.             log(2,"(3.6: x" .. c.flood_identical_trade_messages_trigger .." in a row)"  .. name .. ": " .. msg0,word)
  783.         else
  784.             say(color1 .. name .. ", ты же модератор, не флуди :*")
  785.         end
  786.     elseif messages[name].subsequents >= c.flood_normal_messages_trigger then
  787.         if isModerator(name) == false or (masters[name] and masters[name].canIgnoreModeratorCheckForCW) then
  788.             tempMute(name,c.duration_mute_flood,"automute 3.1 (флуд)")
  789.             persikAnswer(3,name)
  790.             messages[name].previous = nil
  791.             log(2,"(3.1: x" .. c.flood_normal_messages_trigger ..")"  .. name .. ": " .. msg0,word)
  792.         else
  793.             say(color1 .. name .. ", ты же модератор, не флуди :*")
  794.         end
  795.     elseif isTrade and messages[name].anyTradeTimers[1] ~= 0 and (currentTime - messages[name].anyTradeTimers[1]) <= c.flood_any_trade_messages_period then
  796.         if isModerator(name) == false or (masters[name] and masters[name].canIgnoreModeratorCheckForCW) then
  797.             tempMute(name,c.duration_mute_flood,"automute 3.6 (частая реклама+)")
  798.             persikAnswer(4,name)
  799.             messages[name].previous = nil
  800.             log(2,"(3.6+: x" .. c.flood_any_trade_messages_trigger .." in " .. c.flood_any_trade_messages_period .. "s)"  .. name .. ": " .. msg0,word)
  801.         else
  802.             say(color1 .. name .. ", ты же модератор, не флуди :*")
  803.         end
  804.     end
  805. end
  806. function getVoteCurrentGlobalCooldown(command)
  807.     if votes[command] then
  808.         if votes[command].lastActivated == 0 then
  809.             return 0
  810.         else
  811.             local cd = (votes[command].lastActivated + votes[command].StaticGlobalCooldown) - computer.uptime()
  812.             if cd <= 0 then
  813.                 return 0
  814.             elseif cd > 0 then
  815.                 return cd
  816.             end
  817.         end
  818.     else
  819.         error("#1")
  820.     end
  821. end
  822. function getCurrentVoteTimer()
  823.     if activeVote then
  824.         local time = (votes[activeVote].lastActivated + votes[activeVote].duration) - computer.uptime()
  825.         if time > 0 then
  826.             return time
  827.         else
  828.             return 0
  829.         end
  830.     else
  831.         return "NIL"
  832.     end
  833. end
  834. function getVoteCurrentPersonalCooldown(command,name)
  835.     if votes[command] then
  836.         local last = votes[command].lastActivatedByPlayer[name]
  837.         if last then
  838.             local cd = (last + votes[command].StaticPersonalCooldown) - computer.uptime()
  839.             if cd <= 0 then
  840.                 return 0
  841.             elseif cd > 0 then
  842.                 return cd
  843.             end
  844.         else
  845.             return 0
  846.         end
  847.     else
  848.         error("#2")
  849.     end
  850. end
  851. function pushEndvoteSignal()
  852.     event.push("endvote",1) -- 1 значит что голосование закончилось само по себе и выдаст результат
  853. end
  854. function processVoteStart(msg0,name)
  855.     local msg = unicode.lower(msg0)
  856.     if votes[msg] then
  857.         currentTime = computer.uptime()
  858.         if not activeVote then
  859.             if votes[msg].startCondition() == true or (masters[name] and masters[name].canSkipVoteStartCondition) then
  860.                 if getVoteCurrentGlobalCooldown(msg) == 0 or (masters[name] and masters[name].canSkipVoteGlobalCooldown) then
  861.                     if getVoteCurrentPersonalCooldown(msg,name) == 0 or (masters[name] and masters[name].canSkipVotePersonalCooldown) then
  862.                         log(3,name .. ": " .. msg0)
  863.                         activeVote = msg
  864.                         votes[msg].lastActivated = currentTime
  865.                         votes[msg].lastActivatedByPlayer[name] = currentTime
  866.                         activeVoteTimerId = event.timer(votes[msg].duration,pushEndvoteSignal,1)
  867.                         say(color1 .. "Игрок ".. color2 .. name .. color1 .. " начал голосование за " .. votes[msg].text)
  868.                         say(color1 .. "Введите " .. color2 .. c.command_yes .. color1 .. " или " .. color2 .. c.command_no .. color1 .. " в локальный чат. Голосование длится " .. color2 .. votes[msg].duration .. color1 .. " секунд")
  869.                     else
  870.                         local answer = color1 .. "твой личный кулдаун на это голосование еще не истек. Осталось " .. color2 .. math.floor(getVoteCurrentPersonalCooldown(msg,name)) .. color1 .. " секунд"
  871.                         whisper(name,answer)
  872.                     end
  873.                 else
  874.                     local answer = color1 .. "глобальный кулдаун на это голосование еще не истек. Осталось " .. color2 .. math.floor(getVoteCurrentGlobalCooldown(msg)) .. color1 .. " секунд"
  875.                     whisper(name,answer)
  876.                 end
  877.             else
  878.                 local answer = color1 .. votes[msg].denyMsg
  879.                 whisper(name,answer)
  880.             end
  881.         else
  882.             local answer = color1 .. "идет другое голосование"
  883.             whisper(name,answer)
  884.         end
  885.     end
  886. end
  887. function processActiveVote(msg0,name)
  888.     local msg = unicode.lower(msg0)
  889.     if msg == c.command_yes or msg == c.command_no then
  890.         if activeVote then
  891.             if not hasUserVoted[name] or (masters[name] and masters[name].infiniteVote) then
  892.                 if msg == c.command_yes then
  893.                     currentVoteResults.yes = currentVoteResults.yes+1
  894.                     whisper(name,color1 .. "ты проголосовал §2\"за\"")
  895.                 elseif msg == c.command_no then
  896.                     currentVoteResults.no = currentVoteResults.no+1
  897.                     whisper(name,color1 .. "ты проголосовал §4\"против\"")
  898.                 end
  899.                 hasUserVoted[name] = true
  900.             end
  901.         else
  902.             whisper(name,color1 .. "нет активных голосований")
  903.         end
  904.     end
  905. end
  906. function processServerCommand(msg,name)
  907.     local msg = unicode.lower(msg)
  908.     if msg == c.command_server then
  909.         local can,leftt = canPlayerUseServerCommand(name)
  910.         if can or (masters[name] and masters[name].canSkipServerCommandCooldown) then
  911.             log(3,name .. ": " .. msg)
  912.             local _,report = component.opencb.execute("mem")
  913.             if report then
  914.                 local hour = string.match(report,"(%d+)%Dчас") or 0
  915.                 local min = string.match(report,"(%d+)%Dмину") or 0
  916.                 local sec = string.match(report,"(%d+)%Dсеку") or 0
  917.                 local tps = string.match(report,"TPS%D*(.-)\n") or "NIL"
  918.                 local left = c.server_reboot_period-(hour*3600+min*60+sec)
  919.                 local hoursleft = math.floor(left/3600)
  920.                 local minleft = math.floor((left-hoursleft*3600)/60)
  921.                 local secleft = math.floor(left-hoursleft*3600-minleft*60)
  922.                 local answer = color1 .. "До рестарта: "
  923.                 if hoursleft ~= 0 then
  924.                     answer = answer .. color2 .. hoursleft .. color1 .. " час(а) "
  925.                 end
  926.                 local answer = answer .. color2 .. minleft .. color1 .. " минут " .. color2 .. secleft .. color1 .. " секунд"
  927.                 whisper(name,color1 .. "TPS: " .. color2 .. tps)
  928.                 whisper(name,answer)
  929.                 serverCommandCooldowns[name] = computer.uptime() + c.server_command_personal_cooldown
  930.             end
  931.         else
  932.             whisper(name,color1 .. "Времени до повторного использования этой команды: " .. color2 .. leftt .. color1 .. " секунд(ы)")
  933.         end
  934.     end
  935. end
  936. function saveAllStates()
  937.     local currentTime = computer.uptime()
  938.     sayLocal(color2 .. "Подготовка к рестарту:")
  939.     local function saveStateOf(tablename,table,mode) -- mode 1 для обычного сохранения, 2 для пересчитывания computer.uptime()
  940.         local f,err = io.open("__" .. tablename,"w")
  941.         if err then
  942.             print(err)
  943.             sayLocal(color1 .. tablename ..  "§c не сохранен ")
  944.             return true
  945.         elseif mode == 1 then
  946.             f:write(serialization.serialize(table))
  947.             sayLocal(color1 .. tablename .. "§2 сохранен ")
  948.             f:close()
  949.         elseif mode == 2 then
  950.             local newtable = {}
  951.             for k,v in pairs(table) do
  952.                 local newtime = math.floor(v - currentTime)
  953.                 if newtime > 0 then
  954.                     newtable[k] = newtime
  955.                 end
  956.             end
  957.             f:write(serialization.serialize(newtable))
  958.             sayLocal(color1 .. tablename .. "§2 сохранен ")
  959.             f:close()
  960.         end
  961.     end
  962.     saveStateOf("history",history,1)
  963.     --saveStateOf("messages",messages,1)
  964.     saveStateOf("mutes",mutes,2)
  965.     saveStateOf("warns",warns,2)
  966. end
  967.  
  968. function reboot()
  969.     saveAllStates()
  970.     sayLocal(color2 .. "скачивание обновления . . .")
  971.     loadfile("/bin/wget.lua")("-f",c.download_main,"/home/MAIN")
  972.     --shell.execute("wget -f " .. c.download_main .. "/home/MAIN")
  973.     sayLocal(color2 .. "обновление завершено, рестарт")
  974.     computer.shutdown(1)
  975.     --os.exit()
  976. end
  977. function reboot2()
  978.     sayLocal(color2 .. "обновление списка вопросов . . .")
  979.     loadfile("/bin/wget.lua")("-f",c.download_q,"/home/_q")
  980.     sayLocal(color2 .. "обновление списка правил . . .")
  981.     loadfile("/bin/wget.lua")("-f",c.download_rules,"/home/_rules")
  982.     saveAllStates()
  983.     computer.shutdown(1)
  984. end
  985. function fixAutorun()
  986.     if fs.exists("/ShyvanaChatBotInstalled") == false then
  987.         local f,err = io.open("/home/.shrc","a")
  988.         f:write("\n/home/MAIN")
  989.         f:close()
  990.         local ff,err = io.open("/ShyvanaChatBotInstalled","w")
  991.         ff:write("true")
  992.         ff:close()
  993.     end
  994. end
  995. function loadConfig(link)
  996.     if link and link ~= "" then
  997.         local a,b = loadfile("/bin/wget.lua")("-f",link,"_config")
  998.         if a == true then
  999.             sayLocal(color2 .. "loadconfig: ok")
  1000.             reboot()
  1001.         else
  1002.             sayLocal(color2 .. "loadconfig: error " .. tostring(b))
  1003.         end
  1004.     else
  1005.         sayLocal(color2 .. "loadconfig error no link")
  1006.     end
  1007. end
  1008. function stop()
  1009.     local function saveStateOf2(tablename,table,mode) -- порезанная savestateoff только для истории
  1010.         local f,err = io.open("__" .. tablename,"w")
  1011.         if err then
  1012.             print(err)
  1013.             sayLocal(color1 .. tablename ..  "§c не сохранен ")
  1014.             return true
  1015.         elseif mode == 1 then
  1016.             f:write(serialization.serialize(table))
  1017.             sayLocal(color1 .. tablename .. "§2 сохранен ")
  1018.             f:close()
  1019.         end
  1020.     end
  1021.     saveStateOf2("history",history,1)
  1022.     os.exit()
  1023. end
  1024.  
  1025. function randomPersik()
  1026.     return persiki[math.random(1,#persiki)]
  1027. end
  1028. function persikAnswer(reason,name)
  1029.     local persik = randomPersik()
  1030.     local tab = {
  1031.         [1] = {
  1032.             "не капси, " .. persik .. " :*",
  1033.             "отпусти шифт, " .. persik .. " :(",
  1034.         },
  1035.         [2] = {
  1036.             "не ругайся, " .. persik .. " :*",
  1037.             "так некрасиво говорить, " .. persik .. " :(",
  1038.             "как неприлично, " .. persik .. " :(",    
  1039.         },
  1040.         [3] = {
  1041.             "не флуди, " .. persik .. " :*",
  1042.             "не загрязняй чат, " .. persik .. ", пожалуйста :(",
  1043.         },
  1044.         [4] = {
  1045.             "не рекламируй так часто, " .. persik .. " :*",
  1046.         },
  1047.         [5] = {
  1048.             "на этот раз только предупреждение, " .. persik .. ". больше так не делай :*",
  1049.         }
  1050.     }
  1051.     say(color1 .. tab[reason][math.random(1,#tab[reason])])
  1052. end
  1053.  
  1054.  
  1055. function processHelloBye(msg0,name)
  1056.     if c.persiki then
  1057.         local msg = unicode.lower(msg0)
  1058.         local currentTime = computer.uptime()
  1059.         if string.find(msg,"всем") and not string.find(msg,"%Sвсем") then
  1060.             if greetingCooldown < currentTime or (masters[name] and masters[name].canSkipHelloByeCooldowns) then
  1061.                 for _,word in pairs(helloWords) do
  1062.                     if string.find(msg,word) then
  1063.                         local name1 = randomPersik()
  1064.                         local phrase = string.gsub(helloPhrases[math.random(1,#helloPhrases)],"persik",name1)
  1065.                         greetingCooldown = currentTime + c.timeout_greeting
  1066.                         say(color1 .. phrase)
  1067.                         return true
  1068.                     end
  1069.                 end
  1070.             end
  1071.             if byeCooldown < currentTime or (masters[name] and masters[name].canSkipHelloByeCooldowns) then
  1072.                 for _,word in pairs(byeWords) do
  1073.                     if string.find(msg,word) then
  1074.                         local name1 = randomPersik()
  1075.                         local phrase = string.gsub(byePhrases[math.random(1,#byePhrases)],"persik",name1)
  1076.                         byeCooldown = currentTime + c.timeout_bye
  1077.                         say(color1 .. phrase)
  1078.                         return true
  1079.                     end
  1080.                 end
  1081.             end
  1082.         end
  1083.     end
  1084. end
  1085. function processMasterCommand(msg,name)
  1086.     -- msg = unicode.lower(msg) мешает isplayermuted
  1087.     if masters[name] then
  1088.         local answer = ""
  1089.         if msg == c.command_votestats then
  1090.             if masters[name].canAccessVoteStats then
  1091.                 if activeVote then
  1092.                     answer = color1 .. "Активное голосование: " .. color2 .. activeVote .. color1 .. ": §2" .. currentVoteResults.yes .. color1 .. "/§4" .. currentVoteResults.no .. color1 .. ". До окончания: " .. color2 .. math.floor(getCurrentVoteTimer()) .. color1 .. " секунд"
  1093.                 else
  1094.                     answer = color1 .. "нет активных голосований"
  1095.                 end
  1096.             else
  1097.                 answer = color1 .. "у тебя нет доступа к этой команде"
  1098.             end
  1099.         elseif string.find(msg,c.command_is_player_muted) == 1 then
  1100.             local username = string.sub(msg,string.len(c.command_is_player_muted)+2)
  1101.             local a,b = isPlayerMuted(username)
  1102.             if a then
  1103.                 answer = color2 .. tostring(a) .. color1 .. " : " .. color2 .. b .. color1 .. " секунд осталось"
  1104.             else
  1105.                 answer = color2 .. tostring(a)
  1106.             end
  1107.         elseif string.find(msg,c.command_unmute) == 1 then
  1108.             if masters[name].canCancelIssuedMutes then
  1109.                 local username = string.sub(msg,string.len(c.command_unmute)+2)
  1110.                 unmute(username,name)
  1111.             else
  1112.                 whisper(name,"у тебя нет доступа к " .. c.command_unmute)
  1113.             end
  1114.         elseif string.find(msg,c.command_is_player_warned) == 1 then
  1115.             local username = string.sub(msg,string.len(c.command_is_player_warned)+2)
  1116.             local a,b = isPlayerWarned(username)
  1117.             if a then
  1118.                 answer = color2 .. tostring(a) .. color1 .. " : " .. color2 .. b .. color1 .. " секунд осталось"
  1119.             else
  1120.                 answer = color2 .. tostring(a)
  1121.             end
  1122.         elseif string.find(msg,c.command_unwarn) == 1 then
  1123.             if masters[name].canCancelIssuedMutes then
  1124.                 local username = string.sub(msg,string.len(c.command_unwarn)+2)
  1125.                 unwarn(username,name)
  1126.             else
  1127.                 whisper(name,"у тебя нет доступа к " .. c.command_unwarn)
  1128.             end
  1129.         elseif msg == c.command_votestop and masters[name].canStopVotes then
  1130.             event.push("endvote",2,name)
  1131.         elseif msg == c.command_toggle_detect then
  1132.             if masters[name].undetectable then
  1133.                 whisper(name,color1 .. "теперь тебя видно в " .. color2 .. c.command_mods)
  1134.                 masters[name].undetectable = nil
  1135.             else
  1136.                 whisper(name,color1 .. "теперь тебя не видно в " .. color2 .. c.command_mods)
  1137.                 masters[name].undetectable = true
  1138.             end
  1139.         elseif msg == c.command_memory_used then
  1140.             answer = color1 .. "Использование памяти: " .. color2 .. math.floor((computer.totalMemory()-computer.freeMemory())/1024) .. color1 .. "/" .. color2 ..  math.floor(computer.totalMemory()/1024) .. " kB"
  1141.         elseif string.find(msg,c.command_retranslate) == 1 then
  1142.             if masters[name].canUseRetranslate then
  1143.                 local speech = string.sub(msg,unicode.len(c.command_retranslate)+1)
  1144.                 if speech ~= "" then
  1145.                     speech = string.gsub(speech,"#love","§4❤" .. color1)
  1146.                     say(color1 .. speech,true)
  1147.                 end
  1148.             end
  1149.         elseif msg == c.command_reboot and masters[name].canReboot then
  1150.             log(2," *** RESTART *** ")
  1151.             reboot()
  1152.         elseif msg == c.command_reboot_2 and masters[name].canReboot then
  1153.             log(2," *** RESTART2 *** ")
  1154.             reboot2()
  1155.         elseif string.find(msg,c.command_load_config) == 1 and masters[name].canLoadConfig then
  1156.             local args = string.sub(msg,unicode.len(c.command_load_config)+2)
  1157.             loadConfig(args)
  1158.         elseif msg == c.command_stop and masters[name].canReboot then
  1159.             log(2," *** STOP *** ")
  1160.             stop()
  1161.         end
  1162.         if answer ~= "" then
  1163.             whisper(name,answer)
  1164.         end
  1165.     end
  1166. end
  1167. function endCurrentVote(arg,name) --arg 1 или 2, 1 чтоб закончить голосование само по себе (таймером), 2 для принудительного закрытия без результатов
  1168.     if arg == 1 then
  1169.         say(color1 .. "Голосование окончено: §2\"за\"" .. color1 .. ": " .. color2 .. currentVoteResults.yes .. color1 .. ", §4\"против\"" .. color1 .. ": " .. color2 .. currentVoteResults.no)
  1170.         if votes[activeVote].isEasy then
  1171.             if currentVoteResults.yes - currentVoteResults.no >= c.vote_easy_yes_to_pass then
  1172.                 votes[activeVote].passFunction()
  1173.                 say(color1 .. votes[activeVote].passMessage)
  1174.             else
  1175.                 votes[activeVote].failFunction()
  1176.                 say(color1 .. votes[activeVote].failMessage)
  1177.             end
  1178.         end
  1179.         activeVote = nil
  1180.         currentVoteResults = {yes = 0, no = 0}
  1181.         hasUserVoted = {}
  1182.     elseif arg == 2 then
  1183.         if activeVote then
  1184.             event.cancel(activeVoteTimerId)
  1185.             say(color1 .. "Голосование остановлено игроком " .. color2 .. name)
  1186.             activeVote = nil
  1187.             currentVoteResults = {yes = 0, no = 0}
  1188.             hasUserVoted = {}
  1189.         else
  1190.             whisper(name,color1 .. "нет активных голосований")
  1191.         end
  1192.     end
  1193. end
  1194. function unmute(player0,name) -- player - тот, кто в муте, name - заказчик
  1195.     local a,b,player = isPlayerMuted(player0)
  1196.     if a then
  1197.         cmd("unmute " .. player)
  1198.         mutes[player] = nil
  1199.         whisper(name,"мут снят с " .. player .. " (оставалось " .. b .. " секунд)")
  1200.         say(color2 .. name .. color1 .. " отменил мут игрока " .. color2 .. player)
  1201.     else
  1202.         whisper(name,color1 .. "игрок " .. color2 .. player .. color1 .. " не имеет актуальных мутов от бота или неправильно указано имя")
  1203.     end
  1204. end
  1205. function unwarn(player0,name)
  1206.     local a,b,player = isPlayerWarned(player0)
  1207.     if a then
  1208.         cmd("unwarn " .. player)
  1209.         warns[player] = nil
  1210.         say(color2 .. name .. color1 .. " отменил варн игрока " .. color2 .. player)
  1211.     else
  1212.         whisper(name,color1 .. "игрок " .. color2 .. player .. color1 .. " не имеет актуальных варнов от бота или неправильно указано имя")
  1213.     end
  1214. end
  1215. function processHelp(msg,name)
  1216.     msg = unicode.lower(msg)
  1217.     if msg == c.command_help then
  1218.         local answer
  1219.         function addCommand(command,description)
  1220.             answer = answer .. color2 .. command .. " " .. color1 .. "- " .. description .. "\n"
  1221.         end
  1222.         answer = color2 .. "Доступные команды: \n"
  1223.         addCommand(c.command_inf,"информация по определенному пункту правил (напр. " .. color2 .. c.command_inf .. " 3.1" .. color1 .. ")")
  1224.         addCommand(c.command_mods,"список модераторов онлайн")
  1225.         addCommand(c.command_server,"узнать время до рестарта сервера и ТПС")
  1226.         addCommand("-votesun","начать голосование за отключение дождя")
  1227.         addCommand("-voteday","начать голосование за установку времени на утро")
  1228.         addCommand(c.command_yes .. " / " .. c.command_no,"отдать голос в текущем голосовании")
  1229.         whisper(name,answer)
  1230.         log(3,name .. ": " .. msg)
  1231.     end
  1232. end
  1233. function processHelp2(msg,name)
  1234.     msg = unicode.lower(msg)
  1235.     if msg == c.command_help2 and masters[name] then
  1236.         local answer
  1237.         function addCommand(command,description)
  1238.             answer = answer .. color2 .. command .. " " .. color1 .. "- " .. description .. "\n"
  1239.         end
  1240.         answer = color2 .. "Доступные команды для администраторов бота: \n (работают только при наличии соответствующих прав в конфиге)\n"
  1241.         addCommand(c.command_votestats,"получить инфу о текущем голосовании")
  1242.         addCommand(c.command_votestop,"отменить текущее голосование")
  1243.         addCommand(c.command_is_player_muted,"проверить наличие текущих мутов от бота игроку")
  1244.         addCommand(c.command_unmute,"отменить выданный ботом мут (если отменить вручную, бот продолжит игнорировать игрока на время бывшего мута)")
  1245.         addCommand(c.command_is_player_warned,"проверить наличие текущих варнов от бота игроку")
  1246.         addCommand(c.command_unwarn,"отменить выданный ботом варн")
  1247.         addCommand(c.command_toggle_detect,"стать невидимым для команды " .. color2 .. c.command_mods)
  1248.         addCommand(c.command_memory_used,"инфа по оперативной памяти бота")
  1249.         addCommand(c.command_retranslate,"говорить от имени бота, #love = ❤")
  1250.         addCommand(c.command_reboot,"обновить код бота и перезапустить")
  1251.         addCommand(c.command_reboot_2,"обновить список вопросов, список правил и перезапустить")
  1252.         addCommand(c.command_stop,"сохранить только историю и остановить бота")
  1253.         addCommand(c.command_load_config .. " [ссылка]","скачать конфиг файл с указанной ПРЯМОЙ ссылки и перезапустить")
  1254.         whisper(name,answer)
  1255.     end
  1256. end
  1257.  
  1258. function getEvent()
  1259.     local evt,arg1,name,msg = event.pullMultiple("chat_message","endvote")
  1260.     if evt == "chat_message" then
  1261.         msg = deColor(msg)
  1262.         if isGlobal(msg) then
  1263.             if not isPlayerMuted(name,true) or (masters[name] and masters[name].canNOTGetIgnoredByBot) then
  1264.                 msg = string.sub(msg,2)
  1265.                 processHelloBye(msg,name)
  1266.                 processCaps(msg,name)
  1267.                 processQuestions(msg,name)
  1268.                 processCensoredWords(msg,name)
  1269.                 processSymbolFlood(msg,name)
  1270.                 processFlood(msg,name)
  1271.                 --log(2,"[g]" .. name .. ": " .. msg,"test")
  1272.             else
  1273.                 --log(3,"(muted)" .. name .. ": " .. msg,"test")
  1274.             end
  1275.         else -- is local
  1276.             processHelp(msg,name)
  1277.             processHelp2(msg,name)
  1278.             processActiveVote(msg,name)
  1279.             processVoteStart(msg,name)
  1280.             processInf(msg,name)
  1281.             processMods(msg,name)
  1282.             processServerCommand(msg,name)
  1283.             processMasterCommand(msg,name)
  1284.         end
  1285.     elseif evt == "endvote" then
  1286.         endCurrentVote(arg1,name)
  1287.     end
  1288. end
  1289.  
  1290. fixAutorun()
  1291. drawMainFrame()
  1292. --historyInitialize()
  1293. historyDraw()
  1294. while true do
  1295.     getEvent()
  1296. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement