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

memir

🇷🇺
Всефорумный модератор
333
597
Подскажите как можно узнать дистанцию от меня до игрока
distance - расстояние.
Код:
function charpos(playerid)
   local _, anotherped = sampGetCharHandleBySampPlayerId(playerid)
   local x, y, z =getCharCoordinates(playerPed)
   local x1, y1, z1 =getCharCoordinates(anotherped)
   local distance = getDistanceBetweenCoords3d(x, y, z, x1, y1, z1)
end
 
  • Нравится
Реакции: k1sher

k1sher

Известный
201
4
Если от меня до игрока расстояние меньше 10 метров, то будет что-то на него действовать? Вообщем как то проверить дистанцию типа if distance < 10 then
 

memir

🇷🇺
Всефорумный модератор
333
597
Если от меня до игрока расстояние меньше 10 метров, то будет что-то на него действовать? Вообщем как то проверить дистанцию типа if distance < 10 then
Сам на свой вопрос и ответил)
Код:
if distance < 10 then
-- тут делаешь то, что тебе надо
end
 
Последнее редактирование:
  • Нравится
Реакции: 4el0ve4ik

4el0ve4ik

Известный
Всефорумный модератор
1,548
1,338
Если от меня до игрока расстояние меньше 10 метров, то будет что-то на него действовать? Вообщем как то проверить дистанцию типа if distance < 10 then
Получать дистанцию от него до себя и делать сравнение, прям как ты написал
 
  • Нравится
Реакции: memir

k1sher

Известный
201
4
Посмотрите вот...
Код:
require "lib.moonloader"
local hook = require 'lib.samp.events'

local aidi
local dist

function main()
    while not isSampAvailable() do wait(0) end
    qwe = lua_thread.create_suspended(qwer)
    nico = lua_thread.create_suspended(nicofunc)
    kaka = lua_thread.create_suspended(kakafunc)
    while true do
    wait(0)
    for i =0, sampGetMaxPlayerId(true) do
     if sampIsPlayerConnected(i) then
    local result, PlayerHandle = sampGetCharHandleBySampPlayerId(i)
    if result then
    sX, sY, sZ = getCharCoordinates(PLAYER_PED)
    pX, pY, pZ = getCharCoordinates(PlayerHandle)
    local dist = getDistanceBetweenCoords3d(sX, sY, sZ, pX, pY, pZ)
       
                end
            end
        end
    end
end


function qwer(dist, aidi)
wait(0)
    sampSendChat(str1)
end


function hook.onServerMessage(color,text)
    if dist < 10 then
    if string.find(text, "^%>%> ПМ от %S+%(%d+%)%: %s-hp%s-$")
    then
        space_1, space_2, space_3, aidi, space_5 = string.match(text, "%>%>(.-)ПМ(.-)от(.-)%S+%((%d+)%)%:(.-)%s-hp%s-")
        str1=string.format("/sethp %d 160", aidi)
            qwe:run(dist, aidi)
                end
                end

Что-то понять не могу. Вот точно что-то пропустил.
 

memir

🇷🇺
Всефорумный модератор
333
597
Посмотрите вот...
Код:
require "lib.moonloader"
local hook = require 'lib.samp.events'

local aidi
local dist

function main()
    while not isSampAvailable() do wait(0) end
    qwe = lua_thread.create_suspended(qwer)
    nico = lua_thread.create_suspended(nicofunc)
    kaka = lua_thread.create_suspended(kakafunc)
    while true do
    wait(0)
    for i =0, sampGetMaxPlayerId(true) do
     if sampIsPlayerConnected(i) then
    local result, PlayerHandle = sampGetCharHandleBySampPlayerId(i)
    if result then
    sX, sY, sZ = getCharCoordinates(PLAYER_PED)
    pX, pY, pZ = getCharCoordinates(PlayerHandle)
    local dist = getDistanceBetweenCoords3d(sX, sY, sZ, pX, pY, pZ)
      
                end
            end
        end
    end
end


function qwer(dist, aidi)
wait(0)
    sampSendChat(str1)
end


