Advertisement
Guest User

MAIN

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