require('lib.moonloader') -- all const

local imgui = require('imgui')
local sampev = require('lib.samp.events')
local memory = require('memory')
local inicfg = require('inicfg')

local ffi = require('ffi') 
local getbonePosition = ffi.cast("int (__thiscall*)(void*, float*, int, bool)", 0x5E4280)

anims = {'DAM_armL_frmBK', 'DAM_armL_frmFT', 'DAM_armL_frmLT', 'DAM_armR_frmBK', 'DAM_armR_frmFT', 'DAM_armR_frmRT', 'DAM_LegL_frmBK', 'DAM_LegL_frmFT', 'DAM_LegL_frmLT', 'DAM_LegR_frmBK', 'DAM_LegR_frmFT', 'DAM_LegR_frmRT', 'DAM_stomach_frmBK', 'DAM_stomach_frmFT', 'DAM_stomach_frmLT', 'DAM_stomach_frmRT'}
siteAnims = {'GUN_STAND', 'GUNMOVE_L', 'GUNMOVE_R', 'GUNMOVE_FWD', 'GUNMOVE_BWD'}

font = renderCreateFont('Bold', 9, 19)

dow = false
airbreak = false
jumpbmx = false
lastsmooth = -1
lastdist = -1
multiplier = 1
ncr = false
player = -1
input = imgui.ImBuffer(256)

GUI =
{
    windowState = imgui.ImBool(false),
    currentButtonID = 1,
    aimbot = 
    {
        Smooth = imgui.ImFloat(5.0),
        Radius = imgui.ImFloat(80.0),
        Safe = imgui.ImFloat(1.0),
        SuperSmooth = imgui.ImFloat(1.0),
        Enable = imgui.ImBool(false),
        IsFire = imgui.ImBool(false),
        VisibleCheck = imgui.ImBool(false),
        DynamicSmooth = imgui.ImBool(false),
        CFilter = imgui.ImBool(false),
        IgnoreRange = imgui.ImBool(false),
        IgnoreStun = imgui.ImBool(false)
    },
    visual = 
    {
        DrawFOV = imgui.ImBool(false),
        ESPLine = imgui.ImBool(false),
        ESPBones = imgui.ImBool(false),
        ESPBox = imgui.ImBool(false),
        ESPInfo = imgui.ImBool(false)
    },
    actor =
    {
        NoStun = imgui.ImBool(false),
        InfiniteRun = imgui.ImBool(false),
        NoFall = imgui.ImBool(false),
        NoCamRestore = imgui.ImBool(false),
        GodMode = imgui.ImBool(false),
        AirBreak = imgui.ImBool(false)
    },
    vehicle = 
    {
        SpeedHack = imgui.ImBool(false),
        SpeedSmooth = imgui.ImFloat(20.0),
        Drive = imgui.ImBool(false),
        FastExit = imgui.ImBool(false),
        JumpBMX = imgui.ImBool(false),
        BikeFall = imgui.ImBool(false)
    }
}

local config = inicfg.load({
    settings = 
    {
        aimbot_smooth = GUI.aimbot.Smooth.v,
        aimbot_radius = GUI.aimbot.Radius.v,
        aimbot_safe = GUI.aimbot.Safe.v,
        aimbot_supersmooth = GUI.aimbot.SuperSmooth.v,
        aimbot_enable = GUI.aimbot.Enable.v,
        aimbot_isfire = GUI.aimbot.IsFire.v,
        aimbot_visiblecheck = GUI.aimbot.VisibleCheck.v,
        aimbot_dynamicsmooth = GUI.aimbot.DynamicSmooth.v,
        aimbot_cfilter = GUI.aimbot.CFilter.v,
        aimbot_ignorerange = GUI.aimbot.IgnoreRange.v,
        aimbot_ignorestun = GUI.aimbot.IgnoreStun.v,
        visual_drawfov = GUI.visual.DrawFOV.v,
        visual_espline = GUI.visual.ESPLine.v,
        visual_espbones = GUI.visual.ESPBones.v,
        visual_espbox = GUI.visual.ESPBox.v,
        visual_espinfo = GUI.visual.ESPInfo.v,
        actor_nostun = GUI.actor.NoStun.v,
        actor_infiniterun = GUI.actor.InfiniteRun.v,
        actor_nofall = GUI.actor.NoFall.v,
        actor_nocamrestore = GUI.actor.NoCamRestore.v,
        actor_godmode = GUI.actor.GodMode.v,
        actor_airbreak = GUI.actor.AirBreak.v,
        vehicle_speedhack = GUI.vehicle.SpeedHack.v,
        vehicle_speedsmooth = GUI.vehicle.SpeedSmooth.v,
        vehicle_drive = GUI.vehicle.Drive.v,
        vehicle_fastexit = GUI.vehicle.FastExit.v,
        vehicle_jumpbmx = GUI.vehicle.JumpBMX.v,
        vehicle_bikefall = GUI.vehicle.BikeFall.v
    }
})

