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

tomate kudasai/

Участник
94
18
Кароче, почему то кикает запись маршрутов на раксамп лайт. На обычном сампе, все работает.
Код раксампа:
Lua:
function sampev.onSendPlayerSync()
    if play then return false end
end
function sampev.onSendVehicleSync()
    if play then return false end
end
function sampev.onSendTrailerSync()
    if play then return false end
end
local pack = 0
local sleeping = 50

local message = function(text) return print('[Router-Recorder] '..text) end

function playRoute(name)
    local f = io.open('routes\\'..name..'.rr', 'r')
    if not f then
        return message("Маршрут не найден!")
    end
    local r = f:read('a')
    f:close()
    playroute = json.decode(r)
    play = true
    message('Запустил маршрут "'..name..'" ')
    playcurrsetroute()
end
function bitStream.sendTrailerSynchronization(PACKET)
    local bs = bitStream.new()
    bs:writeUInt8(210)
    bs:writeVector3(PACKET)
    bs:writeUInt16(TrID)
    bs:writeFloat(PACKET.q0)
    bs:writeFloat(PACKET.q1)
    bs:writeFloat(PACKET.q2)
    bs:writeFloat(PACKET.q3)
    bs:writeVector3({x = PACKET.sx, y = PACKET.sy, z = PACKET.sz})
    bs:writeVector3({x = PACKET.sx, y = PACKET.sy, z = PACKET.sz})
    bs:writeVector3({x = 0.0, y = 0.0, z = 0.0}) -- вот тут тупанул, записал маршрут без turnSpeed
    bs:writeVector3({x = PACKET.rx, y = PACKET.ry, z = PACKET.rz})
    bs:writeVector3({x = PACKET.dx, y = PACKET.dy, z = PACKET.dz})
    bs:writeVector3({x = PACKET.spx, y = PACKET.spy, z = PACKET.spz})
    bs:writeUInt32(PACKET.unk)
    bs:sendPacket()
end
function bitStream.sendVehicleSynchronization(PACKET)
    local bs = bitStream.new()
    bs:writeUInt8(200)
    bs:writeUInt16(getBotVehicle())
    bs:writeUInt16(PACKET.lr)
    bs:writeUInt16(PACKET.ud)
    bs:writeUInt16(PACKET.keys)
    bs:writeFloat(PACKET.q0)
    bs:writeFloat(PACKET.q1)
    bs:writeFloat(PACKET.q2)
    bs:writeFloat(PACKET.q3)
    bs:writeVector3(PACKET)
    bs:writeVector3({x = PACKET.sx, y = PACKET.sy, z = PACKET.sz})
    bs:writeFloat(1500)
    bs:writeUInt8(getBotHealth() )
    bs:writeUInt8(getBotArmor() )
    bs:writeUInt8(0)
    bs:writeUInt8(0)
    bs:writeUInt8(0)
    bs:writeUInt16(TrID or 0)
    bs:writeFloat(PACKET.lean)
    bs:writeFloat(0)
    bs:sendPacket()
end
function playcurrsetroute()
    newTask(function ()
       while play do
            pack = pack + 1
            if not playroute[pack] or not play then pack = #playroute goto pepe end
            if playroute[pack].veh_ == 1 and TrID ~= 0 then
                if not playroute[pack] or not play then pack = #playroute goto pepe end
                bitStream.sendVehicleSynchronization(playroute[pack].veh)
                sleeping = int(playroute[pack].veh.timer)
                if not sleeping then sleeping = int(playroute[pack].tr.timer) elseif sleeping < 5 then sleeping = int(playroute[pack].tr.timer) end
                print(sleeping)
                bitStream.sendTrailerSynchronization(playroute[pack].tr)
                setBotPosition(playroute[pack].veh.x, playroute[pack].veh.y, playroute[pack].veh.z)
            end
            if playroute[pack].veh_ == 1 and TrID == 0 then
                if not playroute[pack] or not play then pack = #playroute goto pepe end
                bitStream.sendVehicleSynchronization(playroute[pack].veh)
                setBotPosition(playroute[pack].veh.x, playroute[pack].veh.y, playroute[pack].veh.z)
            end
            ::pepe::
            if pack == #playroute then
                play = false;
                message('Закончил маршрут.')
                playroute = {}
            end
            wait(sleeping)
        end
    end)
