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

copypaste_scripter

Известный
1,261
235
Lua:
require "lib.moonloader"
require "lib.samp.events"
local sampev = require "lib.samp.events"

local font_flag = require('moonloader').font_flag
local my_font = renderCreateFont('Verdana', 12, font_flag.BOLD + font_flag.SHADOW)

local premquest = false
local alrd_cut = 0

function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
    
    sampAddChatMessage("Premium Quest", -1)
    
    sampRegisterChatCommand('pqt', function()
        premquest = not premquest
    end)
    
    while true do
    wait(0)
    
    if alrd_cut == 20 then
        premquest = false
    end
    
    for id = 0, 2048 do
        local result = sampIs3dTextDefined( id )
        if result then
            local text, color, posX, posY, posZ, distance, ignoreWalls, playerId, vehicleId = sampGet3dTextInfoById( id )
            if text:find("высшего качества") and premquest then
                local wposX, wposY = convert3DCoordsToScreen(posX, posY, posZ)
                local resX, resY = getScreenResolution()
                if wposX < resX and wposY < resY and isPointOnScreen (posX, posY, posZ,1) then
                    x2, y2, z2 = getCharCoordinates(PLAYER_PED)
                    x10, y10 = convert3DCoordsToScreen(x2, y2, z2)
                    renderFontDrawText(my_font, text, wposX, wposY, -1)
                end
            end
        end
    end
    
    end
end
    
    
function sampev.onServerMessage(color, text)
    if text:find("{ffffff}Осталось срубить дерева: 20 шт") then
        premquest = true
        --sampAddChatMessage("premquest started", -1)
    end
    if text:find("Вам был добавлен предмет 'Осколок Premium VIP'. Откройте инвентарь, используйте клавишу 'Y' или /invent") then
        premquest = false
        --sampAddChatMessage("premquest finished", -1)
    end
    if text:find("%[Информация%] {ffffff}Вы успешно спилили дерево высшего качества%.") then
        alrd_cut = alrd_cut + 1
        --sampAddChatMessage(""..alrd_cut, -1)
        return false
    end
end

Решил сделать на заказ помощник для квеста на премиум вип в ПХ. Работает все отлично, но когда сажусь в тс на жкране выскакивает текстуры которые закрывают пол экрана и потом игра вылетает. как починить?
 

Corrygan228

Участник
132
9
Как сделать так, чтобы скрипт не спамил строкой - Вы не верно указали время! Для разделения используйте ":"?
Все находится в беск.цикле

Lua:
--main беск цикл
        if autogov_switch == 1 then
            if autogov[1].v == '' or autogov[2].v == '' or autogov[3].v == '' or autogov['time'].v == '' then
                autogov_switch = 2
                sampAddChatMessage('{0099FF}[Prison Helper]:' .. white_color .. ' Вы заполнили не все строки!', -1)
                sampAddChatMessage('{0099FF}[Prison Helper]:' .. white_color .. ' Автоподача /gov выключена!', -1)
            else
                local h, m, s = autogov['time'].v:match("(%d+):(%d+):(%d+)")
                if h and m and s then
                    if os.date("%S") == s and os.date("%H") == h and os.date("%M") == m then
                        sampSendChat(u8:decode(autogov[1].v))
                        wait(2500)
                        sampSendChat(u8:decode(autogov[2].v))
                        wait(2500)
                        sampSendChat(u8:decode(autogov[3].v))
                    end
                else
                    sampAddChatMessage('Вы не верно указали время! Для разделения используйте "{0099FF}:{FFFFFF}"', -1)
                    autogov_switch = 2
                end
            end
        end
 

MLycoris

На вид оружие массового семяизвержения
Проверенный
1,993
2,186
как в мимгуи зарендерить картинку (в самом окне)
 

h0los

Активный
192
30
кто знает какой флаг надо в мимгуи использовать чтобы сделать прозрачное окно?
 

h0los

Активный
192
30
а как сделать когда у чела в руках дигл чтобы менялась картинка (и другие оружия)
 

Corrygan228