function load_ini()
    local ini_file = inicfg.load(config)
    if ini_file then
        GUI.aimbot.Smooth.v = ini_file.settings.aimbot_smooth
        GUI.aimbot.Radius.v = ini_file.settings.aimbot_radius
        GUI.aimbot.Safe.v = ini_file.settings.aimbot_safe
        GUI.aimbot.SuperSmooth.v = ini_file.settings.aimbot_supersmooth
        GUI.aimbot.Enable.v = ini_file.settings.aimbot_enable
        GUI.aimbot.IsFire.v = ini_file.settings.aimbot_isfire
        GUI.aimbot.VisibleCheck.v = ini_file.settings.aimbot_visiblecheck
        GUI.aimbot.DynamicSmooth.v = ini_file.settings.aimbot_dynamicsmooth
        GUI.aimbot.CFilter.v = ini_file.settings.aimbot_cfilter
        GUI.aimbot.IgnoreRange.v = ini_file.settings.aimbot_ignorerange
        GUI.aimbot.IgnoreStun.v = ini_file.settings.aimbot_ignorestun
        GUI.visual.DrawFOV.v = ini_file.settings.visual_drawfov
        GUI.visual.ESPLine.v = ini_file.settings.visual_espline
        GUI.visual.ESPBones.v = ini_file.settings.visual_espbones
        GUI.visual.ESPBox.v = ini_file.settings.visual_espbox
        GUI.visual.ESPInfo.v = ini_file.settings.visual_espinfo
        GUI.actor.NoStun.v = ini_file.settings.actor_nostun
        GUI.actor.InfiniteRun.v = ini_file.settings.actor_infiniterun
        GUI.actor.NoFall.v = ini_file.settings.actor_nofall
        GUI.actor.NoCamRestore.v = ini_file.settings.actor_nocamrestore
        GUI.actor.GodMode.v = ini_file.settings.actor_godmode
        GUI.actor.AirBreak.v = ini_file.settings.actor_airbreak
        GUI.vehicle.SpeedHack.v = ini_file.settings.vehicle_speedhack
        GUI.vehicle.SpeedSmooth.v = ini_file.settings.vehicle_speedsmooth
        GUI.vehicle.Drive.v = ini_file.settings.vehicle_drive
        GUI.vehicle.FastExit.v = ini_file.settings.vehicle_fastexit
        GUI.vehicle.JumpBMX.v = ini_file.settings.vehicle_jumpbmx
        GUI.vehicle.BikeFall.v = ini_file.settings.vehicle_bikefall
    end
end

function save_ini()
    config.settings.aimbot_smooth = GUI.aimbot.Smooth.v
    config.settings.aimbot_radius = GUI.aimbot.Radius.v
    config.settings.aimbot_safe = GUI.aimbot.Safe.v
    config.settings.aimbot_supersmooth = GUI.aimbot.SuperSmooth.v
    config.settings.aimbot_enable = GUI.aimbot.Enable.v
    config.settings.aimbot_isfire = GUI.aimbot.IsFire.v
    config.settings.aimbot_visiblecheck = GUI.aimbot.VisibleCheck.v
    config.settings.aimbot_dynamicsmooth = GUI.aimbot.DynamicSmooth.v
    config.settings.aimbot_cfilter = GUI.aimbot.CFilter.v
    config.settings.aimbot_ignorerange = GUI.aimbot.IgnoreRange.v
    config.settings.aimbot_ignorestun = GUI.aimbot.IgnoreStun.v
    config.settings.visual_drawfov = GUI.visual.DrawFOV.v
    config.settings.visual_espline = GUI.visual.ESPLine.v
    config.settings.visual_espbones = GUI.visual.ESPBones.v
    config.settings.visual_espbox = GUI.visual.ESPBox.v
    config.settings.visual_espinfo = GUI.visual.ESPInfo.v
    config.settings.actor_nostun = GUI.actor.NoStun.v
    config.settings.actor_infiniterun = GUI.actor.InfiniteRun.v
    config.settings.actor_nofall = GUI.actor.NoFall.v
    config.settings.actor_nocamrestore = GUI.actor.NoCamRestore.v
    config.settings.actor_godmode = GUI.actor.GodMode.v
    config.settings.actor_airbreak = GUI.actor.AirBreak.v
    config.settings.vehicle_speedhack = GUI.vehicle.SpeedHack.v
    config.settings.vehicle_speedsmooth = GUI.vehicle.SpeedSmooth.v
    config.settings.vehicle_drive = GUI.vehicle.Drive.v
    config.settings.vehicle_fastexit = GUI.vehicle.FastExit.v
    config.settings.vehicle_jumpbmx = GUI.vehicle.JumpBMX.v
    config.settings.vehicle_bikefall = GUI.vehicle.BikeFall.v
    inicfg.save(config, script.this.filename..'.ini')
end

function reset_ini()
    GUI =
    {
        windowState = imgui.ImBool(true),
        currentButtonID = 1,
        aimbot = 
        {
            Smooth = imgui.ImFloat(5.0),
            Radius = imgui.ImFloat(80.0),
            Safe = imgui.ImFloat(1.0),
            SuperSmooth = imgui.ImFloat(1.0),
            Enable = imgui.ImBool(false),
            IsFire = imgui.ImBool(false),
            VisibleCheck = imgui.ImBool(false),
            DynamicSmooth = imgui.ImBool(false),
            CFilter = imgui.ImBool(false),
            IgnoreRange = imgui.ImBool(false),
            IgnoreStun = imgui.ImBool(false)
        },
        visual = 
        {
            DrawFOV = imgui.ImBool(false),
            ESPLine = imgui.ImBool(false),
            ESPBones = imgui.ImBool(false),
            ESPBox = imgui.ImBool(false),
            ESPInfo = imgui.ImBool(false)
        },
        actor =
        {
            NoStun = imgui.ImBool(false),
            InfiniteRun = imgui.ImBool(false),
            NoFall = imgui.ImBool(false),
            NoCamRestore = imgui.ImBool(false),
            GodMode = imgui.ImBool(false),
            AirBreak = imgui.ImBool(false)
        },
        vehicle = 
        {
            SpeedHack = imgui.ImBool(false),
            SpeedSmooth = imgui.ImFloat(20.0),
            Drive = imgui.ImBool(false),
            FastExit = imgui.ImBool(false),
            JumpBMX = imgui.ImBool(false),
            BikeFall = imgui.ImBool(false)
        }
    }
    save_ini()
