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

Орк

Известный
300
218
посмотрел в поисковике, вряд ли поддерживается апи в браузер
обычно хукают на наличие дискорда в пк и отправляют запрос на апи дискорда
Я имею в виду, как через игру использовать api дискорда, чтобы напрямую на аккаунт выводить статус, без клиента на ПК/браузера, в принципе, без дискорда.
Так вообще реально? Или api там строго для ботов?
 
  • Нравится
Реакции: kyrtion

kyrtion

Известный
1,110
403
Я имею в виду, как через игру использовать api дискорда, чтобы напрямую на аккаунт выводить статус, без клиента на ПК/браузера, в принципе, без дискорда.
Так вообще реально? Или api там строго для ботов?
мб увидишь это

максимум нужно поднять сервер для поддерживание онлайн дискорда и туда создавать запросы на RPC рич пресенц
 

Naito

Активный
161
35
How to play an animation when sending a message to the chat? EXAMPLE: if "Congratulations" appears in the chat, you must play some celebration animation.

Как воспроизвести анимацию при отправке сообщения в чат? ПРИМЕР: если в чате появилось «Поздравляем», необходимо воспроизвести анимацию праздника.
 

kyrtion

Известный
1,110
403
@Naito
1. Hook event on server message
2. In hook if found and if you message writed, create thread lua:
2.1. Add wait 10 ms (if server says no flood, add 1 sec)
2.2. Write animation command with number, for example /anim 51
 
  • Нравится
Реакции: Naito

taizx

Новичок
3
0
дайте адрес памяти искр от пуль и как их можно было бы полностью убрать
 
  • Эм
Реакции: qdIbp

fokichevskiy

Известный
472
243
как создать образец пиньяты, если идентификатор пиньяты все время меняется, но ее цвет остается прежним?? пример идентификатора пиньяты?

Lua:
local font = renderCreateFont('Tahoma', 6, 5)
local act = false
local pinjatosTex = "triadprops_lvs.txd"
local pinjatosDff = "trdlamp01.dff"
pcall(require, 'sflua')

function main()
    while not isSampAvailable() do wait(0) end

    sampRegisterChatCommand('pinjata', function ()
        act = not act
        sampAddChatMessage(act and 'PINJATŲ SKRIPTAS ON' or 'PINJATŲ SKRIPTAS OFF', -1)
    end)

    while true do
        wait(0)
        if act then
            for _, objectHandle in pairs(getAllObjects()) do
                local objTex = getObjectTextureName(objectHandle)
                local objDff = getObjectModelName(objectHandle)
                if objTex == pinjatosTex and objDff == pinjatosDff then
                    local result, positionX, positionY, positionZ = getObjectCoordinates(objectHandle)
                    if result then
                        local x, y, z = getCharCoordinates(PLAYER_PED)
                        local dist = getDistanceBetweenCoords3d(x, y, z, positionX, positionY, positionZ)
                        if dist < 50 then
                            local cx, cy = convert3DCoordsToScreen(positionX, positionY, positionZ)
                            if isPointOnScreen(positionX, positionY, positionZ, 1) then
                                renderDrawLine(cx, cy, cx, cy, 1, 0xFFFF0000)
                                renderFontDrawText(font, 'PINJATA!', cx, cy, 0xFFFF0000)
                            end
                        end
                    end
                end
            end
        end
    end
end

У меня есть целый сценарий, сценарий работает, но когда я рядом с пиньятой, я не слышу строки


Посмотреть вложение 260705

что-то вроде этого
write it in English, I don't really understand what you're talking about.
 

fsrxvdd

Участник
90
19
lua:
function sampev.onServerMessage(color, text)
    local pattern = "<Warning | PC Launcher> [^%s]+%[(%d+)%]: Возможно Fly Hack"
    local id = text:match(pattern)
    if id then
        sampSendChat("/id " .. id)
        local nick = sampGetPlayerNickname(id)
        sampAddChatMessage('<Warning | PC Launcher> '..nick..'['..id..']: Возможно Fly Hack - В машине', 0xFF0033)
    end
    return true
end
скажите пж что не так, почему не робит скрипт
 

kyrtion

Известный
1,110
403
lua:
function sampev.onServerMessage(color, text)
    local pattern = "<Warning | PC Launcher> [^%s]+%[(%d+)%]: Возможно Fly Hack"
    local id = text:match(pattern)
    if id then
        sampSendChat("/id " .. id)
        local nick = sampGetPlayerNickname(id)
        sampAddChatMessage('<Warning | PC Launcher> '..nick..'['..id..']: Возможно Fly Hack - В машине', 0xFF0033)
    end
    return true
end
скажите пж что не так, почему не робит скрипт
Сравни текст и матч
 

Skittless

Известный
3
0
Парни, кто может написать простенький луа на удаление (Ломание) 630 обьекта для лаунчера арз?
 

