require("vrmod")


local frame, tabselect
local friendlist = {}
local blockedhooks = {}

surface.CreateFont("MAIN", {
    font = "Minecraft",
    size = 13,
    weight = 1000,
    antialias = true
})

local vars = {
    me = LocalPlayer(),
    cmdfont = "MAIN",

    MenuToggle = false,

    bSendPacket = true,

    sw = ScrW(),
    sh = ScrH(),
    model = nil,
    vieworigin = LocalPlayer():EyePos(),
    fa = LocalPlayer():EyeAngles(),
    activeWeapon = LocalPlayer():GetActiveWeapon(),
    activeWeaponClass = IsValid(LocalPlayer():GetActiveWeapon()) and LocalPlayer():GetActiveWeapon():GetClass() or "",
    CustomSpread = {},
    SpreadComps = {},
    cones = {},
    bulletImpacts = {},
    traceStruct = { mask = MASK_SHOT, filter = me },
    hitlogs = {data = {}},
    add = {x = 0, y = 0},
    CurTime = CurTime,
    realFrameTime = RealFrameTime,
    GetLatency = (LocalPlayer():Ping()/1000),
    nulVec = Vector(),
    WeaponPrefixes = {
        "m9k_",
        "fas2",
        "tfa",
        "cw",
        "arccw",
        "swb"
    },

    hooksToRemove = {},
    hAdd = hook.Add,
    hGetTable = hook.GetTable(),
    hRemove = hook.Remove,

    baseyaw = 0,

    toStr = tostring,
    isValid = IsValid,
    j = jit,

    sg = false,

    math_deg = math.deg,
    math_cos = math.cos,
    math_asin = math.asin,
    math_abs = math.abs,
    math_sin = math.sin,
    math_tan = math.tan,
    math_acos = math.acos,
    math_sqrt = math.sqrt,
    math_pi = math.pi,
    math_floor = math.floor,
    math_rad = math.rad,
    math_round = math.Round,
    math_NormAngle = math.NormalizeAngle,
    math_huge = math.huge,
    math_random = math.random,
    math_rand = math.Rand,
    math_randomseed = math.randomseed,
    math_atan = math.atan,
    math_clamp = math.Clamp,

    dSimpleText = draw.SimpleText,
    dSimpleTextOutlined = draw.SimpleTextOutlined,
    dRoundedBox = draw.RoundedBox,

    sPlaySound = surface.PlaySound,
    sSetDrawColor = surface.SetDrawColor,
    sDrawRect = surface.DrawRect,
    sDrawLine = surface.DrawLine,
    sDrawText = surface.DrawText,
    sDrawCircle = surface.DrawCircle,
    sSetFont = surface.SetFont,
    sSetTextColor = surface.SetTextColor,
    sSetTextPos = surface.SetTextPos,
    sDrawOutlinedRect = surface.DrawOutlinedRect,
    sGetTextSize = surface.GetTextSize,

    rRView = render.RenderView,
    rClear = render.Clear,
    rCap = render.Capture,
    rCapPixels = render.CapturePixels,
    rSupEngLight = render.SuppressEngineLighting,
    rMatOver = render.MaterialOverride,
    rModelLight = render.SetModelLighting,
    rColorMod = render.SetColorModulation,
    rDepthRange = render.DepthRange,
    rBlend = render.SetBlend,
    rColorMat = render.SetColorMaterial,
    rDrawBox = render.DrawBox,

    vCreate = vgui.Create,
    vGetWorldPanel = vgui.GetWorldPanel,

    hudpaint = true,

    bhop = true,
    bhop_as = true,
    desync = false,
    
    thirdPersonEnabled = false,
    tps = true,
    tps_fov = 100,

    cam_fov = false,
    fov = 120,

    w_fov = false,
    wfov = 110,
 
    esp = true,
    esp_boxes = true,
    esp_chams = false,

    w_chams = false,

    hitsound = true,

    act = false,

    aim_fov = 10,
    aim_aimbot = true,
    aim_silent = true,
    aim_psilent = false,
    aim_autofire = false,
    aim_rapidfire = false,
    aim_wallz = false,
    aim_nospread = true,
    aim_norecoil = true,
    boneAim = 'ValveBiped.Bip01_Head1',

    predtype = 'classic',

    antiaim = false,
    aa_mode = 'none',
}
vars.j.on()
vars.j.flush()

local selfillum = {
    ["$basetexture"] = "vgui/white_additive",
    ["$bumpmap"] = "vgui/white_additive",
    ["$model"] = "1",
    ["$nocull"] = "0",
    ["$selfillum"] = 1,
    ["$selfIllumFresnel"] = 1,
    ["$selfIllumFresnelMinMaxExp"] = "[0.0 0.3 0.6]",
    ["$selfillumtint"] = "[0 0 0]",
}

local Glow2 = CreateMaterial("selfillum", "VertexLitGeneric", selfillum)

local function shouldFire(b)
    local wep = vars.activeWeaponClass
    local wepactive = vars.activeWeapon
    local weps = {
        'weapon_physgun',
        "weapon_physcannon",
        "gmod_tool",
        'hands',
        'none',
        'pocket',
        'inventory',
        'weapon_physcannon',
        'weapon_vape*',
    }
    if vars.me:Alive() and wep then
        for k, v in pairs( weps ) do
            if wep == v then return false end
        end
    end
    return true
end

local function screengrab()
	if vars.sg then return end
	vars.sg = true
 
	vars.rClear( 0, 0, 0, 255, true, true )
	vars.rRView( {
		origin = LocalPlayer():EyePos(),
		angles = LocalPlayer():EyeAngles(),
		x = 0,
		y = 0,
		w = ScrW(),
		h = ScrH(),
		dopostprocess = true,
		drawhud = true,
		drawmonitors = true,
		drawviewmodel = true
	} )
 
	local vguishits = vars.vGetWorldPanel()
 
	if IsValid( vguishits ) then
		vguishits:SetPaintedManually( true )
	end
 
	timer.Simple( 0.1, function()
		vars.vGetWorldPanel():SetPaintedManually( false )
		vars.sg = false
	end)
end
 
render.Capture = function(data)
	screengrab()
	local cap = vars.rCap( data )
    print("ScreenGrabbed | RenderCapture" )
	return cap
end

render.CapturePixels = function(data)
	screengrab()
	local cap = vars.rCapPixels( data )
    print("ScreenGrabbed | RenderCapturePixels" )
	return cap
end

local function IsFriend(steamID)
    for _, id in ipairs(friendlist) do
        if id == steamID then return true end
    end
    return false
end

