Advertisement
Guest User

MAIN

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