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

mixeq

Известный
66
8
как картинку перенести в этот квадрат? (условно)
upload_2018-12-4_17-50-19.png

размер подгоню
 

utmpL

Активный
309
65
А если я хочу сделать в принципе тоже самое но без команды после отыгровки, а чисто отыгровку.
Lua:
function main()
    repeat wait(0) until isSampAvailable()
    sampRegisterChatCommand('komanda2', komanda2)
    repeat wait(0) until false
end

function komanda2()
lua_thread.create(function()
    sampSendChat("/me отыгровка")
    wait(1000)
    sampSendChat("/me отыгровка")
    wait(1000)
    sampSendChat("/me отыгровка")
end)
end
 
  • Нравится
Реакции: Licht

Licht

Известный
238
32
Lua:
function main()
    repeat wait(0) until isSampAvailable()
    sampRegisterChatCommand('komanda2', komanda2)
    repeat wait(0) until false
end

function komanda2()
lua_thread.create(function()
    sampSendChat("/me отыгровка")
    wait(1000)
    sampSendChat("/me отыгровка")
    wait(1000)
    sampSendChat("/me отыгровка")
end)
end
пасиб, но я уже сделал чутка покрасивее и по сложнее:)

как картинку перенести в этот квадрат? (условно)
Посмотреть вложение 22219
размер подгоню
нужно поменять координаты картинки
Это та ещё морока. но помочь не смогу. с имгуи ещё не в ладах
 

mixeq

Известный
66
8
пасиб, но я уже сделал чутка покрасивее и по сложнее:)


нужно поменять координаты картинки
Это та ещё морока. но помочь не смогу. с имгуи ещё не в ладах
окей, а можно ли как то в столбик написать кнопки "Карта 1" и тд?
картинку тогда под ними сделаю
 
Последнее редактирование:

Inquten

Известный
3
1
Lua:
local ev = require 'lib.samp.events'
local damaglog = {out = {}, inc = {}}
local timetoshow = 0
local lasttime = 1
local weaponz = ""
local weaponz2 = ""

local names = {
  [0] = "Fist",
  [1] = "Brass Knuckles",
  [2] = "Golf Club",
  [3] = "Nightstick",
  [4] = "Knife",
  [5] = "Baseball Bat",
  [6] = "Shovel",
  [7] = "Pool Cue",
  [8] = "Katana",
  [9] = "Chainsaw",
  [10] = "Purple Dildo",
  [11] = "Dildo",
  [12] = "Vibrator",
  [13] = "Silver Vibrator",
  [14] = "Flowers",
  [15] = "Cane",
  [16] = "Grenade",
  [17] = "Tear Gas",
  [18] = "Molotov Cocktail",
  [19] = "Vehicle M4 (custom)",
  [20] = "Vehicle minigun (custom)",
  [22] = "9mm",
  [23] = "Silenced 9mm",
  [24] = "Desert Eagle",
  [25] = "Shotgun",
  [26] = "Sawnoff Shotgun",
  [27] = "Combat Shotgun",
  [28] = "Micro SMG/Uzi",
  [29] = "MP5",
  [30] = "AK-47",
  [31] = "M4",
  [32] = "Tec-9",
  [33] = "Country Rifle",
  [34] = "Sniper Rifle",
  [35] = "RPG",
  [36] = "HS Rocket",
  [37] = "Flamethrower",
  [38] = "Minigun",
  [39] = "Satchel Charge",
  [40] = "Detonator",
  [41] = "Spraycan",
  [42] = "Fire Extinguisher",
  [43] = "Camera",
  [44] = "Night Vis Goggles",
  [45] = "Thermal Goggles",
  [46] = "Parachute",
  [47] = "Fake pistol",
  [48] = "Pistol whip",
  [49] = "Vehicle",
  [50] = "Helicopter blades",
  [51] = "Explosion",
  [52] = "Car park",
  [53] = "Drowning",
  [54] = "Fall" }