end

function main()
    if not initialized then
        if not isSampAvailable() then return false end 
        load_ini()
        guiCustomStyle()
        lua_thread.create(Aimbot)
        lua_thread.create(Visual)
        lua_thread.create(Actor)
        lua_thread.create(Vehicle)
        initialized = true
    end
    if wasKeyPressed(VK_OEM_3) then
        GUI.windowState.v = not GUI.windowState.v
    end
    imgui.Process = GUI.windowState.v
    return false
end

function imgui.OnDrawFrame()
    if GUI.windowState.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(600, 300), imgui.Cond.FirstUseEver)
        imgui.Begin('FPSUP', nil, imgui.WindowFlags.NoCollapse + imgui.WindowFlags.NoResize + imgui.WindowFlags.NoMove)
        imgui.SetCursorPos(imgui.ImVec2(15, 25))
        if imgui.Button('Aimbot', imgui.ImVec2(100, 24)) then
            GUI.currentButtonID = 1
        end
        imgui.SetCursorPos(imgui.ImVec2(120, 25)) 
        if imgui.Button('Visual', imgui.ImVec2(100, 24)) then
            GUI.currentButtonID = 2
        end
        imgui.SetCursorPos(imgui.ImVec2(225, 25))
        if imgui.Button('Self', imgui.ImVec2(100, 24)) then
            GUI.currentButtonID = 3
        end
        imgui.SetCursorPos(imgui.ImVec2(330, 25))
        if imgui.Button('Motor', imgui.ImVec2(100, 24)) then
            GUI.currentButtonID = 4
        end
        imgui.SetCursorPos(imgui.ImVec2(435, 25))
        if imgui.Button('Settings', imgui.ImVec2(100, 24)) then
            GUI.currentButtonID = 5
        end
        imgui.SetCursorPos(imgui.ImVec2(540, 25))
        if imgui.Button('Console', imgui.ImVec2(50, 24)) then
            GUI.currentButtonID = 6
        end
        if imgui.CollapsingHeader("Developers") then
            imgui.Text('    > Carrentine ')
            imgui.Text('    > Techiecious ')
            
        end
        if GUI.currentButtonID == 1 then
            imgui.SetCursorPosX(5)
            imgui.SliderFloat('Smooth', GUI.aimbot.Smooth, 1.0, 25.0, "%.1f")
            imgui.SetCursorPosX(5)
            imgui.SliderFloat('Radius', GUI.aimbot.Radius, 1.0, 300.0, "%.1f")
            imgui.SetCursorPosX(5)
            imgui.SliderFloat('SafeZone', GUI.aimbot.Safe, 1.0, 300.0, "%.1f")
            imgui.SetCursorPosX(5)
            imgui.SliderFloat('SuperSmooth', GUI.aimbot.SuperSmooth, 1.0, 25.0, "%.1f")
            imgui.SetCursorPosX(5)
            imgui.Checkbox('Enable', GUI.aimbot.Enable)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('IsFire', GUI.aimbot.IsFire)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('VisibleCheck', GUI.aimbot.VisibleCheck)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('DynamicSmooth', GUI.aimbot.DynamicSmooth)
            imgui.SetCursorPos(imgui.ImVec2(150, 221))
            imgui.Checkbox('CFilter', GUI.aimbot.CFilter)
            imgui.SetCursorPos(imgui.ImVec2(150, 197))
            imgui.Checkbox('IgnoreRange', GUI.aimbot.IgnoreRange)
            imgui.SetCursorPos(imgui.ImVec2(150, 173))
            imgui.Checkbox('IgnoreStun', GUI.aimbot.IgnoreStun)
        end
        if GUI.currentButtonID == 2 then
            imgui.SetCursorPosX(5)
            imgui.Checkbox('ESP Line', GUI.visual.ESPLine)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('ESP Bones', GUI.visual.ESPBones)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('ESP Box', GUI.visual.ESPBox)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('ESP Info', GUI.visual.ESPInfo)
            imgui.SetCursorPos(imgui.ImVec2(150, 77))
            imgui.Checkbox('Draw FOV', GUI.visual.DrawFOV)
        end
        if GUI.currentButtonID == 3 then
            imgui.SetCursorPosX(5)
            imgui.Checkbox('NoStun', GUI.actor.NoStun)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('NoFall', GUI.actor.NoFall)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('NoCamRestore', GUI.actor.NoCamRestore)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('InfiniteRun', GUI.actor.InfiniteRun)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('GodMode', GUI.actor.GodMode)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('AirBreak', GUI.actor.AirBreak)
        end
        if GUI.currentButtonID == 4 then
            imgui.SetCursorPosX(5)
            imgui.SliderFloat('SpeedSmooth', GUI.vehicle.SpeedSmooth, 1.0, 30.0, "%.1f")
            imgui.SetCursorPosX(5)
            imgui.Checkbox('SpeedHack', GUI.vehicle.SpeedHack)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('DriveInWater', GUI.vehicle.Drive)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('FastExit', GUI.vehicle.FastExit)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('JumpBMX', GUI.vehicle.JumpBMX)
            imgui.SetCursorPosX(5)
            imgui.Checkbox('BikeFall', GUI.vehicle.BikeFall)
        end
        if GUI.currentButtonID == 5 then
            imgui.SetCursorPosX(5)
            if imgui.Button('Import', imgui.ImVec2(590, 25)) then load_ini() end
            imgui.SetCursorPosX(5)
            if imgui.Button('Save', imgui.ImVec2(590, 25)) then save_ini() end
            imgui.SetCursorPosX(5)
            if imgui.Button('Reset', imgui.ImVec2(590, 25)) then reset_ini() end
        end
        if GUI.currentButtonID == 6 then
            imgui.SetCursorPosX(5)
            imgui.InputText('Input', input) 
            imgui.SetCursorPosX(5)
            if imgui.Button('Send') then
                if input.v == 'DEATH' or input.v == 'death' then
                    setCharHealth(PLAYER_PED, 0)
                end
                if input.v == 'RECON' or input.v == 'recon' then
                    local ip, port = sampGetCurrentServerAddress()
                    sampDisconnectWithReason(false)
                    sampConnectToServer(ip, port)
                end
                if input.v == 'RELOAD' or input.v == 'reload' then
                    sampToggleCursor(false)
                    showCursor(false)
                    thisScript():reload()
                end
                input.v = ''
            end
            imgui.Text('All commands:\n\nDEATH\nRECON\nRELOAD')
        end
        imgui.End()
    end
