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

Samirca

Активный
209
25
Как установить Moonloader 0.27 Prewiew 3? Я все установил правильно и все-равно не работает
 

fibagr123

Известный
20
2
как отцентровать число в inputint в обычном имгуи, че-то полистали документация и не нашел нужного флага

как посчитать количество строк в InputTextMultiline? попытался с помощью данной либы https://www.blast.hk/threads/147968/ подсчитать кол-во знаков переноса строк:
Lua:
binder[i].text.v:count('[\n]')
но по кд выдает 0, хотя например в методе split - "[\n]" нормально обрабатывается и строка правильно разбивается

to call global 'str' (a nil value)
Я плохо разбираюсь в мимгуи, но вроде чтобы прочитать значение из буфера строки надо использовать: ffi.string(buffer)
 
Последнее редактирование:

North Trees

Участник
39
2
Вечер добрый, хотел бы по интересоваться в написании основных функций скрипта вх. Уточнение вх тип обычный на ники, язык луа я достаточно знаю для этого т. к уже писал скриптики.
 

2elnwndrer.

Известный
59
19
Как хукнуть клисты игроков на радаре и заменить их на картинку, например?
 

MLycoris

На вид оружие массового семяизвержения
Проверенный
1,980
2,200
Вечер добрый, хотел бы по интересоваться в написании основных функций скрипта вх. Уточнение вх тип обычный на ники, язык луа я достаточно знаю для этого т. к уже писал скриптики.
на форуме вх хоть жопой жуй и в большинстве случаев код открыт
в основном используют что-то типа такого

Lua:
-- где нибудь в начале
local font = renderCreateFont('TimesNewRoman', 9, 5)

-- в main
for k, v in pairs(getAllChars()) do
    local cx, cy, cz = getCharCoordinates(v)
    local res, playerId = sampGetPlayerIdByCharHandle(v)
    if res and v ~= PLAYER_PED and isPointOnScreen(cx, cy, cz, 1) then
        local convX, convY = convert3DCoordsToScreen(cx, cy, cz)
        renderFontDrawText(font, sampGetPlayerNickname(playerId), convX, convY, 0xFFFFFFFF)
    end
end
 

North Trees

Участник
39
2
на форуме вх хоть жопой жуй и в большинстве случаев код открыт
в основном используют что-то типа такого

Lua:
-- где нибудь в начале
local font = renderCreateFont('TimesNewRoman', 9, 5)

-- в main
for k, v in pairs(getAllChars()) do
    local cx, cy, cz = getCharCoordinates(v)
    local res, playerId = sampGetPlayerIdByCharHandle(v)
    if res and v ~= PLAYER_PED and isPointOnScreen(cx, cy, cz, 1) then
        local convX, convY = convert3DCoordsToScreen(cx, cy, cz)
        renderFontDrawText(font, sampGetPlayerNickname(playerId), convX, convY, 0xFFFFFFFF)
    end
end
Спасибо)))

Посоветуйте пожалуйста скрипт который при зажатии клавиши флудит другую клавишу. Тип я зажал 1, а скрипт мне флудит 2
 
Последнее редактирование:
  • Нравится
Реакции: MLycoris

fibagr123

Известный
20
2
Спасибо)))

Посоветуйте пожалуйста скрипт который при зажатии клавиши флудит другую клавишу. Тип я зажал 1, а скрипт мне флудит 2
Lua:
if wasKeyPressed(клавиша) and not sampIsCursorActive() then
    setCharKeyDown(клавиша, true)
    wait(100)
    setCharKeyDown(клавиша, false)
end
 
  • Нравится
Реакции: North Trees

uvie

Известный
274
54
how could I make a script so that the police officer would send me a fine and I would automatically accept it?
Lua:
pcall(require, 'sflua')

function isFinePaymentRequestDisplayed()
    for i = 0, sampGetChatStringLength() - 1 do
        local chatText = sampGetChatString(i)
        if string.match(chatText, "jums siūlo moketi bauda: %d+ €. Moketi?") then
            return true
        end
    end
    return false
end

function main()
    repeat wait(0) until isSampAvailable()
    while true do
        wait(0)
        if isFinePaymentRequestDisplayed() then
            sampSendChat("/taip")
        end
    end
end


I only have one, a script, and I don't know how to get the code, where should I click YES from the following tables?

I have creations, sampSendChat, but in chat you don't need to write /yes, to accept the fine you need to press yes in the table
 

Вложения

  • ApplicationFrameHost_FQzr1liIFX.png
    ApplicationFrameHost_FQzr1liIFX.png
    25.2 KB · Просмотры: 15
  • msedge_t54T1aUBsi.png
    msedge_t54T1aUBsi.png
    25 KB · Просмотры: 15

Dimok228