local function VARhooks(event, func)
    local hooks = vars.hGetTable
    local possibleHooks = {}

    for hookEvent, funcTable in pairs(hooks) do
        if hookEvent == event then
            for id, _ in pairs(funcTable) do
                table.insert(possibleHooks, id)
            end
        end
    end

    local hookID
    if #possibleHooks > 0 then
        local randomIndex = vars.math_random(1, #possibleHooks)
        hookID = util.CRC(vars.math_random(10^4)+SysTime()) --possibleHooks[randomIndex]
    else
        hookID = util.CRC(vars.math_random(10^4)+SysTime()) --event
    end
    vars.hAdd(event, hookID, func)
    if !vars.hooksToRemove[event] then
        vars.hooksToRemove[event] = {}
    end
    table.insert(vars.hooksToRemove[event], hookID)

    print("Hook ajouté → Événement:", event, "| ID:", hookID)
end

local colors = {
    white = Color(255, 255, 255),
    red = Color(255, 0, 0),
    grey = Color(100, 100, 100, 255),
    armor = Color(0, 100, 255, 255),
    background = Color(0, 0, 0, 200),
    darkGrey = Color(50, 50, 50),
    unhover = Color(173, 16, 171),
    hover = Color(138, 14, 136),
    header = Color(204, 16, 201),
    bg = Color(65, 65, 65, 230),
    seafoam = Color(201, 255, 229)
}

-- === FONCTIONS CUSTOM ===
local function DrawText(col, x, y, str, font)
    vars.sSetFont(font)
    vars.sSetTextColor(col.r, col.g, col.b, col.a)
    vars.sSetTextPos(x, y)
    vars.sDrawText(str)
end

local function GetTextSize(font, str)
    vars.sSetFont(font)
    return vars.sGetTextSize(str)
end

local function ThemeBox(name,x,y,x1,y1,col,col2)
    DrawText(col, x + 30, y - 7, name, vars.cmdfont)
    local w,h = GetTextSize(vars.cmdfont,name)
    vars.sSetDrawColor(col2.r, col2.g, col2.b, col2.a)
    vars.sDrawLine(x,y,x+25,y)
    vars.sDrawLine(x+w+35,y,x+x1,y)
    vars.sDrawLine(x,y+y1,x+x1,y+y1)
    vars.sDrawLine(x,y+y1,x,y)
    vars.sDrawLine(x+x1,y+y1,x+x1,y)
end

local function IsOutOfFOV( ent )
    if vars.me:GetObserverMode() == 0 then
        local Width = ent:BoundingRadius()
        local Disp = ent:GetPos() -vars.me:GetShootPos()
        local Dist = Disp:Length()
        local MaxCos = vars.math_abs( vars.math_cos( vars.math_acos( Dist /vars.math_sqrt( Dist *Dist +Width *Width ) ) +56 *( vars.math_pi /180 ) ) )
        Disp:Normalize()
        local dot = Disp:Dot( vars.me:EyeAngles():Forward() )
        return dot <MaxCos
    end
end

-- === INTERFACE === --
local lastActiveTab = "GUI"

local function createTabButton(name, x, panel)
    local btn = vars.vCreate('DButton', frame)
    btn:SetText(name)
    btn:SetTextColor(colors.white)
    btn:SetSize(frame:GetWide() / 4 - 10, 19)
    btn:SetPos(x, 3)

    btn.Paint = function()
        vars.sSetDrawColor(tabselect == name and colors.hover or colors.unhover)
        vars.sDrawRect(0, 0, btn:GetWide(), btn:GetTall())
    end

    btn.DoClick = function()
        tabselect = name
        lastActiveTab = name
        hookpanel:SetVisible(panel == hookpanel)
        guipanel:SetVisible(panel == guipanel)
        friendslistpanel:SetVisible(panel == friendslistpanel)
        lastActivePanel = panel
    end
end

local function checkbox( name, tooltip, val, x, y, parent )
    local checkbox = vars.vCreate( "DCheckBoxLabel", parent )
    checkbox:SetText( name )
    checkbox:SetPos( x, y )
    checkbox:SetChecked( vars[val] )
    if isstring( tooltip ) then
        checkbox:SetTooltip( tooltip )
    end
    function checkbox:OnChange(bval)
            vars[val] = bval
    end
    function checkbox:PaintOver()
    vars.dRoundedBox( 0, 0, 0, 15, 15, Color( 0, 0, 0 ) )
        if checkbox:GetChecked() then
    vars.dRoundedBox( 0, 4, 4, 7.5, 7.5, Color( 100, 0, 0 ) )
        end
    end
end
 
local function slider( name, val, min, max, x, y, w, h, parent)
    local slider = vars.vCreate( "DNumSlider", parent)
        slider:SetMin( min )
        slider:SetMax( max )
        slider:SetText( name )
        slider:SetSize(w, h)
        slider:SetPos(x, y)
        slider:SetValue( vars[val] )
        slider:SetDecimals(0)
    function slider:OnValueChanged( num )
        vars[val] = num
    end
end

local function showPanel(panel)
    hookpanel:SetVisible(panel == hookpanel)
    guipanel:SetVisible(panel == guipanel)
    friendslistpanel:SetVisible(panel == friendslistpanel)
end

-- === UI PRINCIPALE ===
local function ui()
    if vars.isValid(frame) and !frame:IsVisible() then
        frame:SetVisible(true)
        frame:MakePopup()
        showPanel(lastActiveTab == "Hooks" and hookpanel or lastActiveTab == "Friends" and friendslistpanel or guipanel)
        return
    elseif vars.isValid(frame) and frame:IsVisible() then
        frame:SetVisible(false)
    end
    frame = vars.vCreate('DFrame')
    frame:SetSize(700, 230)
    frame:Center()
    frame:MakePopup()
    frame:ShowCloseButton(false)
    frame:SetTitle('')

    frame.Paint = function()
        vars.sSetDrawColor(colors.header)
        vars.sDrawRect(0, 0, frame:GetWide(), 25)

        vars.sSetDrawColor(colors.bg)
        vars.sDrawRect(0, 25, frame:GetWide(), frame:GetTall() - 25)
    end

    -- === PANELS ===
    hookpanel = vars.vCreate('DPanel', frame)
    hookpanel:Dock(FILL)
    hookpanel:SetVisible(false)
    hookpanel.Paint = function()
        vars.sSetDrawColor(Color(255,255,255,0))
        vars.sDrawRect(0, 0, hookpanel:GetWide(), hookpanel:GetTall())
    end

    guipanel = vars.vCreate('DPanel', frame)
    guipanel:Dock(FILL)
    guipanel:SetVisible(false)

    friendslistpanel = vars.vCreate('DPanel', frame)
    friendslistpanel:Dock(FILL)
    friendslistpanel:SetVisible(false)
    friendslistpanel.Paint = function()
        vars.sSetDrawColor(Color(255,255,255,0))
        vars.sDrawRect(0, 0, friendslistpanel:GetWide(), friendslistpanel:GetTall())
    end

    -- === TABS ===
    createTabButton('Hooks', 3, hookpanel)
    createTabButton('Friends', frame:GetWide() / 4 + 3, friendslistpanel)
    createTabButton('GUI', frame:GetWide() / 2 + 3, guipanel)

    showPanel(lastActiveTab == "Hooks" and hookpanel or lastActiveTab == "Friends" and friendslistpanel or guipanel)

    local function styleListView(listview)
        listview:SetHeaderHeight(20)
        listview.Paint = function(_, w, h)
            vars.sSetDrawColor(Color(0, 0, 0, 150))
            vars.sDrawRect(0, 0, w, h)
        end

        listview.OnRowSelected = function(_, _, row)
            for _, column in pairs(row.Columns) do
                column:SetTextColor(Color(255, 255, 255))
            end
        end

        listview:AddLine("Loading...", "Please wait")
        for _, line in pairs(listview:GetLines()) do
            for _, column in pairs(line.Columns) do
                column:SetTextColor(Color(255, 255, 255))
            end
        end
        listview:Clear()
    end

    -- === GUI PANEL ===
    guipanel.Paint = function()
        local col = colors.white

        ThemeBox("ESP", 5, 5, 150, 180, col, col)
        ThemeBox("AA", 5, 85, 150, 100, col, col)
        ThemeBox("Aimbot", 160, 5, 315, 180, col, col)
        ThemeBox("Movement", 160, 95, 125, 90, col, col)
        ThemeBox("CamCtrl", 285, 95, 145, 90, col, col)
    end
    
    -- esp stuff
    checkbox("ESP: Toggle", "esp elements", "esp", 9, 14, guipanel)
    checkbox("ESP: Boxes", "toggles boxes", "esp_boxes", 9, 30, guipanel) -- + 17
    checkbox("ESP: Chams", "chams", "esp_chams", 9,  46, guipanel)
    checkbox("ESP: Weapon Chams", "chams", "w_chams", 9,  62, guipanel)

    -- aa stuff
    checkbox("AA: Toggle", "antiaim", "antiaim", 9, 92, guipanel)
    local aa_mode = vars.vCreate( "DComboBox", guipanel )
        aa_mode:SetPos( 9, 112 )
        aa_mode:SetSize( 115, 20 )
        aa_mode:SetSortItems(false)
        aa_mode:SetValue( "AA Methods" )
        aa_mode:AddChoice( "none")
        aa_mode:AddChoice( "sway")
        aa_mode:AddChoice( "spin")
        aa_mode:AddChoice( "side left")
        aa_mode:AddChoice( "side right")
    function aa_mode:OnSelect( _, mode )
        vars.aa_mode = mode
    end
    --aimbot stuff
    checkbox("AIM: Aimbot", "fire on mousepress", "aim_aimbot", 165, 14, guipanel)
    checkbox("AIM: Silent", "defucked view", "aim_silent", 165, 30, guipanel)
    checkbox("AIM: AutoPistol", "auto fire", "aim_autopistol", 165, 46, guipanel) --  62
    local boneAim = vars.vCreate( "DComboBox", guipanel )
        boneAim:SetPos( 165, 65 )
        boneAim:SetSize( 115, 20 )
        boneAim:SetSortItems(false)
        boneAim:SetValue( "head" )
        boneAim:AddChoice( "head")
        boneAim:AddChoice( "neck")
        boneAim:AddChoice( "spine")

        local boneMappings = {
            head = "ValveBiped.Bip01_Head1",
            neck = "ValveBiped.Bip01_Neck1",
            spine = "ValveBiped.Bip01_Spine1"
        }

    function boneAim:OnSelect(_, mode)
        vars.boneAim = boneMappings[mode] or mode
    end

    checkbox("AIM: No Spread", "reverse the spread", "aim_nospread", 315, 14, guipanel)
    checkbox("AIM: No Recoil", "reverse the recoil", "aim_norecoil", 315, 30, guipanel)
    slider("AimFOV", "aim_fov", 0, 90, 315, 49, 150, 10, guipanel)
    local predbox = vars.vCreate( "DComboBox", guipanel )
        predbox:SetPos( 315, 65 )
        predbox:SetSize( 115, 20 )
        predbox:SetSortItems(false)
        predbox:SetValue( "classic" )
        predbox:AddChoice( "none")
        predbox:AddChoice( "classic")
        predbox:AddChoice( "engine")
        predbox:AddChoice( "velocity")
        predbox:AddChoice( "ping")
        predbox:AddChoice( "gtick")
    function predbox:OnSelect( _, mode )
        vars.predtype = mode
    end

	-- mouvement
    checkbox("MV: Bunnyhop", "toggle bunnyhop", "bhop", 165, 105, guipanel)
    checkbox("MV: Autostrafe", "toggle autostrafe", "bhop_as", 165, 121, guipanel)
    checkbox("MV: Desync", "Desync", "desync", 165, 137, guipanel)
    checkbox("MV: Act", "toggle act", "act", 165, 153, guipanel)
    -- cam stuff
    checkbox("CAM: Thirdperson", "thirdperson", "tps", 290, 106, guipanel)
    checkbox("CAM: Fov", "fov", "cam_fov", 290, 122, guipanel)
    checkbox("CAM: Weapon Fov", "weapon fov", "w_fov", 290, 138, guipanel)
    slider("WFov", "wfov", 90, 130, 290, 156, 150, 10, guipanel)
    slider("TFov", "tps_fov", 30, 130, 290, 170, 150, 10, guipanel)

    -- === MODELE 3D ===
    local coolhoob2 = vars.vCreate('DModelPanel', guipanel)
    coolhoob2:SetSize(195, 180)
    coolhoob2:SetPos(480, 5)
    coolhoob2:SetModel(vars.model)
    coolhoob2:SetAnimated(false)

    function coolhoob2:LayoutEntity(ent)
        ent:SetSequence(0)
        self:SetCamPos(Vector(53, 0, 60))
    end

    -- === FRIENDS LIST PANEL ===
    local function styleListViewHeader(listview)
        listview:SetHeaderHeight(25)

        for _, column in pairs(listview.Columns) do
            column.Header:SetFont(vars.cmdfont)
            column.Header:SetTextColor(Color(255, 255, 255))

            column.Header.Paint = function(_, w, h)
                vars.dRoundedBox(0, 0, 0, w, h, colors.header)
            end
        end
    end
    

    local friendslist = vars.vCreate('DListView', friendslistpanel)
    friendslist:Dock(FILL)
    friendslist:AddColumn('Player')
    friendslist:AddColumn('Steam ID')
    friendslist:AddColumn('Friend')
    friendslist.Paint = function(_, w, h)
        vars.sSetDrawColor(Color(0,0,0,0))
        vars.sDrawRect(0, 0, w, h)
    end

    local function updateFriends()
        friendslist:Clear()
        for _, ply in ipairs(player.GetAll()) do
            if ply:IsBot() then continue end
            local line = friendslist:AddLine(ply:Nick(), ply:SteamID(), friendlist[ply:SteamID()] and "Yes" or "No")
            for _, column in pairs(line.Columns) do
                if column then
                    column:SetTextColor(Color(255, 255, 255))
                    column:SetFont(vars.cmdfont)
                end
            end
        end
    end

    styleListViewHeader(friendslist)

    friendslist.OnRowSelected = function(_, _, line)
        local steamID = line:GetColumnText(2)
        friendlist[steamID] = !friendlist[steamID]
        updateFriends()
    end

    updateFriends()
    
    -- Hooks
    local refreshBlocked
    local hooklist = vars.vCreate('DListView', hookpanel)
    hooklist:Dock(LEFT)
    hooklist:SetWidth(350)
    hooklist:AddColumn('Name')
    hooklist:AddColumn('Type')
    hooklist.VBar:SetEnabled(false)
    hooklist.VBar.Paint = function(_, w, h) 
        vars.dRoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 0))
    end
    hooklist.VBar.btnUp.Paint = function(_, w, h) 
        vars.dRoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 0))
    end
    hooklist.VBar.btnDown.Paint = function(_, w, h) 
        vars.dRoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 0))
    end
    hooklist.VBar.btnGrip.Paint = function(_, w, h) 
        vars.dRoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 0))
    end

    hooklist.Paint = function(_, w, h)
        vars.sSetDrawColor(Color(255,255,255,0))
        vars.sDrawRect(0, 0, w, h)
    end
    styleListViewHeader(hooklist)


    local function refreshHooks()
        hooklist:Clear()
        for htype, hooks in pairs(hook.GetTable()) do
            if !istable(hooks) then continue end
            for hname, _ in pairs(hooks) do
                htype = tostring(htype)
                hname = tostring(hname)

                hooklist:AddLine(hname, htype)
            end
        end
        for _, line in pairs(hooklist.Lines) do
            function line:Paint()
                if line:IsHovered() then
                    vars.sSetDrawColor(Color(100, 100, 100))
                else
                    vars.sSetDrawColor(Color(50, 50, 50))
                end
                vars.sDrawRect(0, 0, self:GetWide(), self:GetTall())
            end
            for _, column in pairs(line.Columns) do
                column:SetTextColor(Color(255, 255, 255))
                column:SetFont(vars.cmdfont)
            end
        end
    end

    function hooklist:OnRowSelected()
        for _, v in pairs(hooklist:GetSelected()) do
            local hname = tostring(v:GetValue(1))
            local htype = tostring(v:GetValue(2))
            if !istable(blockedhooks[htype]) then blockedhooks[htype] = {} end
            blockedhooks[htype][hname] = vars.hGetTable[htype][hname]
            vars.hRemove(htype, hname)
        end
        refreshHooks()
        refreshBlocked()
    end
    refreshHooks()
    
    local blocklist = vars.vCreate('DListView', hookpanel)
    blocklist:Dock(RIGHT)
    blocklist:SetWidth(350)
    blocklist:AddColumn('Blocked Name')
    blocklist:AddColumn('Type')
    blocklist.Paint = function(_, w, h)
        vars.sSetDrawColor(Color(255,255,255,0))
        vars.sDrawRect(0, 0, w, h)
    end
    styleListViewHeader(blocklist)

    function refreshBlocked()
        blocklist:Clear()
        for htype, hooks in pairs(blockedhooks) do
            if !istable(hooks) then continue end
            for hname, _ in pairs(hooks) do
                htype = tostring(htype)
                hname = tostring(hname)
                blocklist:AddLine(hname, htype)
            end
        end
        for _, line in pairs(blocklist.Lines) do
            function line:Paint()
                if line:IsHovered() then
                    vars.sSetDrawColor(Color(100, 100, 100))
                else
                    vars.sSetDrawColor(Color(50, 50, 50))
                end

                vars.sDrawRect(0, 0, self:GetWide(), self:GetTall())
            end
            for _, column in pairs(line.Columns) do
                column:SetTextColor(Color(255, 255, 255))
                column:SetFont(vars.cmdfont)
            end
        end
    end
    function blocklist:OnRowSelected()
        for _, v in pairs(blocklist:GetSelected()) do
            local hname = tostring(v:GetValue(1))
            local htype = tostring(v:GetValue(2))
            vars.hAdd(htype, hname, blockedhooks[htype][hname])
            blockedhooks[htype][hname] = nil
        end
        refreshBlocked()
        refreshHooks()
    end
    refreshBlocked()
