Вопросы по Lua скриптингу

Общая тема для вопросов по разработке скриптов на языке программирования Lua, в частности под MoonLoader.
  • Задавая вопрос, убедитесь, что его нет в списке частых вопросов и что на него ещё не отвечали (воспользуйтесь поиском).
  • Поищите ответ в теме посвященной разработке Lua скриптов в MoonLoader
  • Отвечая, убедитесь, что ваш ответ корректен.
  • Старайтесь как можно точнее выразить мысль, а если проблема связана с кодом, то обязательно прикрепите его к сообщению, используя блок [code=lua]здесь мог бы быть ваш код[/code].
  • Если вопрос связан с MoonLoader-ом первым делом желательно поискать решение на wiki.

Частые вопросы

Как научиться писать скрипты? С чего начать?
Информация - Гайд - Всё о Lua скриптинге для MoonLoader(https://blast.hk/threads/22707/)
Как вывести текст на русском? Вместо русского текста у меня какие-то каракули.
Изменить кодировку файла скрипта на Windows-1251. В Atom: комбинация клавиш Ctrl+Shift+U, в Notepad++: меню Кодировки -> Кодировки -> Кириллица -> Windows-1251.
Как получить транспорт, в котором сидит игрок?
Lua:
local veh = storeCarCharIsInNoSave(PLAYER_PED)
Как получить свой id или id другого игрока?
Lua:
local _, id = sampGetPlayerIdByCharHandle(PLAYER_PED) -- получить свой ид
local _, id = sampGetPlayerIdByCharHandle(ped) -- получить ид другого игрока. ped - это хендл персонажа
Как проверить, что строка содержит какой-то текст?
Lua:
if string.find(str, 'текст', 1, true) then
-- строка str содержит "текст"
end
Как эмулировать нажатие игровой клавиши?
Lua:
local game_keys = require 'game.keys' -- где-нибудь в начале скрипта вне функции main

setGameKeyState(game_keys.player.FIREWEAPON, -1) -- будет сэмулировано нажатие клавиши атаки
Все иды клавиш находятся в файле moonloader/lib/game/keys.lua.
Подробнее о функции setGameKeyState здесь: lua - setgamekeystate | BlastHack — DEV_WIKI(https://www.blast.hk/wiki/lua:setgamekeystate)
Как получить id другого игрока, в которого целюсь я?
Lua:
local valid, ped = getCharPlayerIsTargeting(PLAYER_HANDLE) -- получить хендл персонажа, в которого целится игрок
if valid and doesCharExist(ped) then -- если цель есть и персонаж существует
  local result, id = sampGetPlayerIdByCharHandle(ped) -- получить samp-ид игрока по хендлу персонажа
  if result then -- проверить, прошло ли получение ида успешно
    -- здесь любые действия с полученным идом игрока
  end
end
Как зарегистрировать команду чата SAMP?
Lua:
-- До бесконечного цикла/задержки
sampRegisterChatCommand("mycommand", function (param)
     -- param будет содержать весь текст введенный после команды, чтобы разделить его на аргументы используйте string.match()
    sampAddChatMessage("MyCMD", -1)
end)
Крашит игру при вызове sampSendChat. Как это исправить?
Это происходит из-за бага в SAMPFUNCS, когда производится попытка отправки пакета определенными функциями изнутри события исходящих RPC и пакетов. Исправления для этого бага нет, но есть способ не провоцировать его. Вызов sampSendChat изнутри обработчика исходящих RPC/пакетов нужно обернуть в скриптовый поток с нулевой задержкой:
Lua:
function onSendRpc(id)
  -- крашит:
  -- sampSendChat('Send RPC: ' .. id)

  -- норм:
  lua_thread.create(function()
    wait(0)
    sampSendChat('Send RPC: ' .. id)
  end)
end
 
Последнее редактирование:

#SameLine

Активный
424
37
Lua:
-- Писал не через редактор
function main()
    repeat wait(0) until isSampAvailable()
  
    sampRegisterChatCommand('b', function()
        sampSendChat('/b откат')
    end)
  
    while true do wait(0)
    end
end
когда используешь /b и !, пишется /b откат, это мне нужно, а твой код просто заменяет всю систему /b на /b откат...
 

Rice.

Известный
Модератор
1,716
1,515
когда используешь /b и !, пишется /b откат, это мне нужно, а твой код просто заменяет всю систему /b на /b откат...
Через SAMP.Lua оформи:
Lua:
local sampev = require('lib.samp.events')

function sampev.onSendCommand(cmd)
    if cmd == '/b !' then
        sampSendChat('/b откат')
        return false
    end
end

Lua:
sampRegisterChatCommand("b", function(text)
    if text == "!" then
        sampAddChatMessage("/b откат", -1)
    end
end)
А если игроку нужна данная команда, чтобы написать OOC информацию?
 
  • Нравится
Реакции: #SameLine

eqzzz

Участник
126
19
Как изменить размер imgui.Separator?

Помогите, добавил все функции, а smooth не работает, никакие ошибки не выдаёт, просто не доводит.


function smooth_aimbot()
if smooth_enable.v and isKeyDown(VK_RBUTTON) then
if not smooth_is_fire.v or (smooth_is_fire.v and isKeyDown(VK_LBUTTON)) then
local playerID = GetNearestPed()
if playerID ~= -1 then
local pedID = sampGetPlayerIdByCharHandle(PLAYER_PED)
if (smooth_ingore_stun.v and not CheckStuned()) then return false end
if (smooth_check_filer.v and sampGetPlayerColor(pedID) == sampGetPlayerColor(playerID)) then return false end
local _, handle = sampGetCharHandleBySampPlayerId(playerID)
local myPos = {getActiveCameraCoordinates()}
local enPos = {GetBodyPartCoordinates(GetNearestBone(handle), handle)}
if not smooth_visible_smooth.v or (smooth_visible_smooth.v and isLineOfSightClear(myPos[1], myPos[2], myPos[3], enPos[1], enPos[2], enPos[3], true, true, false, true, true)) then
local pedWeapon = getCurrentCharWeapon(PLAYER_PED)
if (pedWeapon >= 22 and pedWeapon <= 29) or pedWeapon == 32 then
coefficent = 0.04253
elseif pedWeapon == 30 or pedWeapon == 31 then
coefficent = 0.028
elseif pedWeapon == 33 then
СЃoefficent = 0.01897
end
local vector = {myPos[1] - enPos[1], myPos[2] - enPos[2]}
local angle = math.acos(vector[1] / math.sqrt((math.pow(vector[1], 2) + math.pow(vector[2], 2))))
local view = {fix(representIntAsFloat(readMemory(0xB6F258, 4, false))), fix(representIntAsFloat(readMemory(0xB6F248, 4, false)))}
if (vector[1] <= 0.0 and vector[2] >= 0.0) or (vector[1] >= 0.0 and vector[2] >= 0.0) then
dif = (angle + coefficent) - view[1]
end
if (vector[1] >= 0.0 and vector[2] <= 0.0) or (vector[1] <= 0.0 and vector[2] <= 0.0) then
dif = (-angle + coefficent) - view[1]
end
if dynamic_smooth.v then multiplier = 5 else multiplier = 1 end
local smooth = dif / ((smooth_smooth.v * multiplier) * super_smooth.v)
if dynamic_smooth.v then
if smooth > 0.0 then
if smooth < lastsmooth then
smooth = smooth * (lastsmooth / smooth)
end
else
if -smooth < -lastsmooth then
smooth = smooth * (-lastsmooth / -smooth)
end
end
lastsmooth = smooth
end
if smooth > -1.0 and smooth < 0.5 and dif > -2.0 and dif < 2.0 then
view[1] = view[1] + smooth
setCameraPositionUnfixed(view[2], view[1])
end
end
end
end
end
return false
end
 
Последнее редактирование:

barjik

Известный
464
190
Как сделать проверку на этот текст?
Screenshot_2.png
 

Nicolas

Активный
113
66
как удалить текст сделанный при помощи renderFontDrawText
остановить поток, в котором прописан твой renderFontDrawText

Доброй ночи, решил в сниппетах покопаться, и нашел такую интересную функцию от Cosmo, как подсказки, вставляю в код, как навожу на подсказку скрипт моментально крашит с ошибкой:

Код:
[23:30:06.669369] (error)    Media Helper: ...mes\ARIZONA GAMES\bin\Arizona\moonloader\MediaHelper.lua:521: attempt to call field 'PushStyleVarFloat' (a nil value)
stack traceback:
    ...mes\ARIZONA GAMES\bin\Arizona\moonloader\MediaHelper.lua:521: in function 'Hint'
    ...mes\ARIZONA GAMES\bin\Arizona\moonloader\MediaHelper.lua:275: in function 'OnDrawFrame'
    C:\Games\ARIZONA GAMES\bin\Arizona\moonloader\lib\imgui.lua:1379: in function <C:\Games\ARIZONA GAMES\bin\Arizona\moonloader\lib\imgui.lua:1368>
[23:30:06.670369] (error)    Media Helper: Script died due to an error. (3569FE34)

Ниже представлен код:

Lua:
function imgui.Hint(str_id, hint, delay)
    local hovered = imgui.IsItemHovered()
    local animTime = 0.2
    local delay = delay or 0.00
    local show = true

    if not allHints then allHints = {} end
    if not allHints[str_id] then
        allHints[str_id] = {
            status = false,
            timer = 0
        }
    end

    if hovered then
        for k, v in pairs(allHints) do
            if k ~= str_id and os.clock() - v.timer <= animTime  then
                show = false
            end
        end
    end

    if show and allHints[str_id].status ~= hovered then
        allHints[str_id].status = hovered
        allHints[str_id].timer = os.clock() + delay
    end

    if show then
        local between = os.clock() - allHints[str_id].timer
        if between <= animTime then
            local s = function(f)
                return f < 0.0 and 0.0 or (f > 1.0 and 1.0 or f)
            end
            local alpha = hovered and s(between / animTime) or s(1.00 - between / animTime)
            imgui.PushStyleVarFloat(imgui.StyleVar.Alpha, alpha)
            imgui.SetTooltip(hint)
            imgui.PopStyleVar()
        elseif hovered then
            imgui.SetTooltip(hint)
        end
    end
end

Ошибка возникает на строчке 521(Скрин)
Посмотреть вложение 122050


@Cosmo помоги, в чем проблема, ты больше понимаешь в своей функции)) МБ библиотеки не хватает, не уверен точно(
Эта хуйня не работает на старом Dear Imgui
 

CaJlaT

Овощ
Модератор
2,808
2,623
Доброй ночи, решил в сниппетах покопаться, и нашел такую интересную функцию от Cosmo, как подсказки, вставляю в код, как навожу на подсказку скрипт моментально крашит с ошибкой:

Код:
[23:30:06.669369] (error)    Media Helper: ...mes\ARIZONA GAMES\bin\Arizona\moonloader\MediaHelper.lua:521: attempt to call field 'PushStyleVarFloat' (a nil value)
stack traceback:
    ...mes\ARIZONA GAMES\bin\Arizona\moonloader\MediaHelper.lua:521: in function 'Hint'
    ...mes\ARIZONA GAMES\bin\Arizona\moonloader\MediaHelper.lua:275: in function 'OnDrawFrame'
    C:\Games\ARIZONA GAMES\bin\Arizona\moonloader\lib\imgui.lua:1379: in function <C:\Games\ARIZONA GAMES\bin\Arizona\moonloader\lib\imgui.lua:1368>
[23:30:06.670369] (error)    Media Helper: Script died due to an error. (3569FE34)

Ниже представлен код:

Lua:
function imgui.Hint(str_id, hint, delay)
    local hovered = imgui.IsItemHovered()
    local animTime = 0.2
    local delay = delay or 0.00
    local show = true

    if not allHints then allHints = {} end
    if not allHints[str_id] then
        allHints[str_id] = {
            status = false,
            timer = 0
        }
    end

    if hovered then
        for k, v in pairs(allHints) do
            if k ~= str_id and os.clock() - v.timer <= animTime  then
                show = false
            end
        end
    end

    if show and allHints[str_id].status ~= hovered then
        allHints[str_id].status = hovered
        allHints[str_id].timer = os.clock() + delay
    end

    if show then
        local between = os.clock() - allHints[str_id].timer
        if between <= animTime then
            local s = function(f)
                return f < 0.0 and 0.0 or (f > 1.0 and 1.0 or f)
            end
            local alpha = hovered and s(between / animTime) or s(1.00 - between / animTime)
            imgui.PushStyleVarFloat(imgui.StyleVar.Alpha, alpha)
            imgui.SetTooltip(hint)
            imgui.PopStyleVar()
        elseif hovered then
            imgui.SetTooltip(hint)
        end
    end
end

Ошибка возникает на строчке 521(Скрин)
Посмотреть вложение 122050


@Cosmo помоги, в чем проблема, ты больше понимаешь в своей функции)) МБ библиотеки не хватает, не уверен точно(
Это код для mimgui, если у тебя старый imgui, то просто вместо функции imgui.PushStyleVarFloat используй imgui.PushStyleVar
 
  • Влюблен
  • Нравится
Реакции: Pashyka и Nicolas

chapo

🫡 В армии с 17.10.2023. В ЛС НЕ ОТВЕЧАЮ
Друг
8,781
11,243
Lua:
local imgui = require 'imgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
require 'moonloader'
local requests = require 'requests'
local window = imgui.ImBool(false)

function main()
    while not isSampAvailable() do wait(200) end
    local file = io.open("ff.json", "r") -- Открываем файл в режиме чтения
    a = file:read("*a") -- Читаем файл, там у нас таблица
    file:close() -- Закрываем
   
    table = decodeJson(a) -- Читаем нашу JSON-Таблицу
   
    print(table["players"]["Michael_Jordan"]) -- Выведет Bulls
    while true do
        wait(0)
    end
end
JSON:
{
    "players" : {
        "Michael_Jordan" : "Bulls",
        "Edward_Bill" : "Defenders",
        "Katrin_White" : "Poop"
    }
}
Почему не работает?
1636880805541.png

Lua:
function jsonSave(jsonFilePath, t)
    file = io.open(jsonFilePath, "w")
    file:write(encodeJson(t))
    file:flush()
    file:close()
end

function jsonRead(jsonFilePath)
    local file = io.open(jsonFilePath, "r+")
    local jsonInString = file:read("*a")
    file:close()
    local jsonTable = decodeJson(jsonInString)
    return jsonTable
end

function main()
    while not isSampAvailable() do wait(0) end
    local t = jsonRead(getWorkingDirectory()..'\\ff.json')
    print(t['players']['Michael_Jordan'])
    while true do
        wait(0)
        
    end
end
 
  • Нравится
Реакции: Andrinall

chapo

🫡 В армии с 17.10.2023. В ЛС НЕ ОТВЕЧАЮ
Друг
8,781
11,243
[ML] (error) json.lua: C:\Program Files (x86)\cheat pack\moonloader\json.lua:19: attempt to index field 'players' (a nil value)
stack traceback:
C:\Program Files (x86)\cheat pack\moonloader\json.lua: in function <C:\Program Files (x86)\cheat pack\moonloader\json.lua:16>
[ML] (error) json.lua: Script died due to an error. (2248CCC4)

[ML] (exception) json.lua: CJSON: Expected value but found T_END at character 1
либо не тот json, либо ты неверно указал путь к файлу
 
  • Нравится
Реакции: P!NK.

Corrygan228

Участник
132
9
Есть ли какая-то функция кликабельного imgui.Text? Или придётся через это делать
Lua:
imgui.Text('Text')
if imgui.IsItemClicked() then
    --code
end
 

Rice.

Известный
Модератор
1,716
1,515
Есть ли какая-то функция кликабельного imgui.Text? Или придётся через это делать
Lua:
imgui.Text('Text')
if imgui.IsItemClicked() then
    --code
end
1636893539485.png


Lua:
function imgui.Link(link,name,myfunc)
    myfunc = type(name) == 'boolean' and name or myfunc or false
    name = type(name) == 'string' and name or type(name) == 'boolean' and link or link
    local size = imgui.CalcTextSize(name)
    local p = imgui.GetCursorScreenPos()
    local p2 = imgui.GetCursorPos()
    local resultBtn = imgui.InvisibleButton('##'..link..name, size)
    if resultBtn then
            if not myfunc then
                    os.execute('explorer '..link)
            end
    end
    imgui.SetCursorPos(p2)
    if imgui.IsItemHovered() then
            imgui.TextColored(imgui.GetStyle().Colors[imgui.Col.ButtonHovered], name)
            imgui.GetWindowDrawList():AddLine(imgui.ImVec2(p.x, p.y + size.y), imgui.ImVec2(p.x + size.x, p.y + size.y), imgui.GetColorU32(imgui.GetStyle().Colors[imgui.Col.ButtonHovered]))
    else
            imgui.TextColored(imgui.GetStyle().Colors[imgui.Col.Button], name)
    end
    return resultBtn
end
Lua:
imgui.Text(u8'Автор скрипта: Rice.')
imgui.SameLine()
imgui.Link('https://vk.com/xkelling', 'VK')

P.S. Подумал, что тебе нужна ссылка. Ты сделал единственный правильный вариант в своём примере.
 

woodware

Потрачен
Проверенный
4,680
1,301
как сделать в этом скрипте меньше задержку на отправление объявления? подскажите пожалуйста строку
Lua:
script_name('NEWS-HELPER')
script_author("Serhiy_Rubin")

local inicfg, sampev, milisec, vkeys = require 'inicfg', require 'lib.samp.events', require 'socket', require 'lib.vkeys'
require 'lib.sampfuncs'
require 'lib.moonloader'
local antiflood = os.clock() * 1000 ; timer = os.clock() ; adid = 21 ; arrayAD = {} ; ad_check = 0

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
    repeat wait(0) until sampGetCurrentServerName() ~= 'SA-MP'
    server = sampGetCurrentServerName():gsub('|', '')
    server = (server:find('02') and 'Two' or (server:find('Revolution') and 'Revolution' or (server:find('Legacy') and 'Legacy' or (server:find('Classic') and 'Classic' or (server:find('02') and 'Two' or (server:find('TEST') and 'Test' or '')) ))))
    if server == '' then thisScript():unload() end
    _, my_id = sampGetPlayerIdByCharHandle(PLAYER_PED)
    my_nick = sampGetPlayerNickname(my_id)
    ini = inicfg.load({
        Settings = {
            send_number = 0,
            mili_time = 100,
            ad_cena = 100
        },
        Activation = {
            [my_nick] = false,
        },
        Auto = {
            [my_nick] = false,
        },
        Render = {
            FontName='Segoe UI',
            FontSize=10,
            FontFlag=15,
            Color='FFFFFF'
        },
        Pos = {
            X = 0,
            Y = 0
        },
        Key = {
            read = 'VK_1',
            send = 'VK_3',
            auto = 'VK_4',
            ad_list = 'VK_N',
            check_ad = 'VK_O'
        }
    })
    inicfg.save(ini)
    font = renderCreateFont(ini.Render.FontName, ini.Render.FontSize, ini.Render.FontFlag)
    -- Auto-Send settings
    last_send = tonumber(os.date("%S")) ; next_second = math.fmod(last_send + 16, 60) ; status = false
    if math.fmod(next_second, 2) ~= ini.Settings.send_number then
        next_second = next_second - 1
    end
    while true do
        wait(0)
        if ini.Activation[my_nick] then
            doAutoSend()
            doRender()
            doKeyCheck()
            doPos()
            doSetKey()
        end
    end
end

-- main
function doAutoSend()
    local this_second = tonumber(os.date("%S"))
    local this_milisecond = tonumber(tostring(milisec.gettime()):sub(12, 14))
    if this_milisecond ~= nil and this_milisecond ~= 999 and this_second  == next_second and this_milisecond > ini.Settings.mili_time then
        status = true
    end
    if ini.Auto[my_nick] and status and (os.clock() * 1000 - antiflood) > 1000 then
        sampSendChat("/adsend "..adid)
    end
end

function doRender()
    if sampIsScoreboardOpen() or not sampIsChatVisible() or isKeyDown(116) or isKeyDown(121) then return end
    local S1 = os.clock() * 1000
    local S2 = timer * 1000
    local S3 = (S1 - S2) / 1000
    local autot = (ini.Auto[my_nick] and '!' or '')
    local rttext = string.format("{%s}%s%0.1f", ini.Render.Color, autot, S3)
    renderFontDrawText(font, rttext, ini.Pos.X, ini.Pos.Y, 0xFFFFFFFF)
end

function doKeyCheck()
    if (not sampIsDialogActive() or (sampGetCurrentDialogType() ~= 1 and sampGetCurrentDialogType() ~= 3)) and not sampIsChatInputActive() then
        if wasKeyPressed(vkeys[ini.Key.read]) then
            sampSendChat("/adedit "..adid)
        end
        if wasKeyPressed(vkeys[ini.Key.send]) then
            sampSendChat("/adsend "..adid)
        end
        if wasKeyPressed(vkeys[ini.Key.auto]) then
            ini.Auto[my_nick] = not ini.Auto[my_nick]
            inicfg.save(ini)
        end
        if wasKeyPressed(vkeys[ini.Key.ad_list]) then
            list_ad = 1
            lua_thread.create(function()
                repeat
                    wait(0)
                    if list_ad == 1 and (os.clock() * 1000) - antiflood > 1100 then
                        list_ad = -1
                        sampSendChat('/n')
                    end
                until list_ad == 0
            end)
        end
        if wasKeyPressed(vkeys[ini.Key.check_ad]) then
            ad_check = 1
            lua_thread.create(function()
                repeat
                    wait(0)
                    if ad_check == 1 and (os.clock() * 1000) - antiflood > 1100 then
                        ad_check = -1
                        sampSendChat('/n')
                    end
                until ad_check == 0
            end)
        end
    end
end

function doPos()
    if setpos ~= nil then
        sampSetCursorMode(3)
        curX, curY = getCursorPos()
        ini.Pos.X = curX
        ini.Pos.Y = curY
        if isKeyJustPressed(1) then
            sampSetCursorMode(0)
            setpos = nil
            inicfg.save(ini)
        end
    end
end

function doSetKey()
    if setkey ~= nil then
        local key = ""
        for k, v in pairs(vkeys) do
            if wasKeyPressed(v) and k ~= "VK_ESCAPE" and k ~= "VK_RETURN" then
                key = k
            end
        end
        if key ~= '' then
            ini.Key[setkey] = key
            inicfg.save(ini)
            setkey = nil
            Dialog()
            start_dialog(dialog[1])   
        end
    end
end

-- HOOK

function sampev.onSendChat(message) antiflood = os.clock() * 1000 end
function sampev.onSendCommand(cmd) antiflood = os.clock() * 1000
    if cmd:lower() == "/nn" then
        lua_thread.create(function()
            Dialog()
            start_dialog(dialog[1])   
        end)
        return false
    end
end

function sampev.onServerMessage(color, message)
    if message:find("сотрудник News (.*): (.*)") and my_nick ~= nil then
        if message:find(my_nick) and ini.Auto[my_nick] then
            ini.Auto[my_nick] = false
            inicfg.save(ini)
        end
        last_send = tonumber(os.date("%S"))
        next_second = math.fmod(last_send + 16, 60)
        if math.fmod(next_second, 2) ~= ini.Settings.send_number then
            next_second = next_second - 1
        end
        timer = os.clock()
        status = false
    end
    if message:find('Добавлено новое объявление от .+. Номер объявления (%d+)') then
        local id = tonumber(message:match('Добавлено новое объявление от .+. Номер объявления (%d+)'))
        arrayAD[id] = nil
    end
    if status and message == " Объявления с таким ID не существует" or message == ' Объявление больше не существует' then
        status = false
    end
    if message == ' Не флуди!' then
        if ad_check == -1 then
            ad_check = 1
        end
        if list_ad == -1 then
            list_ad = 1
        end
    end
    if message == ' Вы не репортер' then
        ad_check = 0
        list_ad = 0
        ini.Auto[my_nick] = false
    end
end

function sampev.onShowDialog(dialogId, style, title, button1, button2, text)
    if title == 'Репортеры' and text:find('%[3%] Объявления') then -- Меню /n
        if ad_check == -1 then
            ad_check = 2
            ThreadSendDialog(90, dialogId, 1, 3, '[3] Объявления')
            lua_thread.create(function()
                checking, checkall = 0, 0
                repeat wait(0)
                    local text = 'Checking '..checking..'/'..checkall
                    local x, y = getScreenResolution()
                    x = x - renderGetFontDrawTextLength(font, text)
                    y = y - renderGetFontDrawHeight(font)
                    renderFontDrawText(font, text, x, y, -1)
                until ad_check == 0
            end)
            return false
        end
        if list_ad == -1 then
            list_ad = 0
            ThreadSendDialog(90, dialogId, 1, 3, '[3] Объявления')
            return false
        end
    end   
    if title == 'Объявления' and text:find('%[id: ') then -- Объявления
        local array = split(text, '\n')
        local dialogText = ''
        if ad_check == 2 then
            dialogArray = {}
        end
        for k,v in pairs(array) do
            local id = tonumber(v:match('%[id: (%d+)%]'))
            if id ~= nil then
                if ad_check == 2 and not v:find('Проверил') and arrayAD[id] == nil then
                    checkall = checkall + 1
                    dialogArray[#dialogArray + 1] = { text = v, list = k-1, id = id}
                end
                if arrayAD[id] ~= nil then
                    v = v:gsub('%[id', string.format('{59de00}[%s$]{FFFFFF} [id', arrayAD[id]))
                end
                dialogText = string.format('%s%s\n', dialogText, v)
            end
        end
        if ad_check == 2 then ad_check = -2 end
        if ad_check == -2 or ad_check == 3 then
            if dialogArray[#dialogArray] ~= nil then
                adstring = dialogArray[#dialogArray].text
                adid = dialogArray[#dialogArray].id
                ad_check = 3
                ThreadSendDialog(90, 22, 1, dialogArray[#dialogArray].list, adstring)
                dialogArray[#dialogArray] = nil
                return false
            else
                ad_check = 0
            end
        end
        return {dialogId, style, title, button1, button2, dialogText}
    end
    if title == 'Меню' and text:find('%[0%] Читать') then -- Меню редактировать, отправить
        ShowNewsMenu = 1
        if ad_check == 3 then
            ad_check = -3
            ThreadSendDialog(90, dialogId, 1, 0, '[0] Читать')
            return false
        end
        if ad_check == 4 then
            ad_check = -2
            ThreadSendDialog(90, dialogId, 0, 0, '[0] Читать')
            return false
        end
    end
    if title == 'Сообщение' or title == 'Ввод параметра' and ShowNewsMenu ~= nil then -- Диалог с текстом объявления
        ShowNewsMenu = nil
        if adstring ~= nil and not adstring:find('Проверил') then
            arrayAD[adid] = ((#text * ini.Settings.ad_cena) / 100) * 60
        end
        if ad_check == -3 then
            ad_check = 4
            checking = checking + 1
            ThreadSendDialog(90, dialogId, 0, 0, '')
            return false
        end
    end
end

function ThreadSendDialog(sleep, id, button, listitem, input)
    lua_thread.create(function(sleep, id, button, listitem, input)
        wait(sleep)
        sampSendDialogResponse(id, button, listitem, input)
    end, sleep, id, button, listitem, input)
end

function sampev.onSendDialogResponse(dialogId, button, listboxId, input)
    -- Получаем ID последнего открытого объявления.
    if string.find(sampGetDialogCaption(), "Объявления") and button == 1 then
        local array = split(sampGetDialogText(), '\n')
        for k,v in pairs(array) do
            if listboxId == (k - 1) then
                adid = tonumber(string.match(v, "%[id: (%d+)%]"))
                adstring = input
            end
        end
    end
end


-- Dialog
function Dialog()
dialog = {
    {
        settings = {title = "NEWS-HELPER" ,style = 4 ,btn1 = "Далее" ,btn2 = "Закрыть" ,forward =  "{ffffff}" ,backwards = "\n" ,score = true},
        {
            {
                title = "Таймер объявлений\t"..ON_OFF(ini.Activation[my_nick]),
                click = function(button, list, input , outs)
                    if button == 1 then
                        ini.Activation[my_nick] = not ini.Activation[my_nick]
                        inicfg.save(ini)
                        Dialog()
                        return dialog[1]   
                    end
                end
            },
            {
                title = "Сменить позицию таймера\t",
                click = function(button, list, input , outs)
                    if button == 1 then
                        setpos = 1
                        Dialog()
                        return dialog[1]   
                    end
                end
            },
            {
                title = "[AUTO] Условие 1\t"..(ini.Settings.send_number == 0 and 'Чётные' or 'Нечётные'),
                click = function(button, list, input , outs)
                    if button == 1 then
                        ini.Settings.send_number = (ini.Settings.send_number == 0 and 1 or 0)
                        inicfg.save(ini)
                        Dialog()
                        return dialog[1]   
                    end
                end
            },
            {
                title = "[AUTO] Условие 2\t"..ini.Settings.mili_time..' мс.',
                click = function(button, list, input , outs)
                    if button == 1 then
                        return dialog[2]   
                    end
                end
            },
            {
                title = "Кнопка для проверки\t"..ini.Key.read:gsub("VK_", ''),
                click = function(button, list, input , outs)
                    if button == 1 then
                        setkey = 'read'
                        sampShowDialog(584, "SET POS", "{FFFFFF}Нажмите на нужную клавишу", "Сохранить", "Назад", 0)
                    end
                end
            },
            {
                title = "Кнопка для отправки\t"..ini.Key.send:gsub("VK_", ''),
                click = function(button, list, input , outs)
                    if button == 1 then
                        setkey = 'send'
                        sampShowDialog(584, "SET POS", "{FFFFFF}Нажмите на нужную клавишу", "Сохранить", "Назад", 0)
                    end
                end
            },
            {
                title = "Кнопка для авто-отправки\t"..ini.Key.auto:gsub("VK_", ''),
                click = function(button, list, input , outs)
                    if button == 1 then
                        setkey = 'auto'
                        sampShowDialog(584, "SET POS", "{FFFFFF}Нажмите на нужную клавишу", "Сохранить", "Назад", 0)
                    end
                end
            },
            {
                title = "Кнопка для открытия списка объявлений\t"..ini.Key.ad_list:gsub("VK_", ''),
                click = function(button, list, input , outs)
                    if button == 1 then
                        setkey = 'ad_list'
                        sampShowDialog(584, "SET POS", "{FFFFFF}Нажмите на нужную клавишу", "Сохранить", "Назад", 0)
                    end
                end
            },
            {
                title = "Кнопка для проверки стоимости объявлений\t"..ini.Key.check_ad:gsub("VK_", ''),
                click = function(button, list, input , outs)
                    if button == 1 then
                        setkey = 'check_ad'
                        sampShowDialog(584, "SET POS", "{FFFFFF}Нажмите на нужную клавишу", "Сохранить", "Назад", 0)
                    end
                end
            },
        },
    },
    {
        settings = {title = "NEWS-TIMER" ,style = 1 ,btn1 = "Сохранить",btn2 = "Назад",forward =  "{ff0000}" ,backwards = "\n" ,score = false},
        {
            text = "{ffffff}Введите миллисекунды от 0 до 1000.",
            {
                click = function(button, list, input , outs)
                    if button == 0 then
                        return dialog[1]
                    else
                        sampAddChatMessage("Вы написали в диалог вот это: "..input, 0xffcecece)
                        if input:find('%d+') then
                            ini.Settings.mili_time = tonumber(input:match('%d+'))
                            inicfg.save(ini)
                            Dialog()
                            return dialog[1]
                        else
                            sampAddChatMessage("Ошибка. Введите число от 0 до 1000.", 0xffcecece)   
                            return dialog[2]
                        end
                    end
                end
            }
        }
    },
}
end

function ON_OFF(bool)
    return (bool and '{45d900}ON' or '{ff0000}OFF')
end

-- Function Dialog
function start_dialog(menu)
    function _dialog(menu, id,  outs)
        sampShowDialog(id, menu.settings.title, tbl_split(menu.settings.style, menu, menu.settings.forward ,menu.settings.backwards ,menu.settings.score), menu.settings.btn1, (menu.settings.btn2 ~= nil and menu.settings.btn2 or _), menu.settings.style)
            repeat
                wait(0)
                local result, button, list, input = sampHasDialogRespond(id)
                if result then
                    local out, outs = menu[((menu.settings.style == 0 or menu.settings.style == 1 or menu.settings.style == 3) and 1 or ((list + 1) > #menu[1] and 2 or 1))][((menu.settings.style == 0 or menu.settings.style == 1 or menu.settings.style == 3) and 1 or ((list + 1) > #menu[1] and (list - #menu[1]) + 1  or list + 1))].click(button, list, input, outs)
                    if type(out) == "table" then
                        return _dialog(out, id - 1, outs)
                    elseif type(out) == "boolean" then
                        if not out then
                            return out
                        end
                            return _dialog(menu, id, outs)
                    end
                end
            until result
    end

    function tbl_split(style, tbl, forward ,backwards ,score)
        if style == 2 or style == 4 or style == 5 then
            text = (style == 5 and tbl[1].text.."\n" or "")
            for i, val in ipairs(tbl[1]) do
                text = text..""..forward..""..(score and "["..i.."]{ffffff} " or "")..""..val.title..""..backwards
            end
            if tbl[2] ~= nil then
                for _, val in ipairs(tbl[2]) do
                    text = text..""..forward..""..val.title..""..backwards
                end
            end
            return text
        end
        return tbl[1].text
    end

    return _dialog(menu, 1337, outs)
end


--- Function split
function split(str, delim, plain)
    local tokens, pos, plain = {}, 1, not (plain == false) --[[ delimiter is plain text by default ]]
    repeat
        local npos, epos = string.find(str, delim, pos, plain)
        table.insert(tokens, string.sub(str, pos, npos and npos - 1))
        pos = epos and epos + 1
    until not pos
    return tokens
end