Известный
40
1
Есть у меня скрипт, который нажимает по диалогу сам, но вот хочу модифицировать, не знаю как.
Мне нужно чтобы он не продолжал использование функции когда в диалоге видит определенный текст, то есть когда транспорт в гараже, или если кто-то за рулем
function fdrive(arg)
if #arg == 0 then
sampAddChatMessage("{4682B4}[helper]{FFFFFF 1-8. 9, .", 0xffffff)
end
if tonumber(arg) == 0 then
elseif tonumber(arg) == 1 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 0)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 2 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 1)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 3 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 2)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 4 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 3)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 5 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 4)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 6 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 5)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 7 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 6)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 8 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 7)
sampSendDialogResponse(3124, 1, 1)
end
end
Вот менюшка
image.png
 
Последнее редактирование:

fibagr123

Известный
20
2
Есть у меня скрипт, который нажимает по диалогу сам, но вот хочу модифицировать, не знаю как.
Мне нужно чтобы он не продолжал использование функции когда в диалоге видит определенный текст, то есть когда транспорт в гараже, или если кто-то за рулем
function fdrive(arg)
if #arg == 0 then
sampAddChatMessage("{4682B4}[helper]{FFFFFF 1-8. 9, .", 0xffffff)
end
if tonumber(arg) == 0 then
elseif tonumber(arg) == 1 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 0)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 2 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 1)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 3 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 2)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 4 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 3)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 5 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 4)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 6 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 5)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 7 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 6)
sampSendDialogResponse(3124, 1, 1)
elseif tonumber(arg) == 8 then
sampSendChat("/family")
sampSendDialogResponse(3109, 1, 4)
sampSendDialogResponse(3123, 1, 7)
sampSendDialogResponse(3124, 1, 1)
end
end
Вот менюшка
image.png
Не особо понял, что тебе надо. Можешь перелавливать диалоговое окно с помощью samp events, проверять по тайтлу этот ли диалог нужен, а после регулярками искать текст, и если есть совпадение, то просто возвращать диалог.
samp events - https://www.blast.hk/threads/14624/
документация - https://github.com/THE-FYP/SAMP.Lua/blob/master/samp/events.lua
гайды глянь в ютубе.
примерный код:
Код:
require('lib.moonloader')
local sampev = require('lib.samp.events')

function sampev.onShowDialog(dialogId, style, title, button1, button2, text)
    if title ~= 'название окна' then
        return dialogId, style, title, button1, button2, text
    end
    if не найдено значение then
        --code
    end
end

и кстати всю эту хуйню с if можно заменить на
Lua:
function fdrive(arg)
    if #arg == 0 then
        sampAddChatMessage("{4682B4}[helper]{FFFFFF 1-8. 9, .", 0xffffff)
    end

    num = tonumber(arg)

    if num > 0 and num <= 8 then
        sampSendChat("/family")
        sampSendDialogResponse(3109, 1, 4)
        sampSendDialogResponse(3123, 1, num-1)
        sampSendDialogResponse(3124, 1, 1)
    end
end
 
Последнее редактирование:

Dimok228

Известный
40
1
Не особо понял, что тебе надо. Можешь перелавливать диалоговое окно с помощью samp events, проверять по тайтлу этот ли диалог нужен, а после регулярками искать текст, и если есть совпадение, то просто возвращать диалог.
samp events - https://www.blast.hk/threads/14624/
документация - https://github.com/THE-FYP/SAMP.Lua/blob/master/samp/events.lua
гайды глянь в ютубе.
примерный код:
Код:
require('lib.moonloader')
local sampev = require('lib.samp.events')

function sampev.onShowDialog(dialogId, style, title, button1, button2, text)
    if title ~= 'название окна' then
        return dialogId, style, title, button1, button2, text
    end
    if не найдено значение then
        --code
    end
end

и кстати всю эту хуйню с if можно заменить на
Lua:
function fdrive(arg)
    if #arg == 0 then
        sampAddChatMessage("{4682B4}[helper]{FFFFFF 1-8. 9, .", 0xffffff)
    end

    num = tonumber(arg)

    if num > 0 and num <= 8 then
        sampSendChat("/family")
        sampSendDialogResponse(3109, 1, 4)
        sampSendDialogResponse(3123, 1, num-1)
        sampSendDialogResponse(3124, 1, 1)
    end
end
Чтобы когда была надпись в менюшке "в гараже" дальше ничего не происходило
 

fibagr123

Известный
20
2
Чтобы когда была надпись в менюшке "в гараже" дальше ничего не происходило
хз работоспособно ли, с диалогами почти не работал