end

-- === AA STUFF === --
local pitch, yaw = 0, 0
function GetBaseYaw()
    return vars.fa.y
end

function CalcPitch()
    local x = 0
    x = 0
    if vars.aa_mode == "none" then
        x = 0
    else 
        x = 89
    end
    return x
end

function CalcYaw()
    local y = 0
        y = vars.baseyaw - 180
    if vars.aa_mode == "spin" then
        local s = vars.math_NormAngle( vars.CurTime() * 750 )
        y = s
    elseif vars.aa_mode == "sway" then
        local s = vars.math_sin(vars.CurTime() * 2346) * 75
        y = ( vars.baseyaw - 180 ) + s -- sway
    elseif vars.aa_mode == "side left" then
        y = vars.baseyaw - 90
    elseif vars.aa_mode == "side right" then
        y = vars.baseyaw + 90
    elseif vars.aa_mode == "none" then
        y = vars.baseyaw
    end
    return y
end

function aacheck(cmd)
    if !vars.antiaim then return false end
    if cmd:KeyDown(IN_ATTACK) then return false end
    if cmd:KeyDown(IN_USE) then return false end
    if vars.me:GetMoveType() == MOVETYPE_LADDER then return false end
    if vars.me:GetMoveType() == MOVETYPE_NOCLIP then return false end
    
    return true