end

function Aimbot()
    if GUI.aimbot.Enable.v and isKeyDown(VK_RBUTTON) then
        if not GUI.aimbot.IsFire.v or (GUI.aimbot.IsFire.v and isKeyDown(VK_LBUTTON)) then
            local playerID = GetNearestPed()
            if playerID ~= -1 then
                local pedID = sampGetPlayerIdByCharHandle(PLAYER_PED)
                if (GUI.aimbot.IgnoreStun.v and not CheckStuned()) then return false end
                if (GUI.aimbot.CFilter.v and sampGetPlayerColor(pedID) == sampGetPlayerColor(playerID)) then return false end
                local _, handle = sampGetCharHandleBySampPlayerId(playerID)
                local myPos = {getActiveCameraCoordinates()}
                local enPos = {GetBodyPartCoordinates(GetNearestBone(handle), handle)}
                if not GUI.aimbot.VisibleCheck.v or (GUI.aimbot.VisibleCheck.v and isLineOfSightClear(myPos[1], myPos[2], myPos[3], enPos[1], enPos[2], enPos[3], true, true, false, true, true)) then
                    local pedWeapon = getCurrentCharWeapon(PLAYER_PED)
                    if (pedWeapon >= 22 and pedWeapon <= 29) or pedWeapon == 32 then
                        coefficent = 0.04253
                    elseif pedWeapon == 30 or pedWeapon == 31 then
                        coefficent = 0.028
                    elseif pedWeapon == 33 then
                        сoefficent = 0.01897
                    end
                    local vector = {myPos[1] - enPos[1], myPos[2] - enPos[2]}
                    local angle = math.acos(vector[1] / math.sqrt((math.pow(vector[1], 2) + math.pow(vector[2], 2))))
                    local view = {fix(representIntAsFloat(readMemory(0xB6F258, 4, false))), fix(representIntAsFloat(readMemory(0xB6F248, 4, false)))}
                    if (vector[1] <= 0.0 and vector[2] >= 0.0) or (vector[1] >= 0.0 and vector[2] >= 0.0) then
                        dif = (angle + coefficent) - view[1]
                    end
                    if (vector[1] >= 0.0 and vector[2] <= 0.0) or (vector[1] <= 0.0 and vector[2] <= 0.0) then
                        dif = (-angle + coefficent) - view[1]
                    end
                    if GUI.aimbot.DynamicSmooth.v then multiplier = 5 else multiplier = 1 end
                    local smooth = dif / ((GUI.aimbot.Smooth.v * multiplier) * GUI.aimbot.SuperSmooth.v)
                    if GUI.aimbot.DynamicSmooth.v then
                        if smooth > 0.0 then
                            if smooth < lastsmooth then
                                smooth = smooth * (lastsmooth / smooth)
                            end
                        else 
                            if -smooth < -lastsmooth then
                                smooth = smooth * (-lastsmooth / -smooth)
                            end
                        end
                        lastsmooth = smooth
                    end
                    if smooth > -1.0 and smooth < 0.5 and dif > -2.0 and dif < 2.0 then
                        view[1] = view[1] + smooth
                        setCameraPositionUnfixed(view[2], view[1])
                    end
                end
            end
        end
    end
    return false
end

