Advertisement
Guest User

MAIN

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