end

function ANTIAIM_C(cmd)
    if aacheck(cmd) then
        vars.baseyaw = GetBaseYaw()
        pitch = CalcPitch()
        yaw = CalcYaw()
        local pyAngle = Angle(pitch,yaw,0)
        cmd:SetViewAngles(pyAngle)
    end
end


-- === AILMBOT STUFF === --
function MovementFix(cmd, wish_yaw)
    local pitch = vars.math_NormAngle(cmd:GetViewAngles().x)
    local inverted = -1

    if (pitch > 89 or pitch < -89) then
        inverted = 1
    end

    local ang_diff = vars.math_rad(vars.math_NormAngle((cmd:GetViewAngles().y - wish_yaw) * inverted))
    local forwardmove = cmd:GetForwardMove()
    local sidemove = cmd:GetSideMove()

    local new_forwardmove = forwardmove * -vars.math_cos(ang_diff) * inverted + sidemove * vars.math_sin(ang_diff)
    local new_sidemove = forwardmove * vars.math_sin(ang_diff) * inverted + sidemove * vars.math_cos(ang_diff)

    cmd:SetForwardMove(new_forwardmove)
    cmd:SetSideMove(new_sidemove)
end

function Silent(cmd)
	if !vars.fa then vars.fa = cmd:GetViewAngles() end
	vars.fa = vars.fa + Angle(cmd:GetMouseY() * GetConVarNumber("m_yaw"), cmd:GetMouseX() * -GetConVarNumber("m_yaw"), 0)
	vars.fa.p = vars.math_clamp(vars.fa.p, -89, 89)
    vars.fa.r = 0
    vars.fa:Normalize()