function Visual()
    if GUI.visual.DrawFOV.v then
        local crosshairPos = {convertGameScreenCoordsToWindowScreenCoords(339.1, 179.1)}
        renderFigure2D(crosshairPos[1], crosshairPos[2], GUI.aimbot.Radius.v >= 70 and 144 or 72, (GUI.aimbot.Radius.v - 1.0), 0xFF00FF00)
        renderFigure2D(crosshairPos[1], crosshairPos[2], GUI.aimbot.Safe.v >= 70 and 144 or 72, (GUI.aimbot.Safe.v - 1.0), 0xFFFF0000)
    end
    for i = 0, sampGetMaxPlayerId(true) do
        if sampIsPlayerConnected(i) then
            local find, handle = sampGetCharHandleBySampPlayerId(i)
            if find then
                 if isCharOnScreen(handle) then
                    local myPos = {GetBodyPartCoordinates(3, PLAYER_PED)}
                    local enPos = {GetBodyPartCoordinates(3, handle)}
                    if (isLineOfSightClear(myPos[1], myPos[2], myPos[3], enPos[1], enPos[2], enPos[3], true, true, false, true, true)) then
                        color = 0xFF00FF00
                    else
                        color = 0xFFFF0000
                    end
                    if GUI.visual.ESPLine.v then
                        local myPosScreen = {convert3DCoordsToScreen(GetBodyPartCoordinates(3, PLAYER_PED))}
                        local enPosScreen = {convert3DCoordsToScreen(GetBodyPartCoordinates(3, handle))}
                        renderDrawLine(myPosScreen[1], myPosScreen[2], enPosScreen[1], enPosScreen[2], 1, color)
                    end
                    if GUI.visual.ESPBones.v then
                        local t = {3, 4, 5, 51, 52, 41, 42, 31, 32, 33, 21, 22, 23, 2}
						for v = 1, #t do
							pos1 = {GetBodyPartCoordinates(t[v], handle)}
							pos2 = {GetBodyPartCoordinates(t[v] + 1, handle)}
							pos1Screen = {convert3DCoordsToScreen(pos1[1], pos1[2], pos1[3])}
							pos2Screen = {convert3DCoordsToScreen(pos2[1], pos2[2], pos2[3])}
							renderDrawLine(pos1Screen[1], pos1Screen[2], pos2Screen[1], pos2Screen[2], 1, color)
						end
						for v = 4, 5 do
							pos2 = {GetBodyPartCoordinates(v * 10 + 1, handle)}
							pos2Screen = {convert3DCoordsToScreen(pos2[1], pos2[2], pos2[3])}
							renderDrawLine(pos1Screen[1], pos1Screen[2], pos2Screen[1], pos2Screen[2], 1, color)
						end
						local t = {53, 43, 24, 34, 6}
						for v = 1, #t do
							pos = {GetBodyPartCoordinates(t[v], handle)}
							pos1Screen = {convert3DCoordsToScreen(pos[1], pos[2], pos[3])}
						end
                    end
                    if GUI.visual.ESPBox.v then
                        local headPos = {GetBodyPartCoordinates(8, handle)}
                        local footPos = {GetBodyPartCoordinates(44, handle)}
                        local pointOne =
                        {
                            x = headPos[1] - 0.5,
                            y = headPos[2],
                            z = headPos[3] + 0.35
                        } 
                        local pointTwo =
                        {
                            x = headPos[1] + 0.5,
                            y = headPos[2],
                            z = headPos[3] - 0.35
                        }
                        local pointThree =
                        {
                            x = footPos[1] + 0.5,
                            y = footPos[2],
                            z = footPos[3] - 0.35
                        }
                        local pointOneScreen = {convert3DCoordsToScreen(pointOne.x, pointOne.y, pointOne.z)}
                        local pointTwoScreen = {convert3DCoordsToScreen(pointTwo.x, pointTwo.y, pointOne.z)}
                        local pointThreeScreen = {convert3DCoordsToScreen(pointOne.x, pointThree.y, pointThree.z)}
                        local pointFourScreen = {convert3DCoordsToScreen(pointTwo.x, pointThree.y, pointThree.z)}
                        renderDrawLine(pointOneScreen[1], pointOneScreen[2], pointTwoScreen[1], pointTwoScreen[2], 1, color)
                        renderDrawLine(pointThreeScreen[1], pointThreeScreen[2], pointFourScreen[1], pointFourScreen[2], 1, color)
                        renderDrawLine(pointOneScreen[1], pointOneScreen[2], pointThreeScreen[1], pointThreeScreen[2], 1, color)
                        renderDrawLine(pointTwoScreen[1], pointTwoScreen[2], pointFourScreen[1], pointFourScreen[2], 1, color)
                    end
                    if GUI.visual.ESPInfo.v then
                        local enPosGame = {GetBodyPartCoordinates(8, handle)}
                        local point = 
                        {
                            x = enPosGame[1] - 0.3,
                            y = enPosGame[2],
                            z = enPosGame[3]
                        }
                        local enPosScr = {convert3DCoordsToScreen(point.x, point.y, point.z)}
                        local distance = math.sqrt((math.pow((enPos[1] - myPos[1]), 2) + math.pow((enPos[2] - myPos[2]), 2) + math.pow((enPos[3] - myPos[3]), 2)))
                        renderFontDrawText(font, string.format('Speed: %.1f\nName: %s\nDistance: %.1f\nSkin: %d\nNPC: %s\nAFK: %s', getCharSpeed(handle), sampGetPlayerNickname(i), distance, getCharModel(handle), tostring(sampIsPlayerNpc(i)), tostring(sampIsPlayerPaused(i))), enPosScr[1], enPosScr[2], color)
                    end
                end
            end
        end
    end
    return false
