Вопросы по 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
 
Последнее редактирование:

СоМиК

Известный
458
313
Привет, с массивами и оператором for вчера познакомился :)
К примеру у меня
Lua:
a = {"aboba", "adoda", "abobus"}
for _,v in ipairs(a) do
    sampAddChatMessage(v, -1)
end
Как это вывести не подряд, а в одну строку?)
Lua:
sampAddChatMessage(table.concat(a,", "), -1)
Нашел решение на другом форуме, который посвящен именно луа скриптингу, а не moonloader api, но в любом случае работает, держите кому надо
Где "a" это название массива
 
Последнее редактирование:

SamperJostkiy

Участник
169
19
что тут не так?

я уже замучался с им, это короче типо биндера:
require "lib.moonloader"

local ip = {
"one.monser.ru:7777",
"two.monser.ru:7777",
"three.monser.ru:7777"
}
local keybinds = {
    { VK_1, "/mask"       },
    { VK_2, "/heal"       },
    { VK_3, "/tp"         },
    { VK_5, "/veh 411 1 1"},
    { VK_6, "/veh 510 1 1"},
    { VK_Z, "/anim 8"     },
}

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end
for k, v in pairs(ip) do
    if server ~= v then -- проверка по ИП.
        sampAddChatMessage('Скрипт работает только на серверах "Monser DM" ', -1)
while true do wait(0)
        if not sampIsChatInputActive() and not isSampfuncsConsoleActive() and not sampIsDialogActive() and activate then
            for i = 1, #keybinds do
                if isKeyJustPressed(keybinds[i][1]) then sampSendChat(keybinds[i][2]) end
else
        thisScript():unload()
        do return end
        end
    end
end
 

wulfandr

Известный
637
260
Lua:
local text = renderCreateFont("Verdana", 12, 9)
local render_text = false

local trainPos =
    {
    [1] = {-2681.2800292969, 2149.919921875, 14.445400238037}; [2] = {-2615.6999511719, 1396.1600341797, 6.4714798927307}; [3] = {-2713.6999511719, 1026.4100341797, 1.7189899682999}; [4] = {-2708.169921875, 634.75799560547, 5.2032399177551}; [5] = {-2702.580078125, 243.10299682617, 8.6877498626709};
    }
  
main = function()
    sampRegisterChatCommand("sps", function() render_text = true end)
    while true do wait(0)
            if render_text then
                local x, y, z = getCharCoordinates(PLAYER_PED)
                local dist = getDistanceBetweenCoords3d(x, y, z, table.unpack(trainPos[1]))
                local incar = isCharInAnyCar(PLAYER_PED)
                renderFontDrawText(text, 'dist: '..dist, 100, 400, 0xFFFFFFFF)
                if dist < 2 then
                    i = 1
                    i = i + 1
                    dist = getDistanceBetweenCoords3d(x, y, z,  table.unpack(trainPos[i]))
                end
            end
    end
end

Как решить проблему что условие с дистанцией не выполняется и не переходит к следующему значению из массива
Lua:
local font = renderCreateFont("Verdana", 12, 9)
local render_text = false

local trainPos =
{
    [1] = {-2681.2800292969, 2149.919921875, 14.445400238037}; [2] = {-2615.6999511719, 1396.1600341797, 6.4714798927307}; [3] = {-2713.6999511719, 1026.4100341797, 1.7189899682999}; [4] = {-2708.169921875, 634.75799560547, 5.2032399177551}; [5] = {-2702.580078125, 243.10299682617, 8.6877498626709};
}
  
function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end
    sampRegisterChatCommand("sps", function()
        render_text = not render_text
        if render_text then
            sampAddChatMessage('script was activated.', -1)
            checkCoords()
        else
            sampAddChatMessage('script was disabled.', -1)
        end
    end)
    wait(-1)
end