end

function vars.CustomSpread.swb( cmd, ang ) -- WORK

    local cone = vars.activeWeapon.CurCone
    if !cone then return ang end
    if vars.me:Crouching() then
        cone = cone * 0.85
    end

    vars.math_randomseed( cmd:CommandNumber() )
    return ang  - vars.me:GetViewPunchAngles() - Angle( vars.math_rand(-cone, cone), vars.math_rand(-cone, cone), 0 ) * 25
end

function vars.CustomSpread.cw( cmd, ang ) -- WORK
    local cone = vars.activeWeapon.CurCone
    if !cone then return ang end
    vars.math_randomseed( cmd:CommandNumber() )

    if vars.me:Crouching() then
        cone = cone * 0.85
    end

    Dir = Angle(vars.math_rand(cone, -cone), vars.math_rand(cone, -cone), 0) * 25
    clumpSpread = clumpSpread or vars.activeWeapon.ClumpSpread
    Dir2 = Dir
    if clumpSpread and clumpSpread > 0 then
        Dir2 = Dir + Vector(vars.math_rand(-1, 1), vars.math_rand(-1, 1), vars.math_rand(-1, 1)) * clumpSpread
    end

    return ang - vars.me:GetViewPunchAngles() + Dir2
end

function vars.CustomSpread.arccw( cmd, ang )
    return ang - vars.me:GetViewPunchAngles()
end

function vars.CustomSpread.fas2( cmd, ang )
    local cone = vars.activeWeapon.CurCone
    if !cone then return ang end
    vars.math_randomseed(CurTime())

    Dir2 = Angle(vars.math_rand(cone, -cone), vars.math_rand(cone, -cone), 0) * 25

    return ang - vars.me:GetViewPunchAngles() + Dir2
end


function vars.CustomSpread.tfa(cmd, ang) -- WORK
    local con, rec = vars.activeWeapon:CalculateConeRecoil()
    if !con then return ang end
    local wep = vars.activeWeapon
    local aimAng = Angle( ang )
    local aimDir = aimAng:Forward()
    local Punch = Angle(wep:GetViewPunchP(), wep:GetViewPunchY(), 0):Forward()
    forward = Vector(aimDir.x , aimDir.y, aimDir.z)
    if ( wep:IsValid() && wep.IsTFAWeapon && wep:CanPrimaryAttack() ) then
        wep:CalculateRatios()
        local dYaw, dPitch = wep:ComputeBulletDeviation( 1, 1, con )

        local AimDirX = aimDir.x;
        local AimDirY = aimDir.y;
        local CosYaw = vars.math_cos( vars.math_rad( 90 - vars.math_abs( dYaw ) ) )
        local s = ( dYaw < 0 ) && -1 || 1

        local d = AimDirX*AimDirX + AimDirY*AimDirY - CosYaw*CosYaw
        local e = AimDirX + CosYaw
        
        if ( d >= 0 && e != 0 ) then

            local x = 2*vars.math_atan( ( AimDirY + s*vars.math_sqrt( d ) ) / e )

            local right = Vector( -1*s*vars.math_cos( x ), -1*s*vars.math_sin( x ), 0 )

            aimAng:RotateAroundAxis( right, -dPitch )

            local up = right:Cross( aimAng:Forward() )

            forward = up:Cross( right )
        end
    end
    return forward:Angle() - Punch:Angle()
end

vars.SpreadComps["swb"]     = vars.CustomSpread.swb
vars.SpreadComps["cw"]      = vars.CustomSpread.cw
vars.SpreadComps["arccw"]   = vars.CustomSpread.arccw
vars.SpreadComps["fas2"]    = vars.CustomSpread.fas2
vars.SpreadComps["tfa"]     = vars.CustomSpread.tfa

GAMEMODE["EntityFireBullets"] = function( self, p, data )

    local spread = data.Spread * -1

	if vars.cones[ vars.activeWeaponClass ] == spread or spread == nullVec then return end

    vars.cones[ vars.activeWeaponClass ] = spread;
end

function NoSpread(cmd, ang)
    if not vars.activeWeaponClass or not vars.activeWeapon then return ang end

    local wep = vars.activeWeapon
    local base = string.Split(vars.activeWeaponClass, "_")[1]
    if wep:IsValid() and wep.IsTFAWeapon then
        base = "tfa"
    end
    if vars.SpreadComps[base] then
        ang = vars.SpreadComps[base](cmd, ang)
    elseif vars.cones[vars.activeWeaponClass] then
        local spread = vars.cones[vars.activeWeaponClass]
        return Spread(cmd, ang, spread)
    end

    return ang
end

function Spread( cmd, ang)
    if !vars.cones[ vars.activeWeaponClass ] then return ang end
    local spread = vars.cones[ vars.activeWeaponClass ]
	local dir = ded.PredictSpread( cmd, ang, spread )
	local spreadangle = ang + dir:Angle()
	spreadangle:Normalize()
	return spreadangle
end

local tr = {
	mask = MASK_SHOT,
	filter = vars.me
}

function VisibleCheck( who, where, wall)
    local start = vars.me:EyePos()
    tr.start = start
	tr.endpos = where
	tr.mask = MASK_SHOT
    local trace = util.TraceLine( tr )
    local canhit = trace.Entity == who or trace.Fraction == 1

    return canhit

end

local function GetAngleDifference(from, to)
    return vars.math_deg(vars.math_acos(to:Forward():Dot(from:Forward())))
end

local function GetBestTarget()
    local bestTarget = nil
    local bestFov = vars.aim_fov

    for _, ply in ipairs(player.GetAll()) do
        if ply ~= vars.me and ply:Alive() and !ply:IsDormant() then
            local boneIndex = ply:LookupBone("ValveBiped.Bip01_Head1")
            if boneIndex then
                local bonePos = ply:GetBonePosition(boneIndex)
                if bonePos and VisibleCheck(ply, bonePos) and !IsFriend(ply:SteamID()) and !ply:HasGodMode() and !ply:InVehicle() then
                    local targetDirection = (bonePos - vars.me:GetShootPos()):Angle()
                    targetDirection:Normalize()

                    local angDiff = vars.math_abs(vars.math_NormAngle(GetAngleDifference(vars.fa, targetDirection)))

                    if angDiff < bestFov then
                        bestFov = angDiff
                        bestTarget = ply
                    end
                end
            end
        end
    end

    return bestTarget
