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

Andrinall

Известный
678
531
Помогите народ.
Как мне узнать умер ли персонаж, эвент
onPlayerDeath тупо не работает на аризоне, либо я что то не так делаю, хотя на других проектах все работает отлично.
Можно попробовать хукать CTaskSimpleDie::StartAnim
UPD: ещё можно хукнуть CTaskSimpleDie::CreateFirstSubTask - эффект примерно тот же
hooks.jmp.new('void*(__thiscall*)(int, int)', onPedDie, 0x6302D0)
(но если умирает серверный актёр то координаты через getCharCoordinates будут не верны,
да и в целом с актёрами работает так себе)
Lua:
local hooks = require 'hooks'
function onPedPlayingDieAnim(this, cped)
    pcall(function(cped) -- pcall чтоб не крашить игру в случае косяков в коде)
        local hped = getCharPointerHandle(cped)
        if hped == -1 then return end -- игнор невалидных педов
        --if hped == PLAYER_PED then return end -- игнорить свою смерть
        local res, pid = sampGetPlayerIdByCharHandle(hped)
        --if not res then return end -- игнорить смерть игровых актёров, вывод только смертей игроков
        local x, y, z = getCharCoordinates(hped)

        print("=============================")
        print("Ped is dead")
        print("CPed :", tostring(cped))
        print("Handle:", hped)
        print("IsLocal:", hped == PLAYER_PED)
        print("Coordinates:{", x, y, z ,"}")
        print("IsPlayer:", tostring(res), "ID:", pid)
        if res then print("IsNPC:", sampIsPlayerNPC(pid)) end
        print("=============================")

    end, cped)
    return hook_CTaskSimpleDie_StartAnim(this, cped) -- вызов ориг.метода
end


function main()
    hook_CTaskSimpleDie_StartAnim = hooks.jmp.new('int(__thiscall*)(int, int)', onPedPlayingDieAnim, 0x637520)
    if hook_CTaskSimpleDie_StartAnim then print("hook_CTaskSimpleDie_StartAnim Installed") end
    repeat wait(100) until isSampAvailable()
    -- ... code
end

function onScriptTerminate(sc, qg)
    if sc == thisScript() then
        if hook_CTaskSimpleDie_StartAnim then
            hook_CTaskSimpleDie_StartAnim.stop()
            onPedPlayingDieAnim = nil
            hook_CTaskSimpleDie_StartAnim = nil
        end
        collectgarbage()
        collectgarbage()
    end
end
изображение_2023-05-20_091831534.png


или через samp.Lua обрабатывать ApplyActorAnimation
Lua:
local ev = require 'lib.samp.events'
function ev.onApplyActorAnimation(actorId, animLib, animName, fDelta, bLoop, bLockX, bLockY, bFreeze, time)
    if animLib == "PED" and animName == "KO_SHOT_FRONT" then
        -- вместо PED KO_SHOT_FRONT ту анимку, которая ставится актёру(почекать через print(animLib, animName))
        sampAddChatMessage("Actor is dead", -1)
    end
end
 
Последнее редактирование:
  • Нравится
Реакции: Moorell и why ega

why ega

РП игрок
Модератор
2,540
2,233
Можно попробовать хукать CTaskSimpleDie::StartAnim
UPD: ещё можно хукнуть CTaskSimpleDie::CreateFirstSubTask - эффект примерно тот же
hooks.jmp.new('void*(__thiscall*)(int, int)', onPedDie, 0x6302D0)
(но если умирает серверный актёр то координаты через getCharCoordinates будут не верны,
да и в целом с актёрами работает так себе)
Lua:
local hooks = require 'hooks'
function onPedPlayingDieAnim(this, cped)
    pcall(function(cped) -- pcall чтоб не крашить игру в случае косяков в коде)
        local hped = getCharPointerHandle(cped)
        if hped == -1 then return end -- игнор невалидных педов
        --if hped == PLAYER_PED then return end -- игнорить свою смерть
        local res, pid = sampGetPlayerIdByCharHandle(hped)
        --if not res then return end -- игнорить смерть игровых актёров, вывод только смертей игроков
        local x, y, z = getCharCoordinates(hped)

        print("=============================")
        print("Ped is dead")
        print("CPed :", tostring(cped))
        print("Handle:", hped)
        print("IsLocal:", hped == PLAYER_PED)
        print("Coordinates:{", x, y, z ,"}")
        print("IsPlayer:", tostring(res), "ID:", pid)
        if res then print("IsNPC:", sampIsPlayerNPC(pid)) end
        print("=============================")

    end, cped)
    return hook_CTaskSimpleDie_StartAnim(this, cped) -- вызов ориг.метода