end
Код на самп:
Lua:
local message = function (text) return sampAddChatMessage('[{8de33c}Route-Recorder{ffffff}] {1a9ded}'..text, -1); end
require('moonloader')
local sampev = require('samp.events')
local json = require('cjson')
local route_name
local recording = false
local route = {}
local trailer_record = false
local lasttime = os.clock() * 1000
local playroute = {}
local play = false
local int = tonumber
local loop_route
local trailer_Id = 0
function main()
    while not isSampAvailable() do wait(0) end
    message('Загружен! (/rr rec [route name] | /rr trailer_record | /rr play [route name] [if loop route 1 or 0])')
    createDirectory(getWorkingDirectory()..'\\RouteRecorder')
    sampRegisterChatCommand('rr', function (arg)
        if arg == 'trailer_record' then
            trailer_record = not trailer_record
            message('Запись маршрутов с трейлером: '..(trailer_record and '{68ff00}Включена' or "{ff0000}Выключена"))
        elseif arg:match('rec %S+') then
            route_name = arg:match('rec (%S+)')
            message('Чтобы начать запись маршрута {ff0000}"'..route_name..'"{1a9ded} нажмите клавишу {ff0000} Q')
        elseif arg:match('play %S+ %S+') then
            local name, loop = arg:match('play (%S+) (%S+)')
            print(name, loop)
            local f = io.open('moonloader\\RouteRecorder\\'..name..'.rr', 'r')
            if not f then
                return message("Маршрут не найден!")
            end
            loop_route = loop == "1"
            local r = f:read('a')
            f:close()
            playroute = json.decode(r)
            play = true
            message('Запустил маршрут {ff0000}"'..name..'"{1a9ded} Нажмите клавишу {ff0000}Q{1a9ded} чтобы остановить его.')
            playRoute()
        elseif arg:match('trid %d+') then
            trailer_Id = arg:match('trid (%d+)')
            message('Айди трейлера: {ff0000}'..trailer_Id)
        end
    end)
    while true do
        wait(0)
        if route_name then
            if wasKeyPressed(VK_Q) and not sampIsCursorActive() then
                recording = not recording
                if recording then
                    message('Начал записывать маршрут {ff0000}"'..route_name..'"')
                    lasttime = os.clock() * 1000
                    recording = true
                else
                    message('Закончил записывать маршрут! Сохроняю...')
                    local f = io.open('moonloader\\RouteRecorder\\'..route_name..'.rr', 'w')
                    f:write(json.encode(route))
                    f:close()
                    route_name = ''
                    play = false;
                    route = {}
                    playroute = {}
                    trailer_record = false
                    recording = false
                end
            end
        end
        if play then
            if wasKeyPressed(VK_Q) and not sampIsCursorActive() then
                play = false;
                message('Остановил маршрут.')
                route = {}
                playroute = {}
                trailer_record = false
                recording = false
            end
        end
    end
