помогите с кодом

kalonne

Новичок
Автор темы
13
9
Версия MoonLoader
.026-beta
Приветствую, мой друг.
Я работаю над Lua-скриптом, который отслеживает сообщения из чата в GTA SA:MP. Сценарий такой: есть определённый игрок (допустим, X) и список ключевых слов (например, «член»). Когда игрок X пишет сообщение, содержащее это слово — скрипт срабатывает и выводит его текст мне в чат.

Проблема: всё отлично работает с английскими словами, но русские скрипт вообще не распознаёт. Кодировка используется Windows-1251.

Прошу помощи:
  • Как сделать так, чтобы обработка текста работала как с английскими, так и с русскими словами?
  • По желанию: было бы круто добавить интеграцию с Telegram-ботом, чтобы уведомления приходили и туда. Если в этом разбираешься — подскажи.
Скрипт изначально писал не я, помогал ИИ, так что строго не суди. Надеюсь на помощь. Большое спасибо.


lua:
-- Сохранять в кодировке Windows-1251
local imgui = require 'mimgui'
local ffi = require 'ffi'
local vkeys = require 'vkeys'
local sampev = require 'lib.samp.events'
local inicfg = require 'inicfg'

local wm = require 'windows.message'
local new, str, sizeof = imgui.new, ffi.string, ffi.sizeof

-- Переменные интерфейса
local renderWindow = new.bool()
local darkTheme = new.bool()
local playerName = new.char[256]()
local keyWord = new.char[256]()
local playerID = new.char[16]()
local telegramToken = new.char[256]()
local telegramChatID = new.char[256]()
local searchQuery = new.char[256]()
local sizeX, sizeY = getScreenResolution()

-- Переменные вкладок
local tabs = {
    {name = "Настройки", id = 1},
    {name = "Логи", id = 2},
    {name = "Статистика", id = 3},
    {name = "Telegram", id = 4}
}

-- Переменные логов и статистики
local logs = {}
local playerStats = {}
local maxLogsDisplay = 100
local maxLogsStored = 1000
local logDaysToLoad = 7

-- Загрузка конфигурации из файла
local config = inicfg.load({
    settings = {
        players = "sigmaboy",
        keywords = "hi,ку,привет,член",
        darkTheme = true,
        telegramToken = "7717049161:AAFnmwzAyb11Y2jhiZFl-7Ij10wLfbtsoUA",
        telegramChatID = "838131789",
        windowPosX = sizeX / 2,
        windowPosY = sizeY / 2,
        windowWidth = 600,
        windowHeight = 400,
        monitorChat = true,
        monitorServer = true
    }
}, "monitor.ini")

-- Создание директории для логов
local function createLogsDir()
    local path = "moonloader/logs/monitor"
    local file = io.open(path .. "/test.tmp", "w")
    if file then
        file:close()
        os.remove(path .. "/test.tmp")
        return path
    else
        os.execute("mkdir moonloader\\logs\\monitor")
        return path
    end
end

-- Очистка текста от SAMP-цветов
function cleanSampText(text)
    if not text then return "" end
    return text:gsub("{%x%x%x%x%x%x}", ""):gsub("{%x%x%x%x%x%x%x%x}", "")
end

-- Безопасная обработка строк
local function safeString(str)
    return type(str) == "string" and str or ""
end