function ev.onSendTakeDamage(playerId,damage,weapon)
   timetoshow=lasttime+3
   if #damaglog.inc > 0 then
       ch = false
       for k,v in pairs(damaglog.inc) do
           if v.id == playerId then
               weaponz2 = tostring(names[weapon])
               v.damage = v.damage + damage
               ch = true
           end
       end
       if not ch then
           table.insert(damaglog.inc,1,{id = playerId,damage = damage})
           if #damaglog.inc > 6 then
               table.remove(#damaglog.inc,6)
           end
       end
   else
       table.insert(damaglog.inc,1,{id = playerId,damage = damage})
   end
end
function ev.onSendGiveDamage(playerId,damage,weapon)
   timetoshow=lasttime+3
   if #damaglog.inc > 0 then
       ch = false
       for k,v in pairs(damaglog.inc) do
           if v.id == playerId then
               weaponz2 = tostring(names[weapon])
               v.damage = v.damage + damage
               ch = true
           end
       end
       if not ch then
           table.insert(damaglog.inc,1,{id = playerId,damage = damage})
           if #damaglog.inc > 6 then
               table.remove(#damaglog.inc,6)
           end
       end
   else
       table.insert(damaglog.inc,1,{id = playerId,damage = damage})
   end
end
function main()
   while not isSampAvailable() do wait(0) end
   font = renderCreateFont("Arial", 15, 8)
   while true do wait(0)
       health = getCharHealth(playerPed)
       if health == 0 then damaglog = {out = {}, inc = {}} end
       local posx, posy = convertGameScreenCoordsToWindowScreenCoords(150,400)
       local posx2 = convertGameScreenCoordsToWindowScreenCoords(450)
       lasttime=os.clock()
       if timetoshow > lasttime then
           if #damaglog.out > 0 then
               for k,v in pairs(damaglog.out) do
                   renderFontDrawText(font,sampGetPlayerNickname(v.id)..' - '..weaponz..' +'..string.format('%.2f',v.damage), posx,posy-renderGetFontDrawHeight(font)*k,0xff26e01d)
               end
           end
           if #damaglog.inc > 0 then
               for k,v in pairs(damaglog.inc) do
                   renderFontDrawText(font,sampGetPlayerNickname(v.id)..' - '..weaponz2..' -'..string.format('%.2f',v.damage), posx2,posy-renderGetFontDrawHeight(font)*k,0xFF44A6C5)
               end
           end
       else
           damaglog = {out = {}, inc = {}}
       end
   end
end

Не понимаю почему он перестает работать, когда получает урон от падения, хотя вроде все правильно вписал, помогите пожалуйста. (Выдает варнинг и умирает)
 

Kotovasya

Участник
85
13
Lua:
id = text:match('.+[(%d+)].+')
Вроде так
неа, возвращает всю строку( Вопрос актуален
Не могу додуматься какую регулярку придумать для такого случая. Смысл в том, что бы получить id игрока
[14:14:42] [RoX].Kotovasya.[RoX][152] *тут может быть любой текст* [+plz]
Как понимаете, ник может быть и без квадратных скобок вовсе, нужна регулярка, которая сможет при любом нике получить id. Помогите пожалуйста :3
 

vlads250

Известный
27
0
Есть ли функция, которая при виде двух строк, будет удалять из из чата?
[20:09:16] Интерьер: 0
[20:09:16] Виртуальный мир: 0
 

tlwsn

Известный
537
85
Пробовал, не работает. Так как ник в первом случаем может быть моим, или во втором. Так же может быть моим в обоих случаях или не быть моим вовсе, в обоих случаях.


Lua:
if message:find("АДМ%: .+ дал бан чата игроку .+ на %d+ минут. Причина: .+") then
        local admin, cheater, t, reason = message:match('АДМ%: (.+) дал бан чата игроку (.+) на (%d+) минут. Причина: (.+)')
        for i= 0, 1000 do
            if sampIsPlayerConnected(i) and sampGetPlayerNickname(i) == tostring(admin) then
                adminID = i
            end
            if sampIsPlayerConnected(i) and sampGetPlayerNickname(i) == tostring(cheater) then
                cheaterID = i
            end
        end
        sampAddChatMessage('АДМ: '..admin..'['..adminID..'] дал бан чата игроку '..cheater..'['..cheaterID..'] на '..t..' минут. Причина: '..reason..'', 0xf3684b)
        return false
end

Но почему-то это говно, не работает.
Lua:
function sampGetPlayerIdByNickname(nick)
    local _, myid = sampGetPlayerIdByCharHandle(playerPed)
    if tostring(nick) == sampGetPlayerNickname(myid) then return myid end
    for i = 0, 1000 do if sampIsPlayerConnected(i) and sampGetPlayerNickname(i) == tostring(nick) then return i end end
end
function sampev.onServerMessage(color, message)
    if message:find("АДМ%: .+ дал бан чата игроку .+ на %d+ минут. Причина: .+") then
        local admin, cheater, t, reason = message:match('АДМ%: (.+) дал бан чата игроку (.+) на (%d+) минут. Причина: (.+)')
        adminid = sampGetPlayerIdByNickname(admin)
        cheaterID = sampGetPlayerIdByNickname(cheater)
        return {0xf3684bFF, string.format(' АДМ: %s[%s] дал бан чата игроку %s[%s] на %s минут. Причина: %s', admin, adminid, cheater, cheaterID, t, reason)}
    end
end
 
  • Нравится
Реакции: wD.D159

mrdiimax

Известный
566
79
При входе в игру автоматически крашит, версию саму ПРОВЕРЯЕТ, но дальше при открытии окна имгуи крашит, небо не успевает прогружаться - игра намертво зависает.

Проверка версии
Lua:
function update() -- проверка обновлений
    local zapros = https.request("https://gitlab.com/ThisCold/arx-helpers/raw/master/update.json")

    if zapros ~= nil then
        local info2 = decodeJson(zapros)

        if info2.latest_number ~= nil and info2.latest ~= nil and info2.drop ~= nil then
            updatever = info2.latest
            version = tonumber(info2.latest_number)
            dropver = tonumber(info2.drop)

            print("[Update] Начинаем контроль версий")

            if tonumber(thisScript().version_num) <= dropver then
                print("[Update] Used non supported version: "..thisScript().version_num..", actual: "..version)
                sampAddChatMessage("[Arx]{FFFFFF} Ваша версия более не поддерживается разработчиком, работа скрипта невозможна.", 0x046D63)
                reloadScript = true
                thisScript():unload()
            elseif version > tonumber(thisScript().version_num) then
                print("[Update] Обнаружено обновление")
                sampAddChatMessage("[Arx-Helper]{FFFFFF} Обнаружено обновление до версии "..updatever..".", 0x046D63)
                active_update.v = true
                UpdateNahuy = true
            else
                print("[Update] Новых обновлений нет, контроль версий пройден")
                if checkupd then
                    sampAddChatMessage("[Arx]{FFFFFF} У вас стоит актуальная версия скрипта: "..thisScript().version..".", 0x046D63)
                    sampAddChatMessage("[Arx]{FFFFFF} Необходимости обновлять скрипт - нет, приятного пользования.", 0x046D63)
                    checkupd = false
                end
                UpdateNahuy = true
            end
        else
            sampAddChatMessage("[Arx]{FFFFFF} Ошибка при получении информации об обновлении.", 0x046D63)
            print("[Update] JSON file read error")
            UpdateNahuy = true
        end
    else
        sampAddChatMessage("[Arx]{FFFFFF} Не удалось проверить наличие обновлений, попробуйте позже.", 0x046D63)
        UpdateNahuy = true
    end
end


Она вроде как работает нормально ..
И функция из-за которой предполагаемый краш:
Имгуи:
Lua:
if active_update.v then -- окно обновления скрипта
        local sw, sh = getScreenResolution()
        imgui.SetNextWindowPos(imgui.ImVec2(sw/2, sh/2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
                imgui.SetNextWindowSize(imgui.ImVec2(450, 200), imgui.Cond.FirstUseEver)
                imgui.Begin(u8('Обновление'), nil, imgui.WindowFlags.NoResize)
        imgui.Text(u8'Обнаружено обновление до версии: '..updatever)
        imgui.Separator()
        imgui.TextWrapped(u8("Для установки обновления необходимо подтверждение пользователя, разработчик настоятельно рекомендует принимать обновления ввиду того, что прошлые версии через определенное время отключаются и более не работают."))
        if imgui.Button(u8'Скачать и установить обновление', btn_size) then
            async_http_request('GET', 'https://gitlab.com/ThisCold/arx-helpers/raw/master/ARX-Helper_v0_1b.luac', nil,
                function(response) -- вызовется при успешном выполнении и получении ответа
                local f = assert(io.open(getWorkingDirectory() .. '/ARX-Helper_v0_1b.luac', 'wb'))
                f:write(response.text)
                f:close()
                sampAddChatMessage("[Arx-Helper]{FFFFFF} Обновление успешно, перезагружаем скрипт.", 0x046D63)
                thisScript():reload()
            end,
            function(err) -- вызовется при ошибке, err - текст ошибки. эту функцию можно не указывать
                print(err)
                sampAddChatMessage("[Arx-Helper]{FFFFFF} Произошла ошибка при обновлении, попробуйте позже.", 0x046D63)
                active_update.v = not active_update.v
                return
            end)
        end
        if imgui.Button(u8'Закрыть', btn_size) then active_update.v = not active_update.v end
        imgui.End()
    end
 

Licht

Известный
238
32
короче покапался, и чето до вышло, очень,оооочень костыльно на вид, но за то работает
Lua:
function main()
    repeat wait(0) until isSampAvailable()
    sampRegisterChatCommand('komanda', komanda)
    repeat wait(0) until false
end

function komanda(param)
lua_thread.create(function()
id = tonumber(param)
if param then
    if id ~= nil then
        sampSendChat("/me отыгровка")
        wait(1000)
        sampSendChat("/me отыгровка")
        wait(1000)
        sampSendChat("/me отыгровка")
        wait(1000)
        sampSendChat('/invite '..id)
    end
end
end)
end
Дублируются отыгровки
 

wD.D159

Известный
Друг
446
479
Lua:
function sampGetPlayerIdByNickname(nick)
    local _, myid = sampGetPlayerIdByCharHandle(playerPed)
    if tostring(nick) == sampGetPlayerNickname(myid) then return myid end
    for i = 0, 1000 do if sampIsPlayerConnected(i) and sampGetPlayerNickname(i) == tostring(nick) then return i end end
end
function sampev.onServerMessage(color, message)
    if message:find("АДМ%: .+ дал бан чата игроку .+ на %d+ минут. Причина: .+") then
        local admin, cheater, t, reason = message:match('АДМ%: (.+) дал бан чата игроку (.+) на (%d+) минут. Причина: (.+)')
        adminid = sampGetPlayerIdByNickname(admin)
        cheaterID = sampGetPlayerIdByNickname(cheater)
        return {0xf3684bFF, string.format(' АДМ: %s[%s] дал бан чата игроку %s[%s] на %s минут. Причина: %s', admin, adminid, cheater, cheaterID, t, reason)}
    end
end
Выводит следующее: АДМ: wD.Dl59[nil] дал бан чата игроку Beyonce[38] на 5 минут. Причина: тест
 

astynk

Известный
Проверенный
742
530
Нужно делать кое-какое действие перед тем, как игрок выйдет из игры
Есть какое-нибудь событие вроде OnBeforeDisconnect? (ну типа так) Т.е. игрок уже покидает сервер, однако его данные пока что доступны