end
function sampev.onSendPlayerSync(data)
    if play then return false end
    if recording then
        route[#route+1] = {
            tr_ = 0,
            pl_ = 1,
            veh_ = 0,
            pl = {
                ud = int(data.upDownKeys),
                keys = int(data.keysData),
                x = int(data.position.x),
                y = int(data.position.y),
                z = int(data. position. z),
                q0 = int(data.quaternion[0]),
                q1 = int(data.quaternion[1]),
                q2 = int(data.quaternion[2]),
                q3 = int(data.quaternion[3]),
                sx = int(data.moveSpeed.x),
                sy = int(data.moveSpeed.y),
                sz = int(data.moveSpeed.z),
                aid = int(data.animation.id),
                timer = int(os.clock() * 1000 - lasttime)
            }
        }
        lasttime = os.clock() * 1000
        printStringNow('~g~[Router-Recorder]~b~~h~ Recording player sync... Recorded: '..#route..' packets.', 1000)
    end
end
function sampev.onSendVehicleSync(data)
    if play then return false end
    if recording then
        if trailer_record then
            route[#route+1] = {
                tr_ = 1,
                pl_ = 0,
                veh_ = 1,
                veh = {
                    lr = int(data.leftRightKeys),
                    ud = int(data.upDownKeys),
                    keys = int(data.keysData),
                    q0 = int(data.quaternion[0]),
                    q1 = int(data.quaternion[1]),
                    q2 = int(data.quaternion[2]),
                    q3 = int(data.quaternion[3]),
                    x = int(data.position.x),
                    y = int(data.position.y),
                    z = int(data.position.z),
                    sx = int(data.moveSpeed.x),
                    sy =int( data.moveSpeed.y),
                    sz = int(data.moveSpeed.z),
                    lean = int(data.bikeLean)
                }
            }
        else
            route[#route+1] = {
                tr_ = 0,
                pl_ = 0,
                veh_ = 1,
                veh = {
                    lr = int(data.leftRightKeys),
                    ud = int(data.upDownKeys),
                    keys = int(data.keysData),
                    q0 = int(data.quaternion[0]),
                    q1 = int(data.quaternion[1]),
                    q2 = int(data.quaternion[2]),
                    q3 = int(data.quaternion[3]),
                    x = int(data.position.x),
                    y = int(data.position.y),
                    z = int(data.position.z),
                    sx = int(data.moveSpeed.x),
                    sy =int( data.moveSpeed.y),
                    sz = int(data.moveSpeed.z),
                    lean = int(data.bikeLean),
                    timer = int(os.clock() * 1000 - lasttime)
                }
            }
            printStringNow('~g~[Router-Recorder]~b~~h~ Recording vehicle sync... Recorded: '..#route..' packets.', 1000)
            lasttime = os.clock() * 1000
        end
    end
end
function sampev.onSendTrailerSync(data)
    if play then return false end
    if recording then
        if route[#route] then
            if route[#route].tr_ then
                route[#route].tr = {
                    x = int(data.position.x),
                    y = int(data.position.y),
                    z = int(data.position.z),
                    q0 = int(data.quaternion[0]),
                    q1 = int(data.quaternion[1]),
                    q2 = int(data.quaternion[2]),
                    q3 = int(data.quaternion[3]),
                    sx = int(data.moveSpeed.x),
                    sy = int(data.moveSpeed.y),
                    sz = int(data.moveSpeed.z),
                    rx = int(data.roll.x),
                    ry = int(data.roll.y),
                    rz = int(data.roll.z),
                    dx = int(data.direction.x),
                    dy = int(data.direction.y),
                    dz = int(data.direction.z),
                    spx =int( data.speed.x),
                    spy =int( data.speed.y),
                    spz =int( data.speed.z),
                    unk =int( data.unk),
                    timer =int( os.clock() * 1000 - lasttime)
                }
                printStringNow('~g~[Router-Recorder]~b~~h~ Recording trailer sync... Recorded: '..#route..' packets.', 1000)
                lasttime = os.clock() * 1000
            end
        end
    end
end
function playRoute()
    lua_thread.create(function ()
        local pack = 0
        local sleeping = 50
        while play do
            wait(sleeping)
            pack = pack + 1
            local q = playroute[pack]
           
            if not q or not play then pack = #playroute goto pepe end
            if q.pl_ == 1 then
                if not q or not play then pack = #playroute goto pepe end
                q = q.pl
                local data = samp_create_sync_data('player')
                data.upDownKeys = q.ud
                data.keysData = q.keys
                data.position.x = q.x
                data.position.y = q.y
                data. position. z = q.z
                data.quaternion[0] = q.q0
                data.quaternion[1] = q.q1
                data.quaternion[2] = q.q2
                data.quaternion[3] = q.q3
                data.moveSpeed.x = q.sx
                data.moveSpeed.y = q.sy
                data.moveSpeed.z = q.sz
                data.animation.id = q.aid
                sleeping = q.timer
                data.send()
                setCharCoordinatesNoOffset(PLAYER_PED, q.x, q.y, q.z)
                setCharQuaternion(PLAYER_PED, q.q1, q.q2, q.q3, q.q0)
                printStringNow('~g~[Router-Recorder]~b~~h~ Playing player sync... Played: '..pack..'/'..#playroute..' packets.', 1000)
            end
            if q.veh_ == 1 and trailer_Id ~= 0 then
                if not q or not play then pack = #playroute goto pepe end
                local old, vehsyncsend, trailersyncsend
                old = q
                q = q.veh
                local data = samp_create_sync_data('vehicle')
                data.leftRightKeys = q.lr
                data.upDownKeys = q.ud
                data.keysData = q.keys
                data.quaternion[0] = q.q0
                data.quaternion[1] = q.q1
                data.quaternion[2] = q.q2
                data.quaternion[3] = q.q3
                data.position.x = q.x
                data.position.y = q.y
                data. position. z = q.z
               
                data.moveSpeed.x = q.sx
                data.moveSpeed.y = q.sy
                data.moveSpeed.z = q.sz
                data.bikeLean = q.lean
                data.vehicleId = select(2, sampGetVehicleIdByCarHandle(storeCarCharIsInNoSave(PLAYER_PED)))
                data.trailerId = int(trailer_Id)
                data.vehicleHealth = 1500
                sleeping = int(old.veh.timer)
                if not sleeping then
                    sleeping = int(old.tr.timer)
                else
                    if sleeping < 10 then
                        sleeping = int(old.tr.timer)
                    end
                end
               
                data.send()
                q = old.tr
               
               
                data = samp_create_sync_data('trailer')
                data.position.x = q.x
                data.position.y = q.y
                data. position. z = q.z
                data.quaternion[0] = q.q0
                data.quaternion[1] = q.q1
                data.quaternion[2] = q.q2
                data.quaternion[3] = q.q3
                data.moveSpeed.x = q.sx
                data.moveSpeed.y = q.sy
                data.moveSpeed.z = q.sz
                data.roll.x = q.rx
                data.roll.y = q.ry
                data.roll.z = q.rz
               
                data.direction.x = q.dz
                data.direction.y = q.dy
                data.direction.z = q.dz
               
                data.speed.x = q.spx
                data.speed.y = q.spy
                data.speed.z = q.spz
                data.unk = q.unk
                data.trailerId = int(trailer_Id)
                print('gg')
               
                data.send()
                setCarCoordinatesNoOffset(storeCarCharIsInNoSave(PLAYER_PED), q.x, q.y, q.z)
                printStringNow('~g~[Router-Recorder]~b~~h~ Playing trailer sync... Played: '..pack..'/'..#playroute..' packets.', 1000)
            end
            if q.veh_ == 1 and q.tr_ == 0 then
                if not q or not play then pack = #playroute goto pepe end
                q = q.veh
                local data = samp_create_sync_data('vehicle')
                data.leftRightKeys = int(q.lr)
                data.upDownKeys = q.ud
                data.keysData = q.keys
                data.quaternion[0] = q.q0
                data.quaternion[1] = q.q1
                data.quaternion[2] = q.q2
                data.quaternion[3] = q.q3
                data.position.x = q.x
                data.position.y = q.y
                data. position. z = q.z
               
                data.moveSpeed.x = q.sx
                data.moveSpeed.y = q.sy
                data.moveSpeed.z = q.sz
                data.bikeLean = q.lean
                sleeping = q.timer
                data.vehicleId = select(2, sampGetVehicleIdByCarHandle(storeCarCharIsInNoSave(PLAYER_PED)))
                data.send()
                setCarCoordinatesNoOffset(storeCarCharIsInNoSave(PLAYER_PED), q.x, q.y, q.z)
                printStringNow('~g~[Router-Recorder]~b~~h~ Playing vehicle sync... Played: '..pack..'/'..#playroute..' packets.', 1000)
            end
            ::pepe::
            if pack == #playroute then
                if loop_route then
                    pack = 0
                else
                    play = false;
                    message('Закончил маршрут.')
                    route = {}
                    playroute = {}
                    trailer_record = false
                    recording = false
                end
            end
        end
    end)
end
function samp_create_sync_data(sync_type, copy_from_player)
    local ffi = require 'ffi'
    local sampfuncs = require 'sampfuncs'
    local raknet = require 'samp.raknet'
    copy_from_player = copy_from_player or true
    local sync_traits = {
        player = {'PlayerSyncData', raknet.PACKET.PLAYER_SYNC, sampStorePlayerOnfootData},
        vehicle = {'VehicleSyncData', raknet.PACKET.VEHICLE_SYNC, sampStorePlayerIncarData},
        passenger = {'PassengerSyncData', raknet.PACKET.PASSENGER_SYNC, sampStorePlayerPassengerData},
        aim = {'AimSyncData', raknet.PACKET.AIM_SYNC, sampStorePlayerAimData},
        trailer = {'TrailerSyncData', raknet.PACKET.TRAILER_SYNC, sampStorePlayerTrailerData},
        unoccupied = {'UnoccupiedSyncData', raknet.PACKET.UNOCCUPIED_SYNC, nil},
        bullet = {'BulletSyncData', raknet.PACKET.BULLET_SYNC, nil},
        spectator = {'SpectatorSyncData', raknet.PACKET.SPECTATOR_SYNC, nil}
    }
    local sync_info = sync_traits[sync_type]
    local data_type = 'struct ' .. sync_info[1]
    local data = ffi.new(data_type, {})
    local raw_data_ptr = tonumber(ffi.cast('uintptr_t', ffi.new(data_type .. '*', data)))
    if copy_from_player then
        local copy_func = sync_info[3]
        if copy_func then
            local _, player_id
            if copy_from_player == true then
                _, player_id = sampGetPlayerIdByCharHandle(PLAYER_PED)
            else
                player_id = tonumber(copy_from_player)
            end
            copy_func(player_id, raw_data_ptr)
        end
    end
    local func_send = function()
        local bs = raknetNewBitStream()
        raknetBitStreamWriteInt8(bs, sync_info[2])
        raknetBitStreamWriteBuffer(bs, raw_data_ptr, ffi.sizeof(data))
        raknetSendBitStreamEx(bs, sampfuncs.HIGH_PRIORITY, sampfuncs.UNRELIABLE_SEQUENCED, 1)
        raknetDeleteBitStream(bs)
    end
    local mt = {
        __index = function(t, index)
            return data[index]
        end,
        __newindex = function(t, index, value)
            data[index] = value
        end
    }
    return setmetatable({send = func_send}, mt)
end
 
  • Грустно
Реакции: qdIbp

dmitry.karle

Известный
410
108
каким образом можно получить нажатие Y / N игрока из спека? через функцию
Lua:
function onReceiveRpc(id, bitStream)
end

можно ли как-то через эту функцию ловить Y / N из спека и передавать её в функцию?
Lua:
function onPlayerSync(playerId, data)
end

сервером не получается получить Y / N через onPlayerSync(playerId, data)
 
Последнее редактирование:

droffet

Новичок
2
0
Проблема, выкидывает ошибку ни с того ни с сего от функции getCharInCarPassengerSeat()

Код:
[ML] (error) script.lua: opcode '0432' call caused an unhandled exception
stack traceback:
    [C]: in function 'getCharInCarPassengerSeat'
    C:\GTA San Andreas\moonloader\script.lua:34: in function 'callback'
Код:
function SE.onSendCommand(msg)
    if string.find(msg, "/dkl") then
        local status = isCharOnFoot(PLAYER_PED)
        if status then
            sampAddChatMessage('Нельзя сделать доклад, когда игрок не в машине.', 0xd3d3d3ff)
        else
            local carhandle = storeCarCharIsInNoSave(PLAYER_PED) 
            for i = 1, getMaximumNumberOfPassengers(carhandle) do
                print('Вывод: ' .. getCharInCarPassengerSeat(carhandle, i))
            end
        end
    elseif string.find(msg, "/1057v") then
        local X, Y, Z = ge0CharCoordinates(PLAYER_PED)
        sampSendChat('/r [Officer of HPD]: GPS: ' .. math.floor(X+0.5) .. '.0, ' .. math.floor(Y+0.5) .. '.0, ' .. math.floor(Z+0.5) .. '.0.')
        --sampSendChat
    end
end

 

TSIDEX

Известный
86
8
Можно ли как-то получить позицию маркера на карте так, чтобы через imgui.SetCursorPos() установить точку в имгуи в том же соотношении?
Чтобы грубо говоря, получить в имгуи окне тот же рендер карты и отображать на нём метки по нужным координатам?

Координаты само собой рисуются в своём порядке, мол -2530, 23, -2. Но для imgui.SetCursorPos() нужны совершенно иные значения.
Может есть вариант получить положение метки на карте относительно экрана и передать аналогичное положение в имгуи окно?
gta_sa 2024-11-21 00-51-25-316.jpg
 
Последнее редактирование:

mo.hennessy

Участник
27
2
Что делать, не ищется айди.
Lua:
function main()

    local valid, ped = getCharPlayerIsTargeting()
if valid and doesCharExist(ped) then
  local result, id = sampGetPlayerIdByCharHandle(ped)
  local name = sampGetPlayerNickname(id)

end
Тут получаю айди;
Код:
       if imgui.Button(u8'Оружие(медка)', imgui.ImVec2(100, 40)) then
            lua_thread.create(function ()
            sampSendChat('Для оформления лицензии на оружие необходимо предоставить мед.карту')
            wait(1000)
            sampSendChat('/b /showmc Maestro_Hennessy')
                while not isKeyJustPressed(VK_K) do wait(100) end

            sampSendChat('Хорошо, лицензия на оружие стоит на месяц - 1.000.000$, на 2 - 1.150.000$, на 3 - 1.250.000$')
            wait(1000)
            sampSendChat('На сколько желаете оформить?')
            wait(1500)
                sampSendChat('5')
            wait(1000)
            sampSendChat('/me достал бланк, внёс в него нужную информацию, передал клиенту напротив')
            for id = 1, 999 do 
            sampSendChat('/gliciveense' + id)
            
            end
            end)
        end
Тут пытаюсь сделать, что бы скрипт реагировал на айди, но этого не происходит. Почему так?
 

Minhjhs

Участник
75
24
Здаров, перерыл весь форум БХ, и вики, Не нашёл ответа на свой вопрос..
2024-11-21_13-05-27.png

Как сделать так, чтобы если в ini.coord.cord что - то есть, скрипт создавал новый раздел, к примеру ini.coord.cord2, и туда записывал координату и т.д(Надо много коорд засейвить)
(Видос чапо, и TheChampGuess уже смотрел, ответа нет)
 

chromiusj

модерирую шмодерирую
Модератор
5,958
4,289
Здаров, перерыл весь форум БХ, и вики, Не нашёл ответа на свой вопрос..
Посмотреть вложение 257761
Как сделать так, чтобы если в ini.coord.cord что - то есть, скрипт создавал новый раздел, к примеру ini.coord.cord2, и туда записывал координату и т.д(Надо много коорд засейвить)
(Видос чапо, и TheChampGuess уже смотрел, ответа нет)
используй json
 

solution

Участник
79
11
при определенных действиях нужно быстро сделать реконнект(отключить игрока и так же подключить его)
Lua:
sampDisconnectWithReason(quit)
wait(8000)
sampSetGamestate(1)
использую такой метод(нашел на бх), но почему-то игрока после такого выхода больше не подключает:
1732176216928.png


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

droffet

Новичок
2
0
Проблема, выкидывает ошибку ни с того ни с сего от функции getCharInCarPassengerSeat()

Код:
[ML] (error) script.lua: opcode '0432' call caused an unhandled exception
stack traceback:
    [C]: in function 'getCharInCarPassengerSeat'
    C:\GTA San Andreas\moonloader\script.lua:34: in function 'callback'
Код:
function SE.onSendCommand(msg)
    if string.find(msg, "/dkl") then
        local status = isCharOnFoot(PLAYER_PED)
        if status then
            sampAddChatMessage('Нельзя сделать доклад, когда игрок не в машине.', 0xd3d3d3ff)
        else
            local carhandle = storeCarCharIsInNoSave(PLAYER_PED)
            for i = 1, getMaximumNumberOfPassengers(carhandle) do
                print('Вывод: ' .. getCharInCarPassengerSeat(carhandle, i))
            end
        end
    elseif string.find(msg, "/1057v") then
        local X, Y, Z = ge0CharCoordinates(PLAYER_PED)
        sampSendChat('/r [Officer of HPD]: GPS: ' .. math.floor(X+0.5) .. '.0, ' .. math.floor(Y+0.5) .. '.0, ' .. math.floor(Z+0.5) .. '.0.')
        --sampSendChat
    end
end

up
 

kjtktkjr

Новичок
2
0
Центральный рынок @Cosmo

Как интегрировать таблицу с товарами и её перебор через цикл средних цен?

мол есть таблица с товарами, которые необходимо разово перебрать через цикл командой /cost и получить их среднюю стоимость
Lua:
local cost_table = {
    'Бронзовая рулетка',
    'Серебряная рулетка',
    'Золотая рулетка'
}
получается получить лишь стоимость товара находящегося на последнем индексе 🤷‍♀️

Центральный рынок Cosmo:
local se = require "samp.events"

local analyzing = false
local prev_page_text = ""
local fined_count = 0
local data = {
    list = {},
    last_update = -1
}

local path = getWorkingDirectory() .. "\\config\\prices.json"
if not doesFileExist(path) then
    createDirectory(getWorkingDirectory() .. "\\config\\")
    local file = io.open(path, "wb")
    file:write(encodeJson(data))
    file:close()
else
    local file = io.open(path, "rb")
    data = decodeJson(file:read("*a"))
    file:close()
end

function main()
    assert(isSampLoaded(), "SA:MP is required!")
    repeat wait(0) until isSampAvailable()
    sampRegisterChatCommand("price", get_price)
    wait(-1)
end

function get_price(item)
    item = tostring(item)

    if data.last_update == -1 then
        sampAddChatMessage("[Рынок] {FFFFFF}Средние цены не загружены!", 0xFF6060)
        sampAddChatMessage("[Рынок] {FFFFFF}Загрузить их можно на пикапе средних цен {FF6060}(только с PREMIUM VIP)",  0xFF6060)
        return
    end

    item = string_to_lower(item)
    if item ~= nil and not string.find(item, "^%s*$") then
        local temp, actual = {}, true
        for name, info in pairs(data.list) do
            if string.find(string_to_lower(name), item, 1, true) then
                local sa, vc = "Неизвестно", "Неизвестно"

                if type(info.sa.price) == "table" then
                    local min = sumFormat(info.sa.price[1])
                    local max = sumFormat(info.sa.price[2])
                    sa = string.format("$%s - %s", min, max)
                elseif tonumber(info.sa.price) then
                    sa = "$" .. sumFormat(info.sa.price)
                end

                if type(info.vc.price) == "table" then
                    local min = sumFormat(info.vc.price[1])
                    local max = sumFormat(info.vc.price[2])
                    vc = string.format("%s - %s", min, max)
                elseif tonumber(info.vc.price) then
                    vc = sumFormat(info.vc.price)
                end

                if info.sa.updated and os.time() - info.sa.updated > (86400 * 7) then
                    sa = "{FFAA60}" .. sa
                    actual = false
                else
                    sa = "{FF6060}" .. sa
                end

                if info.vc.updated and os.time() - info.vc.updated > (86400 * 7) then
                    vc = string.format("{FFAA60}(VC$: %s)", vc)
                    actual = false
                else
                    vc = string.format("{EEEEEE}(VC$: %s)", vc)
                end

                temp[#temp + 1] = ("%s) {FFFFFF}%s: %s %s"):format(#temp + 1, name, sa, vc)
            end
        end

        if #temp >= 1 then
            local msg = string.format("[Рынок] {FFFFFF}%s {FF6060}%s{FFFFFF} %s:",
                plural(#temp, {"Найден", "Найдено", "Найдено"}),
                #temp,
                plural(#temp, {"товар", "товара", "товаров"})
            )
            sampAddChatMessage(msg, 0xFF6060)
            for _, msg in ipairs(temp) do
                sampAddChatMessage(msg, 0xFF6060)
            end
            if not actual then
                sampAddChatMessage("[Подсказка] {FFFFFF}Устаревшие цены помечены {FFAA60}оранжвевым{FFFFFF} цветом (Необходимо обновить)", 0xFF6060)
            end
            return
        end
        sampAddChatMessage("[Рынок] {FFFFFF}Не удалось найти товар с похожим названием", 0xFF6060)
        return
    end
    sampAddChatMessage("[Рынок] {FFFFFF}Введите /price [Название товара или его часть]", 0xFF6060)
end

function se.onShowDialog(id, style, title, but_1, but_2, text)
    if id == 15073 and string.find(title, "Средняя цена товаров при продаже") then
        if not analyzing then
            prev_page_text = text
            text = string.gsub(text, "(Поиск по названию\t%s)\n", "%1\n{00FF00}Проанализировать все цены\t \n", 1)
            go_analyzing_list_id = findListInDialog(text, style, "Проанализировать все цены")
        elseif prev_page_text == text then
            sampAddChatMessage("[Рынок] {FFFFFF}Анализ завершён! Средние цены на товары обновлены!", 0xFF6060)
            printStyledString("~w~~g~Prices found: " .. pCount, 2000, 6)
            prev_page_text = nil
            analyzing = false

            local file = io.open(path, "wb")
            if file ~= nil then
                file:write(encodeJson(data))
                file:close()
            else
                sampAddChatMessage("[Рынок] {FFFFFF}Ошибка сохранения файла с ценами!", 0xFF6060)
            end

            lua_thread.create(sendResponse, id, 0, nil, nil)
            return false
        else
            parser(text)
            printStyledString("~w~Prices found: ~r~" .. pCount, 2000, 6)
            prev_page_text = text

            local list = findListInDialog(text, style, "Следующая страница")
            if list == nil then
                analyzing = false
                sampAddChatMessage("[Рынок] {FFFFFF}Ошибка проверки цен! Не удалось перейти на следующую страницу!", 0xFF6060)
                lua_thread.create(sendResponse, id, 0, nil, nil)
                return false
            else
                lua_thread.create(sendResponse, id, 1, list, nil)
            end
            return false
        end
        return { id, style, title, but_1, but_2, text }
    elseif analyzing then
        sampAddChatMessage("[Рынок] {FFFFFF}Ошибка проверки цен! Анализ был сбит другим диалогом!", 0xFF6060)
        lua_thread.create(sendResponse, id, 0, nil, nil)
        return false
    end

    if id == 3082 then
        if data.last_update == -1 then
            text = text:gsub("Стоимость:[^\n]+", "%1\n{FFAA60}Средние цены не загружены!")
            return { id, style, title, but_1, but_2, text }
        end

        for line in string.gmatch(text, "[^\n]+") do
            local item = string.match(line, ".*{%x+}(.+){%x+}.*$")
            local temp = {}

            if item == nil then
                text = string.gsub(text, "Стоимость:[^\n]+", "%1 {FFAA60}(Товар не определён)")
                print("{FFAA60}Не удалось определить товар: «" .. line .. "»")
                return { id, style, title, but_1, but_2, text }
            end

            for name, info in pairs(data.list) do
                if string.find(item, name, 1, true) then
                    local state = string.find(text, "Стоимость: VC$", 1, true) and "vc" or "sa"
                    local price = (state == "vc") and "VC$" or "$"
                    local outdated = info[state].updated and (os.time() - info[state].updated) > (86400 * 7)

                    if type(info[state].price) == "table" then
                        local min = price .. sumFormat(info[state].price[1])
                        local max = price .. sumFormat(info[state].price[2])
                        price = string.format("От %s до %s", min, max)
                        temp[#temp + 1] = { name, price, outdated }
                    elseif tonumber(info[state].price) then
                        price = string.format("~%s%s", price, sumFormat(info[state].price))
                        temp[#temp + 1] = { name, price, outdated }
                    end
                end
            end

            if #temp > 1 then
                local result = ""
                for i = 1, #temp do
                    result = result .. string.format("{67BE55}%s - {FFAA60}%s", temp[i][1], temp[i][2])
                    if i ~= #temp then
                        result = result .. "\n"
                    end
                end
                text = text:gsub("Стоимость:[^\n]+", "%1\n\n{67BE55}Средняя стоимость товаров с похожим названием:\n" .. result)
            elseif #temp == 1 then
                text = text:gsub("Стоимость:[^\n]+", "%1 {FFAA60}(" .. temp[1][2] .. ")")
            else
                text = text:gsub("Стоимость:[^\n]+", "%1 {FFAA60}(Ср. цена не найдена)")
            end
            break
        end
        return { id, style, title, but_1, but_2, text }
    end

    if id == 3060 or id == 26539 then
        local item = string.match(text, "%( {57FF6B}(.+){FFFFFF} %)")
        if item ~= nil then
            local temp = {}
            for name, info in pairs(data.list) do
                if string.find(string_to_lower(name), string_to_lower(item), 1, true) then
                    local sa, vc = "Неизвестно", "Неизвестно"

                    if type(info.sa.price) == "table" then
                        local min = "$" .. sumFormat(info.sa.price[1])
                        local max = "$" .. sumFormat(info.sa.price[2])
                        sa = string.format("%s - %s", min, max)
                    elseif tonumber(info.sa.price) then
                        sa = "$" .. sumFormat(info.sa.price)
                    end

                    if type(info.vc.price) == "table" then
                        local min = sumFormat(info.vc.price[1])
                        local max = sumFormat(info.vc.price[2])
                        vc = string.format("%s - %s", min, max)
                    elseif tonumber(info.vc.price) then
                        vc = sumFormat(info.vc.price)
                    end

                    temp[#temp + 1] = { name, sa, vc }
                end
            end

            local result
            if #temp > 1 then
                result = "Похожие товары:\n"
                for i, info in ipairs(temp) do
                    result = result .. string.format("{67BE55}%s) %s: {FFAA60}%s {BBBBBB}(VC$: %s)", i, info[1], info[2], info[3])
                    if i ~= #temp then result = result .. "\n" end
                end
            elseif #temp == 1 then
                result = string.format("Средняя цена: {FFAA60}%s {BBBBBB}(VC$: %s)", temp[1][2], temp[1][3])
            else
                result = "Средняя цена на этот товар неизвестна"
            end

            text = string.gsub(text, "$", "\n\n{67BE55}" .. result)
            return { id, style, title, but_1, but_2, text }
        end
    end
end

function se.onSendDialogResponse(id, but, list, input)
    if not analyzing and id == 15073 and go_analyzing_list_id ~= nil then
        if list == go_analyzing_list_id and but == 1 then
            local text = sampGetDialogText()
            local style = sampGetCurrentDialogType()
            list = findListInDialog(text, style, "Следующая страница")
            if list == nil then
                sampAddChatMessage("[Рынок] {FFFFFF}Ошибка проверки цен! Не удалось перейти на следующую страницу!", 0xFF6060)
                return { id, 0, list, input }
            else
                analyzing = true
                data.last_update = os.time()
                sampAddChatMessage("[Рынок] {FFFFFF}Запущен анализ цен. Не открывайте до завершения другие диалоги!", 0xFF6060)

                pCount = 0
                parser(text)
                printStyledString("~w~Prices found: ~r~" .. pCount, 2000, 6)
            end
        end

        if list >= go_analyzing_list_id then
            list = list - 1
        end

        go_analyzing_list_id = nil
        return { id, but, list, input }
    end
end

function parser(text)
    local i = 0
    for line in string.gmatch(text, "[^\n]+") do
        i = i + 1
        if i > 3 then
            local item, price = string.match(line, "^(.+)\t%V?C?%$(.+)$")
            if item and price then
                if data.list[item] == nil then
                    data.list[item] = {
                        sa = { price = nil, updated = nil },
                        vc = { price = nil, updated = nil },
                    }
                end
                local t = data.list[item][string.find(line, "VC$", 1, true) and "vc" or "sa"]
                price = string.gsub(price, "%p+", "")
                local int_price = tonumber(string.match(price, "%d+"))
                if int_price == nil then
                    print(("Неудалось обнаружить цену на товар: %s || Out: «%s»"):format(item, price))
                    goto skip
                end

                int_price = normalise_int(int_price)
                if t.updated and (os.time() - t.updated < 60) then
                    if type(t.price) == "table" then
                        if t.price[1] > int_price then
                            t.price[1] = int_price -- min price
                        else
                            t.price[2] = int_price -- max price
                        end
                    else
                        local p = tonumber(t.price)
                        if p > int_price then
                            t.price = { int_price, p }           
                        else
                            t.price = { p, int_price }
                        end
                    end
                else
                    t.price = int_price
                end
                t.updated = os.time()
                pCount = pCount + 1

                ::skip::
            end
        end
    end
end

function findListInDialog(text, style, search)
    local i = 0
    for line in string.gmatch(text, "[^\n]+") do
        if string.find(line, search, 1, true) then
            return i - (style == 5 and 1 or 0)
        end
        i = i + 1
    end
    return nil
end

function string_to_lower(str)
    for i = 192, 223 do
        str = str:gsub(_G.string.char(i), _G.string.char(i + 32))
    end
    str = str:gsub(_G.string.char(168), _G.string.char(184))
    return str:lower()
end

function sumFormat(sum)
    sum = tostring(sum)
    count = sum:match("%d+")
    if count and #count > 3 then
        local b, e = ("%d"):format(count):gsub("^%-", "")
        local c = b:reverse():gsub("%d%d%d", "%1.")
        local d = c:reverse():gsub("^%.", "")
        return sum:gsub(count, (e == 1 and "-" or "") .. d)
    end
    return sum
end

function plural(n, forms)
    n = math.abs(n) % 100
    if n % 10 == 1 and n ~= 11 then
        return forms[1]
    elseif 2 <= n % 10 and n % 10 <= 4 and (n < 10 or n >= 20) then
        return forms[2]
    end
    return forms[3]
end

function normalise_int(int)
    for i = 4, 10 do
        if int < 10^i and int >= 10^2 then
            int = int / 10^(i-3)
            int = math.floor(int) * 10^(i-3)
            break
        end
    end
    
    return int
end

function sendResponse(id, button, list, input)
    wait(100)
    sampSendDialogResponse(id, button, list, input)
end
 

Oki_Bern

Участник
297
8
как проверить загружена ли библиотека, если она ничего не возвращает(например как lib.moonloader)?
 

qdIbp

Автор темы
Проверенный
1,450
1,197
как проверить загружена ли библиотека, если она ничего не возвращает
Он тебе будет выдавать ошибки в случай отсутствие библиотеки, так что юзай pcall

Lua:
local result, fa = pcall(require, 'fAwesome5')
print(result and 'Есть либа' or 'Либы нет')
 
  • Нравится
Реакции: monolith04 и Oki_Bern

shshshpressenter

Новичок
19
3
Каким образом можно отправить серверный ENTER на RakSamp Lite? Имеется ввиду, когда для входа в интерьер, требует нажатия ENTER.
Обычное sendKey(16) и sendKey(13) не помогает (пикап уже взят). Одно и то же как на арз для входа нужен ALT, тут ENTER
 

mo.hennessy

Участник
27
2
Что делать, не ищется айди.
Lua:
function main()

    local valid, ped = getCharPlayerIsTargeting()
if valid and doesCharExist(ped) then
  local result, id = sampGetPlayerIdByCharHandle(ped)
  local name = sampGetPlayerNickname(id)

end
Тут получаю айди;
Код:
       if imgui.Button(u8'Оружие(медка)', imgui.ImVec2(100, 40)) then
            lua_thread.create(function ()
            sampSendChat('Для оформления лицензии на оружие необходимо предоставить мед.карту')
            wait(1000)
            sampSendChat('/b /showmc Maestro_Hennessy')
                while not isKeyJustPressed(VK_K) do wait(100) end

            sampSendChat('Хорошо, лицензия на оружие стоит на месяц - 1.000.000$, на 2 - 1.150.000$, на 3 - 1.250.000$')
            wait(1000)
            sampSendChat('На сколько желаете оформить?')
            wait(1500)
                sampSendChat('5')
            wait(1000)
            sampSendChat('/me достал бланк, внёс в него нужную информацию, передал клиенту напротив')
            for id = 1, 999 do
            sampSendChat('/gliciveense' + id)
           
            end
            end)
        end
Тут пытаюсь сделать, что бы скрипт реагировал на айди, но этого не происходит. Почему так?
up
 
  • Грустно
Реакции: pastow

taizx

Новичок
3
0
подскажите как написать просто смуч на лкм (про выстреле), просто сам отрывок кода, который отвечает за наводку на скин при выстреле