-- Конвертация из UTF-8 в Windows-1251 (для Telegram)
local function utf8_to_cp1251(utf8_str)
    local cp1251_table = {
        [0x410] = 0xC0, [0x411] = 0xC1, [0x412] = 0xC2, [0x413] = 0xC3, [0x414] = 0xC4, [0x415] = 0xC5,
        [0x416] = 0xC6, [0x417] = 0xC7, [0x418] = 0xC8, [0x419] = 0xC9, [0x41A] = 0xCA, [0x41B] = 0xCB,
        [0x41C] = 0xCC, [0x41D] = 0xCD, [0x41E] = 0xCE, [0x41F] = 0xCF, [0x420] = 0xD0, [0x421] = 0xD1,
        [0x422] = 0xD2, [0x423] = 0xD3, [0x424] = 0xD4, [0x425] = 0xD5, [0x426] = 0xD6, [0x427] = 0xD7,
        [0x428] = 0xD8, [0x429] = 0xD9, [0x42A] = 0xDA, [0x42B] = 0xDB, [0x42C] = 0xDC, [0x42D] = 0xDD,
        [0x42E] = 0xDE, [0x42F] = 0xDF, [0x430] = 0xE0, [0x431] = 0xE1, [0x432] = 0xE2, [0x433] = 0xE3,
        [0x434] = 0xE4, [0x435] = 0xE5, [0x436] = 0xE6, [0x437] = 0xE7, [0x438] = 0xE8, [0x439] = 0xE9,
        [0x43A] = 0xEA, [0x43B] = 0xEB, [0x43C] = 0xEC, [0x43D] = 0xED, [0x43E] = 0xEE, [0x43F] = 0xEF,
        [0x440] = 0xF0, [0x441] = 0xF1, [0x442] = 0xF2, [0x443] = 0xF3, [0x444] = 0xF4, [0x445] = 0xF5,
        [0x446] = 0xF6, [0x447] = 0xF7, [0x448] = 0xF8, [0x449] = 0xF9, [0x44A] = 0xFA, [0x44B] = 0xFB,
        [0x44C] = 0xFC, [0x44D] = 0xFD, [0x44E] = 0xFE, [0x44F] = 0xFF, [0x401] = 0xA8, [0x451] = 0xB8
    }
    
    local result = {}
    local i = 1
    while i <= #utf8_str do
        local byte = utf8_str:byte(i)
        if byte < 128 then
            table.insert(result, string.char(byte))
            i = i + 1
        elseif byte >= 0xC0 and byte <= 0xDF then
            local byte2 = utf8_str:byte(i + 1) or 0
            local unicode = ((byte - 0xC0) * 64) + (byte2 - 0x80)
            local cp1251_char = cp1251_table[unicode]
            if cp1251_char then
                table.insert(result, string.char(cp1251_char))
            else
                table.insert(result, "?")
            end
            i = i + 2
        else
            table.insert(result, "?")
            i = i + 1
        end
    end
    return table.concat(result)
end

