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

qwеty

Известный
490
157
Как отправить дамаг игроку через булет синхру?
UPD: что не так?
:70: cannot convert 'string' to 'unsigned short'
qweqwe:
function main()
    while not isSampAvailable() do wait(100) end
    sampRegisterChatCommand('bullet', bullet)
    while true do
        wait(0)
    end
end
function bullet(playerid)
    local result, HandlePlayer = sampGetCharHandleBySampPlayerId(playerid)
    local data = samp_create_sync_data('bullet', false)
    data.targetType = 1
    data.targetId = playerid
    data.origin.x, data.origin.y, data.origin.z = getActiveCameraCoordinates()
    data.target.x, data.target.y, data.target.z = getCharCoordinates(HandlePlayer)
    data.weaponId = getCurrentCharWeapon(PLAYER_PED)
    data.send()
    sampAddChatMessage('отправлена: ' ..playerid, -1)
end

function samp_create_sync_data(sync_type, copy_from_player)
    local ffi = require 'ffi'
    local sampfuncs = require 'sampfuncs'
    -- from SAMP.Lua
    local raknet = require 'samp.raknet'
    require 'samp.synchronization'

    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)))
    -- copy player's sync data to the allocated memory
    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
    -- function to send packet
    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
    -- metatable to access sync data and 'send' function
    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
 
Последнее редактирование:

qwеty

Известный
490
157
Как отправить дамаг игроку через булет синхру?
UPD: что не так?
:70: cannot convert 'string' to 'unsigned short'
qweqwe:
function main()
    while not isSampAvailable() do wait(100) end
    sampRegisterChatCommand('bullet', bullet)
    while true do
        wait(0)
    end
end
function bullet(playerid)
    local result, HandlePlayer = sampGetCharHandleBySampPlayerId(playerid)
    local data = samp_create_sync_data('bullet', false)
    data.targetType = 1
    data.targetId = playerid
    data.origin.x, data.origin.y, data.origin.z = getActiveCameraCoordinates()
    data.target.x, data.target.y, data.target.z = getCharCoordinates(HandlePlayer)
    data.weaponId = getCurrentCharWeapon(PLAYER_PED)
    data.send()
    sampAddChatMessage('отправлена: ' ..playerid, -1)
end

function samp_create_sync_data(sync_type, copy_from_player)
    local ffi = require 'ffi'
    local sampfuncs = require 'sampfuncs'
    -- from SAMP.Lua
    local raknet = require 'samp.raknet'
    require 'samp.synchronization'

    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)))
    -- copy player's sync data to the allocated memory
    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
    -- function to send packet
    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
    -- metatable to access sync data and 'send' function
    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
up
 
Последнее редактирование:

Senya.Volin

Участник
67
4
Как получить "score" Player'a?

Знімок екрана 2022-08-09 223035.png

При вводе данного текста получится:
Lua:
-- Info for Player: / Nickname Artem_Loshara, ID: 921
А мне нужно, чтобы после данного текста писалось:
-- Info for Player: / Nickname Artem_Loshara, ID: 921, Score: (уровень игрока)
 

shawtyglock.

Активный
188
63
Хочу реализовать создание нового текста в BeginChild окне, вместо "Информация" посредством выбора кнопки, но незнаю как.
Например: Выбираю кнопку настройки и вместо "Информация" неким заголовком будет уже "Настройки".
1660073567132.png
 

Senya.Volin

Участник
67
4
Как получить "score" Player'a?

Посмотреть вложение 161772
При вводе данного текста получится:
Lua:
-- Info for Player: / Nickname Artem_Loshara, ID: 921
А мне нужно, чтобы после данного текста писалось:
-- Info for Player: / Nickname Artem_Loshara, ID: 921, Score: (уровень игрока)
Я попробовал с импровизировать, но получился бред:
Знімок екрана 2022-08-09 224343.png

Знімок екрана 2022-08-09 224349.png

Но при вводе текста - получается совсем не то число:
Знімок екрана 2022-08-09 224355.png

У меня на этом аккаунте 1 уровень.
Скорее всего, это просто не уровень, или рандомное число.

Я попробовал с импровизировать, но получился бред:
Знімок екрана 2022-08-09 224343.png