end

function NoRecoil(ang)
    for _, prefix in ipairs(vars.WeaponPrefixes) do
		if string.StartsWith(vars.activeWeaponClass, prefix) then
			return ang
		end
	end

	return ang - vars.me:GetViewPunchAngles()
end

function getCenterBone(ply)
    if not vars.boneAim then return end

    local Bone = ply:LookupBone(vars.boneAim)
    if not Bone then return end
    local matrix = ply:GetBoneMatrix(Bone)
    if not matrix then return end
    local pos, ang = matrix:GetTranslation(), matrix:GetAngles()
    local min, max = ply:GetHitBoxBounds(0, 0)
    if not min or not max then return pos end
    min:Rotate(ang)
    max:Rotate(ang)

    pos = pos + ((min + max) * 0.5)
    return pos
end

function AUTOPISTOL_C( cmd )
    if vars.me:KeyDown( IN_ATTACK ) and vars.me:Alive() and vars.aim_autopistol and shouldFire() then
        cmd:RemoveKey( IN_ATTACK )
    end
end

local function predictTarget(pos,trg)
    if !pos then return nulVec end
    local lvel,tvel,frm,eng = vars.me:GetAbsVelocity(), trg:GetAbsVelocity(), vars.realFrameTime(), engine.TickInterval()
    if vars.predtype == 'none' then return pos end
    if vars.predtype == 'classic' then return pos-(lvel*eng) end
    if vars.predtype == 'velocity' then return pos+((lvel-tvel)*(frm/(1/eng))) end
    if vars.predtype == 'ping'  then return pos+(lvel*eng)*(vars.GetLatency) end
    if vars.predtype == 'engine'  then return tvel == nulVec and pos or pos+tvel*eng*frm-lvel*eng end
    if vars.predtype == 'gtick' then return pos+(((tvel*frm/25)-(tvel*frm/66))-((lvel*frm/25)+(lvel*frm/66))) end
end

function AIM_C(cmd)
    if vars.aim_aimbot and shouldFire() then
        ded.StartPrediction( cmd )
            vars.target = GetBestTarget()
            if cmd:KeyDown(IN_ATTACK) then
                for _, prefix in ipairs(vars.WeaponPrefixes) do
                    if string.StartsWith(vars.activeWeaponClass, prefix) then
                        cmd:RemoveKey( IN_SPEED )
                    end
                end
                local direction = cmd:GetViewAngles()
                if vars.target then
                    local pos = getCenterBone(vars.target)
                    local bonePos = pos
                    
                    bonePos = predictTarget(pos, vars.target)
                    direction = (bonePos - vars.me:GetShootPos()):Angle()
                    direction:Normalize()
                end

                if vars.aim_nospread then
                    direction = NoSpread(cmd, direction)
                end
                direction = NoRecoil(direction)

                cmd:SetViewAngles(direction)
            ded.FinishPrediction( cmd )
        end
    end
end

-- === MOVEMENT STUFF === --
function BHOP_C(cmd)
    if vars.bhop then
    	if cmd:KeyDown( IN_JUMP ) then
	    	if !vars.me:OnGround() then
	    		cmd:SetButtons( cmd:GetButtons() - IN_JUMP )
	    	end
            if !vars.bhop_as then return end
        	if vars.me:IsFlagSet( FL_ONGROUND ) then
        	    cmd:SetForwardMove(10000)
        	else
            	cmd:SetForwardMove(5850 / vars.me:GetVelocity():Length2D())
            	cmd:SetSideMove((cmd:CommandNumber() % 2 == 0) && -400 || 400)
        	end
		end
	end
end

function DESYNC_C(cmd)
    vars.bSendPacket = true
    if vars.desync then
        ded.SetBSendPacket(vars.bSendPacket)
        local tickrate = vars.math_floor(1 / engine.TickInterval())
        local seqshift =  tickrate - 3
        local bRunning = true
        if (vars.bSendPacket) then
            if (seqshift > 0) then
                if (!vars.bRunning) then
                    ded.SetOutSequenceNr(ded.GetOutSequenceNr() + seqshift)
                    vars.bRunning = true
                else
                    ded.SetNetChokedPackets(127)
                end
            else
                vars.bRunning = false
            end
        end
    else
    	vars.bRunning = false
    end
end

-- === SPAM STUFF === --
local players=FindMetaTable("Player")
local oldcmd=players.ConCommand
players.ConCommand=function(p,cmd,...)
	if cmd=="jpeg"then return end
	return oldcmd(p,cmd,...)
end
function SPAM_C(cmd)
    if input.IsKeyDown(KEY_L) then
        RunConsoleCommand("use","gmod_camera")
        if cmd:TickCount()%2==0 then
            cmd:SetButtons(bit.bor(cmd:GetButtons(),IN_ATTACK))
        end
    end
    if input.IsKeyDown(KEY_K) then
        RunConsoleCommand("impulse", "100" )
    end
end

-- === VIEW STUFF === --
local togglethird = false

function THIRDPERSON_C(cmd)
    if !vars.tps then return end
    if input.IsKeyDown(KEY_V) and !togglethird then
        vars.thirdPersonEnabled = !vars.thirdPersonEnabled
        togglethird = true
    elseif !input.IsKeyDown(KEY_V) then
        togglethird = false
    end
end

local function toggleMenu()
    if vars.isValid(frame) then
        frame:SetVisible(!frame:IsVisible())
        gui.EnableScreenClicker(frame:IsVisible())
    else
        ui()
        frame:SetVisible(true)
        frame:MakePopup()
        gui.EnableScreenClicker(true)
    end
end

function MENU_C(cmd)
    if input.IsKeyDown(KEY_J) then
        if !vars.MenuToggle then
            toggleMenu()
            vars.MenuToggle = true
        end
    else
        vars.MenuToggle = false
    end
end

local function UNLOAD_C()
    if input.IsKeyDown(KEY_INSERT) then
        if vars.isValid(vars.frame) and vars.frame:IsVisible() then
            ui()
        end
        for event, hooksList in pairs(vars.hooksToRemove) do
            for _, hookID in ipairs(hooksList) do
                hook.Remove(event, hookID)
            end
        end
        vars.hudpaint = false
    end
end