end

function Actor()
    setCharUsesUpperbodyDamageAnimsOnly(PLAYER_PED, GUI.actor.NoStun.v)
    setPlayerNeverGetsTired(PLAYER_PED, not GUI.actor.InfiniteRun.v)
    if GUI.actor.NoFall.v then
        if isCharPlayingAnim(PLAYER_PED, 'KO_SKID_BACK') or isCharPlayingAnim(PLAYER_PED, 'FALL_COLLAPSE') then
            local charPos = {getCharCoordinates(PLAYER_PED)}
            setCharCoordinates(PLAYER_PED, charPos[1], charPos[2], charPos[3] - 1)
        end
    end
    if GUI.actor.NoCamRestore.v then
        if not ncr then
            memory.write(0x5109AC, 235, 1, true)
            memory.write(0x5109C5, 235, 1, true)
            memory.write(0x5231A6, 235, 1, true)
            memory.write(0x52322D, 235, 1, true)
            memory.write(0x5233BA, 235, 1, true)
            ncr = true
        end
    else
        if ncr then
            memory.write(0x5109AC, 122, 1, true)
            memory.write(0x5109C5, 122, 1, true)
            memory.write(0x5231A6, 117, 1, true)
            memory.write(0x52322D, 117, 1, true)
            memory.write(0x5233BA, 117, 1, true)
            ncr = false
        end
    end
    if GUI.actor.GodMode.v then
        setCharProofs(PLAYER_PED, true, true, true, true, true)
    else
        setCharProofs(PLAYER_PED, false, false, false, false, false)
    end
    if GUI.actor.AirBreak.v then
        if wasKeyPressed(VK_RSHIFT) then
            airbreak = not airbreak
        end
        if airbreak then
            local charCoordinates = {getCharCoordinates(PLAYER_PED)}
            local ViewHeading = getCharHeading(PLAYER_PED)
            Coords = {charCoordinates[1], charCoordinates[2], charCoordinates[3], 0.0, 0.0, ViewHeading}
            local MainHeading = getCharHeading(PLAYER_PED)
            local Camera = {getActiveCameraCoordinates()}
            local Target = {getActiveCameraPointAt()}
            local RotateHeading = getHeadingFromVector2d(Target[1] - Camera[1], Target[2] - Camera[2])
            if isKeyDown(VK_W) then
                Coords[1] = Coords[1] + 0.25 * math.sin(-math.rad(RotateHeading))
                Coords[2] = Coords[2] + 0.25 * math.cos(-math.rad(RotateHeading))
                setCharHeading(PLAYER_PED, RotateHeading)
            elseif isKeyDown(VK_S) then
                Coords[1] = Coords[1] - 0.25 * math.sin(-math.rad(MainHeading))
                Coords[2] = Coords[2] - 0.25 * math.cos(-math.rad(MainHeading))
            end
            if isKeyDown(VK_A) then
                Coords[1] = Coords[1] - 0.25 * math.sin(-math.rad(MainHeading - 90))
                Coords[2] = Coords[2] - 0.25 * math.cos(-math.rad(MainHeading - 90))
            elseif isKeyDown(VK_D) then
                Coords[1] = Coords[1] - 0.25 * math.sin(-math.rad(MainHeading + 90))
                Coords[2] = Coords[2] - 0.25 * math.cos(-math.rad(MainHeading + 90))
            end
            if isKeyDown(VK_SPACE) then Coords[3] = Coords[3] + 0.25 / 1.5 end
            if isKeyDown(VK_LSHIFT) and Coords[3] > -95.0 then Coords[3] = Coords[3] - 0.25 / 1.5 end
            setCharCoordinates(PLAYER_PED, Coords[1], Coords[2], Coords[3] - 1)
        end
    end
    return false
end

function Vehicle()
    if GUI.vehicle.SpeedHack.v then
        if isKeyDown(VK_LMENU) then
            if isCharInAnyCar(PLAYER_PED) then
                local car = storeCarCharIsInNoSave(PLAYER_PED)
                local vector = {getCarSpeedVector(car)}
                local heading = getCarHeading(car)
                local turbo = fpsCorrection() / (GUI.vehicle.SpeedSmooth.v * 10)
                local force = {turbo, turbo, turbo}
                local Sin, Cos = math.sin(-math.rad(heading)), math.cos(-math.rad(heading))
                if vector[1] > -0.01 and vector[1] < 0.01 then force[1] = 0.0 end
                if vector[2] > -0.01 and vector[2] < 0.01 then force[2] = 0.0 end
                if vector[3] < 0 then force[3] = -force[3] end
                if vector[3] > -2 and vector[3] < 15 then force[3] = 0.0 end
                if Sin > 0 and vector[1] < 0 then force[1] = -force[1] end
                if Sin < 0 and vector[1] > 0 then force[1] = -force[1] end
                if Cos > 0 and vector[2] < 0 then force[2] = -force[2] end
                if Cos < 0 and vector[2] > 0 then force[2] = -force[2] end
                applyForceToCar(car, force[1] * Sin, force[2] * Cos, force[3] / 2, 0.0, 0.0, 0.0)
            end
        end
    end
    if GUI.vehicle.Drive.v then
        if not dow then
            memory.write(0x6CC303, 0x621F8A, 3, true)
            memory.write(0x6A90C5, 0xEB, 1, true)
            dow = true
        end
    else
        if dow then
            memory.write(0x6CC303, 0xEFE180, 3, true)
            memory.write(0x6A90C5, 0x7A, 1, true)
            dow = false
        end
    end
    if GUI.vehicle.FastExit.v then
        if wasKeyPressed(VK_F) then
            if isCharInAnyCar(PLAYER_PED) then
                local car = storeCarCharIsInNoSave(PLAYER_PED)
                local speed = getCarSpeed(car)
                clearCharTasksImmediately(PLAYER_PED) 
                local pos = {getCharCoordinates(PLAYER_PED)}
                setCharCoordinates(PLAYER_PED, pos[1], pos[2], pos[3] + 2)
            end
        end
    end
    if GUI.vehicle.JumpBMX then
        if not jumpbmx then
            memory.setint8(0x969161, 1)
            jumpbmx = true
        end
    else
        if jumpbmx then
            memory.setint8(0x969161, 0)
            jumpbmx = false
        end
    end
    setCharCanBeKnockedOffBike(PLAYER_PED, GUI.vehicle.BikeFall.v)
    return false 