-- Загрузка логов из файлов
local function loadLogs()
    logs = {}
    local path = createLogsDir()
    for i = 0, logDaysToLoad - 1 do
        local date = os.date("%Y-%m-%d", os.time() - i * 86400)
        local filename = path .. "/" .. date .. ".log"
        local file = io.open(filename, "r")
        if file then
            for line in file:lines() do
                local timestamp, player, keyword, messageType, message = line:match("%[(.-)%] (.-) %-> (.-) %((.-)%): (.*)")
                if timestamp and player and keyword and messageType and message then
                    local logEntry = {
                        timestamp = os.time({year = date:sub(1, 4), month = date:sub(6, 7), day = date:sub(9, 10)}),
                        player = player,
                        keyword = keyword,
                        messageType = messageType,
                        message = message,
                        date = timestamp
                    }
                    table.insert(logs, 1, logEntry)
                    if not playerStats[player] then
                        playerStats[player] = {count = 0, lastSeen = ""}
                    end
                    playerStats[player].count = playerStats[player].count + 1
                    playerStats[player].lastSeen = timestamp
                end
            end
            file:close()
        end
    end
    while #logs > maxLogsStored do
        table.remove(logs, #logs)
    end
end

-- Сохранение лога
local function saveLog(player, keyword, message, messageType, timestamp)
    local cleanMessage = cleanSampText(message)
    local logEntry = {
        timestamp = timestamp or os.time(),
        player = player,
        keyword = keyword,
        messageType = messageType or "server",
        message = cleanMessage,
        date = os.date("%d.%m.%Y %H:%M:%S", timestamp or os.time())
    }

    table.insert(logs, 1, logEntry)
    if #logs > maxLogsStored then table.remove(logs, #logs) end

    local path = createLogsDir()
    local filename = path .. "/" .. os.date("%Y-%m-%d") .. ".log"
    local file = io.open(filename, "a")
    if file then
        file:write(string.format("[%s] %s -> %s (%s): %s\n", logEntry.date, player, keyword, messageType, cleanMessage))
        file:close()
    else
        sampAddChatMessage("[МОНИТОРИНГ] Ошибка записи лога!", -1)
    end

    if not playerStats[player] then
        playerStats[player] = {count = 0, lastSeen = ""}
    end
    playerStats[player].count = playerStats[player].count + 1
    playerStats[player].lastSeen = logEntry.date
end

-- Отправка уведомления в Telegram
local function sendToTelegram(player, keyword, message, messageType)
    local token = safeString(config.settings.telegramToken)
    local chatID = safeString(config.settings.telegramChatID)
    if token == "" or chatID == "" then
        sampAddChatMessage("[TELEGRAM] Токен или Chat ID не указаны!", -1)
        return
    end

    lua_thread.create(function()
        local cleanMessage = cleanSampText(message or "")
        print(string.format("[DEBUG] Отправка в Telegram: player=%s, keyword=%s, type=%s", player or "nil", keyword or "nil", messageType or "server"))

        local utfPlayer = safeString(player or "Unknown")
        local utfKeyword = safeString(keyword or "Unknown")
        local utfMessage = safeString(cleanMessage or "No message")
        local timeStr = os.date("%d.%m.%Y %H:%M:%S")
        local typeStr = messageType == "chat" and "ЧАТ" or "СЕРВЕР"

        local text = string.format("?? МОНИТОРИНГ (%s)\n\n?? Игрок: %s\n?? Слово: %s\n?? Сообщение: %s\n? Время: %s",
            typeStr, utfPlayer, utfKeyword, utfMessage, timeStr)

        -- URL encode для Telegram
        text = text:gsub("([^%w _%%%-%.~])", function(c)
            return string.format("%%%02X", string.byte(c))
        end):gsub(" ", "%%20")

        local url = string.format("https://api.telegram.org/bot%s/sendMessage", token)
        local postData = string.format("chat_id=%s&text=%s&parse_mode=HTML", chatID, text)

        local wininet = ffi.load('wininet')
        ffi.cdef[[
            void* InternetOpenA(const char* lpszAgent, unsigned long dwAccessType, const char* lpszProxy,
                               const char* lpszProxyBypass, unsigned long dwFlags);
            void* InternetConnectA(void* hInternet, const char* lpszServerName, unsigned short nServerPort,
                                   const char* lpszUserName, const char* lpszPassword, unsigned long dwService,
                                   unsigned long dwFlags, unsigned long dwContext);
            void* HttpOpenRequestA(void* hConnect, const char* lpszVerb, const char* lpszObjectName,
                                   const char* lpszVersion, const char* lpszReferrer,
                                   const char** lplpszAcceptTypes, unsigned long dwFlags, unsigned long dwContext);
            int HttpSendRequestA(void* hRequest, const char* lpszHeaders, unsigned long dwHeadersLength,
                                 const void* lpOptional, unsigned long dwOptionalLength);
            int InternetReadFile(void* hFile, char* lpBuffer, unsigned long dwNumberOfBytesToRead, unsigned long* lpdwNumberOfBytesRead);
            int InternetCloseHandle(void* hInternet);
        ]]

        local hInternet = wininet.InternetOpenA("TelegramBot/1.0", 1, nil, nil, 0)
        if hInternet == nil then
            sampAddChatMessage("[TELEGRAM] Ошибка инициализации Internet!", -1)
            return
        end

        local hConnect = wininet.InternetConnectA(hInternet, "api.telegram.org", 443, nil, nil, 3, 0, 0)
        if hConnect == nil then
            sampAddChatMessage("[TELEGRAM] Ошибка подключения к серверу!", -1)
            wininet.InternetCloseHandle(hInternet)
            return
        end

        local requestPath = string.format("/bot%s/sendMessage", token)
        local hRequest = wininet.HttpOpenRequestA(hConnect, "POST", requestPath, nil, nil, nil, 0x00800000, 0)
        if hRequest == nil then
            sampAddChatMessage("[TELEGRAM] Ошибка создания запроса!", -1)
            wininet.InternetCloseHandle(hConnect)
            wininet.InternetCloseHandle(hInternet)
            return
        end

        local headers = "Content-Type: application/x-www-form-urlencoded\r\n"
        local postDataBuffer = ffi.new("char[?]", #postData + 1, postData)
        local success = wininet.HttpSendRequestA(hRequest, headers, #headers, postDataBuffer, #postData)
        
        if success == 0 then
            sampAddChatMessage("[TELEGRAM] Ошибка отправки запроса!", -1)
        else
            local buffer = ffi.new("char[4096]")
            local bytesRead = ffi.new("unsigned long[1]")
            local response = ""
            while wininet.InternetReadFile(hRequest, buffer, 4096, bytesRead) ~= 0 and bytesRead[0] > 0 do
                response = response .. ffi.string(buffer, bytesRead[0])
            end
            if response:find('"ok":true') then
                sampAddChatMessage("[TELEGRAM] ? Уведомление отправлено!", -1)
            else
                sampAddChatMessage("[TELEGRAM] ? Ошибка отправки", -1)
                print("[TELEGRAM DEBUG] Response: " .. response)
            end
        end

        wininet.InternetCloseHandle(hRequest)
        wininet.InternetCloseHandle(hConnect)
        wininet.InternetCloseHandle(hInternet)
    end)
end

-- Инициализация ImGui
imgui.OnInitialize(function()
    imgui.GetIO().IniFilename = nil

    local safePlayers = safeString(config.settings.players)
    local safeKeywords = safeString(config.settings.keywords)
    local safeToken = safeString(config.settings.telegramToken)
    local safeChatID = safeString(config.settings.telegramChatID)

    imgui.StrCopy(playerName, safePlayers)
    imgui.StrCopy(keyWord, safeKeywords)
    imgui.StrCopy(telegramToken, safeToken)
    imgui.StrCopy(telegramChatID, safeChatID)

    darkTheme[0] = config.settings.darkTheme

    if darkTheme[0] then
        imgui.StyleColorsDark()
    else
        imgui.StyleColorsLight()
    end

    print(string.format("[DEBUG] Загруженные настройки: players=%s, keywords=%s", safePlayers, safeKeywords))
    loadLogs()
end)

-- Функция поиска текста (улучшенная для кириллицы)
local function findText(haystack, needle)
    if not haystack or not needle or needle == "" then
        return false
    end
    
    local cleanHaystack = cleanSampText(haystack):lower()
    local cleanNeedle = cleanSampText(needle):lower()
    
    -- Удаляем лишние пробелы
    cleanHaystack = cleanHaystack:gsub("%s+", " "):gsub("^%s*(.-)%s*$", "%1")
    cleanNeedle = cleanNeedle:gsub("%s+", " "):gsub("^%s*(.-)%s*$", "%1")
    
    print(string.format("[DEBUG] Поиск: '%s' в '%s'", cleanNeedle, cleanHaystack))
    
    return cleanHaystack:find(cleanNeedle, 1, true) ~= nil
end

-- Удаление лишних пробелов
local function trim(s)
    return s:gsub("^%s*(.-)%s*$", "%1")
end

-- Сохранение конфигурации
local function saveConfig()
    config.settings.players = str(playerName)
    config.settings.keywords = str(keyWord)
    config.settings.telegramToken = str(telegramToken)
    config.settings.telegramChatID = str(telegramChatID)
    inicfg.save(config, "monitor.ini")
end

-- Добавление игрока по ID
local function addPlayerByID()
    local id = tonumber(str(playerID))
    if id and sampIsPlayerConnected(id) then
        local nickname = sampGetPlayerNickname(id)
        if nickname then
            local currentPlayers = str(playerName)
            if currentPlayers == "" then
                currentPlayers = nickname
            else
                currentPlayers = currentPlayers .. ", " .. nickname
            end
            imgui.StrCopy(playerName, currentPlayers)
            config.settings.players = currentPlayers
            saveConfig()
            sampAddChatMessage("[МОНИТОРИНГ] Игрок " .. nickname .. " (ID: " .. id .. ") добавлен!", -1)
            imgui.StrCopy(playerID, "")
        end
    else
        sampAddChatMessage("[МОНИТОРИНГ] Игрок с ID " .. str(playerID) .. " не найден!", -1)
    end
end

-- Проверка сообщения на совпадения
local function checkMessage(text, messageType)
    local targetPlayers = safeString(config.settings.players)
    local targetWords = safeString(config.settings.keywords)

    if targetPlayers == "" or targetWords == "" then
        return false
    end

    local cleanText = cleanSampText(text)
    print(string.format("[DEBUG] Проверка %s сообщения: %s", messageType, cleanText))

    for player in targetPlayers:gmatch("[^,]+") do
        player = trim(player)
        if player ~= "" and findText(cleanText, player) then
            for word in targetWords:gmatch("[^,]+") do
                word = trim(word)
                if word ~= "" and findText(cleanText, word) then
                    print(string.format("[DEBUG] Совпадение найдено: игрок='%s', слово='%s'", player, word))
                    saveLog(player, word, text, messageType)
                    sendToTelegram(player, word, text, messageType)
                    
                    local typeStr = messageType == "chat" and "ЧАТ" or "СЕРВЕР"
                    local message = string.format("[МОНИТОРИНГ-%s] Игрок {00FF00}%s {FFFFFF}написал: {FFFF00}%s", typeStr, player, word)
                    sampAddChatMessage(message, -1)
                    sampAddChatMessage("[ТЕКСТ] {FFFFFF}" .. cleanText, -1)
                    return true
                end
            end
        end
    end
    return false
end

-- Основное окно ImGui
imgui.OnFrame(
    function() return renderWindow[0] end,
    function()
        if darkTheme[0] then
            imgui.StyleColorsDark()
        else
            imgui.StyleColorsLight()
        end

        imgui.SetNextWindowPos(imgui.ImVec2(config.settings.windowPosX, config.settings.windowPosY), imgui.Cond.FirstUseEver)
        imgui.SetNextWindowSize(imgui.ImVec2(config.settings.windowWidth, config.settings.windowHeight), imgui.Cond.FirstUseEver)

        if imgui.Begin("Мониторинг игроков v2.1", renderWindow) then
            if imgui.BeginTabBar("MainTabs") then
                if imgui.BeginTabItem("Настройки") then
                    imgui.Text("Основные настройки:")
                    imgui.Separator()

                    if imgui.InputTextMultiline("Игроки (через запятую)", playerName, sizeof(playerName), imgui.ImVec2(550, 80)) then
                        config.settings.players = str(playerName)
                        saveConfig()
                    end

                    imgui.Text("Добавить игрока по ID:")
                    imgui.SameLine()
                    imgui.PushItemWidth(100)
                    imgui.InputText("##playerID", playerID, sizeof(playerID))
                    imgui.PopItemWidth()
                    imgui.SameLine()
                    if imgui.Button("Добавить") then
                        addPlayerByID()
                    end

                    imgui.Spacing()

                    if imgui.InputTextMultiline("Ключевые слова (через запятую)", keyWord, sizeof(keyWord), imgui.ImVec2(550, 80)) then
                        config.settings.keywords = str(keyWord)
                        saveConfig()
                    end

                    imgui.Spacing()
                    imgui.Separator()

                    if imgui.Checkbox("Темная тема", darkTheme) then
                        config.settings.darkTheme = darkTheme[0]
                        saveConfig()
                    end

                    imgui.Text("Мониторить:")
                    if imgui.Checkbox("Чат игроков", new.bool(config.settings.monitorChat or true)) then
                        config.settings.monitorChat = not config.settings.monitorChat
                        saveConfig()
                    end
                    imgui.SameLine()
                    if imgui.Checkbox("Серверные сообщения", new.bool(config.settings.monitorServer or true)) then
                        config.settings.monitorServer = not config.settings.monitorServer
                        saveConfig()
                    end

                    imgui.EndTabItem()
                end

                if imgui.BeginTabItem("Логи") then
                    imgui.Text("Поиск в логах:")
                    imgui.SameLine()
                    imgui.InputText("##search", searchQuery, sizeof(searchQuery))
                    imgui.SameLine()
                    if imgui.Button("Экспорт") then
                        local path = createLogsDir()
                        local filename = path .. "/export_" .. os.date("%Y%m%d_%H%M%S") .. ".txt"
                        local file = io.open(filename, "w")
                        if file then
                            for _, log in ipairs(logs) do
                                file:write(string.format("[%s] %s -> %s (%s): %s\n", log.date, log.player, log.keyword, log.messageType or "server", log.message))
                            end
                            file:close()
                            sampAddChatMessage("[ЭКСПОРТ] Логи сохранены: " .. filename, -1)
                        else
                            sampAddChatMessage("[ЭКСПОРТ] Ошибка сохранения логов!", -1)
                        end
                    end

                    imgui.Separator()

                    if imgui.BeginChild("LogsChild", imgui.ImVec2(0, 250), true) then
                        local searchText = str(searchQuery)
                        for i, log in ipairs(logs) do
                            if i > maxLogsDisplay then break end
                            local shouldShow = searchText == "" or
                                findText(log.player, searchText) or
                                findText(log.keyword, searchText) or
                                findText(log.message, searchText)
                            if shouldShow then
                                local typeColor = log.messageType == "chat" and imgui.ImVec4(0.3, 0.8, 1.0, 1.0) or imgui.ImVec4(0.8, 0.8, 0.8, 1.0)
                                local typeText = log.messageType == "chat" and "[ЧАТ]" or "[СЕРВЕР]"
                                
                                imgui.TextColored(typeColor, typeText)
                                imgui.SameLine()
                                imgui.TextColored(imgui.ImVec4(0.7, 0.7, 0.7, 1.0), log.date)
                                imgui.SameLine()
                                imgui.TextColored(imgui.ImVec4(0.3, 1.0, 0.3, 1.0), log.player)
                                imgui.SameLine()
                                imgui.Text("->")
                                imgui.SameLine()
                                imgui.TextColored(imgui.ImVec4(1.0, 1.0, 0.3, 1.0), log.keyword)
                                imgui.TextWrapped(log.message)
                                imgui.Separator()
                            end
                        end
                        imgui.EndChild()
                    end
                    imgui.EndTabItem()
                end

                if imgui.BeginTabItem("Статистика") then
                    imgui.Text("Статистика игроков:")
                    imgui.Separator()

                    if imgui.BeginChild("StatsChild", imgui.ImVec2(0, 300), true) then
                        for player, stats in pairs(playerStats) do
                            imgui.Text("Игрок: " .. player)
                            imgui.SameLine(200)
                            imgui.Text("Срабатываний: " .. stats.count)
                            imgui.SameLine(350)
                            imgui.Text("Последний раз: " .. stats.lastSeen)
                            imgui.Separator()
                        end
                        imgui.EndChild()
                    end

                    if imgui.Button("Очистить статистику") then
                        playerStats = {}
                    end
                    imgui.EndTabItem()
                end

                if imgui.BeginTabItem("Telegram") then
                    imgui.Text("Настройки Telegram бота:")
                    imgui.Separator()

                    imgui.Text("Токен бота:")
                    imgui.InputText("##token", telegramToken, sizeof(telegramToken), imgui.InputTextFlags.Password)

                    imgui.Text("Chat ID:")
                    imgui.InputText("##chatid", telegramChatID, sizeof(telegramChatID))

                    imgui.Spacing()

                    if imgui.Button("Сохранить") then
                        config.settings.telegramToken = str(telegramToken)
                        config.settings.telegramChatID = str(telegramChatID)
                        saveConfig()
                        sampAddChatMessage("[МОНИТОРИНГ] Настройки Telegram сохранены!", -1)
                    end

                    imgui.Spacing()

                    if imgui.Button("Тест уведомления") then
                        sendToTelegram("TestPlayer", "тест", "Это тестовое сообщение от бота мониторинга", "test")
                    end

                    imgui.Spacing()
                    imgui.Separator()

                    imgui.TextWrapped("Инструкция:\n1. Создайте бота через @BotFather\n2. Получите токен бота\n3. Добавьте бота в чат и получите Chat ID\n4. Введите данные выше\n5. Нажмите 'Тест уведомления' для проверки")
                    imgui.EndTabItem()
                end

                imgui.EndTabBar()
            end
            imgui.End()
        end
    end
)

-- Обработка сообщений в чате (НОВОЕ!)
function sampev.onShowDialog(dialogId, style, title, button1, button2, text)
    return
end

function sampev.onPlayerChatMessage(playerId, message)
    if config.settings.monitorChat then
        local playerName = sampGetPlayerNickname(playerId)
        if playerName then
            checkMessage(playerName .. ": " .. message, "chat")
        end
    end
end

-- Обработка сообщений сервера
function sampev.onServerMessage(color, text)
    if config.settings.monitorServer then
        checkMessage(text, "server")
    end
end

-- Обработка команды /skam
function sampev.onSendCommand(command)
    if command:lower() == "/skam" then
        renderWindow[0] = not renderWindow[0]
        if renderWindow[0] then
            sampSetCursorMode(3) -- CURSOR_MODE_USER
            sampAddChatMessage("[МОНИТОРИНГ] Меню открыто.", -1)
        else
            sampSetCursorMode(0) -- CURSOR_MODE_PLAYER
            sampAddChatMessage("[МОНИТОРИНГ] Меню закрыто.", -1)
        end
        return false
    end
end

-- Главная функция
function main()
    while not isSampAvailable() do wait(0) end
    loadLogs()
    local message = "[МОНИТОРИНГ v2.1] Скрипт загружен! Команда: {FFFF00}/skam"
    print(string.format("[DEBUG] Отправка в чат: %s", message))
    sampAddChatMessage(message, -1)
    wait(-1)
end
 

kirieshki.

Участник
31
17
По желанию: было бы круто добавить интеграцию с Telegram-ботом, чтобы уведомления приходили и туда. Если в этом разбираешься — подскажи.

Как сделать так, чтобы обработка текста работала как с английскими, так и с русскими словами?
создай массив, с транслитом
["а"] = "а", ["б"] = "b", ...
далее через цикл for по массивв проходишься просто через string.gsub буквы заменяешь и получишь слово по-русски