Знімок екрана 2022-08-09 224349.png

Но при вводе текста - получается совсем не то число:
Знімок екрана 2022-08-09 224355.png

У меня на этом аккаунте 1 уровень.
Скорее всего, это просто не уровень, или рандомное число.
upd: я подумал что это хп :), но сейчас при вводе этой команды показывает: Score: 0. Кароче, я хз шо делать(
 

AntonNeath

Известный
252
109
Имеется текстдрав с определенным идом. При изменении текста в текстдраве нужно выполнение действия. Беда в следующем: айди текстдрава статичен. Любое изменение текста в текстдраве не меняет значения при взятии его sampTextdrawGetString.
Выглядит это так:
Появился нужный текстдрав с текстом 1
sampTextdrawGetString: 1
Текст в текстдраве стал 2
sampTextdrawGetString: 1
Текст в текстдраве стал 52
sampTextdrawGetString: 1
Текст в текстдраве стал 1
sampTextdrawGetString: 1
Как это можно реализовать?
 

T1cKz

Известный
595
245
Имеется текстдрав с определенным идом. При изменении текста в текстдраве нужно выполнение действия. Беда в следующем: айди текстдрава статичен. Любое изменение текста в текстдраве не меняет значения при взятии его sampTextdrawGetString.
Выглядит это так:
Появился нужный текстдрав с текстом 1
Консоль: 1
Текст в текстдраве стал 2
Консоль: 1
Текст в текстдраве стал 52
Консоль: 1
Текст в текстдраве стал 1
Консоль: 1
Как это можно реализовать?
Если текстдрав меняет текст то там варика 2. Либо textDrawSetString (хук) либо перепоказ его и ты увидешь в onShowTextdraw(хук) оттуда и можешь ловить
 

AntonNeath

Известный
252
109
Если текстдрав меняет текст то там варика 2. Либо textDrawSetString (хук) либо перепоказ его и ты увидешь в onShowTextdraw(хук) оттуда и можешь ловить
Я кабачек и ничего не понял.
Сейчас код имеет вид:
Lua:
function sampev.onShowTextDraw(textdrawid, textdraw)
    if textdrawid == 1 then
          za = sampTextdrawGetString(1)
          if za:find('w') then
            print(123)
         end
    end
end

Также получал текст путем хука и выводом print(textdraw.text), итог тот же.
 

T1cKz

Известный
595
245
Я кабачек и ничего не понял.
Сейчас код имеет вид:
Lua:
function sampev.onShowTextDraw(textdrawid, textdraw)
    if textdrawid == 1 then
          za = sampTextdrawGetString(1)
          if za:find('w') then
            print(123)
        end
    end
end

Также получал текст путем хука и выводом print(textdrawid.text), итог тот же.
у тебя невозможно получить sampTextdrawGetString, т.к. он ещё не появился. Хук срабатывает до появления самого текстдрава.
правильно проверка будет
Lua:
if textdraw.text:find("w") then print("123") end
И ты уверен что ID текстдрава именно 1?
 

AntonNeath

Известный
252
109
у тебя невозможно получить sampTextdrawGetString, т.к. он ещё не появился. Хук срабатывает до появления самого текстдрава.
Что интересно, если сделать print(za) и print(textdraw.text) в консоле 2 одинаковых сообщения

ты уверен что ID текстдрава именно 1?
Я единицу для примера бахнул. Вообще, это 2136, но да, уверен.
 

OperaGx

Потрачен
38
12
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Помогите пж пофиксить ошибку: samp\moonloader\Screens.lua:30: stack index 3, expected string, received number: (bad argument into 'void(const classstd::basic_string<char,std::char_traits<char>,std::allocator<char> >&)')

Код:

Lua:
local imgui = require('imgui')
local tgidd= imgui.ImBuffer(256)
local inicfg = require("inicfg")
local directIni = 'kladmangrgsdfl.ini'--сохранение настроек
local mainini = inicfg.load(inicfg.load({
    settings = {
        pathtoscreens='ssss',
        tgidd='idd',
        tgtokenn='token',
        work=true,
        date=true
    },
}, directIni))
tgidd.v=(mainini.settings.tgidd)
 

qdIbp

Автор темы
Проверенный
1,434
1,174
Помогите пж пофиксить ошибку: samp\moonloader\Screens.lua:30: stack index 3, expected string, received number: (bad argument into 'void(const classstd::basic_string<char,std::char_traits<char>,std::allocator<char> >&)')

Код:

Lua:
local imgui = require('imgui')
local tgidd= imgui.ImBuffer(256)
local inicfg = require("inicfg")
local directIni = 'kladmangrgsdfl.ini'--сохранение настроек
local mainini = inicfg.load(inicfg.load({
    settings = {
        pathtoscreens='ssss',
        tgidd='idd',
        tgtokenn='token',
        work=true,
        date=true
    },
}, directIni))
tgidd.v=(mainini.settings.tgidd)
Lua:
local imgui = require('imgui')
local inicfg = require("inicfg")

local directIni = 'kladmangrgsdfl.ini'--сохранение настроек
local mainini = inicfg.load(inicfg.load({
    settings = {
        pathtoscreens='ssss',
        tgidd='idd',
        tgtokenn='token',
        work=true,
        date=true
    },
}, directIni))
local tgidd= imgui.ImBuffer(''..mainini.settings.tgidd,256)
 
  • Влюблен
Реакции: OperaGx

OperaGx

Потрачен
38
12
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Шалом. Есть цикл for, он выполняется 10 раз. Как сделать так, что бы после каждого круга он ставился на паузу, и запускался только если переменная ii будет равна 1?
 

shawtyglock.

Активный
188
63
Ошибка в консоли:
[ML] (error) Shawty Helper: D:\Games\EVIL 17K GTA Original\moonloader\lib\rkeys.lua:94: attempt to get length of field 'keys' (a nil value)
stack traceback:
D:\Games\EVIL 17K GTA Original\moonloader\lib\rkeys.lua: in function <D:\Games\EVIL 17K GTA Original\moonloader\lib\rkeys.lua:89>

Впервые сталкиваюсь с таким, ранее такой ошибки не было, появилась с переходом с .json на .ini

Code:
Lua:
script_name('Shawty Helper')
script_author('shawtyglock')

require "lib.moonloader"
local imgui = require 'imgui'
local inicfg = require 'inicfg'
local sampev = require 'lib.samp.events'
local keys = require 'vkeys'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local main_window_state = imgui.ImBool(false)
local rkeys = require 'rkeys'
imgui.HotKey = require('imgui_addons').HotKey

local fa = require 'faIcons'
local fonts = renderCreateFont("Arial", 9, 5)

local tLastKeys = {}

local themes = import "resource/imgui_themes.lua"

local directIni = 'Shawty Helper.ini'--сохранение настроек
local mainIni = inicfg.load(inicfg.load({
    config = {
            armour = {v = {VK_C}},
            mask = {v = {VK_V}},
            drugs = {v = {VK_X}},
            cure = {v = {VK_B}},
            lock = {v = {VK_Z}},
            SizeFont = 9,
            FlagFont = 5,
            fastrep = false,
            probiv = false
    },
}, directIni))

local font = renderCreateFont("Arial", mainIni.config.SizeFont, mainIni.config.FlagFont)

--ImGui
-- local checkkill = imgui.ImBool(config.Kill)
-- local checkstats = imgui.ImBool(config.Stats)
-- local checkhphud = imgui.ImBool(config.HPHud)
-- local checkbell = imgui.ImBool(config.Bell)
local sizefont = imgui.ImInt(mainIni.config.SizeFont)
local flagfont = imgui.ImInt(mainIni.config.FlagFont)

-- Checkbox
-- local choose_Kill = imgui.ImBool(false)
-- local choose_Stats = imgui.ImBool(false)
-- local choose_HPHud = imgui.ImBool(false)
-- local choose_Bell = imgui.ImBool(false)


local fastrep = imgui.ImBool(mainIni.config.fastrep)
local probiv = imgui.ImBool(mainIni.config.probiv)

function CherryTheme()
  imgui.SwitchContext()
  local style = imgui.GetStyle()
  local colors = style.Colors
  local clr = imgui.Col
  local ImVec4 = imgui.ImVec4
  local ImVec2 = imgui.ImVec2


  style.WindowPadding = ImVec2(8, 8)
  style.WindowRounding = 6.0
  style.FramePadding = ImVec2(5, 3)
  style.FrameRounding = 3.0
    style.ItemSpacing = imgui.ImVec2(5, 4)
    style.ItemInnerSpacing = imgui.ImVec2(4, 4)
    style.IndentSpacing = 21
    style.ScrollbarSize = 10.0
    style.ScrollbarRounding = 13
    style.GrabMinSize = 8
    style.GrabRounding = 1
    style.WindowTitleAlign = imgui.ImVec2(0.5, 0.5)
    style.ButtonTextAlign = imgui.ImVec2(0.5, 0.5)

  style.WindowTitleAlign = ImVec2(0.5, 0.5)

  colors[clr.Text] = ImVec4(0.860, 0.930, 0.890, 0.78)
  colors[clr.TextDisabled] = ImVec4(0.860, 0.930, 0.890, 0.28)
  colors[clr.WindowBg] = ImVec4(0.13, 0.14, 0.17, 1.00)
  colors[clr.ChildWindowBg] = ImVec4(0.200, 0.220, 0.270, 0.58)
  colors[clr.PopupBg] = ImVec4(0.200, 0.220, 0.270, 0.9)
  colors[clr.Border] = ImVec4(0.31, 0.31, 1.00, 0.00)
  colors[clr.BorderShadow] = ImVec4(0.00, 0.00, 0.00, 0.00)
  colors[clr.FrameBg] = ImVec4(0.200, 0.220, 0.270, 1.00)
  colors[clr.FrameBgHovered] = ImVec4(0.455, 0.198, 0.301, 0.78)
  colors[clr.FrameBgActive] = ImVec4(0.455, 0.198, 0.301, 1.00)
  colors[clr.TitleBg] = ImVec4(0.232, 0.201, 0.271, 1.00)
  colors[clr.TitleBgActive] = ImVec4(0.502, 0.075, 0.256, 1.00)
  colors[clr.TitleBgCollapsed] = ImVec4(0.200, 0.220, 0.270, 0.75)
  colors[clr.MenuBarBg] = ImVec4(0.200, 0.220, 0.270, 0.47)
  colors[clr.ScrollbarBg] = ImVec4(0.200, 0.220, 0.270, 1.00)
  colors[clr.ScrollbarGrab] = ImVec4(0.09, 0.15, 0.1, 1.00)
  colors[clr.ScrollbarGrabHovered] = ImVec4(0.455, 0.198, 0.301, 0.78)
  colors[clr.ScrollbarGrabActive] = ImVec4(0.455, 0.198, 0.301, 1.00)
  colors[clr.CheckMark] = ImVec4(0.71, 0.22, 0.27, 1.00)
  colors[clr.SliderGrab] = ImVec4(0.47, 0.77, 0.83, 0.14)
  colors[clr.SliderGrabActive] = ImVec4(0.71, 0.22, 0.27, 1.00)
  colors[clr.Button] = ImVec4(0.47, 0.77, 0.83, 0.14)
  colors[clr.ButtonHovered] = ImVec4(0.455, 0.198, 0.301, 0.86)
  colors[clr.ButtonActive] = ImVec4(0.455, 0.198, 0.301, 1.00)
  colors[clr.Header] = ImVec4(0.455, 0.198, 0.301, 0.76)
  colors[clr.HeaderHovered] = ImVec4(0.455, 0.198, 0.301, 0.86)
  colors[clr.HeaderActive] = ImVec4(0.502, 0.075, 0.256, 1.00)
  colors[clr.ResizeGrip] = ImVec4(0.47, 0.77, 0.83, 0.04)
  colors[clr.ResizeGripHovered] = ImVec4(0.455, 0.198, 0.301, 0.78)
  colors[clr.ResizeGripActive] = ImVec4(0.455, 0.198, 0.301, 1.00)
  colors[clr.PlotLines] = ImVec4(0.860, 0.930, 0.890, 0.63)
  colors[clr.PlotLinesHovered] = ImVec4(0.455, 0.198, 0.301, 1.00)
  colors[clr.PlotHistogram] = ImVec4(0.860, 0.930, 0.890, 0.63)
  colors[clr.PlotHistogramHovered] = ImVec4(0.455, 0.198, 0.301, 1.00)
  colors[clr.TextSelectedBg] = ImVec4(0.455, 0.198, 0.301, 0.43)
  colors[clr.ModalWindowDarkening] = ImVec4(0.200, 0.220, 0.270, 0.73)
end
CherryTheme()

local menu = 1
local fa_font = nil
local sizefont = nil

-- KillStatus
-- local kills = 0
-- local deaths = 0
-- local ratio = 0
-- local dead_players = {}
-- local current = 0
-- local total = 0

function imgui.TextQuestion(text)
    imgui.SameLine()
    imgui.TextDisabled("(?)")
    if imgui.IsItemHovered() then
        imgui.BeginTooltip()
        imgui.TextUnformatted(u8(text))
        imgui.EndTooltip()
    end
end

function imgui.CenterTextColoredRGB(text)
    local width = imgui.GetWindowWidth()
    local style = imgui.GetStyle()
    local colors = style.Colors
    local ImVec4 = imgui.ImVec4

    local explode_argb = function(argb)
        local a = bit.band(bit.rshift(argb, 24), 0xFF)
        local r = bit.band(bit.rshift(argb, 16), 0xFF)
        local g = bit.band(bit.rshift(argb, 8), 0xFF)
        local b = bit.band(argb, 0xFF)
        return a, r, g, b
    end

    local getcolor = function(color)
        if color:sub(1, 6):upper() == 'SSSSSS' then
            local r, g, b = colors[1].x, colors[1].y, colors[1].z
            local a = tonumber(color:sub(7, 8), 16) or colors[1].w * 255
            return ImVec4(r, g, b, a / 255)
        end
        local color = type(color) == 'string' and tonumber(color, 16) or color
        if type(color) ~= 'number' then return end
        local r, g, b, a = explode_argb(color)
        return imgui.ImColor(r, g, b, a):GetVec4()
    end

    local render_text = function(text_)
        for w in text_:gmatch('[^\r\n]+') do
            local textsize = w:gsub('{.-}', '')
            local text_width = imgui.CalcTextSize(u8(textsize))
            imgui.SetCursorPosX( width / 2 - text_width .x / 2 )
            local text, colors_, m = {}, {}, 1
            w = w:gsub('{(......)}', '{%1FF}')
            while w:find('{........}') do
                local n, k = w:find('{........}')
                local color = getcolor(w:sub(n + 1, k - 1))
                if color then
                    text[#text], text[#text + 1] = w:sub(m, n - 1), w:sub(k + 1, #w)
                    colors_[#colors_ + 1] = color
                    m = n
                end
                w = w:sub(1, n - 1) .. w:sub(k + 1, #w)
            end
            if text[0] then
                for i = 0, #text do
                    imgui.TextColored(colors_[i] or colors[1], u8(text[i]))
                    imgui.SameLine(nil, 0)
                end
                imgui.NewLine()
            else
                imgui.Text(u8(w))
            end
        end
    end
    render_text(text)
end

function fastreport(text)
    if fastrep.v then
        if #text == 0 then
            sampAddChatMessage('{ff6347}[Shawty Helper]:{ffffff} Введите ваш репорт', 0xff6347)
        else
            sampSendChat('/rep')
            sampSendDialogResponse(32, 1, 0, text)
        end
    else
        sampSendChat('/rep')
    end
end

function main()
    if not isSampLoaded() then return end
    while not isSampAvailable() do wait(100) end
    sampAddChatMessage("{de3163}[Shawty Helper]{ffffff} Скрипт успешно загружен. Активация: {de3163}/sh.", -1)
    sampRegisterChatCommand("sh", function()
 main_window_state.v = not main_window_state.v end)
 sampRegisterChatCommand('rep', fastreport)
 sampRegisterChatCommand('probiv', cmd_probiv)

        bind = rkeys.registerHotKey(mainIni.config.armour.v, true, function()
        sampSendChat("/armour")
    end)

        bind = rkeys.registerHotKey(mainIni.config.mask.v, true, function()
        sampSendChat("/mask")
    end)

        bind = rkeys.registerHotKey(mainIni.config.lock.v, true, function()
        sampSendChat("/lock")
    end)

        bind = rkeys.registerHotKey(mainIni.config.drugs.v, true, function()
            hp = getCharHealth(PLAYER_PED)
            if hp < 120 and not sampIsChatInputActive() and not sampIsDialogActive() and not sampIsScoreboardOpen() and not isSampfuncsConsoleActive() then
                    sampSendChat('/usedrugs 3')
            elseif hp >= 120 and hp < 140 and not sampIsChatInputActive() and not sampIsDialogActive() and not sampIsScoreboardOpen() and not isSampfuncsConsoleActive() then
                    sampSendChat('/usedrugs 2')
            elseif hp >= 140 and not sampIsChatInputActive() and not sampIsDialogActive() and not sampIsScoreboardOpen() and not isSampfuncsConsoleActive() then
                    sampSendChat('/usedrugs 1')
            end
    end)

        bind = rkeys.registerHotKey(mainIni.config.cure.v, true, function()
            local veh, ped = storeClosestEntities(PLAYER_PED)
            local _, id = sampGetPlayerIdByCharHandle(ped)
            if id then
                            if id == -1 then sampAddChatMessage('{de3163}[Shawty Helper]{FFFFFF} Ошибка, рядом никого нет!', -1) else
                                sampSendChat('/cure '..id)
                        end
            end
        end)



    while true do
        wait(0)
        imgui.Process = main_window_state.v
    end
end

function cmd_probiv(id)
    if probiv.v then
        lua_thread.create(function()
        _, id = sampGetPlayerIdByCharHandle(PLAYER_PED)
        wait(500)
        sampAddChatMessage('{de3163}[Shawty Helper] {ffffff}Авто-Пробив начат.', -1)
        wait(2000)
        sampSendChat("/time")
        wait(500)
        sampSendChat("/id "..id.."")
        sampSendChat("/id "..id.."")
        sampSendChat("/id "..id.."")
        wait(600)
        setVirtualKeyDown(VK_TAB, false)
        wait(1000)
        setVirtualKeyDown(VK_TAB, false)
        wait(500)
        setVirtualKeyDown(116, true)
        wait(3100)
        setVirtualKeyDown(116, false)
        wait(600)
        sampSendChat("/skill")
        wait(600)
        sampSendChat("/stats")
        wait(600)
        sampSendChat("/donate")
        wait(600)
        wait(500)
        sampSendChat("/invent")
        wait(1500)
        sampSendClickTextdraw(2071)
        wait(1000)
        sampAddChatMessage('{de3163}[Shawty Helper] {ffffff}Авто-Пробив завершён.', -1)
      end)
    end
end

local fa_glyph_ranges = imgui.ImGlyphRanges({ fa.min_range, fa.max_range })
function imgui.BeforeDrawFrame()
    if fa_font == nil then
        local font_config = imgui.ImFontConfig()
        font_config.MergeMode = true
        fa_font = imgui.GetIO().Fonts:AddFontFromFileTTF('moonloader/resource/fonts/fontawesome-webfont.ttf', 14.0, font_config, fa_glyph_ranges)
    end
end

function imgui.OnDrawFrame()
    if main_window_state.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(750, 400), imgui.Cond.FirstUseEver)
        imgui.Begin(u8"Shawty Helper", main_window_state, imgui.WindowFlags.NoCollapse + imgui.WindowFlags.NoResize + imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.NoScrollWithMouse +
              imgui.WindowFlags.NoTitleBar)
                imgui.BeginChild('##up1',
                imgui.ImVec2(200, 50), true, imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.NoScrollWithMouse)
                imgui.Spacing()
                imgui.Spacing()
                imgui.Spacing()
                imgui.CenterTextColoredRGB('Shawty Helper v0.1.1')
                imgui.EndChild()
                imgui.SameLine()
                imgui.BeginChild('##up2',
                imgui.ImVec2(528, 50), true, imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.NoScrollWithMouse)
                imgui.Spacing()
                imgui.Spacing()
                imgui.Spacing()
                imgui.CenterTextColoredRGB('Информация')
                imgui.EndChild()
                imgui.BeginChild('##left',
                imgui.ImVec2(200, 328), true, imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.NoScrollWithMouse)
             if imgui.Button(u8('Информация'), imgui.ImVec2(-1, 75)) then
                     menu = 1
             end
             if imgui.Button(u8('Функции'), imgui.ImVec2(-1, 75)) then
                     menu = 2
             end
             if imgui.Button(u8('Биндер'), imgui.ImVec2(-1, 75)) then
                     menu = 3
             end
             if imgui.Button(u8('Настройки'), imgui.ImVec2(-1, 75)) then
                     menu = 4
             end
             imgui.EndChild()
             imgui.SameLine()
             imgui.BeginChild('##right', imgui.ImVec2(528, 328), true, imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.NoScrollWithMouse)
             if menu == 1 then
                 imgui.CenterTextColoredRGB('Автор данного скрипта - shawtyglock\nЕсли желаете добавить в скрипт что-то для его доработки\nили нашли ошибки в скрипте, пишите мне в Discord: FluffyBeast#8186')
             end
             if menu == 2 then
                 imgui.Checkbox(u8"Быстрый репорт", fastrep)
                 inicfg.save(mainIni, 'Shawty Helper.ini')
                 imgui.SameLine()
               imgui.TextQuestion("Быстрый репорт в формате:\n/rep *текст репорта*")

                 imgui.Checkbox(u8"Авто-Пробив", probiv)
                 inicfg.save(mainIni, 'Shawty Helper.ini')
                 imgui.SameLine()
                 imgui.TextQuestion("Автоматически пробивает ваш айди, тайм, таб, донат,\nскиллы, обвесы, F5. Активация: /probiv")
             end

             if menu == 3 then

                 if imgui.HotKey("##1", mainIni.config.lock, tLastKeys, 50) then
                            rkeys.changeHotKey(bind, mainIni.config.lock.v)
                            inicfg.save(mainIni, 'Shawty Helper.ini')
                 end

                 imgui.SameLine()
                 imgui.Text(u8"Открытие машины")
                 imgui.TextQuestion("Открывает машину на указанную вами клавишу/комбинацию клавиш")

                 if imgui.HotKey("##2", mainIni.config.armour, tLastKeys, 50) then
                            rkeys.changeHotKey(bind, mainIni.config.armour.v)
                            inicfg.save(mainIni, 'Shawty Helper.ini')
                 end

                 imgui.SameLine()
                 imgui.Text(u8"Использование армора")
                 imgui.TextQuestion("Использует армор на указанную вами клавишу/комбинацию клавиш")

                 if imgui.HotKey("##3", mainIni.config.mask, tLastKeys, 50) then
                            rkeys.changeHotKey(bind, mainIni.config.mask.v)
                            inicfg.save(mainIni, 'Shawty Helper.ini')
                 end

                 imgui.SameLine()
                 imgui.Text(u8"Использование маски")
                 imgui.TextQuestion("Использует маску на указанную вами клавишу/комбинацию клавиш")

                 if imgui.HotKey("##4", mainIni.config.cure, tLastKeys, 50) then
                         rkeys.changeHotKey(bind, mainIni.config.cure.v)
                         inicfg.save(mainIni, 'Shawty Helper.ini')
                 end

                 imgui.SameLine()
                 imgui.Text(u8"Поднятие ближайшего игрока")
                 imgui.TextQuestion("Поднимает ближайшего игрока в стадии смерти уколом\nадреналина на указанную вами клавишу/комбинацию клавиш")

                 if imgui.HotKey("##5", mainIni.config.drugs, tLastKeys, 50) then
                         rkeys.changeHotKey(bind, mainIni.config.drugs.v)
                         inicfg.save(mainIni, 'Shawty Helper.ini')
                 end

                 imgui.SameLine()
                 imgui.Text(u8"Использование наркотиков")
                 imgui.TextQuestion("Использует наркотики в зависимости от количества вашего\nздоровья на указанную вами клавишу/комбинацию клавиш")
             end
             if menu == 4 then
                 imgui.CenterTextColoredRGB('Находится в процессе разработки')
             end
             imgui.EndChild()
             imgui.End()
    end
end