end


function main()
    hook_CTaskSimpleDie_StartAnim = hooks.jmp.new('int(__thiscall*)(int, int)', onPedPlayingDieAnim, 0x637520)
    if hook_CTaskSimpleDie_StartAnim then print("hook_CTaskSimpleDie_StartAnim Installed") end
    repeat wait(100) until isSampAvailable()
    -- ... code
end

function onScriptTerminate(sc, qg)
    if sc == thisScript() then
        if hook_CTaskSimpleDie_StartAnim then
            hook_CTaskSimpleDie_StartAnim.stop()
            onPedPlayingDieAnim = nil
            hook_CTaskSimpleDie_StartAnim = nil
        end
        collectgarbage()
        collectgarbage()
    end
end
Посмотреть вложение 202089


или через samp.Lua обрабатывать ApplyActorAnimation
Lua:
local ev = require 'lib.samp.events'
function ev.onApplyActorAnimation(actorId, animLib, animName, fDelta, bLoop, bLockX, bLockY, bFreeze, time)
    if animLib == "PED" and animName == "KO_SHOT_FRONT" then
        -- вместо PED KO_SHOT_FRONT ту анимку, которая ставится актёру(почекать через print(animLib, animName))
        sampAddChatMessage("Actor is dead", -1)
    end
end
если пошла тема с хуками, то можно попробовать хукать этот метод
C++:
// R1
BOOL CActor::IsDead() {
    return ((BOOL(__thiscall*)(CActor*))GetAddress(0x98020))(this);
}
правда я хрен знает, как он работает и работает ли так, как нужно
 
  • Нравится
Реакции: Andrinall

ArtemHaker228

Новичок
18
3
Хочу задать очень интересный вопрос!
Возможно ли как-то через Lua сделать скрипт который будет заменять текстуру автомобиля в котором сидит игрок? Или другие способа реализовать это идею есть ли?
 

why ega

РП игрок
Модератор
2,540
2,233
Хочу задать очень интересный вопрос!
Возможно ли как-то через Lua сделать скрипт который будет заменять текстуру автомобиля в котором сидит игрок? Или другие способа реализовать это идею есть ли?
Можно изменить модельку автомобиля
 

Dmitriy Makarov

25.05.2021
Проверенный
2,478
1,113
Помоги пожалуйста.
I don't think you can get help with that here. This is not an easy task, because you need to parse the site using asynchronous requests, and not everyone knows this. Even if someone agrees to help you, then most likely he will not do it for free. You can search the forum for topics where they ask the same question as you and do the same as there.
 

mambahit

Новичок
1
0
Помогите хотел написать скрипт для аризоны который при нажатии 3 будет юзать сигареты(/smoke) пока у персонажа не будет 100хп
сигареты используются не всегда с первой попытки иногда выводится строка "достал сигарету с зажигалкой и попытался закурить (Неудачно)" нужно что бы скрипт при нахождении этого сообщения в чате повторял попытку с задержкой 1000мс пока в чате не появится "достал сигарету с зажигалкой и закурил" когда сигарета кончается появляется сообщение в чате "докурил(а) сигарету и выбросил(а) окурок" нужно чтобы после этого использовалась сигарета.
вот говнокод
Lua:
[/B]
script_name('smoke_to_100hp')
script_author('Porovozov')
script_description('Скрипт который использует /smoke пока не будет 100хп')
require "lib.moonloader"
local keys = require "vkeys"
local on = require "lib.samp.events"
local tag = "[smoke to 100 hp]"
local label = 0
local main_color = 0x4392DC
local main_color_text = "{FFADDC}"
local white_color = "{FFFFFF}"
function main()
    if not isSampLoaded() or not isSampfuncsLoaded() then return end
    while not isSampAvailable() do wait(100) end
    sampRegisterChatCommand("smok", cmd_smok)
    sampAddChatMessage(tag .. "smoke", main_collor)
    
    while true do
        wait(0)
        if  isKeyJustPressed(VK_3) then
            sampAddChatMessage("НАКУРКА НАЧАТА {4392DC}", main_color)
            sampSendChat("/smoke")
        end
    end
end
function cmd_smok(arg)
    sampAddChatMessage("Здарова куряга {FFADDC}", main_color)
end
function on.onServerMessage(color, text)
    lua_thread.create(function()
        if text:find("достал сигарету с зажигалкой и попытался закурить (Неудачно)") then
            wait(1000)
            sampSendChat("/smoke")
        end
    end)
end
[B]
 

Andrinall