kyrtion

Известный
1,110
403
Как сделать так, чтобы команда /giverank выдавалась только после того, как человек принял предложение?
То есть, например, я инвайчу человека, и только после этого начинает работать /giverank
Я сделал бы по другому:
1. Создать новые собственные команды (/in [id] [rang], 1-ый арг обязательно, 2-ой нет. если только ид, то отыграется без рп на изменение ранга)
1.1. Затем создать поток на инвайт игрока с рп. (без ранга)
2. Прохукать на чат на изменение после конкретного инвайта
2.1. Если совпадает условиями как и вы принимали, следовать:
2.1.1. Получить 2 аргумент для собственного инвайта, если нет - проходит мимо. Создать поток на повышение ранга с рп

Если следовать без проверки, то игрок может быть задерживает хоть 5, 10 секунд и принимает. А скрипт поторопился.
Поэтому нужно проверять, что игрок принимался и тогда прогресс выполнение скрипта продолжается. Если отказался - скипает процесс

Рекомендую изменить либ imgui на mimgui и обновить функции
mimgui:
 
Последнее редактирование:

kyrtion

Известный
1,110
403
Ты можешь сделать пример как это должно быть так как я только начал писать код и плохо понимаю
Ну сделаем так:
Lua:
local sampev = require('samp.events')

local skinId = 123

---@type table<number, number>
local tempInvite = {
  -- [playerId] = rank,
}

function main()
  repeat wait(0) until isSampAvailable()

  sampRegisterChatCommand('in', function(arg)
    if string.len(arg) == 0 or not arg:find('^%d+%s*%d*$') then
      return sampAddChatMessage('Использование: /in [ID] [ранг]', -1)
    end

    local playerId, rank = arg:match('^(%d+)%s*(%d*)$')
    playerId = tonumber(playerId)
    rank = tonumber(rank)
    if not playerId then return end   -- это оставляю чтобы LLS не затупился, не обращайте на внимание

    -- проверка на существование игрока, находится ли на сервере и в стриме (радар)
    if not sampIsPlayerConnected(playerId) then
      return sampAddChatMessage('Игрок, который Вы указали ID, не в сети!', -1)
    end
    local result, char = sampGetCharHandleBySampPlayerId(playerId)
    if not result or not doesCharExist(char) then
      return sampAddChatMessage('Игрок, который Вы указали ID, не в стриме!', -1)
    end

    -- чекаем на 10 метров - своего педа и игрока
    local myPos, playerPos = { getCharCoordinates(PLAYER_PED) }, { getCharCoordinates(char) }
    local distance = getDistanceBetweenCoords3d(   -- распакуем коорды (x, y, z) из таблицы {}
      table.unpack(myPos),
      table.unpack(playerPos)
    )
    if distance < 10 then
      return sampAddChatMessage('Игрок, который Вы указали ID, находится далеко!', -1)
    end

    -- проверка прошли, принимаем
    -- если команды с задержкой, обязательно с потоком
    local commandInvite = string.format('/invite %d', playerId)
    lua_thread.create(function()
      sampSendChat('/me передал бандану человеку напротив')
      wait(1000)
      sampSendChat(commandInvite)
      if type(rank) == 'number' then
        tempInvite[playerId] = rank
      else
        local fmt = string.format(
          'Вы приняли игрока %s[%d] без ранга',
          sampGetPlayerNickname(playerId), playerId
        )
        sampAddChatMessage(fmt, -1)
      end
    end)
  end)
end

-- после main()
function sampev.onServerMessage(color, text)
  if false and color and text then         -- заменить на свои условия, для авто-повышение, включая проверка в :find
    local playerId = text:match('(%d+)')   -- получение ид игрока после инвайта в чате
    playerId = tonumber(playerId)          -- конвертируем строка на числа
    if not playerId then return end        -- это оставляю чтобы LLS не затупился, не обращайте на внимание
    -- если там прописывается ник без ид'а, тогда получить ник и его узнать ид
    local rank = tempInvite[playerId]
    if rank then   -- если в временной таблице существует игрок с рангом
      local commandGiverank = string.format('/giverank %d %d', playerId, rank)
      local commandGiveskin = string.format('/giveskin %d %d', playerId, skinId)
      local fmt = string.format(
        'Вы приняли игрока %s[%d] с %d рангом и %d скин',
        sampGetPlayerNickname(playerId), playerId,
        rank, skinId
      )
      lua_thread.create(function()
        wait(1000)   -- остатки КД после инвайта
        sampSendChat(commandGiverank)
        wait(1000)
        sampSendChat(commandGiveskin)
        sampAddChatMessage(fmt, -1)
      end)
      table.remove(tempInvite, playerId)
    end
  end
end

В sampev.onServerMessage меняешь на свои условия