end

function sampev.onSendPlayerSync(data)
    if airbreak then
        data.animationId = 1130
        data.moveSpeed = {x = 0.89, y = 0.89, z = -0.89}
    end
end

function sampev.onSetPlayerPos()
    if airbreak then
        return false 
    end
end

function sampev.onRequestSpawnResponse() if GUI.actor.GodMode.v then return false end end
function sampev.onRequestClassResponse() if GUI.actor.GodMode.v then return false end end
function sampev.onResetPlayerWeapons() if GUI.actor.GodMode.v then return false end end
function sampev.onSetCameraBehind() if GUI.actor.GodMode.v then return false end end
function sampev.onTogglePlayerControllable() if GUI.actor.GodMode.v then return false end end
function sampev.onSetPlayerSkin() if GUI.actor.GodMode.v then return false end end
function sampev.onSetPlayerHealth() if GUI.actor.GodMode.v then return false end end
function sampev.onBulletSync() if GUI.actor.GodMode.v then return false end end

function renderFigure2D(x, y, points, radius, color)
    local step = math.pi * 2 / points
    local render_start, render_end = {}, {}
    for i = 0, math.pi * 2, step do
        render_start[1] = radius * math.cos(i) + x
        render_start[2] = radius * math.sin(i) + y
        render_end[1] = radius * math.cos(i + step) + x
        render_end[2] = radius * math.sin(i + step) + y
        renderDrawLine(render_start[1], render_start[2], render_end[1], render_end[2], 1, color)
    end
end

function fpsCorrection()
	return representIntAsFloat(readMemory(0xB7CB5C, 4, false))
end

function fix(angle)
    if angle > math.pi then
        angle = angle - (math.pi * 2)
    elseif angle < -math.pi then 
        angle = angle + (math.pi * 2) 
    end
    return angle
end

function GetNearestPed()
    local maxDistance = nil
    if not GUI.aimbot.IgnoreRange.v then maxDistance = 35 else maxDistance = 20000 end
    local nearestPED = -1
    for i = 0, sampGetMaxPlayerId(true) do
        if sampIsPlayerConnected(i) then
            local find, handle = sampGetCharHandleBySampPlayerId(i)
            if find then
                if isCharOnScreen(handle) then
                    if not isCharDead(handle) then
                        local crosshairPos = {convertGameScreenCoordsToWindowScreenCoords(339.1, 179.1)}
                        local enPos = {GetBodyPartCoordinates(GetNearestBone(handle), handle)}
                        local bonePos = {convert3DCoordsToScreen(enPos[1], enPos[2], enPos[3])}
                        local distance = math.sqrt((math.pow((bonePos[1] - crosshairPos[1]), 2) + math.pow((bonePos[2] - crosshairPos[2]), 2)))
                        if distance < GUI.aimbot.Safe.v or distance > GUI.aimbot.Radius.v then check = true else check = false end 
                        if not check then
                            local myPos = {getCharCoordinates(PLAYER_PED)}
                            local enPos = {getCharCoordinates(handle)}
                            local distance = math.sqrt((math.pow((enPos[1] - myPos[1]), 2) + math.pow((enPos[2] - myPos[2]), 2) + math.pow((enPos[3] - myPos[3]), 2)))
                            if (distance < maxDistance) then
                                nearestPED = i
                                maxDistance = distance
                            end
                        end
                    end
                end
            end
        end
    end
    return nearestPED
end

function CheckStuned()
	for k, v in pairs(anims) do
		if isCharPlayingAnim(PLAYER_PED, v) then
			return false
		end
	end
	return true
end

function GetNearestBone(handle)
    local maxDist = 20000    
    local nearestBone = -1
    bone = {42, 52, 23, 33, 3, 22, 32, 8}
    for n = 1, 8 do
        local crosshairPos = {convertGameScreenCoordsToWindowScreenCoords(339.1, 179.1)}
        local bonePos = {GetBodyPartCoordinates(bone[n], handle)}
        local enPos = {convert3DCoordsToScreen(bonePos[1], bonePos[2], bonePos[3])}
        local distance = math.sqrt((math.pow((enPos[1] - crosshairPos[1]), 2) + math.pow((enPos[2] - crosshairPos[2]), 2)))
        if (distance < maxDist) then
            nearestBone = bone[n]
            maxDist = distance
        end 
    end
    return nearestBone