function checkCoords()
    lua_thread.create(function()
        local i = 1
        while render_text do
            local x, y, z = getCharCoordinates(PLAYER_PED)
            if #trainPos > 0 then
                if trainPos[i] then
                    local xt, yt, zt = table.unpack(trainPos[i])
                    local dist = getDistanceBetweenCoords3d(x, y, z, xt, yt, zt)
                    local wPosX, wPosY = convert3DCoordsToScreen(x, y, z)
                    local wPosX1, wPosY1 = convert3DCoordsToScreen(xt, yt, zt)
                    if isPointOnScreen(xt, yt, zt, 0.0) then
                        renderDrawLine(wPosX1, wPosY1, wPosX, wPosY, 2, 0xFFEE0000)
                        renderDrawPolygon(wPosX1, wPosY1, 10, 10, 14, 0.0, 0xFFEE0000)
                    end
                    renderFontDrawText(font, 'dist: '..math.floor(dist) .. ' | stock: '..#trainPos - i + 1, 100, 400, 0xFFFFFFFF)
                    if dist < 2 then
                        i = i + 1
                        sampAddChatMessage(table.concat(trainPos[i - 1], ', ')..' was picked up.', -1)
                    end
                end
            end
        wait(0) end return
    end)
end

пойдет?
 
  • Нравится
Реакции: danywa

Sanchez.

Известный
704
187
что тут не так?

я уже замучался с им, это короче типо биндера:
require "lib.moonloader"

local ip = {
"one.monser.ru:7777",
"two.monser.ru:7777",
"three.monser.ru:7777"
}
local keybinds = {
    { VK_1, "/mask"       },
    { VK_2, "/heal"       },
    { VK_3, "/tp"         },
    { VK_5, "/veh 411 1 1"},
    { VK_6, "/veh 510 1 1"},
    { VK_Z, "/anim 8"     },
}

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end
for k, v in pairs(ip) do
    if server ~= v then -- проверка по ИП.
        sampAddChatMessage('Скрипт работает только на серверах "Monser DM" ', -1)
while true do wait(0)
        if not sampIsChatInputActive() and not isSampfuncsConsoleActive() and not sampIsDialogActive() and activate then
            for i = 1, #keybinds do
                if isKeyJustPressed(keybinds[i][1]) then sampSendChat(keybinds[i][2]) end
else
        thisScript():unload()
        do return end
        end
    end
end
Во первых, работай с табуляцией, с кодом у тебя полная жопа, во вторых, ты else не туда впихнул
P.s блять я опять посмотрел на твой код и он в полнейшей пизде. Советую переписать адекватно
Вот более адекватный код
Lua:
require "lib.moonloader"

local ip = {
"one.monser.ru:7777",
"two.monser.ru:7777",
"three.monser.ru:7777"
}
local keybinds = {
    { VK_1, "/mask"       },
    { VK_2, "/heal"       },
    { VK_3, "/tp"         },
    { VK_5, "/veh 411 1 1"},
    { VK_6, "/veh 510 1 1"},
    { VK_Z, "/anim 8"     },
}

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end

    for k, v in pairs(ip) do
        if sampGetCurrentServerAddress() ~= v then -- проверка по ИП.
        sampAddChatMessage('Скрипт работает только на серверах "Monser DM" ', -1)
        thisScript():unload()
    end

    while true do
        wait(0)
        if not sampIsChatInputActive() and not isSampfuncsConsoleActive() and not sampIsDialogActive() and activate then
            for i = 1, #keybinds do
                if isKeyJustPressed(keybinds[i][1]) then sampSendChat(keybinds[i][2])
            end                   
        end
    end
end
 
Последнее редактирование:

Next..

Известный
343
135
Во первых, работай с табуляцией, с кодом у тебя полная жопа, во вторых, ты else не туда впихнул
P.s блять я опять посмотрел на твой код и он в полнейшей пизде. Советую переписать адекватно
Вот более адекватный код
Lua:
require "lib.moonloader"

local ip = {
"one.monser.ru:7777",
"two.monser.ru:7777",
"three.monser.ru:7777"
}
local keybinds = {
    { VK_1, "/mask"       },
    { VK_2, "/heal"       },
    { VK_3, "/tp"         },
    { VK_5, "/veh 411 1 1"},
    { VK_6, "/veh 510 1 1"},
    { VK_Z, "/anim 8"     },
}

function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end

    for k, v in pairs(ip) do
        if sampGetCurrentServerAddress() ~= v then -- проверка по ИП.
        sampAddChatMessage('Скрипт работает только на серверах "Monser DM" ', -1)
        thisScript():unload()
    end

    while true do
        wait(0)
        if not sampIsChatInputActive() and not isSampfuncsConsoleActive() and not sampIsDialogActive() and activate then
            for i = 1, #keybinds do
                if isKeyJustPressed(keybinds[i][1]) then sampSendChat(keybinds[i][2])
            end                   
        end
    end
end
Два end'а потерялись
 

четыреста четыре

Известный
120
19
как заспаванить себя через ffi или callfunction ?
void SAMP::CLocalPlayer::RequestSpawn() {
((void(__thiscall *)(CLocalPlayer *))SAMP_ADDROF(0x3EC0))(this);
}

SAMP::CLocalPlayer::CLocalPlayer() {
(void(__thiscall *)(CLocalPlayer *))SAMP_ADDROF(0x4A50))(this);
}


