/* СТИЛИ СТИЛИ СТИЛИ СТИЛИ СТИЛИ СТИЛИ СТИЛИ СТИЛИ СТИЛИ ССТИЛИ */

[#DCBEELINEKZ] БИЛАЙН ХАБЫ КАЗАХСТАН

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.



СКРИПТЫ

Сообщений 1 страница 10 из 23

1

2

История чата с сохранением в файл

Название скрипта: ShortChatHistory
Версия скрипта: 3.2 (2016-01-12)
Описание: Показывает последние сообщения чата по команде и при входе в хаб.
Хабсофт: PtokaX 0.4.1.1 и выше (под более ранними не проверялось)
Версия Lua: 5.1/5.3
Автор: Alexey

Код:
local tCfg = {
	-- ник бота, оставьте "" для использования имени бота хаба
	sBot = "",
	-- отправлять меню при входе в хаб, 1 или 0
	bMenuOnEntry = 1,
	-- сохранять +me сообщения, 1 или 0
	bLogMeCmds = 1,
	-- укорачивать сообщения в истории чата до этого количества символов
	-- оставьте 0, если укорачивать не требуется
	iMaxLen = 0,
	-- максимальное количество сохраняемых в истории чата сообщений
	iMaxMsgs = 100,
	-- количество сообщений при входе в хаб
	iMsgsOnEntry = 12,
	-- корректировка времени, секунд
	iTimeOffset = 0,
	-- интервал автосохранения истории, минут
	iAutoSave = 1,
	-- формат времени написания сообщений в истории чата
	sTimeStamp = "[%H:%M:%S] ",
	-- относительный путь к файлу сохранения истории
	sFile	= "Chat.dat",
	iMenuDefaultContext = 3,
}
local tCmdsConf = { -- настройки команд: название команды; профили с доступом к команде;
-- использовать ли указанные профили при формировании пула профилей-получателей отчётов;
-- создавать меню для команды; показывать команду в справке; очерёдность в меню и в справке;
-- правила создания меню (контекст, родительское меню, название строки с переводом дополнительных параметров,
-- сырые дополнительные параметры меню, разделитель над меню); параметры команды для справки
	tScriptHelp    = { "histhelp",    {0,1,2,3,4,-1},    0, 1, 1, 90,
            {3,"","","",1} },
	tGlobalHelp    = { "help",    	{0,1,2,3,4,-1},    0, 0, 0, 99 },

	tGetChatHistory	= { "history",    {0,1,2,3,4,-1},    0, 1, 1, 10,
            {3, "", "sMenuShowParams"},	" <count>"},
	tDelMsgByString	= { "chdelstr",    {0,1,2},    	1, 1, 1, 20,
            {3, "", "sMenuDMBSParams"},	" <text>"},
	tDelMsgFromNick	= { "chdelnick",	{0,1,2},    	1, 1, 1, 30,
            {	{3,"","sMenuDMBNParams"}, {2,"",""," %[nick]"},	},	" <nick>"},
	tDelMsg    	= { "chdelmsg", 	{0,1,2},    	1, 1, 1, 40,
            {3, "", "sMenuDMParams"},    " <number>[ <number>]"},
	tDelChatHistory	= { "chdelete", 	{0,1},        1, 1, 1, 50,
            {3, "", "sMenuDCHParams"} },
}
local tExceptions = {	-- шаблоны, сообщения с которыми обрезаться не будут
	"magnet:%?xt=urn:tree:tiger:[a-zA-Z%d]+&xl=%-?%d+&dn=%S+",	-- магнет-ссылки
	"https?://%S+",	-- веб-ссылки
	"www%.%S+",    -- веб-ссылки
	"ftp[:.]%S+",	-- фтп-ссылки
	"dchub://%S+",	-- хаб-ссылки
}
-- соответствие страны пользователя языку получаемых им сообщений от скрипта
local tLangs = {
	Status	= "Russian",	-- Рассылка операторам
}

local tMsgs = {}
tMsgs["Russian"] = {
	sBadBotName	= "Имя бота содержит запрещённые символы ($ или | или пробел). Они были заменены на их коды.",
	sCHEmpty	= "История чата пуста.",
	sCHLong    = "Последние [COUNT] сообщений в чате:\n [MSGS]\n",
	sCHShort	= "Предыдущие сообщения в чате:",
	sCHCleared	= "%s очистил историю чата.",
	sDelMsg    = "%s удалил из истории чата %s сообщений: %s",
	sDelMsgNick	= "%s удалил из истории чата %s сообщений от ника '%s'.",
	sDelMsgPat	= "%s удалил из истории чата %s сообщений, содержащих строку '%s'.",
	sHelpHeader	= "Вам доступны следующие команды:\n",
	sMsgNotFound	= "%s\n\tСообщение #%s не найдено.",
	sNickNotFound	= "В истории чата не найдено сообщений от ника '%s'.",
	sNoArg    = "Не найден необходимый параметр команды.",
	sFileError	= "Не удалось открыть файл",
	sPatternNotFound = "В истории чата не найдено сообщений, содержащих строку '%s'.",
	sRegBotFail    = "Не удалось зарегистрировать бота '%s'.",
	sSubMenu    = "История чата",
	sMenuDCHParams    = "Вы действительно хотите удалить все сообщения в истории чата?",
	sMenuDMBNParams    = "Введите ник",
	sMenuDMBSParams    = "Введите образец строки для удаления",
	sMenuDMParams    = "Введите номера удаляемых сообщений (через пробел)",
	sMenuShowParams    = "Сколько сообщений показать?",

	sHelpDelChatHistory	= "очистить историю чата",
	sHelpDelMsg    	= "удалить сообщения с указанными номерами (нумерация от новейшего сообщения)",
	sHelpDelMsgByString = "удалить сообщения, содержащие указанный образец текста",
	sHelpDelMsgFromNick = "удалить сообщения от указанного ника",
	sHelpGetChatHistory = "показать последние <count> сообщений в истории чата (без параметра - все сообщения)",
	sHelpScriptHelp    = "эта справка по командам",
	sMenuDelChatHistory	= "Очистить",
	sMenuDelMsg    	= "Удалить по номеру",
	sMenuDelMsgByString = "Удалить по образцу",
	sMenuDelMsgFromNick = "Удалить сообщения ника",
	sMenuDelMsgFromNick2 = "Удалить сообщения этого юзера",
	sMenuGetChatHistory	= "Показать",
	sMenuScriptHelp    = "Справка",
}


------------------------------------------------------------

local tCmds, tChat, sChatHistory
local tUC, tHelp = {}, {}
local bToSave, bChanges = true, true

function OnError(sErrMsg)
	Core.SendToOps("<"..Core.GetHubSecAlias().."> Error "..sErrMsg)
	return true
end

function OnStartup()
	tCfg.sBot = tCfg.sBot and tCfg.sBot ~= "" and tCfg.sBot
    or SetMan.GetString( SetMan.tStrings and SetMan.tStrings.HubBotNick or 21 )
	for i,v in pairs(tCfg) do
    if i:byte(1) == 98 then -- b
    	tCfg[i] = v == 1
    end
	end
	tCfg.bTruncateMsgs = tCfg.iMaxLen ~= 0

	local sPrefixes = SetMan.GetString( SetMan.tStrings and SetMan.tStrings.ChatCommandsPrefixes or 29 )
	if not sPrefixes or #sPrefixes == 0 then sPrefixes = "!" end
	local sPrefix = sPrefixes:sub(1,1)
	sPrefixes = sPrefixes:gsub("[%^%%%.%[%]%-]","%%%1")
	tCfg.sMcPattern = "^<[^ |$]+> %s*(["..sPrefixes.."]%S+)"
	tCfg.sPmPattern = "^$To:%s+([^ ]+)%s+From:%s+[^ ]+%s+$<[^ |$]+>( %s*["..sPrefixes.."](%S+).*)|$"
	local sUC = "$UserCommand 1 [CONTEXT] [MENU]$<%[mynick]> [COMMAND][PARAMS]||"

	if not tLangs.Status	then tLangs.Status	= next(tMsgs) end
	if not tLangs.Other    then tLangs.Other	= tLangs.Status end
	if not tLangs.NoIP2C	then tLangs.NoIP2C	= tLangs.Status end
	local t = {}
	for i,v in pairs(tLangs) do
    if not tMsgs[v] then
    	table.insert(t, i)
    end
	end
	for i,v in ipairs(t) do tLangs[v] = nil end

	for sLangName, tLangMsgs in pairs(tMsgs) do
    t = {}
    for i,v in pairs(tLangMsgs) do
    	if (i:sub(1,5) == "sMenu" or i:sub(1,5) == "sHelp") and #v == 0 then
        table.insert(t, i)
    	end
    end
    for i,v in ipairs(t) do tLangMsgs[v] = nil end
	end

	local tTempStrings, tTempUC, tTempHelp, tReportToProfs = {}, {}, {}, {}
	for k,tComConf in pairs(tCmdsConf) do
    tTempStrings[k] = {}
    for sLangName, tLangMsgs in pairs(tMsgs) do
    	tTempStrings[k][sLangName] = {}
    	local tTempStringsLang = tTempStrings[k][sLangName]
    	if tComConf[4] == 1 then
        if tComConf[7] and tComConf[7][1] and type(tComConf[7][1]) == 'table' then
        	for i,v in ipairs(tComConf[7]) do
            local sSubMenu = tLangMsgs['sSubMenu'..(v[2] or "")]
            if v[5] then
            	tTempStringsLang[1] = (tTempStringsLang[1] or "").."$UserCommand 0 "..(v[1] or tCfg.iMenuDefaultContext).." |"
            end
            tTempStringsLang[1] = (tTempStringsLang[1] or "")..(sUC:gsub("%[([A-Z]+)%]", {
            	CONTEXT	= v[1] or tCfg.iMenuDefaultContext,
            	MENU	= (sSubMenu and #sSubMenu ~= 0 and sSubMenu.."\\" or "")
                ..(tLangMsgs["sMenu"..k:sub(2)..i] or tLangMsgs["sMenu"..k:sub(2)] or k:sub(2)),
            	COMMAND = sPrefix..tComConf[1],
            	PARAMS	=
                  (v[3] and #v[3] ~= 0 and (" %%[line:%s]"):format(tLangMsgs[ v[3] ]) or "")
                ..(v[4] and #v[4] ~= 0 and v[4]  or ""),
            }))
        	end
        else
        	local sSubMenu = tLangMsgs['sSubMenu'..(tComConf[7] and tComConf[7][2] or "")]
        	if tComConf[7] and tComConf[7][5] then
            tTempStringsLang[1] = "$UserCommand 0 "..(tComConf[7][1] or tCfg.iMenuDefaultContext).." |"
        	end
        	tTempStringsLang[1] = (tTempStringsLang[1] or "")..(sUC:gsub("%[([A-Z]+)%]", {
            CONTEXT	= tComConf[7] and tComConf[7][1] or tCfg.iMenuDefaultContext,
            MENU	= (sSubMenu and #sSubMenu ~= 0 and sSubMenu.."\\" or "")
            	..(tLangMsgs["sMenu"..k:sub(2)] or k:sub(2)),
            COMMAND = sPrefix..tComConf[1],
            PARAMS	= (
            	tComConf[7] and tComConf[7][3] and #tComConf[7][3] ~= 0
            	and (" %%[line:%s]"):format(tLangMsgs[ tComConf[7][3] ]) or ""
            ) .. (
            	tComConf[7] and tComConf[7][4] and #tComConf[7][4] ~= 0
            	and tComConf[7][4] or ""
            ),
        	}))
        end
    	else
        tTempStringsLang[1] = ""
    	end
    	table.insert(tTempStringsLang, tComConf[5] == 1 and ("\n\t%s%s%s - %s."):format(
        sPrefix, tComConf[1], tComConf[8] or "", tLangMsgs["sHelp"..k:sub(2)] or "not described yet") or "")
    end

    local tPerms = {}
    for _,iProf in ipairs(tComConf[2]) do
    	tPerms[iProf] = true

    	if tComConf[3] == 1 then
        tReportToProfs[iProf] = true
    	end

    	if tComConf[4] == 1 then
        if not tTempUC[iProf] then tTempUC[iProf] = {} end
        table.insert(tTempUC[iProf], k)
    	end
    	if tComConf[5] == 1 then
        if not tTempHelp[iProf] then tTempHelp[iProf] = {} end
        table.insert(tTempHelp[iProf], k)
    	end
    end
    if tCmds[tComConf[1]] then
    	table.insert(tCmds[tComConf[1]], tPerms)
    end
	end

	for iProf,tComs in pairs(tTempUC) do
    table.sort(tComs, function(a,b) return tCmdsConf[a][6] < tCmdsConf[b][6] end)
    for _,sCmdsConfIdx in ipairs(tComs) do
    	for sLangName, tLangUC in pairs(tTempStrings[sCmdsConfIdx]) do
        if not tUC[sLangName] then tUC[sLangName] = {} end
        tUC[sLangName][iProf] = (tUC[sLangName][iProf] or "")..tLangUC[1]
    	end
    end
	end
	for iProf,tComs in pairs(tTempHelp) do
    table.sort(tComs, function(a,b) return tCmdsConf[a][6] < tCmdsConf[b][6] end)
    for _,sCmdsConfIdx in ipairs(tComs) do
    	for sLangName, tLangHelp in pairs(tTempStrings[sCmdsConfIdx]) do
        if not tHelp[sLangName] then tHelp[sLangName] = {} end
        tHelp[sLangName][iProf] = (tHelp[sLangName][iProf] or "")..tLangHelp[2]
    	end
    end
	end

	local tReportTo = {}
	for i in pairs(tReportToProfs) do
    table.insert(tReportTo, i)
	end
	if #tReportTo == 0 then table.insert(tReportTo, 0) end
	Report = function(sMsg)
    if SetMan.GetBool( SetMan.tBooleans and SetMan.tBooleans.SendStatusMessagesAsPm or 30 ) then
    	local sMsg = "*** "..tostring(sMsg)
    	for i,v in ipairs(tReportTo) do
        Core.SendPmToProfile(v, tCfg.sBot, sMsg)
    	end
    else
    	local sMsg = "<"..tCfg.sBot.."> *** "..tostring(sMsg)
    	for i,v in ipairs(tReportTo) do
        Core.SendToProfile(v, sMsg)
    	end
    end
	end

	local bBotExists
	if tCfg.sBot == SetMan.GetString( SetMan.tStrings and SetMan.tStrings.HubBotNick or 21 ) then
    bBotExists = true
	else
    for i,v in ipairs(Core.GetBots()) do
    	if v.sName == tCfg.sBot then
        bBotExists = true
        break
    	end
    end
	end
	if not bBotExists then
    if tCfg.sBot:find"[|$ ]" then
    	tCfg.sBot = tCfg.sBot:gsub("[|$ ]", function(s) return('\\'..string.byte(s)) end)
    	Report(tMsgs[tLangs.Status].sBadBotName)
    end
    if not Core.RegBot(tCfg.sBot,"","",true) then
    	Report(tMsgs[tLangs.Status].sRegBotFail:format(tCfg.sBot))
    end
	end

	tCfg.sFile = Core.GetPtokaXPath().."scripts/"..tCfg.sFile
	local Ret = loadfile(tCfg.sFile)
	if Ret then Ret() end

	tChat = _G.tChat or {}
	while #tChat > tCfg.iMaxMsgs do
    table.remove(tChat, 1)
	end
	tCfg.iAutoSave = tCfg.iAutoSave * 60 * 1000
	TmrMan.AddTimer(tCfg.iAutoSave, 'OnExit')
	OnExit()
end

function Serialize(tTable, sTableName, hFile, sTab)
	sTab = sTab or ''
	hFile:write(sTab..sTableName.." = {\n")
	for k, v in pairs(tTable) do
    if type(v) ~= "function" then
    	local sKey = type(k) == "string" and ("[%q]"):format(k) or ("[%d]"):format(k)
    	if type(v) == "table" then
        Serialize(v, sKey, hFile, sTab..'\t')
    	else
        local sValue = type(v) == "string" and ("%q"):format(v) or tostring(v)
        hFile:write(sTab..'\t'..sKey.." = "..sValue)
    	end
    	hFile:write(",\n")
    end
	end
	hFile:write(sTab.."}")
end

function SaveTable(sFile, tTable, sTableName)
	local hFile, sErr = io.open(sFile, "w+")
	if hFile then
    Serialize(tTable, sTableName, hFile)
    hFile:flush()
    hFile:close()
    return true
	end
	error( ("%s %s\n%s"):format(tMsgs[tLangs.Status].sFileError, sFile, sErr), 0 )
end

function OnExit()
	if bToSave then
    bToSave = false
    SaveTable(tCfg.sFile, tChat, "tChat")
	end
end

function ChatArrival(tUser, sData)
	sData = sData:sub(1,-2)
	local sCmdOrNick = sData:match(tCfg.sMcPattern)
	if sCmdOrNick then
    local sCmd = sCmdOrNick:sub(2):lower()
    if tCmds[sCmd] and tCmds[sCmd][2][tUser.iProfile] then
--    	local sLang = tLangs[IP2Country.GetCountryCode(tUser.sIP) or "NoIP2C"] or tLangs.Other
    	local sLang = tLangs[Core.GetUserValue(tUser, 26) or "NoIP2C"] or tLangs.Other
    	local bRet, sResult = tCmds[sCmd][1](tUser, sLang, sData:sub(#tUser.sNick + 3))
    	if sResult and type(sResult) == "string" then
        Core.SendToUser(tUser, "<"..tCfg.sBot.."> "..sResult)
    	end
    	return bRet
    elseif Core.GetUser(sCmdOrNick) or Core.GetUser(sCmdOrNick:sub(1,-2)) then
    	sCmdOrNick = nil
    else
    	sCmdOrNick = sCmdOrNick:match("^.(%a%w+)$")
    end
	end
	if not sData:find"is kicking" and (not sCmdOrNick or (tCfg.bLogMeCmds and sCmdOrNick == "me")) then
    if sCmdOrNick then
    	sData = "* "..tUser.sNick..sData:sub(#tUser.sNick + 7)
    end
    if tCfg.bTruncateMsgs then
    	local bTrimMsg = true
    	local iLen = #sData - #tUser.sNick - 3
    	for i,v in ipairs(tExceptions) do
        if sData:find(v) then
        	bTrimMsg = false
        	break
        end
    	end
    	if bTrimMsg and iLen > tCfg.iMaxLen then
        sData = sData:sub(1, tCfg.iMaxLen - iLen - 1).."[…]"
    	end
    end
    if not bToSave then bToSave = true end
    bChanges = true
    table.insert(tChat, os.date(tCfg.sTimeStamp, os.time() + tCfg.iTimeOffset)..sData)
    while #tChat > tCfg.iMaxMsgs do
    	table.remove(tChat, 1)
    end
	end
end

function ToArrival(tUser, sData)
	local sTo, sMsg, sCmd = sData:match(tCfg.sPmPattern)
	if sTo and sTo == tCfg.sBot and tCmds[sCmd:lower()] and tCmds[sCmd:lower()][2][tUser.iProfile] then
--    local sLang = tLangs[IP2Country.GetCountryCode(tUser.sIP) or "NoIP2C"] or tLangs.Other
    local sLang = tLangs[Core.GetUserValue(tUser, 26) or "NoIP2C"] or tLangs.Other
    local bRet, sResult = tCmds[sCmd:lower()][1](tUser, sLang, sMsg, true)
    if sResult and type(sResult) == "string" then
    	Core.SendPmToUser(tUser, tCfg.sBot, sResult)
    end
    return bRet
	end
end

function UserConnected(tUser)
--	local sLang = tLangs[IP2Country.GetCountryCode(tUser.sIP) or "NoIP2C"] or tLangs.Other
	local sLang = tLangs[Core.GetUserValue(tUser, 26) or "NoIP2C"] or tLangs.Other
	if tCfg.bMenuOnEntry and Core.GetUserValue(tUser, 12) and tUC[sLang] and tUC[sLang][tUser.iProfile] then
    Core.SendToUser(tUser, tUC[sLang][tUser.iProfile])
	end
	if bChanges then
    if #tChat ~= 0 then
    	bChanges = false
    	sChatHistory = ("\n\173%s\n"):format(table.concat(
        tChat, "\n\173", #tChat - math.min(tCfg.iMsgsOnEntry, #tChat) + 1))
    else
    	Core.SendToUser(tUser, "<"..tCfg.sBot.."> "..tMsgs[sLang].sCHEmpty)
    	return
    end
	end
	Core.SendToUser(tUser, ("<%s> %s %s"):format(tCfg.sBot, tMsgs[sLang].sCHShort, sChatHistory) )
end
RegConnected, OpConnected = UserConnected, UserConnected

tCmds = {
	[tCmdsConf.tScriptHelp[1]] = {function(tUser, sLang)
    return true, tMsgs[sLang].sHelpHeader..tHelp[sLang][tUser.iProfile]
	end},
	[tCmdsConf.tGlobalHelp[1]] = {function(tUser, sLang, _, bPM)
    if not bPM and SetMan.GetBool( SetMan.tBooleans and SetMan.tBooleans.ReplyToHubCommandsAsPm or 36 ) then
    	Core.SendPmToUser(tUser, tCfg.sBot, tMsgs[sLang].sHelpHeader..tHelp[sLang][tUser.iProfile])
    	return false
    end
    return false, tMsgs[sLang].sHelpHeader..tHelp[sLang][tUser.iProfile]
	end},

	[tCmdsConf.tGetChatHistory[1]] = {function(tUser, sLang, sData)
    if #tChat == 0 then
    	return true, tMsgs[sLang].sCHEmpty
    end

    local iMsgs = sData:match"^%s+[^ ]+%s+(%d+)"
    iMsgs = math.min(tonumber(iMsgs) or #tChat, #tChat)
    return true, tMsgs[sLang].sCHLong:gsub("%[([A-Z]+)%]", {
    	COUNT = iMsgs,
    	MSGS  = table.concat(tChat, "\n ", #tChat - iMsgs + 1),
    })
	end},
	[tCmdsConf.tDelChatHistory[1]] = {function(tUser)
    tChat = {}
    bToSave = true
    bChanges = true
    Report(tMsgs[tLangs.Status].sCHCleared:format(tUser.sNick))
    return true
	end},
	[tCmdsConf.tDelMsgByString[1]] = {function(tUser, sLang, sData)
    local sPattern = sData:match"^%s+[^ ]+%s+(.*)"
    if not sPattern or sPattern == "" then
    	return true, tMsgs[sLang].sNoArg
    end

    local t = {}
    for i,v in ipairs(tChat) do
    	if v:find(sPattern,1,true) then
        table.insert(t,i)
    	end
    end
    if #t == 0 then
    	return true, tMsgs[sLang].sPatternNotFound:format(sPattern)
    end

    table.sort(t)
    for i=#t,1,-1 do
    	table.remove(tChat, t[i])
    end
    bToSave = true
    bChanges = true
    Report(tMsgs[tLangs.Status].sDelMsgPat:format(tUser.sNick, #t, sPattern))
    return true
	end},
	[tCmdsConf.tDelMsgFromNick[1]] = {function(tUser, sLang, sData)
    local sNick = sData:match"^%s+[^ ]+%s+([^ ]+)"
    if not sNick then
    	return true, tMsgs[sLang].sNoArg
    end

    local sTS = (tCfg.sTimeStamp:gsub("[%^%$%(%)%%%.%[%]%*%+%-%?]","%%%1")):gsub("%%%%[a-zA-Z]","%[%%da-zA-Z%]+")
    local sNickP = sNick:gsub("[%^%$%(%)%%%.%[%]%*%+%-%?]","%%%1")
    local sPattern1 = "^"..sTS.."<"	..sNickP..">"
    local sPattern2 = "^"..sTS.."%* "..sNickP
    local t = {}
    for i,v in ipairs(tChat) do
    	if v:find(sPattern1) or v:find(sPattern2) then
        table.insert(t,i)
    	end
    end
    if #t == 0 then
    	return true, tMsgs[sLang].sNickNotFound:format(sNick)
    end

    table.sort(t)
    for i=#t,1,-1 do
    	table.remove(tChat, t[i])
    end
    bToSave = true
    bChanges = true
    Report(tMsgs[tLangs.Status].sDelMsgNick:format(tUser.sNick, #t, sNick))
    return true
	end},
	[tCmdsConf.tDelMsg[1]] = {function(tUser, sLang, sData)
    local t = {}
    for n in sData:gmatch" (%d+)" do
    	table.insert(t, tonumber(n))
    end
    if #t == 0 then
    	return true, tMsgs[sLang].sNoArg
    end

    local iChat, iCounter, sRet = #tChat, 0, ""
    table.sort(t)
    for i=1,#t do
    	local sMsg = table.remove(tChat, iChat - t[i] + 1)
    	if sMsg then
        iCounter = iCounter + 1
        sRet = ("%s\n\t%s: %s"):format(sRet, t[i], sMsg)
    	else
        sRet = tMsgs[sLang].sMsgNotFound:format(sRet, t[i])
    	end
    end
    if iCounter == 0 then
    	return true, sRet
    end

    bToSave = true
    bChanges = true
    Report(tMsgs[tLangs.Status].sDelMsg:format(tUser.sNick, iCounter, sRet))
    return true
	end},
}


Особенности:

Команды: просмотра истории чата, удаления сообщений по образцу, удаления сообщений по нику автора, удаления сообщений по номеру, полной очистки истории чата и справки по командам.
Меню для команд.
Возможность логирования сообщений от третьего лица (команд +me).
Возможность при сохранении обреза́ть длинные сообщения (при этом не обрезает сообщения с ссылками).
Не сохраняет сообщения кика (is kicking Spamer because: spam).
Не сохраняет сообщения, похожие на команды.
Возможность установить корректировку времени сохраняемых сообщений (если время на сервере отличается от реального).
Сохранение в файл при выключении скрипта (или хаба) и по таймеру (по умолчанию, каждую минуту, если были новые сообщения).
Возможность использовать разный язык сообщений скрипта в зависимости от страны пользователя (по IP).

3

FAQ СКРИПТ ОТ ХАБА DCBEELINEKZ

Код:
local sBot = "DCBEELINEKZ"

local sMsg=[[	ЧАСТЫЕ ВОПРОСЫ
  
  
  СКАЧАЙ: magnet:?xt=urn:tree:tiger:L4EJPCQQNVVHARMQU77FDSQNX5ZTOU32ZLWJTOA&xl=28235518&dn=!%D0%9B%D0%A3%D0%A7%D0%A8%D0%98%D0%99+FAQ+%D0%9F%D0%9E+%D0%A5%D0%90%D0%91%D0%90%D0%9C+DC%2B%2B+%5BDCBEELINEKZ%5D+Full.chm
  НАСТРОЙКИ СО СКРИНШОТАМИ
 
 КАК РАСШАРИТЬ СВОИ ФАЙЛЫ
  Файл > Настройки > Шара, выберите папки, которые вы хотите расшарить.
  После того, как закончится хэширование файлов, они появятся в списке ваших файлов.
 
 КАК ПОСМОТРЕТЬ СВОЮ ШАРУ
  Файл > Открыть свой список файлов. Или комбинация клавиш CTRL+SHIFT+L

 КУДА СКАЧИВАЮТСЯ ФАЙЛЫ
  Файл > Папка для скачивания
  Файл > Настройки > Скачивание, в поле Папка для скачиваний по умолчанию 


 КАК ОТМЕНИТЬ СКАЧИВАНИЕ
  Для отмены загрузки файла не достаточно простого нажатия в нижнем
  окне и выборе в меню [Закрыть соединение] Открываем Очередь скачивания,
  через панель Передачи > Очередь скачивания или нажатием CTRL+D,
  по файлу пр.мышью [Удалить] или поставить Установить приоритет > [Пауза]


 КАК ОБНОВИТЬ СВОЙ СПИСОК ФАЙЛОВ
  По мне, в чате вбить команду /refresh, и [Enter] 
  Или: 
  Файл > Обновить свой список файлов, либо зажать CTRL+E.
  Когда в нижнем правом углу процесс хеширования завершиться
  Затем: 
  Файл > Очистить базу данных ТТН от "мертвых" записей.
  Это для того чтобы не презаходить на хаб!


 КАК ПОЛЬЗОВАТЬСЯ ПОИСКОМ
  Зажать Ctrl + S (или значок с простой лупой), или выбрать Вид > Поиск,
  вбить в Поиск...то, что хотите найти, и нажать на [Поиск] 
  Обратите внимание на строчку [Тип файла]. Если вы ищете, например,
  фильм, то указывайте, что вам нужен именно Видео это облегчает поиск.
  Маленький секрет. Поиск иногда помогает ускорить возобновление прерванной скачки.
  Если прерванная скачка не продолжается автоматически
  (хотя все условия есть: источник, расшаренный файл и т.п.),
  нужно набрать имя скачиваемого файла (или часть имени) в Поиске и нажать [Enter].
  Скачка должна продолжиться.
  

 КАК СДЕЛАТЬ ССЫЛКУ НА ФАЙЛ (МАГНЕТ-ССЫЛКА)
  Необходимо открыть ваш список файлов Файл > Открыть свой список файлов, 
  либо зажать CTRL+SHIFT+L, выбрать необходимую папку где хранятся ваши файлы,
  и на необходимом файле(или файлах, при удержание CTRL, более актуально для сериалов, 
  чтобы не выбирать по одному файлу) Пр.мышки Копировать > Копировать магнет-ссылку,
  после чего, смело вставляем содержимое из буфера обмена.

--------------------------------------------------------------------
http://DCBEELINEKZ.1bb.ru МОРЕ ИНФОРМАЦИИ
http://DCBEELINEKZ.do.am САЙТ БИЛАЙН ХАБЫ КАЗАХСТАН
]]
------------------------------------------------------------------------------------------------
local sMsg2 = [[	ОСНОВНЫЕ КОМАНДЫ
 
 
  +myip - Твой IP
  /clear - Отчистить главный чат
  /close - закрытие активного окна
  /help - Вывести список встроенных в DC команд
  /flylinkdc++ - Информация о DC и ссылка где можно скачать DC++
  /fav или /favorite - Добавить активный хаб в избраное.
  /removefavorite - Удалить активный хаб из списка избранных
  /w или /winamp - Отображает какая у вас сейчас песня играет в винампе
  /refresh - Обновить ваш список файлов
  /rebuild - Перехэшировать файлы, то есть переделать шаринг заново
  /connection - Показать ваш IP адрес и порты, которые использует DC для работы

 ГОРЯЧИЕ КЛАВИШИ

  Ctrl + 1 - Включить/выключить панель управления
  Ctrl + 2 - Включить/выключить статусную строку
  Ctrl + 3 - Включить/выключить панель передачи файлов
  Ctrl + C - Копировать выделенный текст
  Ctrl + D - Открыть список файлов в очереди
  Ctrl + E - Обновить ваш список файлов
  Ctrl + F - Открыть избранные хабы.
  Ctrl + N - Открыть блокнот
  Ctrl + L - Открыть список файлов
  Ctrl + P - Открыть публичные хабы
  Ctrl + Q - Быстрое подключение к хабу
  Ctrl + R - Переподелючиться к хабу
  Ctrl + S - Открыть поиск
  Ctrl + T - Следовать последнему перенаправлению
  Ctrl + U - Открыть список избранных пользователей
  Ctrl + V - Вставить скопированный текст
  Ctrl + X - Вырезать выделенный текст

--------------------------------------------------------------------
http://DCBEELINEKZ.1bb.ru МОРЕ ИНФОРМАЦИИ
http://DCBEELINEKZ.do.am САЙТ БИЛАЙН ХАБЫ КАЗАХСТАН
]]
------------------------------------------------------------------------------------------------
local sMsg3 = [[	ЕСЛИ НЕ КАЧАЕТ
  

Если вы видите список пользователей, но не можете ничего с них скачать и получить список файлов, то оборудование и/или 
программное обеспечение блокирует прохождение пакетов к программе.

ПРИЧИНЫ ПОЧЕМУ НЕ КАЧАЕТ:
     Firewall (Брандмауэр Windows, антивирус, отдельный файрволл)
     Роутер (маршрутизатор)
     Другое (Ограничение по слотам, Бан по шаре, полный хард)

FIREWALL
  Программные средства защиты компьютера, в частности Kaspersky Internet Security, Eset Smart Security и прочие.   
  Проблема решается путем добавления клиента DC++ в доверенные приложения firewall-а, а также снижением уровня защиты до среднего и ниже.

РОУТЕР
  Если у вас роутер (белая коробочка), вам необходимо настроить переадресацию портов. Это связанно с тем, что прямой   
  доступ в Интернет имеет сам роутер, позволяя компьютерам и устройствам внутренней домашней сети пользоваться своим соединением.
  Поэтому «снаружи» «видно» только роутер. Чтобы получить из внешнего мира доступ к сервисам внутренней сети (в нашем случае к DC-клиенту FlyLink) нужно, чтобы роутер переадресовывал IP-пакеты на нужный внутренний адрес и порт.
  С точки зрения рядового пользователя, настройка этого устройства представляет наибольшую сложность по сравнению с предыдущими, однако разобраться в этом не так долго, как может показаться на первый взгляд.
 НАСТРОЙКА РОУТЕРОВ ТУТ http://vk.com/topic-49673700_27695244

 ДРУГОЕ 
  Отсутствуют свободные слоты, нужно подождать.
  Ваш хард переполнен, нужно почистить жезтянку, именно в какой диск идет скачка!
  Пользователь удалил файл из шары. и пока не обновилась его шара.
  Пользователь запретил вам скачивать, забанил вас лично или бан за малый размер вашей шары ( BAN for Share < 20 Gb)
  
 НЕДОСТАТКИ ПАССИВНОГО РЕЖИМА
  Пользователь в "Пассивном режиме" не может скачивать файлы с другого пользователя, находящегося тоже в "пассивном режиме". Пользователей в пассивном режиме на хабе в среднем 1/3, поэтому ВЫ теряете 33% источников если находитесь в ПАССИВНОМ режиме!
  Падение скорости у пользователей в режиме "Пассив" гораздо сильнее (в sp2). В конце обычно приводит к разрыву связи и потере слота.
  При поиске ответы от юзеров в пассивном режиме проходят через хаб, в активном - идут напрямую. Хаб не транслирует ответы с неполными источниками (если файл не докачан), поэтому, при появлении нового файла (фильма), активный юзер увидит много источников для скачки (всех, кто подключился к скачке и что-то успел скачать), а пассивный - только тех, кто скачал файл полностью и расшарил.
"Пассивов" можно узнать по кирпичной стене напротив ника в списке пользователей: 

Я настоятельно рекомендую настроить соединение и перейти на "актив" для повышения эффективности системы в ваших же интересах!

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: http://dcbeelinekz.1bb.ru

--------------------------------------------------------------------
http://DCBEELINEKZ.1bb.ru МОРЕ ИНФОРМАЦИИ
http://DCBEELINEKZ.do.am САЙТ БИЛАЙН ХАБЫ КАЗАХСТАН
]]
------------------------------------------------------------------------------------------------
local sMsg4 = [[	СПИСОК  ХАБОВ. ЛЕТО 17-ГО
  ВСЕГДА СВЕЖИЙ СПИСОК ТУТ:
 http://dcbeelinekz.do.am/hubs.html

1. dchub://10.24.9.2 + ВНЕШКА dchub://prosto-host.ru
2. dchub://10.90.66.46 (ЧАСТО МЕНЯЕТСЯ IP)
3. dchub://10.16.89.44 (ЖДЕМ ЗАПУСК)

--------------------------------------------------------------------
http://DCBEELINEKZ.1bb.ru МОРЕ ИНФОРМАЦИИ
http://DCBEELINEKZ.do.am САЙТ БИЛАЙН ХАБЫ КАЗАХСТАН
]]
------------------------------------------------------------------------------------------------
local sMsg5 = [[  
.   Прокси-сервер для пользователей
.   Адрес:  10.24.2.9  Порт: 3128
.   Бесплатный:  1 МБит/сек.
.   Платный:  от 4 до 8 МБит/сек.
.   Стоимость платного:  500 тг.

 ТАК ЖЕ НАСКАНЕННЫЕ ПРОКСИ СЕРВЕРЫ ЮЗЕРАМИ ХАБА:
 magnet:?xt=urn:tree:tiger:HDIRP2A343LGXW26WDJQQFAJQMCDNBWZFQYMCYQ&xl=732890&dn=!+%D0%A1%D0%9A%D0%90%D0%9D%D0%95%D0%A0+%D0%9F%D0%A0%D0%9E%D0%9A%D0%A1%D0%98+2017+%5BDCBEELINEKZ%5D.rar

 10.50.18.95 3128 (ЧАСТО РАБОТАЕТ ВЕЧЕРОМ)
 10.87.71.85 3128 (НОВЫЙ)

 ДЛЯ РАБОТЫ С ПРОКСИ
 magnet:?xt=urn:tree:tiger:CENKXFBKP3D7P2T5N5VDRCAIDW54RHJDM4THOGY&xl=5958238&dn=Proxifier+%5BDCBEELINEKZ%5D.rar
 magnet:?xt=urn:tree:tiger:PXN2PWO7SZOMUYNI4UFEY6SDOC27VMWK27J4VRY&xl=1511&dn=Proxifier+%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5+%D0%BB%D0%BE%D0%BA%D0%B0%D0%BB%D0%BA%D0%B8+DCBEELINEKZ.ppx
]]
------------------------------------------------------------------------------------------------
function UserConnected(tUser)
  Core.SendToUser(tUser,"$UserCommand 1 3 ТЕХ.ПОДДЕРЖКА\\ ЧАСТЫЕ ВОПРОСЫ$<%[mynick]> !rf1|")
  Core.SendToUser(tUser,"$UserCommand 1 3 ТЕХ.ПОДДЕРЖКА\\ ОСНОВНЫЕ КОМАНДЫ$<%[mynick]> !rf2|")
  Core.SendToUser(tUser,"$UserCommand 1 3 ТЕХ.ПОДДЕРЖКА\\ ЕСЛИ НЕ КАЧАЕТ$<%[mynick]> !rf3|")
  Core.SendToUser(tUser,"$UserCommand 1 3 ТЕХ.ПОДДЕРЖКА\\ СПИСОК ХАБОВ$<%[mynick]> !rf4|")
  Core.SendToUser(tUser,"$UserCommand 1 3 ТЕХ.ПОДДЕРЖКА\\ ПРОКСИ$<%[mynick]> !rafa|")
end
RegConnected=UserConnected
OpConnected=UserConnected
function ChatArrival(tUser,sData)
  sData=sData:sub(tUser.sNick:len()+4,-2)
  if sData=="!rf1" then
    Core.SendPmToUser(tUser,sBot,sMsg)
    return true
  elseif sData=="!rf2" then
    Core.SendPmToUser(tUser,sBot,sMsg2)
    return true
  elseif sData=="!rf3" then
    Core.SendPmToUser(tUser,sBot,sMsg3)
    return true
  elseif sData=="!rf4" then
    Core.SendPmToUser(tUser,sBot,sMsg4)
    return true
  elseif sData=="!rafa" then
    Core.SendPmToUser(tUser,sBot,sMsg5)
    return true
  end
end

4

БОТ ИНФОРМАЦИЯ В СПИСКЕ ЮЗЕРОВ

Код:
--[[
	Для оформления фраз из таблицы tFormat[i]["tPhrases"] можно использовать:
	------------------------------------------------------------------------------------------------------------------
    HOURS    -	часы
    MINUTES    -	минуты
    SECONDS    -	секунды
    DAY    	-	число
    WEEK    -	неделя
    MONTH    -	месяц
    YEAR    -	год
    HUB    	-	название хаба
    SHARE    -	шара хаба
    USERS    -	кол-во юзеров на хабе
	------------------------------------------------------------------------------------------------------------------
]]--
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Конфиг бота:
	
	-- Таблица с названиями месяцев
	tMonths = {".01.", ".02.", ".03.", ".04.", ".05.", ".06.", ".07.", ".08.", ".09.", ".10.", ".11.", ".12."}
	
	 -- Часовые пояса, 1 параметр здесь служит приставкой для времени и даты, первый параметр - смещение относительно текущего времени:
	tTimeZones = {
    {0, "MSK"},
	}
	
	-- Таблица с названиями дней недели
	tWeeks = {"Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"}

	-- Таблица с названиями едениц измерения шар
	tShareUnits = {"Б", "КБ", "МБ", "ГБ", "ТБ", "ПБ"}

	-- Таблица с блоками информации:
	-- (каждый блок состоит из: ["iInteval"] = время_в_секундах_для_смены_информации, ["sWhatBeforeInfo"] = символ_перед_инфомацией, ["tPhrases"] = таблица_с_инфомацией)
	tFormat = {
    [1] = {
    	["iInteval"] = 10,
    	["sWhatBeforeInfo"] = "[",
    	["tPhrases"] = {
        "Хаб сети Билайн KZ]",
        "Админ хаба: MarkDark]",
        "Время: HOURS:MINUTES]",
        "Дата: DAYMONTHYEARг.]",
        "Юзеров на хабе: USERS]",
        "Шара хаба: SHARE]",
    	},
    },
	}
	
botDesc = "Информация о хабе" --Описание бота
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function OnStartup()
	for i,v in ipairs(tTimeZones) do
    v[1] = v[1] * 3600
	end
	sBot = SetMan.GetString(21)
	sHub = SetMan.GetString(0)
	tNeedToSend = {}
	AddTempToTable()
	TmrMan.AddTimer(1000)
end 

function OnExit()
	for i, v in pairs(tFormat) do
    Core.SendToAll("$Quit "..v["sInformation"])
	end
end
OnError = OnExit

function UserConnected(curUser)
	table.insert(tNeedToSend, curUser.sNick)
end
OpConnected = UserConnected
RegConnected = UserConnected

function GetNickListArrival(curUser,sData)
	table.insert(tNeedToSend, curUser.sNick)
end

function OnTimer()
	for i, v in pairs(tFormat) do
    tFormat[i]["iTimer"] = v["iTimer"] + 1
    if tFormat[i]["iTimer"] > v["iInteval"] then
    	tFormat[i]["iTimer"] = 1
    	tFormat[i]["iStatus"] = v["iStatus"] + 1
    	if v["iStatus"] > #v["tPhrases"] then
        tFormat[i]["iStatus"] = 1
    	end
    	Core.SendToAll("$Quit "..tFormat[i]["sInformation"])
    	tFormat[i]["sInformation"] = v["sWhatBeforeInfo"]..DoGsub(v["tPhrases"][v["iStatus"]])
    	Core.SendToAll("$OpList "..tFormat[i]["sInformation"])
    end
	end
	if tNeedToSend ~= {} then
    SendBotToNewUsers()
    tNeedToSend = {}
	end
end

function AddTempToTable()
	for i, v in pairs(tFormat) do
    tFormat[i]["iStatus"] = 1
    tFormat[i]["iTimer"] = 1
    tFormat[i]["sInformation"] = v["sWhatBeforeInfo"]..DoGsub(v["tPhrases"][1])
    Core.SendToAll("$OpList "..tFormat[i]["sInformation"])
	end
end

function DoGsub(sMsg)
	for _, t in ipairs(tTimeZones) do
    local iTime = os.time() + t[1]
    sMsg = sMsg:gsub(t[2].."HOURS", tonumber(os.date("%H", iTime)))
    sMsg = sMsg:gsub(t[2].."MINUTES", os.date("%M", iTime))
    sMsg = sMsg:gsub(t[2].."SECONDS", os.date("%S", iTime))
    sMsg = sMsg:gsub(t[2].."DAY", tonumber(os.date("%d", iTime)))
    sMsg = sMsg:gsub(t[2].."WEEK", tWeeks[tonumber(os.date("%w", iTime))] or tWeeks[7])
    sMsg = sMsg:gsub(t[2].."MONTH", tMonths[tonumber(os.date("%m", iTime))])
    sMsg = sMsg:gsub(t[2].."YEAR", (os.date("%Y", iTime)))
	end
	sMsg = sMsg:gsub("HOURS", tonumber(os.date("%H")))
	sMsg = sMsg:gsub("MINUTES", os.date("%M"))
	sMsg = sMsg:gsub("SECONDS", os.date("%S"))
	sMsg = sMsg:gsub("DAY", tonumber(os.date("%d")))
	sMsg = sMsg:gsub("WEEK", tWeeks[tonumber(os.date("%w"))] or tWeeks[7])
	sMsg = sMsg:gsub("MONTH", tMonths[tonumber(os.date("%m"))])
	sMsg = sMsg:gsub("YEAR", (os.date("%Y")))
	sMsg = sMsg:gsub("HUB", sHub)
	sMsg = sMsg:gsub("SHARE", DoShareUnits())
	sMsg = sMsg:gsub("USERS", Core.GetUsersCount())
	return sMsg
end

function SendBotToNewUsers()
	for i , v in pairs(tNeedToSend) do
    local sUser = Core.GetUser(v)
    if sUser then
    	for k, y in pairs(tFormat) do
        Core.SendToUser(sUser,"$OpList "..y["sInformation"])
    	end
    end
	end
end

function DoShareUnits()
	local iSize = Core.GetCurrentSharedSize()
	local stSize = #tShareUnits
	local iSize = tonumber(iSize)
	local sUserNits = ""
	for index = 1, stSize do
    if iSize < 1024 then
    	sUserNits = tShareUnits[index]
    	break
    elseif index == stSize then
    	sUserNits = tShareUnits[stSize]
    else
    	iSize = iSize / 1024
    end
	end
	return string.gsub(string.format("%0.2f %s", iSize, sUserNits), "%.", ",")
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

5

Скрипт для периодической отправки в чат динамической информации, прочитываемой из файла

Название: MsgToChatFromFile.lua
Платформа: PtokaX
API: API 2
Автор: Ksan

http://mydc.ru/topic5767.html

Для работы скрипта нужно наличие папки MsgToChatFromFile в папке скриптов. В этой папке должен лежать файл с текстом, отправляемым в чат. В предлагаемом архиве папка с файлом уже присутствует, надо только положить куда надо (не забудьте поправить текст на нужный).

Описание: При старте скрипт проверяет наличие файла, если его нет, сообщает админу, чей ник прописан в настройках скрипта, и остаётся в рабочем режиме. При наступлении времени отправки информации в чат (сработал таймер №2 - (1 час, изменить можно в настройках) проверяется файл, считывается текст (админ может в любое время изменить текст в файле) и отправляется в чат (либо как есть, либо от имени бота хаба (в скрипте представлены оба варианта отправки, один вариант закомментен)). При отсутствии же файла с информацией (либо файл есть, но внутри нет текста) скрипт запускает таймер (№1) ожидания файла с информацией (проверяется каждые 55 секунд, но вы можете сами выставить нужный период в настройках), и при появлении информации сразу же отправляет его в чат, и таймер (№1) отключается.. Дальше - в обычном режиме - отправка по таймеру (№2).
Примечание: Срабатывание короткого таймера (появление файла и последующая отправка информации в чат) может произойти в произвольное время (зависит от того, когда вы положите файл в папку), так что возможно одноразовое сокращённое время вывода в чат.

6

Информер

Код:
--###################################################################################
--	InformEr 1.02 by alex82
--	PtokaX 0.3.6./0.4.0/0.4.1, LUA 5.1
--	http://mydc.ru/topic1209.html
--###################################################################################

--###################################################################################
--ОСНОВНЫЕ НАСТРОЙКИ

sConfigFile = "InformEr.tbl"	--Файл базы данных
AdminMenu = "Admin\\InformEr\\"	--Название меню
FAQMenu = "Справка\\"
SaveIP = true	--Метод сохранения количества рассылок. false - сохранять по нику; true - сохранять по IP

sSettingsFolder = ""	--Папка для сохранения файла настроек. Если не указано, используется папка "scripts".
sTextFolder = ""	--Папка для текстовых файлов. Если не указано, используется папка "scripts".

--###################################################################################
--НАСТРОЙКИ АНТИФЛУДА

bDeflood = true	--Включить антифлуд. Если включено, автоматический вывод информации в чат будет приостановлен при отсутствии сообщений пользователей, и возобновлён при их появлении.
iDefloodTimer = 1	--Время отправки первого сообщения после выхода из режима антифлуда (минут).

sCmdPrefix = "!"	--Префикс команд, используемых на хабе
--sCmdPrefix = "[!%+%-%*]"

sCmdPattern = "%w+"	--Шаблон команд, используемых на хабе
--sCmdPattern = "%S+"	--Раскомментируйте эту строку, если на хабе используются команды, содержащие символы кириллицы.

--###################################################################################
--НАСТРОЙКИ СПРАВКИ

bEnableFAQ = true	--Включить справку (true - да, false - нет)
bFaqToPM = true	--Отправлять справку в личку (true - да, false - нет)

--###################################################################################
--НАСТРОЙКИ ПРАВ ДОСТУПА

tControl = {	--Профили, имеющие доступ к настройкам
	[0] = 1,    -- =[Master]=
	[1] = 0,    -- =[OP]=
	[2] = 0,    -- =[ViP]=
	[3] = 0,    -- =[Reg]=
	[4] = 0,    -- =[LidShare]=
	[5] = 0,    -- =[LidNov]=
   [-1] = 0,   	-- =[UnReg]=
}

tSend = {    --Профили, имеющие доступ к рассылке сообщений
	[0] = 1,    -- =[Master]=
	[1] = 1,    -- =[OP]=
	[2] = 0,    -- =[ViP]=
	[3] = 0,    -- =[Reg]=
	[4] = 0,    -- =[LidShare]=
	[5] = 0,    -- =[LidNov]=
   [-1] = 0,   	-- =[UnReg]=
}

--###################################################################################
--НАСТРОЙКИ КОМАНД

prefix = "!"	--Префикс команд
info = "info"	--Включение/выключение рассылки сообщений
timeinfo = "timeinfo"	--Установка времени рассылки
impinfo = "impinfo"	--Включение/выключение рассылки важных сообщений (в личку)
showallinfo = "showallinfo"	--Показать все
manual = "manualinfo"	--Вручную
addinfo = "addinfo"	--Добавить сообщение
delinfo = "delinfo"	--Удалить сообщение
addimpinfo = "addimpinfo"	--Добавить важное сообщение
delimpinfo = "delimpinfo"	--Удалить важное сообщение
send = "send"	--Рассылка сообщения
sendpm = "sendpm"	--Рассылка сообщения в личку
faq = "faq"	--Вызов справки
showfaq = "showfaq"	--Показать все разделы
addfaq = "addfaq"	--Добавить раздел справки
delfaq = "delfaq"	--Удалить раздел справки
--###################################################################################
--###################################################################################
tConfig={Auto = 1, Timer = 15, ImpMsg = 1}
tMessage={}
tImpMessage={}
tImpData={}
tFAQ = {}

SaveCount = 0

function Main()
	if Core then
    NewAPI = true
    stop = true
    _,_,ver,subver = string.find(Core.Version,"^%d+%.(%d+)%.(%d+)")
    if (tonumber(ver) >=4 and tonumber(subver) >=1) or tonumber(ver) > 4 then
    	local path = "scripts/"
    	if sSettingsFolder == "" then
        sSettingsFolder = path..sSettingsFolder
    	end
    	if sTextFolder == "" then
        sTextFolder = path..sTextFolder
    	end
    end
    bot = SetMan.GetString(21)
	else
    NewAPI = false
    stop = 1
    bot = frmHub:GetHubBotName()
	end
	if loadfile(sSettingsFolder..sConfigFile) then dofile(sSettingsFolder..sConfigFile) end
	if tConfig.Auto==1 then
    StartTmr()
	end
end

OnStartup = Main

function StartTmr()
	if NewAPI then
    TimerID = TmrMan.AddTimer(tConfig.Timer*60*1000,"OnTimer")
	else
    SetTimer (tConfig.Timer*60*1000)
    StartTimer()
	end
	bDefloodPause = false
end

function StartTmr2()
	if NewAPI then
    TimerID = TmrMan.AddTimer(iDefloodTimer*60*1000,"OnTimer")
	else
    SetTimer (iDefloodTimer*60*1000)
    StartTimer()
	end
end

function StopTmr()
	if NewAPI then
    TmrMan.RemoveTimer(TimerID)
	else
    StopTimer()
	end
end

function OnExit()
	Save()
end

function OnTimer()
	if bMessage or not bDeflood then
    if bDefloodPause then
    	StopTmr()
    	StartTmr()
    end
    bMessage = false
    SendInfo()
	else
    bDefloodPause = true
    StopTmr()
	end
end

function NewUserConnected(user)
	if bEnableFAQ and next(tFAQ) then
    for i,v in ipairs(tFAQ) do
    	SendFAQMenu(user, v[1].."$<%[mynick]> "..prefix..faq.." "..i)
    end
	end
	if tControl[user.iProfile] == 1 then
    SendMenu(user, "Показать все$<%[mynick]> "..prefix..showallinfo.." ")
    SendMenu(user, "Настройки\\Вывод информации в чат\\Включить$<%[mynick]> "..prefix..info.." 1")
    SendMenu(user, "Настройки\\Вывод информации в чат\\Отключить$<%[mynick]> "..prefix..info.." 0")
    SendMenu(user, "Настройки\\Время вывода информации в чат$<%[mynick]> "..prefix..timeinfo.." %[line:Укажите время (в минутах)]")
    SendMenu(user, "Настройки\\Рассылка важной информации в личку\\Включить$<%[mynick]> "..prefix..impinfo.." 1")
    SendMenu(user, "Настройки\\Рассылка важной информации в личку\\Отключить$<%[mynick]> "..prefix..impinfo.." 0")
    SendMenu(user, "Информация\\Добавить сообщение$<%[mynick]> "..prefix..addinfo.." %[line:Введите текст]")
    SendMenu(user, "Информация\\Удалить сообщение$<%[mynick]> "..prefix..delinfo.." %[line:Введите номер]")
    SendMenu(user, "Важная информация\\Добавить сообщение$<%[mynick]> "..prefix..addimpinfo.." %[line:Введите текст] %[line:Укажите количество отправок]")
    SendMenu(user, "Важная информация\\Удалить сообщение$<%[mynick]> "..prefix..delimpinfo.." %[line:Введите номер]")
    if bEnableFAQ then
    	SendMenu(user, "Справка\\Показать все разделы$<%[mynick]> "..prefix..showfaq)
    	SendMenu(user, "Справка\\Добавить раздел$<%[mynick]> "..prefix..addfaq.." name:%[line:Введите имя раздела] text:%[line:Введите текст]")
    	SendMenu(user, "Справка\\Удалить раздел$<%[mynick]> "..prefix..delfaq.." %[line:Введите номер]")
    end
	end
	if tSend[user.iProfile] == 1 then
    SendMenu(user, "Разослать сообщение$<%[mynick]> "..prefix..send.." %[line:Введите текст]")
    SendMenu(user, "Разослать сообщение в личку$<%[mynick]> "..prefix..sendpm.." %[line:Введите текст]")
	end
	for i in pairs(tImpMessage) do
    nick = user.sNick or user.sName
    local id = ""
    if SaveIP then
    	id = user.sIP
    else
    	id = nick
    end
    if not(tImpMessage[i][3][id]) then
    	tImpMessage[i][3][id] = 1
    end
    if tImpMessage[i][3][id] <= tImpMessage[i][2] or tImpMessage[i][2] == 0 then
    	local s,e,file = string.find(tImpMessage[i][1],"^file:(.+)$")
    	local msg = ""
    	if file then
        msg = ReadFile(sTextFolder,file)
    	else
        msg = tImpMessage[i][1]
    	end
    	if msg then
        msg = string.gsub(msg,"%[USER%]",nick)
        SendPM(user,msg)
        tImpMessage[i][3][id] = tImpMessage[i][3][id]+1
        SaveCount = SaveCount+1
        if SaveCount >=10 then
        	SaveCount = 0
        	Save()
        end
    	end
    end
	end
end

UserConnected = NewUserConnected
OpConnected = NewUserConnected
RegConnected = NewUserConnected

function ChatArrival(user, data)
	local data = data:sub(1,-2)
	if tConfig.Auto==1 and not data:find("^%b<>%s+"..sCmdPrefix..sCmdPattern) then
    if bDefloodPause and not bMessage then
    	StartTmr2()
    end
    bMessage = true
	end
	if tControl[user.iProfile] == 1 or tSend[user.iProfile] == 1 or bEnableFAQ then
    local pre,cmd = data:match("^%b<>%s+(%p)(%S+)")
    if pre and cmd and pre==prefix then
    	local tdata = data:match("^%b<>%s+%S+%s(.+)$")
    	if bEnableFAQ then
        if cmd == faq then
        	FAQ(user,tdata)
        	return stop
        end
    	end
    	if tControl[user.iProfile] == 1 and tControlCmd[cmd] then
        local result = tControlCmd[cmd](user,tdata)
        if result then SendMsg(user,result) end
        return stop
    	end
    	if tSend[user.iProfile] == 1 and (cmd == send or cmd == sendpm) then
        local pm = false
        if cmd == sendpm then pm = true end
        if tdata == nil or tdata == "" then
        	return "Ошибка: Вы должны ввести текст"
        else
        	Send(tdata,pm)
        end
        return stop
    	end
    end
	end
end

function ToArrival(user, data)
	local data = data:sub(1,-2)
	if tControl[user.iProfile] == 1 or tSend[user.iProfile] == 1 or bEnableFAQ then
    local to = data:match("^%$To:%s(%S+)%s")
    if to == bot then
    	local pre,cmd = data:match("^%$To:%s%S+%sFrom:%s%S+%s%$%b<>%s+(%p)(%S+)")
    	if pre and cmd and pre==prefix then
        local tdata = data:match("^%$To:%s%S+%sFrom:%s%S+%s%$%b<>%s+%p%S+%s+(.+)$")
        if bEnableFAQ then
        	if cmd == faq then
            FAQ(user,tdata)
            return stop
        	end
        end
        if tControl[user.iProfile] == 1 and tControlCmd[cmd] then
        	local result = tControlCmd[cmd](user,tdata)
        	if result then SendPM(user,result) end
        	return stop
        end
        if tSend[user.iProfile] == 1 and (cmd == send or cmd == sendpm) then
        	local pm = false
        	if cmd == sendpm then pm = true end
        	if tdata == nil or tdata == "" then
            return "Ошибка: Вы должны ввести текст"
        	else
            Send(tdata,pm)
        	end
        	return stop
        end
    	end
    end
	end
end

function FAQ(user,tdata)
	tdata = tonumber(tdata)
	if tdata then
    if tFAQ[tdata] then
    	local file = string.match(tFAQ[tdata][2],"^file:(.+)$")
    	if file then
        msg = ReadFile(sTextFolder,file)
    	else
        msg = tFAQ[tdata][2]
    	end
    	if msg then
        msg = string.gsub(msg,"%[USER%]",user.sName or user.sNick)
        SendFAQ(user, tFAQ[tdata][1].."\n"..msg)
    	else
        SendFAQ(user,"Произошла ошибка при отправке раздела. Обратитесь к администратору хаба.")
    	end
    else
    	SendFAQ(user,"Ошибка: не найден указанный раздел справки")
    end
	else
    if next(tFAQ) then
    	local msg = "\r\n\t::: ::: ::: Разделы справки ::: ::: :::\r\n"
    	for i,v in pairs(tFAQ) do
        msg = msg.."\t"..i..". "..v[1].."\r\n"
    	end
    	msg = msg.."Чтобы выбрать раздел, введите "..prefix..faq.." <номер раздела>"
    	SendFAQ(user, msg)
    else
    	SendFAQ(user, "Нет ни одного раздела справки")
    end
	end
end

tControlCmd = {
	[addfaq] = function(user,tdata)
    tdata = tdata or ""
    local s,e,name,text = string.find(tdata, "^name:(.+)%s+text:(.+)$")
    if name and text then
    	local tTemp = {name,text}
    	table.insert(tFAQ,tTemp)
    	Save()
    	return "Раздел сохранен в базе под номером "..table.maxn(tFAQ)
    else
    	return "Ошибка синтаксиса. Синтаксис: "..prefix..addfaq.." name:<имя раздела> text:<текст>"
    end
	end,
	[delfaq] = function(user,tdata)
    if tdata == nil or tdata == "" then
    	return  "Ошибка: Вы должны ввести номер"
    else
    	tdata  = tonumber(tdata)
    	if tFAQ[tdata] then
        table.remove(tFAQ,tdata)
        Save()
        return "Раздел № "..tdata.." успешно удален из базы"
    	else
        return "Ошибка: Раздел с номером "..tdata.." не существует в базе"
    	end
    end
	end,
	[showfaq] = function(user,tdata)
    local msg = "\r\n::: ::: ::: Разделы справки ::: ::: :::\r\n"
    if next(tFAQ) then
    	for i in ipairs(tFAQ) do
        local s,e,file = string.find(tFAQ[i][2],"^file:(.+)$")
        local msg2 = ""
        if file then
        	msg2 = "*Содержимое файла "..file.."*"
        	if not(CheckFile(sTextFolder,file)) then
            msg2 = msg2.." (ошибка)"
        	end
        else
        	msg2 = tFAQ[i][2]
        end
        msg = msg.."\r\n\t"..i..".  "..tFAQ[i][1]..": "..msg2.."\r\n"
    	end
    else
    	msg = msg.."\r\n\tРазделы отсутствуют\r\n"
    end
    SendPM(user, msg)
	end,
	[showallinfo] = function(user,tdata)
    local msg = "\r\n::: ::: ::: Настройки ::: ::: :::\r\n"
    local state = "включен"
    if tConfig["Auto"]==0 then
    	state = "отключен"
    end
    msg = msg.."\r\n\tВывод информации в чат: "..state.."\r\n"
    msg = msg.."\r\n\tВремя отправки сообщений: "..tConfig["Timer"].." мин.\r\n"
    state = "включена"
    if tConfig["ImpMsg"]==0 then
    	state = "отключена"
    end
    msg = msg.."\r\n\tРассылка важной информации в личку: "..state.."\r\n"
    msg = msg.."\r\n::: ::: ::: Информация ::: ::: :::\r\n"
    if next(tMessage) then
    	for i in ipairs(tMessage) do
        local s,e,file = string.find(tMessage[i],"^file:(.+)$")
        local msg2 = ""
        if file then
        	msg2 = "*Содержимое файла "..file.."*"
        	if not(CheckFile(sTextFolder,file)) then
            msg2 = msg2.." (ошибка)"
        	end
        else
        	msg2 = tMessage[i]
        end
        msg = msg.."\r\n\t"..i..".  "..msg2.."\r\n"
    	end
    else
    	msg = msg.."\r\n\tСообщения отсутствуют\r\n"
    end
    msg = msg.."\r\n::: ::: ::: Важная информация ::: ::: :::\r\n"
    if next(tImpMessage) then
    	for i in ipairs(tImpMessage) do
        local s,e,file = string.find(tImpMessage[i][1],"^file:(.+)$")
        local msg2 = ""
        if file then
        	msg2 = "*Содержимое файла "..file.."*"
        	if not(CheckFile(sTextFolder,file)) then
            msg2 = msg2.." (ошибка)"
        	end
        else
        	msg2 = tImpMessage[i][1]
        end
        msg3 = ""
        if tImpMessage[i][2] > 0 then
        	msg3 = " (Отправлять "..tImpMessage[i][2].." раз(а))"
        end
        msg = msg.."\r\n\t"..i..".  "..msg2..msg3.."\r\n"
    	end
    else
    	msg = msg.."\r\n\tСообщения отсутствуют\r\n"
    end
    SendPM(user, msg)
	end,
	[info] = function(user,tdata)
    if not tdata or tdata == "" then
    	return "Ошибка"
    else
    	tdata = tonumber(tdata)
    	if tdata == 0 then
        if tConfig.Auto == 1 then
        	StopTmr()
        end
        tConfig.Auto = 0
        Save()
        return "Вывод информации в чат отключен"
    	else
        if tConfig.Auto == 0 then
        	StartTmr()
        end
        tConfig.Auto = 1
        Save()
        return "Вывод информации в чат включен"
    	end
    end
	end,
	[timeinfo] = function(user,tdata)
    if not tdata or tdata == "" then
    	return "Ошибка"
    else
    	tdata = tonumber(tdata)
    	if tdata > 0 then
        tConfig.Timer = tdata
        Save()
        if tConfig.Auto == 1 then
        	StopTmr()
        	StartTmr()
        end
        return "Установлено время отправки сообщений в чат - "..tConfig.Timer.." мин."
    	else
        return "Ошибка"
    	end
    end
	end,
	[impinfo] = function(user,tdata)
    if not tdata or tdata == "" then
    	return "Ошибка"
    else
    	tdata = tonumber(tdata)
    	if tdata == 0 then
        tConfig.ImpMsg = 0
        Save()
        return "Рассылка важной информации в личку отключена" 
    	else
        tConfig.ImpMsg = 1
        Save()
        return "Рассылка важной информации в личку включена"
    	end
    end
	end,
	[addinfo] = function(user,tdata)
    if tdata == nil or tdata == "" then
    	return "Ошибка: Вы должны ввести текст"
    else
    	table.insert(tMessage,tdata)
    	Save()
    	return "Сообщение успешно сохранено в базе под номером "..table.maxn(tMessage)
    end
	end,
	[delinfo] = function(user,tdata)
    if tdata == nil or tdata == "" then
    	return "Ошибка: Вы должны ввести номер"
    else
    	tdata  = tonumber(tdata)
    	if tMessage[tdata] then
        table.remove(tMessage,tdata)
        Save()
        return "Сообщение № "..tdata.." успешно удалено из базы"
    	else
        return "Ошибка: Сообщение с номером "..tdata.." не существует в базе"
    	end
    end
	end,
	[addimpinfo] = function(user,tdata)
    local s,e,smsg, num = string.find(tdata, "^(.+)%s(%d+)$")
    num = tonumber(num)
    if smsg == nil or smsg == "" then
    	return "Ошибка: Вы должны ввести текст сообщения и указать количество отправок сообщения каждому пользователю. Введите 0 чтобы рассылка никогда не заканчивалась."
    else
    	local index=table.maxn(tImpMessage)+1
    	tImpMessage[index] = {[1] = smsg, [2] = num, [3] = {}}
    	Save()
    	return "Сообщение успешно сохранено в базе под номером "..index
    end
	end,
	[delimpinfo] = function(user,tdata)
    if tdata == nil or tdata == "" then
    	SendMsg(user, "Ошибка: Вы должны ввести номер")
    else
    	tdata  = tonumber(tdata)
    	if tImpMessage[tdata] then
        table.remove(tImpMessage,tdata)
        Save()
        return "Сообщение № "..tdata.." успешно удалёно из базы"
    	else
        return "Ошибка: Сообщение с номером "..tdata.." не существует в базе"
    	end
    end
	end
}

function SendInfo()
	if table.maxn(tMessage) > 0 then
    local temp = tMessage[math.random(1,table.getn(tMessage))]
    Send(temp,false)
	end
end

function Send(data,pm)
	local s,e,file = string.find(data,"^file:(.+)$")
	local msg = ""
	if file then
    msg = ReadFile(sTextFolder,file)
	else
    msg = data
	end
	if msg then
    local temp = string.find(msg,"%[USER%]")
    if temp then
    	local OnlineTab = {}
    	if NewAPI then
        OnlineTab = Core.GetOnlineUsers(true)
    	else
        OnlineTab = frmHub:GetOnlineUsers()
    	end
    	for i, v in pairs(OnlineTab) do
        local nick = v.sNick or v.sName
        local msg2 = string.gsub(msg,"%[USER%]",nick)
        if pm then
        	SendPM(v,msg2)
        else
        	SendMsg(v,msg2)
        end
    	end
    else
    	if pm then
        SendPMToAll(msg)
    	else
        SendMsgToAll(msg)
    	end
    end
	end
end

--Функции работы с файлами
function CheckFile(folder,file)
	local f = io.open( folder..file, "r" )
	local result = false
	if f then
    f:close()
    result = true
	end
	return result
end

function ReadFile(folder,file)
	local f = io.open( folder..file, "r" )
	local content = nil
	if f then
    content = f:read("*all")
    f:close()
	else
    SendMsgToOps("Ошибка при отправке сообщения: невозможно прочитать файл "..file)
	end
	return content
end

--Функции отправки сообщений
function SendMsg(user, msg)
	if NewAPI then
    Core.SendToUser(user,"<"..bot.."> "..msg)
	else
    user:SendData(bot, msg)
	end
end

function SendPM(user, msg)
	if NewAPI then
    Core.SendPmToUser(user,bot,msg)
	else
    user:SendPM(bot, msg)
	end
end

function SendFAQ(user, msg)
	if bFaqToPM then
    SendPM(user, msg)
	else
    SendMsg(user, msg)
	end
end

function SendMsgToAll(msg)
	if NewAPI then
    Core.SendToAll("<"..bot.."> "..msg)
	else
    SendToAll(bot, msg)
	end
end

function SendPMToAll(msg)
	if NewAPI then
    Core.SendPmToAll(bot, msg)
	else
    SendPmToAll(bot, msg)
	end
end

function SendMsgToOps(msg)
	if NewAPI then
    Core.SendToOps("<"..bot.."> "..msg)
	else
    SendToOps(bot, msg)
	end
end

function SendMenu(user, menu)
	if NewAPI then
    Core.SendToUser(user,"$UserCommand 1 3 "..AdminMenu..menu.."|")
	else
    user:SendData("$UserCommand 1 3 "..AdminMenu..menu.."|")
	end
end

function SendFAQMenu(user, menu)
	if NewAPI then
    Core.SendToUser(user,"$UserCommand 1 3 "..FAQMenu..menu.."|")
	else
    user:SendData("$UserCommand 1 3 "..FAQMenu..menu.."|")
	end
end

function SendSpacer(user, menu)
	if NewAPI then
    Core.SendToUser(user,"$UserCommand 0 3")
	else
    user:SendData("$UserCommand 0 3")
	end
end

--Функции сохранения
function Save()
	local hFile = io.open(sSettingsFolder..sConfigFile, "w+")
	Serialize(tConfig, "tConfig", hFile)
	Serialize(tMessage, "tMessage", hFile)
	Serialize(tImpMessage, "tImpMessage", hFile)
	Serialize(tFAQ, "tFAQ", hFile)
	hFile:close()
end

function Serialize(tTable, sTableName, hFile, sTab)
	sTab = sTab or "";
	hFile:write(sTab..sTableName.." = {\n");
	for key, value in pairs(tTable) do
    if (type(value) ~= "function") then
    	local sKey = (type(key) == "string") and string.format("[%q]", key) or string.format("[%d]", key);
    	if(type(value) == "table") then
        Serialize(value, sKey, hFile, sTab.."\t");
    	else
        local sValue = (type(value) == "string") and string.format("%q", value) or tostring(value);
        hFile:write(sTab.."\t"..sKey.." = "..sValue);
    	end
    	hFile:write(",\n");
    end
	end
	hFile:write(sTab.."}");
end

7

Код:
bot = "MAINBOT"
taimer = 180 -- в минутах

messarray={ 
[[Мы рады приветствовать вас на нашем хабе! Посетите наши веб ресурсы:
Сайт: http://core.pvt.454.ru
Форум: http://core.pvt.454.ru/forum]],
}

function OnStartup()
    tmr = TmrMan.AddTimer (taimer*60*1000)
end

function OnTimer(tmr)
    Core.SendToAll("<"..bot.."> "..messarray[math.random(1,#messarray)])
end

8

Код:
---------------------------------------------------------------------------------------------------------------------------------------------------------------  
--  Скрипт "Информер v1.1" by Wariner под API 2  
--  Для портала администраторов хаба http://mydc.ru
--  Доработал Damaks (http://ddd-dc.ru)
----------------------------------------------------------------------------------------------------------------------------------------------------------------

local gBot = "Информер"
local gTaimer = 5 --  время в минутах через которое будуи выходить сообщение в интервале заданных часов
local tDays = {
   ["Monday"] = "Понедельник",
   ["Tuesday"] = "Вторник",
   ["Wednesday"] = "Среда",
   ["Thursday"] = "Четверг", 
   ["Friday"] = "Пятница",
   ["Saturday"] = "Суббота",
   ["Sunday"] = "Воскресенье", 
}

local msg = {
'Сообщение для понедельника',
'Сообщение для вторника',
'Сообщение для среды',
'Сообщение для четверга',
'Сообщение для пятницы',
'Сообщение для субботы',
'Сообщение для воскресенья',
}

function OnStartup()
	tmr = TmrMan.AddTimer (gTaimer*60*1000)
end

function OnTimer(tmr)
	local day = os.date("%A")
	local hour = os.date("%H")
	local min = os.date("%M")
	for i,v in pairs(tDays) do
        day = string.gsub(day,i,v)
    end
	
	if (day == "Понедельник") then
	    if (tonumber(hour) >= 18) and (tonumber(hour) < 19) and (tonumber(min) >= 1) and (tonumber(min) < 5) then    -- hour - часы, от и до;	min - минуты, от и до.	 Интервал минут лучше ставить в количестве gTaimer-1
    	Core.SendToAll("<"..gBot.."> "..msg[1])
     end
   end
	if (day == "Вторник") then
	    if (tonumber(hour) >= 18) and (tonumber(hour) < 19) and (tonumber(min) >= 1) and (tonumber(min) < 5) then
    	Core.SendToAll("<"..gBot.."> "..msg[2])
     end
   end
	if (day == "Среда") then
	    if (tonumber(hour) >= 18) and (tonumber(hour) < 19) and (tonumber(min) >= 1) and (tonumber(min) < 5) then
    	Core.SendToAll("<"..gBot.."> "..msg[3])
     end
   end
	if (day == "Четверг") then
	    if (tonumber(hour) >= 18) and (tonumber(hour) < 19) and (tonumber(min) >= 1) and (tonumber(min) < 5) then
    	Core.SendToAll("<"..gBot.."> "..msg[4])
     end
   end
	if (day == "Пятница") then
	    if (tonumber(hour) >= 18) and (tonumber(hour) < 19) and (tonumber(min) >= 1) and (tonumber(min) < 5) then
    	Core.SendToAll("<"..gBot.."> "..msg[5])
     end
   end
	if (day == "Суббота") then
	    if (tonumber(hour) >= 18) and (tonumber(hour) < 19) and (tonumber(min) >= 1) and (tonumber(min) < 5) then
    	Core.SendToAll("<"..gBot.."> "..msg[6])
    end
	end
	if (day == "Воскресенье") then
	    if (tonumber(hour) >= 18) and (tonumber(hour) < 19) and (tonumber(min) >= 1) and (tonumber(min) < 5) then
    	Core.SendToAll("<"..gBot.."> "..msg[7])
     end
   end

end

9

Скрипт предназначен для перенаправления юзеров, упорно пытающихся войти на хаб
несколько раз под одним ником. Используется при слиянии крупных хабов.

Алгоритм работы следующий: При первой попытке входа клона, запоминаем время
сего знаменательного события, а затем, при каждой последующей попытке, смотрим,
прошло ли с момента первой попытки входа iTime минут. Если да, перенаправляем
юзера. Сделано это для того, чтобы избежать перенаправления тех юзеров, что
отвалились от хаба из-за проблем с сетью, и теперь не могут войти по той причине,
что их ник по-прежнему висит в списке юзеров. Если в промежутке между iTime и
iDelTime юзер не предпринял ни одной попытки входа, то предполагаем, что юзер
таки заметил неладное и сменил ник (или его просто заебало ломиться в закрытую
дверь :D) , и удаляем его из списка ожидающих перенаправления.

Clone Redirect

iTime = 20 -- Таймаут перенаправления, минут
iDelTime = 30 -- Таймаут удаления юзера из списка, минут
sRedirAddr = "bceti.com" -- Адрес перенаправления

sLog = Core.GetPtokaXPath().."logs/clone_redirect.log"

--###################################################################################

tClone = {}

function OnStartup()
TmrMan.AddTimer(60000,"MainTimer")
end

function ValidateDenideArrival(user,nick)
    if tClone[nick] then
    if tClone[nick]+iTime*60 < os.time() then
    Core.SendToUser(user,"$ForceMove "..sRedirAddr)
    tClone[nick] = nil
    Report("Юзер "..nick.." был перенаправлен на резервный хаб, поскольку на хабе уже есть юзер с таким ником")
    end
else
    tClone[nick] = os.time()
    Report("Юзер "..nick.." был добавлен в список ожидающих перенаправления")
end
end

function UserConnected(user)
if tClone[user.sNick] then
    tClone[user.sNick] = nil
    Report("Юзер "..user.sNick.." был удален из списка дублирующихся юзеров, поскольку успешно вошел на хаб.")
end
end
OpConnected = UserConnected
RegConnected = UserConnected

function MainTimer()
for i,v in pairs(tClone) do
    if v+iDelTime*60 < os.time() then
    tClone[i] = nil
    Report("Юзер "..i.." был удален из списка дублирующихся юзеров, поскольку прекратил попытки входа.")
    end
end
end

function Report(msg)
local f = io.open(sLog,"a")
if f then
    f:write(os.date("[%Y-%m-%d %H:%M:%S] "),msg,"\n")
    f:close()
end
end

10

Если Вы переходите на данную версию с более новой, хранящей настройки и список скриптов в файлах .pxt, то Вам будет полезен конвертер

Скрипт предназначен для конвертирования настроек и списка скриптов из текстового
формата обратно в XML. Скрипт используется в том случае, если Вы желаете откатиться
с PtokaX 0.5.2.1 mod (или более новой) на PtokaX 0.5.0.1 mod (или более старую).

ВНИМАНИЕ!
Скрипт не умеет парсить файлы настроек, он получает данные из памяти PtokaX при
помощи API Lua. Следовательно, необходимо запускать его непосредственно на хабе,
использующем новый формат настроек.

Скрипт

tSetBool = {
    "AntiMoGlo",
    "AutoStart",
    "RedirectAll",
    "RedirectWhenHubFull",
    "AutoRegister",
    "RegOnly",
    "RegOnlyRedir",
    "ShareLimitRedir",
    "SlotsLimitRedir",
    "HubSlotRatioRedir",
    "MaxHubsLimitRedir",
    "ModeToMyINFO",
    "ModeToDescription",
    "StripDescription",
    "StripTag",
    "StripConnection",
    "StripEmail",
    "RegBot",
    "UseBotNickAsHubSec",
    "RegOpChat",
    "TempBanRedir",
    "PermBanRedir",
    "EnableScripting",
    "KeepSlowUsers",
    "CheckNewReleases",
    "EnableTrayIcon",
    "StartMinimized",
    "FilterKickMessages",
    "SendKickMessagesToOps",
    "SendStatusMessages",
    "SendStatusMessagesAsPm",
    "EnableTextFiles",
    "SendTextFilesAsPm",
    "StopScriptOnError",
    "MOTDAsPm",
    "DefloodReport",
    "ReplyToHubCommandsAsPm",
    "DisableMOTD",
    "DontAllowPingers",
    "ReportPingers",
    "Report3xBadPass",
    "AdvancedPassProtection",
    "BindOnlySingleIp",
    "ResolveToIp",
    "NickLimitRedir",
"SendUserIP2ToUserOnLogin",
    "BanMessageShowIp",
    "BanMessageShowRange",
    "BanMessageShowNick",
    "BanMessageShowReason",
    "BanMessageShowBy",
    "ReportSuspiciousTag",
"AcceptUnknownTag",
"CheckIpInCommands",
"PopupScriptsWindow",
    "LogScriptErrors",
    "NoQuackSupports",
"ShowWelcome",
"BlockUnknownCmd",
"CheckKeys",
"UseCompression",
"ScriptErrorsToOps",
"ScriptStackTraceback",
"KeepMagicByte",
"LockDelayed",
};

tSetNumber = {
    "MaxUsers",
    "MinShareLimit",
    "MinShareUnits",
    "MaxShareLimit",
    "MaxShareUnits",
    "MinSlotsLimit",
    "MaxSlotsLimit",
    "HubSlotRatioHubs",
    "HubSlotRatioSlots",
    "MaxHubsLimit",
    "NoTagOption",
    "FullMyINFOOption",
    "MaxChatLen",
    "MaxChatLines",
    "MaxPmLen",
    "MaxPmLines",
    "DefaultTempBanTime",
    "MaxPassiveSr",
    "MyINFODelay",
    "MainChatMessages",
    "MainChatTime",
    "MainChatAction",
    "SameMainChatMessages",
    "SameMainChatTime",
    "SameMainChatAction",
    "SameMultiMainChatMessages",
    "SameMultiMainChatLines",
    "SameMultiMainChatAction",
    "PmMessages",
    "PmTime",
    "PmAction",
    "SamePmMessages",
    "SamePmTime",
    "SamePmAction",
    "SameMultiPmMessages",
    "SameMultiPmLines",
    "SameMultiPmAction",
    "SearchMessages",
    "SearchTime",
    "SearchAction",
    "SameSearchMessages",
    "SameSearchTime",
    "SameSearchAction",
    "MyINFOMessages",
    "MyINFOTime",
    "MyINFOAction",
    "GetNickListMessages",
    "GetNickListTime",
    "GetNickListAction",
    "NewConnectionsCount",
    "NewConnectionsTime",
    "DefloodWarningCount",
    "DefloodWarningAction",
    "DefloodTempBanTime",
    "GlobalMainChatMessages",
    "GlobalMainChatTime",
    "GlobalMainChatTimeOut",
    "GlobalMainChatAction",
    "MinSearchLen",
    "MaxSearchLen",
    "MinNickLen",
    "MaxNickLen",
    "BruteForcePassProtectBanType",
    "BruteForcePassProtectTempBanTime",
    "MaxPmCountToUser",
    "MaxSimultaneousLogins",
    "MainChatMessages2",
    "MainChatTime2",
    "MainChatAction2",
    "PmMessages2",
    "PmTime2",
    "PmAction2",
    "SearchMessages2",
    "SearchTime2",
    "SearchAction2",
    "MyINFOMessages2",
    "MyINFOTime2",
    "MyINFOAction2",
    "MaxMyINFOLen",
    "CTMMessages",
    "CTMTime",
    "CTMAction",
    "CTMMessages2",
    "CTMTime2",
    "CTMAction2",
    "RCTMMessages",
    "RCTMTime",
    "RCTMAction",
    "RCTMMessages2",
    "RCTMTime2",
    "RCTMAction2",
    "MaxCTMLen",
    "MaxRCTMLen",
    "SRMessages",
    "SRTime",
    "SRAction",
    "SRMessages2",
    "SRTime2",
    "SRAction2",
    "MaxSRLen",
    "MaxDownAction",
    "MaxDownKb",
    "MaxDownTime",
    "MaxDownAction2",
    "MaxDownKb2",
    "MaxDownTime2",
    "ChatIntervalMessages",
    "ChatIntervalTime",
    "PMIntervalMessages",
    "PMIntervalTime",
    "SearchIntervalMessages",
    "SearchIntervalTime",
    "MaxConnSameIP",
    "MinReConnTime",
"MaxTempBanTimeDays",
"ServiceLoopInterval",
    "MaxUsersPeak",
};

tSetStr = {
    "HubName",
    "AdminNick",
    "HubAddress",
    "TCPPorts",
    "UDPPort",
    "HubDescription",
    "RedirectAddress",
    "RegisterServers",
    "RegOnlyMessage",
    "RegOnlyRedirAddress",
    "HubTopic",
    "ShareLimitMessage",
    "ShareLimitRedirAddress",
    "SlotsLimitMessage",
    "SlotsLimitRedirAddress",
    "HubSlotRatioMessage",
    "HubSlotRatioRedirAddress",
    "MaxHubsLimitMessage",
    "MaxHubsLimitRedirAddress",
    "NoTagMessage",
    "NoTagRedirAddress",
    "BotNick",
    "BotDescription",
    "BotEmail",
    "OpChatNick",
    "OpChatDescription",
    "OpChatEmail",
    "TempBanRedirAddress",
    "PermBanRedirAddress",
    "ChatCommandsPrefixes",
    "HubOwnerEmail",
    "NickLimitMessage",
    "NickLimitRedirAddress",
    "MessageToAddToBanMessage",
    "Language",
    "IPv4Address",
    "IPv6Address",
"LocaleWin",
"LocaleNix",
};

function OnStartup()
function XMLEscape(str)
    str=str:gsub("&","&amp;")
    for i,v in pairs({["'"] = "&apos;", ["\""] = "&quot;", ["<"] = "&lt;", [">"] = "&gt;", }) do
    str=str:gsub(i,v)
    end
    return str
end

local f = io.open(Core.GetPtokaXPath().."cfg/Settings.xml", "wb")
if f then
    f:write('<?xml version="1.0" encoding="windows-1251" standalone="yes" ?>\n<PtokaX Version="0.5.0.1 mod 11">\n    <Booleans>\n')
    for i, v in ipairs(tSetBool) do
    f:write('\t\t<Bool Name="', v, '">', (SetMan.GetBool(i-1) and '1' or '0'), '</Bool>\n')
    end
   
    f:write("\t</Booleans>\n\t<Integers>\n")
    for i, v in ipairs(tSetNumber) do
    f:write('\t\t<Integer Name="', v, '">', SetMan.GetNumber(i-1), '</Integer>\n')
    end
   
    f:write("\t</Integers>\n\t<Strings>\n")
    for i, v in ipairs(tSetStr) do
    f:write('\t\t<String Name="', v, '">', XMLEscape(SetMan.GetString(i-1) or ""), '</String>\n')
    end
   
    f:write("\t</Strings>\n</PtokaX>\n")
   
    f:close()
end

f = io.open(Core.GetPtokaXPath().."cfg/Scripts.xml", "wb")

if f then
    f:write('<?xml version="1.0" encoding="windows-1251" standalone="yes" ?>\n<Scripts>\n')
    for i, v in ipairs(ScriptMan.GetScripts()) do
    f:write('\t<Script>\n\t\t<Name>', XMLEscape(v.sName), '</Name>\n\t\t<Enabled>', v.sName == 'settings_back.lua' and '0' or (v.bEnabled and '1' or '0'), '</Enabled>\n\t</Script>\n')
    end
   
    f:write('</Scripts>\n')

    f:close()
end

print("Settings and scripts was saved in old format.")
ScriptMan.StopScript('settings_back.lua')
end