function a(cmd)
    if vars.me:IsTyping() or !vars.isValid(vars.me) then return end
    Silent(cmd)

    local psa = vars.aim_silent or vars.antiaim and shouldFire()

    if psa then
        cmd:SetViewAngles(vars.fa)
    end

    local wish_yaw = vars.fa.y

    vars.activeWeaponClass = vars.isValid(vars.me:GetActiveWeapon()) and vars.me:GetActiveWeapon():GetClass() or ""
    vars.activeWeapon = vars.me:GetActiveWeapon()
    vars.model = vars.me:GetModel()

    local createmove_functions = {
        SPAM_C, ANTIAIM_C, AUTOPISTOL_C,
        BHOP_C, THIRDPERSON_C, DESYNC_C, MENU_C, 
        UNLOAD_C
    }

    for _, func in ipairs(createmove_functions) do
        func(cmd)
    end

    if psa then
        MovementFix(cmd, wish_yaw)
    else
        vars.fa = cmd:GetViewAngles()
    end
end

VARhooks("CreateMove", a)
function GAMEMODE:CreateMove(cmd) return true end

VARhooks("PostCreateMove", AIM_C)

vieworigin = vars.me:EyePos()
local function getView(fangs, origin, angles, fov)
    local view = {
        origin = origin,
        angles = fangs,
        fov = vars.cam_fov and vars.fov or fov,
        drawviewer = false
    }

    if vars.thirdPersonEnabled then
        view.origin = origin - (fangs:Forward() * vars.tps_fov)
        view.drawviewer = true
    end

    return view
end

VARhooks("CalcView", function(ply, origin, angles, fov, znear, zfar)
    local fangs = vars.fa or angles
    local view = getView(fangs, origin, angles, fov)
    vieworigin = origin
    return view
end)

-- local VMCalcCalled

-- VARhooks("CalcViewModelView", function(wep, vm, oldPos, oldAng, pos, ang, ...)
--     if VMCalcCalled then return end
--     VMCalcCalled = true
--     pos = vieworigin
--     if vars.aim_silent or vars.antiaim then
--         ang = vars.fa
--     end
--     VMCalcCalled = nil
--     return pos, ang
-- end)

local IsDrawingGlow = false
local drawing = false
local fov = false
VARhooks("PreDrawViewModel", function(vm)
	if vars.w_chams and !vars.sg then
        if !drawing then 
            vars.rSupEngLight(true)
            Glow2:SetVector("$color2", Vector(1, 1, 1))
            vars.rMatOver(Glow2)
            for i = 0, 5 do
                local colors = {
                    {1, 0.3, 0.3}, {0.3, 1, 0.3}, {0.3, 0.3, 1},
                    {1, 1, 0}, {1, 0, 1}, {0, 1, 1}
                }
                
                vars.rModelLight(i, unpack(colors[i + 1]))
            end
        else
            vars.rSupEngLight(false)
            vars.rMatOver()
        end

    else
        vars.rSupEngLight(false)
        vars.rMatOver()
	end

    if vars.w_fov then
        if !fov and !vars.sg then
            cam.Start3D(nil, nil, vars.wfov)
            vars.rDepthRange( 0.2, 0 )
            fov = true
            vm:DrawModel()
            fov = false
            cam.End3D()
        else
            return
        end
        return true
    else
        return false
    end
end)

VARhooks("PostDrawViewModel", function()
	if vars.w_chams then
		vars.rColorMod(1, 1, 1)
		vars.rMatOver(None)
		vars.rBlend(1)
		vars.rSupEngLight(false)
		if IsDrawingGlow then return end

		IsDrawingGlow = true
		vars.me:GetViewModel():DrawModel()
		IsDrawingGlow = false
	end
end)

local em = FindMetaTable("Entity")
local vm = FindMetaTable("Vector")

local function GetEntityColor(v)
    if !vars.isValid(v) or !v:IsPlayer() then return Color(255, 0, 0) end
    return IsFriend(v:SteamID()) and Color(0, 255, 0) or Color(255, 0, 0)
end

local function camignorez(bool)
    vars.rDepthRange( 0,bool and 0.8 or 1 )
end

local function chamz(v)
    local col = GetEntityColor(v)
    vars.rSupEngLight(true)
    camignorez(true)

    vars.rColorMod(col.r/255,col.g/255,col.b/255)
    vars.rMatOver(Material("models/wireframe"))
    vars.rBlend(0.1)
    v:DrawModel()

    vars.rMatOver()
    vars.rColorMod(1, 1, 1)
    vars.rSupEngLight(false)
    camignorez(false)
end

VARhooks('PreDrawEffects', function()
    for k,v in pairs(player.GetAll()) do
        if (vars.isValid(v) and v:Alive() and v ~= vars.me) and !vars.sg then
            if vars.esp_chams then chamz(v) end
        end
    end
end)

local function GetHealthColor(health)
    local r = Lerp(health / 100, 255, 0)
    local g = Lerp(health / 100, 0, 255)
    return Color(r, g, 0, 255)
end

local lerpData = {}

local function boxcorners(v)
    if !IsValid(v) or !v:IsPlayer() then return end

    if !lerpData[v] then
        lerpData[v] = {
            health = v:Health(),
            armor = v:Armor()
        }
    end

    local min, max = em.GetCollisionBounds(v)
    local pos = em.GetPos(v)
    local pos2 = pos + Vector(0, 0, max.z)

    pos = vm.ToScreen(pos)
    pos2 = vm.ToScreen(pos2)

    local h = pos.y - pos2.y
    local w = h / 2
    local color = GetEntityColor(v)

    vars.sSetDrawColor(Color(0, 0, 0))
    vars.sDrawOutlinedRect(pos.x - w / 2 - 1, pos.y - h - 1, w + 2, h + 2)

    vars.sSetDrawColor(color)
    vars.sDrawOutlinedRect(pos.x - w / 2, pos.y - h, w, h)

    local health = vars.math_clamp(v:Health(), 0, 100)
    local healthColor = GetHealthColor(health)
    local armor = vars.math_clamp(v:Armor(), 0, 100)

    lerpData[v].health = Lerp(FrameTime() * 10, lerpData[v].health, health)
    lerpData[v].armor = Lerp(FrameTime() * 10, lerpData[v].armor, armor)

    local textX = pos.x + w / 2 + 5
    
    vars.sSetFont(vars.cmdfont)
    
    vars.sSetTextColor(healthColor)
    vars.sSetTextPos(textX, pos.y - h)
    vars.sDrawText(tostring(vars.math_round(lerpData[v].health)))
    
    vars.sSetTextColor(Color(0, 150, 255))
    vars.sSetTextPos(textX, pos.y - h + 20)
    vars.sDrawText(tostring(vars.math_round(lerpData[v].armor)))
    
end