Lua:
разобрался, мб кому надо
function Spawn()
    ffi.cast( 'void ( __thiscall * )( void * )', getModuleHandle("samp.dll") + 0x3AD0)( ffi.cast('struct stSAMPPools*', sampGetSampPoolsPtr()).pPlayer.pLocalPlayer )
end
 
Последнее редактирование:

abnomegd

Активный
335
35
Хотел сделать типо при нацеливании на игрока и нажатие на клавишу "X" то открывалось диалоговое окно.

dialogscript:
require "lib.moonloader" -- подключение библиотеки
local color_dialog = 0xDEB887

-- Для диалога с ID 12
local dialogArr = {"История ников", "Добавить в записную книгу", "Показать документы", "Действия", "Имущество"}
local dialogStr = ""

for _, str in ipairs(dialogArr) do
    dialogStr = dialogStr .. str .. "\n"
end

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end

    sampRegisterChatCommand("dialog", cmd_dialog)

    while true do
        wait(0)
        -- Блок выполняющийся бесконечно (пока самп активен)
    end
end
        local valid, ped = getCharPlayerIsTargeting(PLAYER_HANDLE)
        if valid and doesCharExist(ped) then
            local result, id = sampGetPlayerIdByCharHandle(ped)
            if result and isKeyJustPressed(VK_X) then
               sampHasDialogRespond(12)
                playerid = id

        local result, button, list, input = sampHasDialogRespond(11) -- /dialog1 (InputBox)

        if result then -- если диалог открыт
            if button == 1 then -- если нажата первая кнопка (Выбрать)
            else -- если нажата вторая кнопка (Закрыть)
            end
        end


        local result, button, list, input = sampHasDialogRespond(12) -- /dialog2 (ListBox)

        if result then -- если диалог открыт
            if button == 1 then -- если нажата первая кнопка (Выбрать)
                if list == 0 then
                elseif list == 1 then
                elseif list == 2 then
                elseif list == 3 then
                end
            else -- если нажата вторая кнопка (Закрыть)
            end
        end
    end
end

function cmd_dialog(arg)
    if #arg == 0 then
        sampAddChatMessage("Введите аргумент [1-2]", color_dialog)
    elseif tonumber(arg) == 1 then
        sampShowDialog(11, "Диалог с типом ID 1 (InputBox)", "Введите какую-либо строку", "Выбрать", "Закрыть", 1)
    elseif tonumber(arg) == 2 then
        sampShowDialog(12, "Меню взаимодействия с игроком", dialogStr, "Выбрать", "Закрыть", 2)
    end
end
 

horacy

Известный
102
92
Как я могу проверить, есть ли в чате частично изменяющееся сообщение? например, «ваше оружие: m4» и каждый раз, когда появляется другое оружие, как я могу проверить, появилось ли сообщение с фрагментом «ваше оружие»?
 

neverlane

t.me/neverlane00
Друг
1,000
1,136
Как я могу проверить, есть ли в чате частично изменяющееся сообщение? например, «ваше оружие: m4» и каждый раз, когда появляется другое оружие, как я могу проверить, появилось ли сообщение с фрагментом «ваше оружие»?
это называется регулярки
Lua:
local ev = require("samp.events")

function ev.onServerMessage(color, text)
    local gunname = text:match("ваше оружие: (.+)");
    if gunname then
        -- code
    end
end
 
  • Нравится
Реакции: horacy

abnomegd

Активный
335
35
Хотел сделать типо при нацеливании на игрока и нажатие на клавишу "X" то открывалось диалоговое окно.

dialogscript:
require "lib.moonloader" -- подключение библиотеки
local color_dialog = 0xDEB887

-- Для диалога с ID 12
local dialogArr = {"История ников", "Добавить в записную книгу", "Показать документы", "Действия", "Имущество"}
local dialogStr = ""

for _, str in ipairs(dialogArr) do
    dialogStr = dialogStr .. str .. "\n"
end

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end

    sampRegisterChatCommand("dialog", cmd_dialog)

    while true do
        wait(0)
        -- Блок выполняющийся бесконечно (пока самп активен)
    end