function hook.onServerMessage(color,text)
    if dist < 10 then
    if string.find(text, "^%>%> ПМ от %S+%(%d+%)%: %s-hp%s-$")
    then
        space_1, space_2, space_3, aidi, space_5 = string.match(text, "%>%>(.-)ПМ(.-)от(.-)%S+%((%d+)%)%:(.-)%s-hp%s-")
        str1=string.format("/sethp %d 160", aidi)
            qwe:run(dist, aidi)
                end
                end

Что-то понять не могу. Вот точно что-то пропустил.
Разбирайся с основами, без них ничего не поймешь
 

4el0ve4ik

Известный
Всефорумный модератор
1,548
1,338
Привет, игрочки!
Столкнулся с проблемой. что код крашит игру, даже не мунлоадер.
В логе естественно об этих крашах ничего нет. Нужна помощь!
Крашит при том условии, когда указываешь айди игрока(adm), которого на сервере нет. Проверки вроде-как да стоят, но видимо неправильно они стоят!
Над этим и Ринг колдовал, но и у него не вышло это пофиксить.
Код:
function prosb(param)
 local id, adm, reason = string.match(param, '(%d+) (%d+) (%d+)')
 if id ~= nil and adm ~= nil and reason ~= nil then
    id = tonumber(id)
    adm = tonumber(adm)
    reason = tonumber(reason)
    if sampIsPlayerConnected(id) ~= nil then
    if sampIsPlayerConnected(adm) ~= nil then
        if sampGetPlayerNickname(adm) ~= nil then
        local nick, _ = string.match(sampGetPlayerNickname(adm), "(%g+)_(%g+)")
        if reason < 1 or reason > 9 then sampAddChatMessage("[ fADM ]: Номер наказания должно быть НЕ меньше 1 и НЕ больше 9.", 0xC1C1C1) end
            if reason == 1 then sampSendChat(string.format("/ban %d 7 Читы. | %s.", id, nick)) end
            if reason == 2 then sampSendChat(string.format("/prison %d 60 DM | %d.", id, nick)) end
            if reason == 3 then
                sampSendChat(string.format("/gunwarn %s 1 DM в Зеленой Зоне. | %s.", id, nick))
                sampSendChat(string.format("/prison %s 60 DM в Зеленой Зоне. | %s.", id, nick))
                sampSendChat(string.format("/warn %s DM в Зеленой Зоне. | %s.", id, nick))
            end
            if reason == 4 then sampAddChatMessage(string.format("/prison %d 60 SK. | %s.", id, nick)) end
            if reason == 5 then
                sampSendChat(string.format("/gamewarn %s 2 TK. | %s.", id, nick))
                sampSendChat(string.format("/prison %s 60 TK. | %s.", id, nick))
            end
            if reason == 6 then sampSendChat(string.format("/warn %s Сбив анимации [+C/отвод]. | %s.", id, nick)) end
            if reason == 7 then sampSendChat(string.format("/prison %s 60 Отсутствие цвета на капте. | %s.", id, nick)) end
            if reason == 8 then sampSendChat(string.format("/prison %d 60 Неотыгровка RP режима. | %s.", id, nick)) end
            if reason == 9 then sampSendChat(string.format("/prison %d 60 Нарушение правил [ /action ]. | %s.", id, nick)) end
        end
    else sampAddChatMessage("[ fADM ]: ID админа не на сервере.", 0xC1C1C1) end
    else sampAddChatMessage("[ fADM ]: ID игрока не на сервере.", 0xC1C1C1) end
else
            sampAddChatMessage("[ fADM ]: Выполнить просьбу о наказании. [ /prosb [ ID-игрока ] [ ID-админа ] [ Номер наказания ] ]", 0xC1C1C1)
            sampAddChatMessage("[ 1 [ Читы ] | 2 [ DM ] | 3 [ DM в ЗЗ ] | 4 [ SK ] | 5 [ TK ] | 6 [ +С ] | 7 [ Без цвета на капте ] | 8 [ nRP ] | 9 [ nRP action ] ]", 0xC1C1C1)
    end