local function txtesp(v)
    local ppos = v:GetPos()
    local pos  = ppos:ToScreen()
    local tpos = ppos + Vector( 0, 0, 75 )
    local ttpos  = tpos:ToScreen()
    local str = string.Explode('/',v:GetModel())
    local nn = str[#str]
    local w,h = GetTextSize(vars.cmdfont,nn)
    local color = GetEntityColor(v)

    vars.dSimpleTextOutlined(v:Nick(), vars.cmdfont, ttpos.x, ttpos.y-h/2+5, color, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, Color(30, 30, 30, 255))
end

local function xhair()
    if !vars.thirdPersonEnabled then
        vars.sSetDrawColor(colors.white)
        vars.sDrawRect(vars.sw/2-3,vars.sh/2,7,2)
        vars.sDrawRect(vars.sw/2,vars.sh/2-3,2,7)
    end
end

local helpers = {
    lerp = function(self, start, end_pos, time, delta)
        if (vars.math_abs(start - end_pos) < (delta or 0.01)) then return end_pos end

        time = FrameTime() * (time * 175)
        if time < 0 then
          time = 0.01
        elseif time > 1 then
          time = 1
        end
        return ((end_pos - start) * time + start)
    end,
}

local MultiColorText = function(data, x, y)
    local total_width = 0
    local width = 0
    vars.sSetFont( vars.cmdfont )

    for _, v in pairs(data) do
        local text = v[1]
        if text == nil then continue end
        local text_width, text_height = vars.sGetTextSize( text )
        total_width = total_width + text_width
    end

    for _, v in ipairs(data) do
        local text = v[1]
        if text == nil then continue end
        local text_width, text_height = vars.sGetTextSize( text )
        local x2 = (x - total_width / 2 + width)
        vars.dSimpleText( v[1], vars.cmdfont, x2 + 1, y + 1, Color( 0, 0, 0, v[2].a) )
        vars.dSimpleText( v[1], vars.cmdfont, x2, y, v[2] )
        width = width + text_width
    end
end

vars.hitlogs.on_draw = function()
    local sc = {x = vars.sw, y = vars.sh}
    local x, y = sc.x/2, sc.y/1.1
    vars.add.y = 0
    for k, v in ipairs(vars.hitlogs.data) do
        local text = v[1]
        local r, g, b = v.color.r, v.color.g, v.color.b
        local realtime = RealTime()
        if v.time + 1 > realtime then
            v.alpha = helpers:lerp(v.alpha, 1, 0.095)
            v.alpha1 = helpers:lerp(v.alpha, 1, 0.05)
        end

        vars.add.y = vars.add.y + 15*v.alpha
        local wh = Color(255, 255, 255, v.alpha*255)
        local ch = Color(r, g, b, v.alpha*255)
        MultiColorText({
            {
                text[1],
                wh
            },
            {
                text[2],
                ch
            },
            {
                text[3],
                wh
            },
            {
                text[4],
                ch
            },
            {
                text[5],
                wh
            },
            {
                text[6],
                ch
            },
            {
                text[7],
                wh
            },
            {
                text[8],
                ch
            },
            {
                text[9],
                wh
            }
        }, x + v.alpha1*100 - 100, y - vars.add.y)

        if v.time + 5 < realtime then
            v.alpha = helpers:lerp(v.alpha, 0, 0.05)
            v.alpha1 = helpers:lerp(v.alpha1, 2, 0.04)
        end
        if v.alpha < 0.01 and (v.time + 6 < realtime) or #vars.hitlogs.data > 50 then
            table.remove(vars.hitlogs.data, k)
        end
    end
end

gameevent.Listen( "player_hurt" )
VARhooks("player_hurt", function( data )
    local health = data.health
	local priority = SERVER and data.Priority or 5
	local attackerid = data.attacker
    local ply = Player( data.attacker )
    local plu = Player( data.userid )

    if (ply == nil or ply:IsPlayer() == false) or plu == nil then return end
    if attackerid == vars.me:UserID() then
        vars.lastplayerhit = plu
        table.insert(vars.hitlogs.data, {
        {
            "Hit ",
            plu:Nick(),
            " for ",
            vars.toStr(string.gsub(data.health-plu:Health(), "-", "")),
            " damage (",
            vars.toStr(plu:Health()), " HP | ", vars.toStr(plu:Armor()),
            " ARMOR remaining)",
        },
        alpha = 0,
        alpha1 = 0,
        time = RealTime(),
        color = Color(255, 0, 0),
        })
    end
end)

VARhooks('HUDPaint', function()
    if vars.hudpaint and not vars.sg then
        for k, v in pairs(player.GetAll()) do
            if not IsValid(v) or v == vars.me or not v:Alive() or v:IsDormant() or vars.me:GetPos():Distance(v:GetPos()) > 5000 then continue end
            if not vars.antiaim and not vars.thirdPersonEnabled and IsOutOfFOV(v) then continue end
            if vars.esp_boxes then boxcorners(v) end
            if vars.esp then txtesp(v) end
        end
        
        if vars.aim_aimbot then
            local X1 = vars.math_tan(vars.math_rad(vars.aim_fov) / 1.25)
            local X2 = vars.math_tan(vars.math_rad(vars.me:GetFOV() / 2))
            local r = X1 / X2
            local pxR = r * (ScrW() / 2)
            vars.sDrawCircle(ScrW() / 2, ScrH() / 2, pxR, colors.red)
            
            if vars.target and shouldFire() then
                local bonePos = getCenterBone(vars.target)
                local pos = vm.ToScreen(bonePos)
                vars.sSetDrawColor(colors.red)
                vars.sDrawLine(pos.x, pos.y, vars.sw / 2, vars.sh / 2)
            end
        end
        
        xhair()
        vars.hitlogs.on_draw()
    end
end)

VARhooks('ScalePlayerDamage', function(_, _, d)
    if vars.hitsound then
        if d:GetAttacker() == vars.me then
            vars.sPlaySound('garrysmod/balloon_pop_cute.wav')
        end
    end
end)

VARhooks("OnImpact", function(data)
    vars.bulletImpacts[#vars.bulletImpacts + 1] = {
        shootTime = vars.CurTime(),
        pos = data.m_vOrigin,
        alpha = 255
    }
end)

VARhooks("PostDrawOpaqueRenderables", function()
    local currentTime = vars.CurTime()
    local DieTime = 0.5
    local maxSize = 4

    for i = #vars.bulletImpacts, 1, -1 do
        local impact = vars.bulletImpacts[i]
        local timeElapsed = currentTime - impact.shootTime
        local timeLeft = DieTime - timeElapsed

        if timeLeft <= 0 then
            table.remove(vars.bulletImpacts, i)
        else
            local fadeFactor = vars.math_clamp(timeLeft / DieTime, 0, 1)
            local size = maxSize * fadeFactor
            local color = Color(255 * fadeFactor, 0, 255 * (1 - fadeFactor), 255 * fadeFactor)

            cam.Start3D()
                vars.rColorMat()
                vars.rDrawBox(impact.pos, Angle(0, 0, 0), Vector(-size, -size, -size), Vector(size, size, size), color)
            cam.End3D()
        end
    end
end)
print("[JIT] Status initial: ", vars.j.status())