end
        local valid, ped = getCharPlayerIsTargeting(PLAYER_HANDLE)
        if valid and doesCharExist(ped) then
            local result, id = sampGetPlayerIdByCharHandle(ped)
            if result and isKeyJustPressed(VK_X) then
               sampHasDialogRespond(12)
                playerid = id

        local result, button, list, input = sampHasDialogRespond(11) -- /dialog1 (InputBox)

        if result then -- если диалог открыт
            if button == 1 then -- если нажата первая кнопка (Выбрать)
            else -- если нажата вторая кнопка (Закрыть)
            end
        end


        local result, button, list, input = sampHasDialogRespond(12) -- /dialog2 (ListBox)

        if result then -- если диалог открыт
            if button == 1 then -- если нажата первая кнопка (Выбрать)
                if list == 0 then
                elseif list == 1 then
                elseif list == 2 then
                elseif list == 3 then
                end
            else -- если нажата вторая кнопка (Закрыть)
            end
        end
    end
end

function cmd_dialog(arg)
    if #arg == 0 then
        sampAddChatMessage("Введите аргумент [1-2]", color_dialog)
    elseif tonumber(arg) == 1 then
        sampShowDialog(11, "Диалог с типом ID 1 (InputBox)", "Введите какую-либо строку", "Выбрать", "Закрыть", 1)
    elseif tonumber(arg) == 2 then
        sampShowDialog(12, "Меню взаимодействия с игроком", dialogStr, "Выбрать", "Закрыть", 2)
    end
end
up
 

chapo

🫡 В армии с 17.10.2023. В ЛС НЕ ОТВЕЧАЮ
Друг
8,776
11,226
Lua:
require "lib.moonloader" -- подключение библиотеки
local color_dialog = 0xDEB887

-- Для диалога с ID 12
local dialogArr = {"История ников", "Добавить в записную книгу", "Показать документы", "Действия", "Имущество"}
local dialogStr = ""

for _, str in ipairs(dialogArr) do
    dialogStr = dialogStr .. str .. "\n"
end

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
    sampRegisterChatCommand("dialog", cmd_dialog)
    while true do
        wait(0)
        -- Блок выполняющийся бесконечно (пока самп активен)
        local valid, ped = getCharPlayerIsTargeting(PLAYER_HANDLE)
        if valid and doesCharExist(ped) then
            local result, id = sampGetPlayerIdByCharHandle(ped)
            if result and isKeyJustPressed(VK_X) then
                playerid = id
                cmd_dialog(2)
            end
        end

        local result, button, list, input = sampHasDialogRespond(11) -- /dialog1 (InputBox)
        if result then -- если диалог открыт
            if button == 1 then -- если нажата первая кнопка (Выбрать)
          
            end
        end

        local result, button, list, input = sampHasDialogRespond(12) -- /dialog2 (ListBox)
        if result then -- если диалог открыт
            if button == 1 then -- если нажата первая кнопка (Выбрать)
                if list == 0 then
                elseif list == 1 then
                elseif list == 2 then
                elseif list == 3 then
                end
            end
        end
    end
end

function cmd_dialog(arg)
    if tonumber(arg) == 1 then
        sampShowDialog(11, "Диалог с типом ID 1 (InputBox)", "Введите какую-либо строку", "Выбрать", "Закрыть", 1)
    elseif tonumber(arg) == 2 then
        sampShowDialog(12, "Меню взаимодействия с игроком", dialogStr, "Выбрать", "Закрыть", 2)
    end
end
 
  • Нравится
Реакции: abnomegd

Warklot

Участник
112
3
is there a way to make is3dtextOnScreen(i) because now it draws lines even when im not looking at that 3d text.
Lua:
        for i=0, 5000 do
            if sampIs3dTextDefined(i) then
                if enabled then
                local text, color, vx, vy, vz, distance, ignoreWalls, pID, vID = sampGet3dTextInfoById(i)
                    if text:find("(.*)House(.*)") then

                        local x, y, z = getCharCoordinates(PLAYER_PED)
                        local GET_COORDS_X, GET_COORDS_Y = convert3DCoordsToScreen(vx, vy, vz)
                        local GET_COORDS_me_X, GET_COORDS_me_Y = convert3DCoordsToScreen(x, y, z)
                        local dist = getDistanceBetweenCoords3d (vx, vy, vz, x,y, z)
                        renderDrawLine(GET_COORDS_X, GET_COORDS_Y ,GET_COORDS_me_X, GET_COORDS_me_Y, 1.1, 0xFFD00000)
                        renderFontDrawText(font,"distance "..dist, GET_COORDS_X, GET_COORDS_Y, -1)

                    end
                end   
            end
        end