end

function GetBodyPartCoordinates(id, handle)
    if doesCharExist(handle) then
        local pedptr = getCharPointer(handle)
        local vec = ffi.new("float[3]")
        getbonePosition(ffi.cast("void*", pedptr), vec, id, true)
        return vec[0], vec[1], vec[2]
    end
end

function guiCustomStyle()
    imgui.SwitchContext()
    local style = imgui.GetStyle()
    local colors = style.Colors
    local clr = imgui.Col
    local ImVec4 = imgui.ImVec4
    style.WindowRounding = 10.0
    style.WindowTitleAlign = imgui.ImVec2(0.5, 0.5)
    style.ChildWindowRounding = 10.0
    style.FrameRounding = 10.0
    style.ItemSpacing = imgui.ImVec2(9.0, 4.0)
    style.ScrollbarSize = 13.0
    style.ScrollbarRounding = 15.0
    style.GrabMinSize = 10.0
    style.GrabRounding = 30.0
    colors[clr.FrameBg]                = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.FrameBgHovered]         = ImVec4(0, 0.90, 0, 0.90)
    colors[clr.FrameBgActive]          = ImVec4(0, 0.90, 0, 0.30)
    colors[clr.TitleBg]                = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.TitleBgActive]          = ImVec4(0, 0.60, 0, 0.90)
    colors[clr.TitleBgCollapsed]       = ImVec4(0.48, 0.16, 0.16, 1.00)
    colors[clr.CheckMark]              = ImVec4(0, 0.90, 0, 0.90)
    colors[clr.SliderGrab]             = ImVec4(0, 0.90, 0, 0.80)
    colors[clr.SliderGrabActive]       = ImVec4(0, 0.90, 0, 0.60)
    colors[clr.Button]                 = ImVec4(0, 0.90, 0, 0.50)
    colors[clr.ButtonHovered]          = ImVec4(0, 0.90, 0, 0.20)
    colors[clr.ButtonActive]           = ImVec4(0, 0.90, 0, 0.60)
    colors[clr.Header]                 = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.HeaderHovered]          = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.HeaderActive]           = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.Separator]              = colors[clr.Border]
    colors[clr.SeparatorHovered]       = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.SeparatorActive]        = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.ResizeGrip]             = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.ResizeGripHovered]      = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.ResizeGripActive]       = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.TextSelectedBg]         = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.Text]                   = ImVec4(1.00, 1.00, 1.00, 1.00)
    colors[clr.TextDisabled]           = ImVec4(0.50, 0.50, 0.50, 1.00)
    colors[clr.WindowBg]               = ImVec4(0.06, 0.06, 0.06, 0.94)
    colors[clr.ChildWindowBg]          = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.PopupBg]                = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.ComboBg]                = colors[clr.PopupBg]
    colors[clr.Border]                 = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.BorderShadow]           = ImVec4(0.00, 0.00, 0.00, 0.00)
    colors[clr.MenuBarBg]              = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.ScrollbarBg]            = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.ScrollbarGrab]          = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.ScrollbarGrabHovered]   = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.ScrollbarGrabActive]    = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.CloseButton]            = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.CloseButtonHovered]     = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.CloseButtonActive]      = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.PlotLines]              = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.PlotLinesHovered]       = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.PlotHistogram]          = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.PlotHistogramHovered]   = ImVec4(0, 0.90, 0, 0.40)
    colors[clr.ModalWindowDarkening]   = ImVec4(0, 0.90, 0, 0.40)
end 

Lua online compiler

Write, Run & Share Lua code online using OneCompiler's Lua online compiler for free. It's one of the robust, feature-rich online compilers for Lua language, running the latest Lua version 5.4. Getting started with the OneCompiler's Lua editor is easy and fast. The editor shows sample boilerplate code when you choose language as Lua and start coding.

Taking inputs (stdin)

OneCompiler's Lua online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample Lua program which takes name as input and prints hello message with your name.

name = io.read("*a")
print ("Hello ", name)

About Lua

Lua is a light weight embeddable scripting language which is built on top of C. It is used in almost all kind of applications like games, web applications, mobile applications, image processing etc. It's a very powerful, fast, easy to learn, open-source scripting language.

Syntax help

Variables

  • By default all the variables declared are global variables
  • If the variables are explicitly mentioned as local then they are local variables.
  • Lua is a dynamically typed language and hence only the values will have types not the variables.

Examples

-- global variables
a = 10

-- local variables

local x = 30
Value TypeDescription
numberRepresents numbers
stringRepresents text
nilDifferentiates values whether it has data or not
booleanValue can be either true or false
functionRepresents a sub-routine
userdataRepresents arbitary C data
threadRepresents independent threads of execution.
tableCan hold any value except nil

Loops

1. While:

While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.

while(condition)
do
--code
end

2. Repeat-Until:

Repeat-Until is also used to iterate a set of statements based on a condition. It is very similar to Do-While, it is mostly used when you need to execute the statements atleast once.

repeat
   --code
until( condition )

3. For:

For loop is used to iterate a set of statements based on a condition.

for init,max/min value, increment
do
   --code
end

Functions

Function is a sub-routine which contains set of statements. Usually functions are written when multiple calls are required to same set of statements which increase re-usuability and modularity.

optional_function_scope function function_name( argument1, argument2, argument3........, argumentn)
--code
return params with comma seperated
end