Lua:
local mt = getmetatable("String") function mt.__index:insert(implant, pos)     if pos == nil then         return self .. implant     end     return self:sub(1, pos) .. implant .. self:sub(pos + 1) end  function mt.__index:extract(pattern)     self = self:gsub(pattern, "")     return self end  function mt.__index:array()     local array = {}     for s in self:sub(".") do         array[#array + 1] = s     end     return array end  function mt.__index:isEmpty()     return self:find("%S") == nil end  function mt.__index:isDigit()     return self:find("%D") == nil end  function mt.__index:isAlpha()     return self:find("[%d%p]") == nil end  function mt.__index:split(sep, plain)     assert(not sep:isEmpty(), "Empty separator")         result, pos = {}, 1     repeat         local s, f = self:find(sep or " ", pos, plain)         result[#result + 1] = self:sub(pos, s and s - 1)         pos = f and f + 1     until pos == nil     return result end  local orig_lower = string.lower function mt.__index:lower()     for i = 192, 223 do         self = self:gsub(string.char(i), string.char(i + 32))     end     self = self:gsub(string.char(168), string.char(184))     return orig_lower(self) end  local orig_upper = string.upper function mt.__index:upper()     for i = 224, 255 do         self = self:gsub(string.char(i), string.char(i - 32))     end     self = self:gsub(string.char(184), string.char(168))     return orig_upper(self) end  function mt.__index:isSpace()     return self:find("^[%s%c]+$") ~= nil end  function mt.__index:isUpper()     return self:upper() == self end  function mt.__index:isLower()     return self:lower() == self end  function mt.__index:isSimilar(str)     return self == str end  function mt.__index:isTitle()     local p = self:find("[A-z�-���]")     local let = self:sub(p, p)     return let:isSimilar(let:upper()) end  function mt.__index:startsWith(str)     return self:sub(1, #str):isSimilar(str) end  function mt.__index:endsWith(str)     return self:sub(#self - #str + 1, #self):isSimilar(str) end  function mt.__index:capitalize()     local cap = self:sub(1, 1):upper()     self = self:gsub("^.", cap)     return self end  function mt.__index:tabsToSpace(count)     local spaces = (" "):rep(count or 4)     self = self:gsub("\t", spaces)     return self end  function mt.__index:spaceToTabs(count)     local spaces = (" "):rep(count or 4)     self = self:gsub(spaces, "t")     return self end  function mt.__index:center(width, char)     local len = width - #self     local s = string.rep(char or " ", len)      return s:insert(self, math.ceil(len / 2)) end  function mt.__index:count(search, p1, p2)     assert(not search:isEmpty(), "Empty search")     local area = self:sub(p1 or 1, p2 or #self)     local count, pos = 0, p1 or 1     repeat         local s, f = area:find(search, pos, true)         count = s and count + 1 or count         pos = f and f + 1     until pos == nil     return count end  function mt.__index:trimEnd()     self = self:gsub("%s*$", "")     return self end  function mt.__index:trimStart()     self = self:gsub("^%s*", "")     return self end  function mt.__index:trim()     self = self:match("^%s*(.-)%s*$")     return self end  function mt.__index:swapCase()     local result = {}     for s in self:gmatch(".") do         if s:isAlpha() then             s = s:isLower() and s:upper() or s:lower()         end         result[#result + 1] = s     end     return table.concat(result) end  function mt.__index:splitEqually(width)     assert(width > 0, "Width less than zero")     assert(width <= self:len(), "Width is greater than the string length")     local result, i = {}, 1     repeat         if #result == 0 or #result[#result] >= width then             result[#result + 1] = ""         end         result[#result] = result[#result] .. self:sub(i, i)         i = i + 1     until i > #self     return result end  function mt.__index:rFind(pattern, pos, plain)     local i = pos or #self     repeat         local result = { self:find(pattern, i, plain) }         if next(result) ~= nil then             return table.unpack(result)         end         i = i - 1     until i <= 0     return nil end  function mt.__index:wrap(width)     assert(width > 0, "Width less than zero")     assert(width < self:len(), "Width is greater than the string length")     local pos = 1     self = self:gsub("(%s+)()(%S+)()", function(sp, st, word, fi)         if fi - pos > (width or 72) then             pos = st             return "\n" .. word         end     end)        return self end  function mt.__index:levDist(str)     if #self == 0 then         return #str     elseif #str == 0 then         return #self     elseif self == str then         return 0     end          local cost = 0     local matrix = {}     for i = 0, #self do matrix[i] = {}; matrix[i][0] = i end     for i = 0, #str do matrix[0][i] = i end     for i = 1, #self, 1 do         for j = 1, #str, 1 do             cost = self:byte(i) == str:byte(j) and 0 or 1             matrix[i][j] = math.min(                 matrix[i - 1][j] + 1,                 matrix[i][j - 1] + 1,                 matrix[i - 1][j - 1] + cost             )         end     end     return matrix[#self][#str] end  function mt.__index:getSimilarity(str)     local dist = self:levDist(str)     return 1 - dist / math.max(#self, #str) end

require('lib.moonloader')

function fdrive(arg)
    if #arg == 0 then
        sampAddChatMessage("{4682B4}[helper]{FFFFFF 1-8. 9, .", 0xffffff)
    end

    num = tonumber(arg)

    if num > 0 and num <= 8 then
        text = sampGetDialogText():split('[\n]')
        if not text[num]:find('В гараже') then
            sampSendChat("/family")
            sampSendDialogResponse(3109, 1, 4)
            sampSendDialogResponse(3123, 1, num-1)
            sampSendDialogResponse(3124, 1, 1)
        end
    end
end