end
sampIsPlayerConnected - возвращает булевую переменную, так что
Lua:
if sampIsPlayerConnected(id) and sampIsPlayerConnected(adm) then
.
Это что за говно? Если первые две проверки прошли, то естественно ник будет получен.
Lua:
if sampGetPlayerNickname(adm) ~= nil then
Исходя из такого кода то лучше было бы использовать конструкию elseif, можно использовать таблицы, код получился бы значительно меньше.
 

itsLegend

Фонд борьбы за жуков 🐞
Администратор
2,695
1,448
Привет, помогите, что я делаю не так. Мне нужно получить из ниже приведённого текста переменные: Первая часть ника, вторая часть ника, ид игрока. Траблы возникли с [].
Lua:
local messageTargetNick,
      messageTargetName,
      messageTargetId = string.match( "Сообщение от Nick_Name[123]: Привет.", "Сообщение от (%g+)_(%g+)\[(%d+)\]" )
moonloader.log
Код:
invalid escape sequence near '"Сообщение от (%g+)_(%g+)'

В string.match используется не RegExp, а специальные паттерны. Так что для экранирования символов используется %, вместо \
 
  • Нравится
Реакции: eiuhuth

k1sher

Известный
201
4
Подскажите пожалуйста ошибки в скрипте.
Код:
local hook = require 'lib.samp.events'


function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand("radius", adrCMD)
    qwe = lua_thread.create_suspended(qwer)
    wait(-1)
end


function qwer(str, id, radius)
    wait(0)
    if radius ~= 0.0 then
        if doesCharExist(PLAYER_PED) then
            if sampIsPlayerConnected(id) then
                local _, PlayerHandle = sampGetCharHandleBySampPlayerId(id)
                if doesCharExist(PlayerHandle) then
                    local sX, sY, sZ = getCharCoordinates(PLAYER_PED)
                    local pX, pY, pZ = getCharCoordinates(PlayerHandle)
                    local dist = getDistanceBetweenCoords3d(sX, sY, sZ, pX, pY, pZ)
                    sampSendChat(radius)
                    if dist <= tonumber(radius) then
                        sampSendChat(str)
                    end
                end
            end
        end
    else
        sampSendChat(str)
    end
end


function hook.onServerMessage(color, text)
    if adrToggle == 1 then
    if string.find(text, "^%>%> ПМ от %S+%(%d+%)%: %s*hp%s*$") then
        local aidi = string.match(text, "%>%> ПМ от %S+%((%d+)%)%: %s*hp%s*")
        local str = string.format("/sethp %d 160", aidi)
        qwe:run(str, aidi)
    end
    if string.find(text, "^%>%> ПМ от %S+%(%d+%)%: %s*guns%s*$") then
        local aidi = string.match(text, "^%>%> ПМ от %S+%((%d+)%)%: %s*guns%s*$")
        local str = string.format("/sellgun %d eagle", aidi)
        qwe:run(str, aidi)
    end
    if string.find(text, "^%>%> ПМ от %S+%(%d+%)%: %s*tpme%s*$") then
        local aidi = string.match(text, "^%>%> ПМ от %S+%((%d+)%)%: %s*exit%s*$")
        local str = string.format("/sethp %d 0", aidi)
        qwe:run(str, aidi)
        end
    end
end

function adrCMD(arg)
if adrToggle == 1 then
        adrToggle = 0
        sampAddChatMessage("Скрипт деактивирован.", 0xc40000)
    else
            if string.find(arg, "^%s*%d+%s*") then
            radius = string.match(arg, "^%s*(%d+)%s*")
            radius = tonumber(radius)
            adrToggle = 1
            sampAddChatMessage("Скрипт активирован.", 0x08a800)
            sampAddChatMessage("{00fadd}Дистанция до игрока установлена: {FFFFFF}" .. radius .. " {ffffff}М.", 0xFFFFFF)
        else
            sampAddChatMessage("{c40000}Ошибка! {FFFFFF}Введите радиус. Например /radius [Дистанция]", 0xFFFFFF)
        end
    end
end
Не хочет радиус работать.
 

itsLegend

Фонд борьбы за жуков 🐞
Администратор
2,695
1,448
Может быть потому что radius в qwer равен nil?
 
  • Нравится
Реакции: eiuhuth