Известный
678
531
если пошла тема с хуками, то можно попробовать хукать этот метод
C++:
// R1
BOOL CActor::IsDead() {
    return ((BOOL(__thiscall*)(CActor*))GetAddress(0x98020))(this);
}
правда я хрен знает, как он работает и работает ли так, как нужно
Ну тут уже скорее не хук, а вызов метода.
Работать это будет не как обработка "события", а именно как вызов того же, например, муновского isCharDead(Ped ped), только в прослойке будет ffi
 
  • Нравится
Реакции: why ega

why ega

РП игрок
Модератор
2,540
2,233
Ну тут уже скорее не хук, а вызов метода.
Работать это будет не как обработка "события", а именно как вызов того же, например, муновского isCharDead(Ped ped), только в прослойке будет ffi
Да, затупил чет, почему-то подумал, что этот метод вызывается при смерти
 
  • Нравится
Реакции: Andrinall

m1racles

Активный
199
32
Lua:
function func_string(arg, arg2)
    if arg == 1 then
        mainIni.strings.string1 = arg2
        sampAddChatMessage(mainIni.strings.string1, -1)
        inicfg.save(mainIni, 'strings.ini')
    end
end
поможет кто нибудь? не сохраняется
 

Sadow

Известный
1,436
585
Lua:
function func_string(arg, arg2)
    if arg == 1 then
        mainIni.strings.string1 = arg2
        sampAddChatMessage(mainIni.strings.string1, -1)
        inicfg.save(mainIni, 'strings.ini')
    end
end
поможет кто нибудь? не сохраняется
Если это функция команды, то попробуй так:
Lua:
function func_string(arg, arg2)
    if arg == "1" then -- или вместо "1" введи tostring(1)
        mainIni.strings.string1 = arg2
        sampAddChatMessage(mainIni.strings.string1, -1)
        inicfg.save(mainIni, 'strings.ini')
    end
end
 
  • Bug
  • Нравится
Реакции: m1racles, zzalupka и DZONE

bulba$h

Активный
332
91
почему оба скрипта при запуске гташки просто напросто крашит?

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

function sampev.onPlayerDeathNotification(killerID, killerID2, reason)
    local nick = sampGetPlayerNickname(killerID)
    local nick2 = sampGetPlayerNickname(killerID2)
    local gun = weap.get_name(reason)
    local format = string.format("{FF5151}%s >> {FFFFFF}%s << {51C0FF}%s",nick, gun, nick2)
    sampAddChatMessage(format, 0xFFFFFFFF)
end

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

local hui = {}

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

    local font = renderCreateFont("Arial", 10, 13)

    while true do wait(0)

        local x, y = 500, 500
        for i = 1, #hui do
            renderFontDrawText(font, hui[i], x, y, 0xFFFFFFFF)
            y = y + 20
        end
    end
end

function sampev.onPlayerDeathNotification(killer, victim, reason)
    local killernick = sampGetPlayerNickname(killer)
    local victimnick = sampGetPlayerNickname(victim)
    local gun = weap.get_name(reason)
    local format = string.format("Игрок: %s Убил: %s Оружие: %s", killernick, victimnick, gun)
    table.insert(hui, format)
    if #hui > 5 then
        table.remove(hui, 1)
    end
end
 
  • Эм
Реакции: percheklii

Moorell

Участник
55
12
почему оба скрипта при запуске гташки просто напросто крашит?

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

function sampev.onPlayerDeathNotification(killerID, killerID2, reason)
    local nick = sampGetPlayerNickname(killerID)
    local nick2 = sampGetPlayerNickname(killerID2)
    local gun = weap.get_name(reason)
    local format = string.format("{FF5151}%s >> {FFFFFF}%s << {51C0FF}%s",nick, gun, nick2)
    sampAddChatMessage(format, 0xFFFFFFFF)
end

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

local hui = {}

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

    local font = renderCreateFont("Arial", 10, 13)

    while true do wait(0)

        local x, y = 500, 500
        for i = 1, #hui do
            renderFontDrawText(font, hui[i], x, y, 0xFFFFFFFF)
            y = y + 20
        end
    end
end

function sampev.onPlayerDeathNotification(killer, victim, reason)
    local killernick = sampGetPlayerNickname(killer)
    local victimnick = sampGetPlayerNickname(victim)
    local gun = weap.get_name(reason)
    local format = string.format("Игрок: %s Убил: %s Оружие: %s", killernick, victimnick, gun)
    table.insert(hui, format)
    if #hui > 5 then
        table.remove(hui, 1)
    end
end
Надо не local sampev = require("samp.events"), а нужно local sampev = require("lib.samp.events")