Участник
132
9
В чем ошибка? Отправляется просто команда /invite без id
Мне надо, чтобы после отправки инпут очистился
Lua:
if imgui.BeginPopupModal('##invite_human', _, imgui.WindowFlags.NoResize + imgui.WindowFlags.NoMove) then
    imgui.SetNextWindowSize(imgui.ImVec2(350, 150))
    imgui.SetNextWindowPos(imgui.ImVec2(sw / 2, sh / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
    imgui.CenterText(u8'Введите ID игрока, которого хотите принять.')
    imgui.SetCursorPosX((350-90)/2)
    imgui.PushItemWidth(90)
    imgui.InputText(u8'##ID', invite_id)
    imgui.PopItemWidth()
    imgui.NewLine()
    imgui.SetCursorPosX(35)
    if imgui.Button(u8'Принять', imgui.ImVec2(120, 30)) then
        if invite_id.v == '' then
            imgui.CloseCurrentPopup()
            sampAddChatMessage('{0099FF}[Prison Helper]:' .. white_color .. ' Вы не ввели ID!', -1)
        else
            imgui.CloseCurrentPopup()
            lua_thread.create(function()
                wait(1500)
                sampAddChatMessage('Вы нам подходите!', -1)
                wait(1500)
                sampAddChatMessage('/do В руках пакет с формой и ключом от шкафчика.', -1)
                wait(1500)
                sampAddChatMessage('/todo Передав пакет с формой*Можете приступать к работе', -1)
                wait(1500)
                sampAddChatMessage('/invite ' .. invite_id.v, -1) --тут ошибка
            end)
            invite_id.v = ''
        end
    end
    imgui.SameLine()
    imgui.SetCursorPosX(194)
    if imgui.Button(u8'Отмена', imgui.ImVec2(120, 30)) then
        imgui.CloseCurrentPopup()
    end
    imgui.EndPopup()
end
 
Последнее редактирование:
D

deleted-user-139653

Гость
Снова я...
Почему не показывает дистанцию когда игрок получает урон, за которым в спеке?
Хотя когда наношу урон, все показывает правильно...
EE9POYv.png


Lua:
local ev = require("samp.events")
local weap = require("game.weapons")

local spectatedPlayerId = nil
local damagelist = {}

function ev.onSpectatePlayer(playerId)
    spectatedPlayerId = playerId
end

local posY = 200

local weapons = {
    [0] = "Fist", "Brass Knuckles", "Golf Club", "Nightstick", "Knife", "Baseball Bat", "Shovel", "Pool Cue", "Katana", "Chainsaw",
    "Purple Dildo", "Dildo", "Vibrator", "Vibrator", "Flowers", "Cane", "Grenade", "Tear Gas", "Molotov", "", "", "",
    "9m", "Silenced 9mm", "Desert Eagle", "Shotgun", "Sawnoff Shotgun", "Combat Shotgun", "Micro Uzi", "MP5", "AK-47", "M4",
    "Tec-9", "Country Rifle", "Sniper Rifle", "RPG", "HS Rocket", "Flamethrower", "Minigun", "Satchel Charge", "Detonator",
    "Spraycan", "Extinguisher"
}

function ev.onBulletSync(playerId, data)
    if spectatedPlayerId and ((spectatedPlayerId == playerId and data.targetType == 1) or (data.targetId == spectatedPlayerId and data.targetType == 1)) then
        local nameT, nameP = sampGetPlayerNickname(data.targetId), sampGetPlayerNickname(playerId)
        local in_stream, TPED = sampGetCharHandleBySampPlayerId(data.targetId)

        if in_stream then
            local x, y, z = getCharCoordinates(TPED)
            local result, ped = sampGetCharHandleBySampPlayerId(spectatedPlayerId)
            local mX, mY, mZ = getCharCoordinates(ped)
            local dist = getDistanceBetweenCoords3d(x, y, z, mX, mY, mZ)

            if result then
                local damageInfo = (spectatedPlayerId == playerId) and
                    string.format("{30FF30}%s[%d] {F0F0F0}нанёс урон {FF3030}%s[%d]{F0F0F0}. Оружие: {303030}%s. {F0F0F0}Дистанция: {03FF03}%sм", nameP, playerId, nameT, data.targetId, weapons[data.weaponId], math.floor(dist)) or
                    string.format("{FF3030}%s[%d] {F0F0F0}получил урон {30FF30}%s[%d]{F0F0F0}. Оружие: {303030}%s. {F0F0F0}Дистанция: {03FF03}%sм", nameT, data.targetId, nameP, playerId, weapons[data.weaponId], math.floor(dist))

                table.insert(damagelist, { damageInfo = damageInfo })

                if #damagelist > 10 then
                    table.remove(damagelist, 1)
                end
            end
        end
    end
end

function main()
    local font = renderCreateFont("Arial", 10, 13)
    while true do
        wait(0)
        local pos = posY
        for i = 1, #damagelist do
            renderFontDrawText(font, i .. damagelist[i]["damageInfo"], 10, pos, 0xFFFFFFFF)
            pos = pos - renderGetFontDrawHeight(font)
        end
    end
end
 

Andrinall

Известный
702
518
В чем ошибка? Отправляется просто команда /invite без id
Мне надо, чтобы после отправки инпут очистился
Lua:
if imgui.BeginPopupModal('##invite_human', _, imgui.WindowFlags.NoResize + imgui.WindowFlags.NoMove) then
    imgui.SetNextWindowSize(imgui.ImVec2(350, 150))
    imgui.SetNextWindowPos(imgui.ImVec2(sw / 2, sh / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
    imgui.CenterText(u8'Введите ID игрока, которого хотите принять.')
    imgui.SetCursorPosX((350-90)/2)
    imgui.PushItemWidth(90)
    imgui.InputText(u8'##ID', invite_id)
    imgui.PopItemWidth()
    imgui.NewLine()
    imgui.SetCursorPosX(35)
    if imgui.Button(u8'Принять', imgui.ImVec2(120, 30)) then
        if invite_id.v == '' then
            imgui.CloseCurrentPopup()
            sampAddChatMessage('{0099FF}[Prison Helper]:' .. white_color .. ' Вы не ввели ID!', -1)
        else
            imgui.CloseCurrentPopup()
            lua_thread.create(function()
                wait(1500)
                sampAddChatMessage('Вы нам подходите!', -1)
                wait(1500)
                sampAddChatMessage('/do В руках пакет с формой и ключом от шкафчика.', -1)
                wait(1500)
                sampAddChatMessage('/todo Передав пакет с формой*Можете приступать к работе', -1)
                wait(1500)
                sampAddChatMessage('/invite ' .. invite_id.v, -1) --тут ошибка
            end)
            invite_id.v = ''
        end
    end
    imgui.SameLine()
    imgui.SetCursorPosX(194)
    if imgui.Button(u8'Отмена', imgui.ImVec2(120, 30)) then
        imgui.CloseCurrentPopup()
    end
    imgui.EndPopup()
end
Ну так очищай его после отправки, а не сразу после запуска потока)
Прикол в том, что поток после запуска работает параллельно и, следовательно, у тебя очищается раньше, чем отправляется.
(invite_id.v = '' перекинь в поток после отправки /invite)

Снова я...
Почему не показывает дистанцию когда игрок получает урон, за которым в спеке?
Хотя когда наношу урон, все показывает правильно...
EE9POYv.png


Lua:
local ev = require("samp.events")
local weap = require("game.weapons")

local spectatedPlayerId = nil
local damagelist = {}

function ev.onSpectatePlayer(playerId)
    spectatedPlayerId = playerId
end

local posY = 200

local weapons = {
    [0] = "Fist", "Brass Knuckles", "Golf Club", "Nightstick", "Knife", "Baseball Bat", "Shovel", "Pool Cue", "Katana", "Chainsaw",
    "Purple Dildo", "Dildo", "Vibrator", "Vibrator", "Flowers", "Cane", "Grenade", "Tear Gas", "Molotov", "", "", "",
    "9m", "Silenced 9mm", "Desert Eagle", "Shotgun", "Sawnoff Shotgun", "Combat Shotgun", "Micro Uzi", "MP5", "AK-47", "M4",
    "Tec-9", "Country Rifle", "Sniper Rifle", "RPG", "HS Rocket", "Flamethrower", "Minigun", "Satchel Charge", "Detonator",
    "Spraycan", "Extinguisher"
}

function ev.onBulletSync(playerId, data)
    if spectatedPlayerId and ((spectatedPlayerId == playerId and data.targetType == 1) or (data.targetId == spectatedPlayerId and data.targetType == 1)) then
        local nameT, nameP = sampGetPlayerNickname(data.targetId), sampGetPlayerNickname(playerId)
        local in_stream, TPED = sampGetCharHandleBySampPlayerId(data.targetId)

        if in_stream then
            local x, y, z = getCharCoordinates(TPED)
            local result, ped = sampGetCharHandleBySampPlayerId(spectatedPlayerId)
            local mX, mY, mZ = getCharCoordinates(ped)
            local dist = getDistanceBetweenCoords3d(x, y, z, mX, mY, mZ)

            if result then
                local damageInfo = (spectatedPlayerId == playerId) and
                    string.format("{30FF30}%s[%d] {F0F0F0}нанёс урон {FF3030}%s[%d]{F0F0F0}. Оружие: {303030}%s. {F0F0F0}Дистанция: {03FF03}%sм", nameP, playerId, nameT, data.targetId, weapons[data.weaponId], math.floor(dist)) or
                    string.format("{FF3030}%s[%d] {F0F0F0}получил урон {30FF30}%s[%d]{F0F0F0}. Оружие: {303030}%s. {F0F0F0}Дистанция: {03FF03}%sм", nameT, data.targetId, nameP, playerId, weapons[data.weaponId], math.floor(dist))

                table.insert(damagelist, { damageInfo = damageInfo })

                if #damagelist > 10 then
                    table.remove(damagelist, 1)
                end
            end
        end
    end
end

function main()
    local font = renderCreateFont("Arial", 10, 13)
    while true do
        wait(0)
        local pos = posY
        for i = 1, #damagelist do
            renderFontDrawText(font, i .. damagelist[i]["damageInfo"], 10, pos, 0xFFFFFFFF)
            pos = pos - renderGetFontDrawHeight(font)
        end
    end
end
По ощущениям я почти нифига не поменял, но у меня показывает в обе стороны дистанцию.
И зачем тебе отдельная таблица с названиями ганов, если можно local weapons = require('game.weapons').names ?
Lua:
function ev.onBulletSync(playerId, data)
    if not spectatedPlayerId or data.targetType ~= 1 then return true end
   
    local nameT, nameP = sampGetPlayerNickname(data.targetId), sampGetPlayerNickname(playerId)
    local in_stream, TPED = sampGetCharHandleBySampPlayerId(data.targetId)
    if not in_stream then return true end

    local x, y, z = getCharCoordinates(TPED)
    local result, ped = sampGetCharHandleBySampPlayerId(playerId)
    if not result then return true end
   
    local mX, mY, mZ = getCharCoordinates(ped)
    local dist = getDistanceBetweenCoords3d(x, y, z, mX, mY, mZ)

    local damageInfo = (spectatedPlayerId == playerId) and
        ("{30FF30}%s[%d] {F0F0F0}нанёс урон {FF3030}%s[%d]{F0F0F0}. Оружие: {303030}%s. {F0F0F0}Дистанция: {03FF03}%sм"):format(nameP, playerId, nameT, data.targetId, weapons[data.weaponId], math.floor(dist)) or
        ("{FF3030}%s[%d] {F0F0F0}получил урон {30FF30}%s[%d]{F0F0F0}. Оружие: {303030}%s. {F0F0F0}Дистанция: {03FF03}%sм"):format(nameT, data.targetId, nameP, playerId, weapons[data.weaponId], math.floor(dist))

    table.insert(damagelist, { damageInfo = damageInfo })

--    sampAddChatMessage(damageInfo, -1)

    if #damagelist > 10 then
        table.remove(damagelist, 1)
    end
end
1702572229904.png
 
Последнее редактирование:
  • Влюблен
Реакции: deleted-user-139653