
local Env = {}
Env.hooks = Env.hooks or {}
setmetatable(Env, { __index = _G })
Env.require("vrmod")
for k, v in pairs(ded) do
    Env[k] = v
end
Env.frame = nil
Env.tabselect = "GUI"
Env.blockedhooks = {}
Env.ip = ipairs

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

Env.vars = {
    friendlist = {},
    me = LocalPlayer(),
    cmdfont = "MAIN",

    MenuToggle = false,

    bSend = true,

    tScreen = Vector(0, 0, 0).ToScreen,
    sw = ScrW(),
    sh = ScrH(),
    model = LocalPlayer():GetModel(),
    vieworigin = LocalPlayer():EyePos(),
    fa = LocalPlayer():EyeAngles(),
    activeWeapon = LocalPlayer():GetActiveWeapon(),
    activeWeaponClass = IsValid(LocalPlayer():GetActiveWeapon()) and LocalPlayer():GetActiveWeapon():GetClass() or "",

    CustomSpread = {},
    SpreadComps = {},
    cones = {},
    bulletImpacts = {},

    CurTime = CurTime,
    realFrameTime = RealFrameTime,
    GetLatency = (LocalPlayer():Ping()/1000),
    nulVec = Vector(),
    Vec = Vector,

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

    baseyaw = 0,

    toStr = tostring,
    isValid = IsValid,

    math_deg = math.deg,
    math_cos = math.cos,
    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_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,
    dDrawText = draw.DrawText,

    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,

    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,

    kDown = input.IsKeyDown,

    Cam3Ds = cam.Start3D,
    Cam3De = cam.End3D,

    tInsert = table.insert, 
    tRemove = table.remove,

    unload = true,

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

    cam_fov = false,
    fov = 120,

    freecam = false,

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

    w_chams = 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,
    predtype = 'velocity',
    boneAim = 'ValveBiped.Bip01_Head1',

    antiaim = false,
    aa_mode = 'none',
}
do
    Env.SetInterpolation( true )
    Env.SetSequenceInterpolation( true )
    Env.EnableAnimFix( false )
end

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

function Env.IsFriend(steamID)
    for _, id in Env.ip(Env.vars.friendlist) do
        if id == steamID then return true end
    end
    return false
end

function Env.VARhooks(event, func)
    local hID = util.CRC(Env.vars.math_random(10^4) + SysTime())

    Env.hook.Add(event, hID, func)
    Env.hooks[#Env.hooks + 1] = { event = event, id = hID }

    Env.print("Hook ajouté → ", event, "| ID:", hID)
end
setfenv(Env.VARhooks, Env)

Env.colors = {
    white = Color(255, 255, 255),
    red = Color(255, 0, 0),
    armor = Color(0, 100, 255, 255),
    background = Color(0, 0, 0, 200),
    unhover = Color(56, 56, 56),
    hover = Color(46, 46, 46),
    header = Color(50, 50, 50),
    bg = Color(65, 65, 65, 230),

    Background1 = Color(33, 33, 38),
    TopBar1 = Color(247, 23, 23)
}

-- === FONCTIONS CUSTOM ===

function Env.DrawText(col, x, y, str, font)
    Env.vars.sSetFont(font)
    Env.vars.sSetTextColor(col.r, col.g, col.b, col.a)
    Env.vars.sSetTextPos(x, y)
    Env.vars.sDrawText(str)
end

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

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

function Env.IsOutOfFOV(ent)
    if Env.vars.me:GetObserverMode() == 0 then
        local Disp = (ent:GetPos() - Env.vars.me:GetShootPos()):GetNormalized()
        return Disp:Dot(Env.vars.me:EyeAngles():Forward()) < Env.vars.math_cos(Env.vars.math_atan(ent:BoundingRadius() / (ent:GetPos():Distance(Env.vars.me:GetShootPos()))) + Env.vars.math_rad(56))
    end
end


-- === INTERFACE === --
Env.lastActiveTab = "GUI"

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

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

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

function Env.checkbox( name, tooltip, val, x, y, parent )
    local checkbox = Env.vars.vCreate( "DCheckBoxLabel", parent )
    checkbox:SetText( name )
    checkbox:SetPos( x, y )
    checkbox:SetChecked( Env.vars[val] )
    if isstring( tooltip ) then
        checkbox:SetTooltip( tooltip )
    end
    function checkbox:OnChange(bval)
            Env.vars[val] = bval
    end
    function checkbox:PaintOver()
    Env.vars.dRoundedBox( 0, 0, 0, 15, 15, Color( 0, 0, 0 ) )
        if checkbox:GetChecked() then
    Env.vars.dRoundedBox( 0, 4, 4, 7.5, 7.5, Color( 100, 0, 0 ) )
        end
    end
end

function Env.combobox(name, val, x, y, choices, mappings, parent)
    local combo = Env.vars.vCreate("DComboBox", parent)
    combo:SetPos(x, y)
    combo:SetSize(140, 20)
    combo:SetSortItems(false)
    combo:SetValue(choices[1])
    combo:SetTextColor(Color(210, 210, 210))

    for _, choice in ipairs(choices) do
        combo:AddChoice(choice)
    end

    function combo:OnSelect(index, mode)
        Env.vars[val] = mappings and mappings[mode] or mode
    end

    combo.Paint = function(self, w, h)
        Env.vars.sSetDrawColor(Env.colors.hover)
        Env.vars.sDrawRect(0, 0, w, h)
        Env.vars.sDrawOutlinedRect(0, 0, w, h)
    end

    combo.DropButton.Paint = function(self, w, h)
        Env.vars.sSetDrawColor(Env.colors.hover)
        Env.vars.sDrawRect(0, 0, w, h)
    end

    combo.OnMenuOpened = function(pnl)
        local menu = pnl.Menu
        if Env.vars.isValid(menu) then
            menu.Paint = function(self, w, h)
                Env.vars.sSetDrawColor(Env.colors.hover)
                Env.vars.sDrawRect(0, 0, w, h)
            end
            for _, option in ipairs(menu:GetCanvas():GetChildren()) do
                option:SetTextColor(Color(210, 210, 210))
            end
        end
    end
end

function Env.slider( name, val, min, max, x, y, w, h, parent)
    local slider = Env.vars.vCreate( "DNumSlider", parent)
        slider:SetMin( min )
        slider:SetMax( max )
        slider:SetText( name )
        slider:SetSize(w, h)
        slider:SetPos(x, y)
        slider:SetValue( Env.vars[val] )
        slider:SetDecimals(0)
    function slider:OnValueChanged( num )
        Env.vars[val] = num
    end
end

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

-- === UI PRINCIPALE ===
function Env.ui()
    if Env.vars.isValid(Env.frame) then
        if Env.frame:IsVisible() then
            Env.frame:SetVisible(false)
            gui.EnableScreenClicker(false)
            gui.HideGameUI()
        else
            Env.frame:SetVisible(true)
            Env.frame:MakePopup()
            gui.EnableScreenClicker(true)
            Env.updateFriends()
            -- Env.vars.rCC("gameui_activate")
        end
        return
    end

    -- Env.vars.rCC("gameui_activate")
    timer.Simple(0.1, function()
        Env.frame = Env.vars.vCreate('DFrame')
        Env.frame:SetSize(700, 230)
        Env.frame:Center()
        Env.frame:MakePopup()
        Env.frame:ShowCloseButton(false)
        Env.frame:SetTitle('')

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

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

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

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

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

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

        showPanel(Env.lastActiveTab == "Hooks" and hookpanel or Env.lastActiveTab == "Friends" and friendslistpanel or aimpanel)

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

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

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

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

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

        -- aa stuff
        Env.checkbox("AA: Toggle", "antiaim", "antiaim", 9, 92, aimpanel)
        Env.combobox("AA Methods", "aa_mode", 9, 112, {"none", "sway", "spin", "side left", "side right", "square"}, nil, aimpanel)
        
        --aimbot stuff
        Env.checkbox("AIM: Aimbot", "fire on mousepress", "aim_aimbot", 165, 14, aimpanel)
        Env.checkbox("AIM: Silent", "defucked view", "aim_silent", 165, 30, aimpanel)
        Env.checkbox("AIM: AutoPistol", "auto fire", "aim_autopistol", 165, 46, aimpanel) --  62
        local boneMappings = {
            head = "ValveBiped.Bip01_Head1",
            neck = "ValveBiped.Bip01_Neck1",
            spine = "ValveBiped.Bip01_Spine1"
        }
        
        Env.combobox("boneAim", "boneAim", 165, 65, {"head", "neck", "spine"}, boneMappings, aimpanel)        

        Env.checkbox("AIM: No Spread", "reverse the spread", "aim_nospread", 315, 14, aimpanel)
        Env.checkbox("AIM: No Recoil", "reverse the recoil", "aim_norecoil", 315, 30, aimpanel)
        Env.slider("AimFOV", "aim_fov", 0, 90, 315, 49, 150, 10, aimpanel)
        Env.combobox("predtype", "predtype", 315, 65, {"none", "velocity", "classic", "engine", "ping"}, nil, aimpanel)

        -- mouvement
        Env.checkbox("MV: Bunnyhop", "toggle bunnyhop", "bhop", 165, 105, aimpanel)
        Env.checkbox("MV: Autostrafe", "toggle autostrafe", "bhop_as", 165, 121, aimpanel)
        Env.checkbox("MV: Desync", "Desync", "desync", 165, 137, aimpanel)
        Env.checkbox("MV: Act", "toggle act", "act", 165, 153, aimpanel)
        -- cam stuff
        Env.checkbox("CAM: Thirdperson", "thirdperson", "tps", 290, 106, aimpanel)
        Env.checkbox("CAM: Fov", "fov", "cam_fov", 290, 122, aimpanel)
        Env.checkbox("CAM: Weapon Fov", "weapon fov", "w_fov", 290, 138, aimpanel)
        Env.slider("WFov", "wfov", 90, 130, 290, 156, 150, 10, aimpanel)
        Env.slider("TFov", "tps_fov", 30, 130, 290, 170, 150, 10, aimpanel)
        
        -- === MODELE 3D ===
        local coolhoob2 = Env.vars.vCreate('DModelPanel', aimpanel)
        coolhoob2:SetSize(195, 180)
        coolhoob2:SetPos(480, 5)
        coolhoob2:SetModel(Env.vars.model)
        coolhoob2:SetAnimated(true)

        function coolhoob2:LayoutEntity()
            self:RunAnimation()
            self:SetCamPos(Env.vars.Vec(50, 50, 50))
        end

        -- === FRIENDS LIST PANEL ===
        local function styleListViewHeader(listview)
            listview:SetHeaderHeight(25)
        
            for _, column in Env.ip(listview.Columns) do
                column.Header:SetFont(Env.vars.cmdfont)
                column.Header:SetTextColor(Color(255, 255, 255))
                
                column.Header.Paint = function(_, w, h)
                    Env.vars.dRoundedBox(0, 0, 0, w, h, Env.colors.header)
                end
            end
        end
        

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

        local function AddFriend(steamID)
            if not Env.IsFriend(steamID) then
                Env.vars.tInsert(Env.vars.friendlist, steamID)
            end
        end

        local function RemoveFriend(steamID)
            for i, id in Env.ip(Env.vars.friendlist) do
                if id == steamID then
                    Env.vars.tRemove(Env.vars.friendlist, i)
                    break
                end
            end
        end

        function Env.updateFriends()
            friendslist:Clear()
            for _, ply in Env.ip(Env.player.GetAll()) do
                local line = friendslist:AddLine(ply:Nick(), ply:SteamID(), Env.IsFriend(ply:SteamID()) and "Yes" or "No")
                if Env.vars.isValid(line) then
                    for _, column in Env.ip(line.Columns) do
                        if column then
                            column:SetTextColor(Color(255, 255, 255))
                        end
                    end
                end
            end
        end

        styleListViewHeader(friendslist)

        friendslist.OnRowSelected = function(_, _, line)
            local steamID = line:GetColumnText(2)
            if Env.IsFriend(steamID) then
                RemoveFriend(steamID)
            else
                AddFriend(steamID)
            end
            Env.updateFriends()
        end
        
        Env.updateFriends()
        
        -- Hooks
        local refreshBlocked
        local hooklist = Env.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) 
            Env.vars.dRoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 0))
        end
        hooklist.VBar.btnUp.Paint = function(_, w, h) 
            Env.vars.dRoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 0))
        end
        hooklist.VBar.btnDown.Paint = function(_, w, h) 
            Env.vars.dRoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 0))
        end
        hooklist.VBar.btnGrip.Paint = function(_, w, h) 
            Env.vars.dRoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 0))
        end

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


        local function refreshHooks()
            hooklist:Clear()
            for htype, hooks in Env.ip(Env.vars.hGetTable) do
                if !istable(hooks) then continue end
                for hname, _ in Env.ip(hooks) do
                    htype = Env.vars.toStr(htype)
                    hname = Env.vars.toStr(hname)

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

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

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

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

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

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

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

function Env.aacheck(cmd)
    if !Env.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 Env.vars.me:GetMoveType() == MOVETYPE_LADDER then return false end
    if Env.vars.me:GetMoveType() == MOVETYPE_NOCLIP then return false end
    
    return true
end

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

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

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

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

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

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

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

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

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

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

function Env.vars.CustomSpread.cw(cmd, ang) -- WORK
    if not (cmd and ang) then return ang end
    if not Env.vars.isValid(Env.vars.me) or not Env.vars.isValid(Env.vars.activeWeapon) then return ang end
    if not isnumber(Env.vars.activeWeapon.CurCone) then return ang end

    local cone = Env.vars.activeWeapon.CurCone
    if not cone then return ang end
    Env.vars.math_randomseed(cmd:CommandNumber())

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

    if not isnumber(cone) then return ang end
    Dir = Angle(Env.vars.math_rand(cone, -cone), Env.vars.math_rand(cone, -cone), 0) * 25

    clumpSpread = clumpSpread or Env.vars.activeWeapon.ClumpSpread
    if not isnumber(clumpSpread) then clumpSpread = 0 end

    Dir2 = Dir
    if clumpSpread > 0 then
        Dir2 = Dir + Env.vars.Vec(Env.vars.math_rand(-1, 1), Env.vars.math_rand(-1, 1), Env.vars.math_rand(-1, 1)) * clumpSpread
    end

    if not isangle(ang) or not isangle(Dir2) then return ang end

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

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

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

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

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

function Env.vars.CustomSpread.tfa(cmd, ang) -- WORK
    if not Env.vars or not Env.vars.activeWeapon or not Env.vars.isValid(Env.vars.activeWeapon) then return ang end
    local wep = Env.vars.activeWeapon
    if not isfunction(wep.CalculateConeRecoil) or not isfunction(wep.ComputeBulletDeviation) then return ang end

    local con, _ = wep:CalculateConeRecoil()
    if not con or not wep:CanPrimaryAttack() then return ang end

    local dYaw, dPitch = wep:ComputeBulletDeviation(1, 1, con)
    if not dYaw or not dPitch then return ang end

    local aimAng = Angle(ang)
    local right, up = aimAng:Right(), aimAng:Up()

    aimAng:RotateAroundAxis(up, -dYaw)
    aimAng:RotateAroundAxis(right, -dPitch)

    return aimAng
end

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

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

    local spread = data.Spread * -1

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

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

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

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

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

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

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

    return canhit

end

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

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

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

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

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

    return bestTarget
end

function Env.NoRecoil(ang)
    local wep = Env.vars.activeWeapon
    if Env.vars.activeWeaponClass == "weapon_pistol" or string.StartsWith(Env.vars.activeWeaponClass, "m9k_") or 
       string.StartsWith(Env.vars.activeWeaponClass, "fas2") or string.StartsWith(Env.vars.activeWeaponClass, "cw") or 
       string.StartsWith(Env.vars.activeWeaponClass, "arccw") or string.StartsWith(Env.vars.activeWeaponClass, "swb") then
        return ang
    elseif wep and wep.IsTFAWeapon then
        ang.p = ang.p - wep:GetViewPunchP()
        ang.y = ang.y - wep:GetViewPunchY()
    else
        ang = ang - Env.vars.me:GetViewPunchAngles()
    end

    return ang
end

function Env.getCenterBone(ply)
    if not ply then return end
    local Bone = ply:LookupBone(Env.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)
    min:Rotate(ang)
    max:Rotate(ang)
    
    pos = pos + ((min + max) * 0.5)
    return pos
end

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

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

function Env._CAIM(cmd)
    if not (Env.vars.aim_aimbot and Env.shouldFire()) then return end

    Env.StartPrediction(cmd)

        Env.vars.target = Env.GetBestTarget()
        local direction = cmd:GetViewAngles()

        if Env.vars.target and cmd:KeyDown(IN_ATTACK) then
            if string.StartsWith(Env.vars.activeWeaponClass, "m9k_") then
                cmd:RemoveKey(IN_SPEED)
            end

            local pos = Env.getCenterBone(Env.vars.target)
            local bonePos = Env.predictTarget(pos, Env.vars.target)

            direction = (bonePos - Env.vars.me:GetShootPos()):Angle()
            direction:Normalize()
        end

        if Env.vars.aim_nospread and cmd:KeyDown(IN_ATTACK) then
            direction = Env.NoSpread(cmd, direction)
        end

        direction = Env.NoRecoil(direction)
        cmd:SetViewAngles(direction)

    Env.FinishPrediction(cmd)
end
setfenv( Env._CAIM, Env )

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

function Env.DESYNC_C(cmd)
    Env.vars.bSend = true
    if Env.vars.desync and !cmd:KeyDown(IN_ATTACK) then
        Env.SetBSendPacket(Env.vars.bSend)
        local tickrate = Env.vars.math_floor(1 / engine.TickInterval())
        local seqshift =  tickrate - (tickrate / 2) + 2
        local bRunning = true
        if (Env.vars.bSend) then
            if (seqshift > 0) then
                if (!Env.vars.bRunning) then
                    Env.SetOutSequenceNr(Env.GetOutSequenceNr() + seqshift)
                    Env.vars.bRunning = true
                else
                    Env.SetNetChokedPackets(127*1.25)
                end
            else
                Env.vars.bRunning = false
            end
        end
    else
    	Env.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 Env.SPAM_C(cmd)
    if Env.vars.kDown(KEY_L) then
        RunConsoleCommand("use","gmod_camera")
        if cmd:TickCount()%2==0 then
            cmd:SetButtons(bit.bor(cmd:GetButtons(),IN_ATTACK))
        end
    end
    if Env.vars.kDown(KEY_K) then
        RunConsoleCommand("impulse", "100" )
    end
end

local tauntActive, nextAct = false, 0

function Env.DANCE_C(cmd)
    if tauntActive or nextAct > Env.vars.CurTime() or not LocalPlayer():Alive() or not Env.vars.act then return end
    RunConsoleCommand("_darkrp_doanimation", "1642")
    RunConsoleCommand("act", "dance")
    tauntActive, nextAct = true, Env.vars.CurTime() + 0.3
    timer.Simple(7, function() tauntActive = false end)
end

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

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

local freecamAngles = Angle()
local freecamAngles2 = Angle()
local freecamPos = Env.vars.Vec()
local freecamSpeed = 7
local keyPressed = false

function Env.FREECAM_C(cmd)
    if Env.vars.kDown(KEY_F) then
        if not keyPressed then
            Env.vars.freecam = not Env.vars.freecam
            freecamAngles = Env.vars.me:EyeAngles()
            freecamAngles2 = Env.vars.me:EyeAngles()
            freecamPos = Env.vars.me:EyePos()
            keyPressed = true
        end
    else
        keyPressed = false
    end

    if Env.vars.freecam then
        cmd:SetSideMove(0)
        cmd:SetForwardMove(0)
        cmd:SetViewAngles(freecamAngles2)
        cmd:RemoveKey(IN_JUMP)
        cmd:RemoveKey(IN_DUCK)

        freecamAngles = freecamAngles + Angle(cmd:GetMouseY() * 0.023, cmd:GetMouseX() * -0.023, 0)
        freecamAngles.p = Env.vars.math_clamp(freecamAngles.p, -89, 89)
        freecamAngles.y = Env.vars.math_NormAngle(freecamAngles.y)
        freecamAngles.x = Env.vars.math_NormAngle(freecamAngles.x)

        local curFreecamSpeed = Env.vars.kDown(KEY_LSHIFT) and (freecamSpeed * 2) or freecamSpeed

        if Env.vars.kDown(KEY_Z) then
            freecamPos = freecamPos + (freecamAngles:Forward() * curFreecamSpeed)
        end
        if Env.vars.kDown(KEY_S) then
            freecamPos = freecamPos - (freecamAngles:Forward() * curFreecamSpeed)
        end
        if Env.vars.kDown(KEY_Q) then
            freecamPos = freecamPos - (freecamAngles:Right() * curFreecamSpeed)
        end
        if Env.vars.kDown(KEY_D) then
            freecamPos = freecamPos + (freecamAngles:Right() * curFreecamSpeed)
        end
    end
end

function Env.MENU_C(cmd)
    if Env.vars.kDown(KEY_J) and not Env.vars.MenuToggle then
        Env.vars.MenuToggle = true
        Env.ui()
    elseif not Env.vars.kDown(KEY_J) then
        Env.vars.MenuToggle = false
    end
end

function Env.UnloadHooks()
    for _, v in ipairs(Env.hooks) do
        Env.hook.Remove(v.event, v.id)
        
    end
    Env.print("Unloaded.")
    Env.hooks = {}
end
setfenv(Env.UnloadHooks, Env)

function Env.UNLOAD_C(cmd)
    if Env.vars.kDown(KEY_INSERT) then
        if Env.frame:IsVisible() and vars.isValid(Env.frame) then
            ui()
        end
        Env.UnloadHooks()
        Env.vars.unload = false
    end
end

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

    local psa = Env.vars.aim_silent or Env.vars.antiaim

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

    local wish_yaw = Env.vars.fa.y

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

    local createmove_functions = {
        Env.SPAM_C, Env.ANTIAIM_C, Env.AUTOPISTOL_C,
        Env.BHOP_C, Env.THIRDPERSON_C, Env.DESYNC_C,
        Env.FREECAM_C, Env.DANCE_C, Env.MENU_C, Env.UNLOAD_C
    }

    for _, func in Env.ip(createmove_functions) do
        func(cmd)
    end

    if psa and Env.shouldFire() then
        Env.MovementFix(cmd, wish_yaw)
    else
        Env.vars.fa = cmd:GetViewAngles()
    end
end
setfenv( Env._C, Env )

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

    if Env.vars.thirdPersonEnabled then
        local rightOffset = 35
        view.origin = origin - (fangs:Forward() * Env.vars.tps_fov) + (fangs:Right() * rightOffset)
        view.drawviewer = true
    end

    if Env.vars.freecam then
        view.origin = freecamPos
        view.angles = freecamAngles
        view.drawviewer = true
    end

    return view
end

function Env._CV(ply, origin, angles, fov, znear, zfar)
    local fangs = Env.vars.fa or angles
    local view = getView(fangs, origin, angles, fov)
    vieworigin = origin
    return view
end
setfenv( Env._CV, Env )

function Env._CVMV(wep, vm, oldPos, oldAng, pos, ang, ...)
    if Env.vars.antiaim then
        pos = vieworigin
        ang = Env.vars.fa
        return pos, ang
    end
end
setfenv( Env._CVMV, Env )

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

local IsDrawingGlow = false
local fov = false
local chamsMaterial = Material("models/debug/debugwhite")

function Env._PDVM(vm)
    if Env.vars.w_chams then
        Env.vars.rSupEngLight(true)
    
        if IsDrawingGlow then
            Env.vars.rMatOver(chamsMaterial)

            local lightColors = {
                {0.2, 0.2, 0.5}, {0.3, 0.1, 0.6}, {0.1, 0.3, 0.7},
                {0.2, 0.4, 0.8}, {0.4, 0.2, 0.6}, {0.1, 0.5, 0.6}
            }

            for i, color in ipairs(lightColors) do
                Env.vars.rModelLight(i - 1, unpack(color))
            end
        else
            Env.vars.rColorMod(1, 1, 1)
            Env.vars.rBlend(1)
        end
    end

    if Env.vars.w_fov then
        if !fov then
            Env.vars.Cam3Ds(nil, nil, Env.vars.wfov)
            Env.vars.rDepthRange( 0.2, 0 )
            fov = true
            vm:DrawModel()
            fov = false
            Env.vars.Cam3De()
        else
            return
        end
        return true
    else
        return false
    end
end
setfenv( Env._PDVM, Env )

function Env._PODVM()
	if Env.vars.w_chams then
		Env.vars.rColorMod(1, 1, 1)
		Env.vars.rMatOver(None)
		Env.vars.rBlend(1)
		Env.vars.rSupEngLight(false)
		if IsDrawingGlow then return end

		IsDrawingGlow = true
		Env.vars.me:GetViewModel():DrawModel()
		IsDrawingGlow = false
	end
end
setfenv( Env._PODVM, Env )

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

local function chamz(v)
    if not Env.vars.isValid(v) or v == Env.vars.me or not v:Alive() or v:IsDormant() or Env.vars.me:GetPos():Distance(v:GetPos()) > 10000 then return end
    if not Env.vars.me:InVehicle() and not Env.vars.antiaim and Env.IsOutOfFOV(v) then return end

    local teamColor = team.GetColor(v:Team())
    local r, g, b = teamColor.r / 255, teamColor.g / 255, teamColor.b / 255

    local lightColors = {
        {r * 0.2 + 0.05, g * 0.1 + 0.05, b * 0.3 + 0.2}, -- BOX_FRONT 
        {r * 0.4, g * 0.3 - 0.05, b * 0.2 + 0.1},       -- BOX_BACK 
        {r * 0.7, g * 0.6 - 0.05, b * 0.2 - 0.1},      -- BOX_RIGHT
        {r * 0.8, g * 0.5, b * 0.3 - 0.2},            -- BOX_LEFT
        {r * 0.9, g * 0.8, b * 0.3 - 0.1},            -- BOX_TOP
        {r * 0.4, g * 0.3, b * 0.5 + 0.2}             -- BOX_BOTTOM
    }

    local GodAndNoclip = {
        {0.01, 0.01, 0.02}, {0.10, 0.00, 0.20}, {0.25, 0.00, 0.40}, 
        {0.50, 0.00, 0.20}, {0.70, 0.00, 0.10}, {0.30, 0.00, 0.35} 
    }

    local isGod = v:HasGodMode()
    local isNoclipped = v:GetMoveType() == MOVETYPE_NOCLIP
    local colorTable = (isGod or isNoclipped) and GodAndNoclip or lightColors

    Env.vars.rSupEngLight(true)
    camignorez(true)

    Env.vars.rMatOver(chamsMaterial)
    if IsGod and isNoclipped then
        Env.vars.rBlend(0.3)
    end
    for i, color in ipairs(colorTable) do
        Env.vars.rModelLight(i - 1, unpack(color))
    end
    v:DrawModel()

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

function Env._PDE()
    for k,v in Env.ip(player.GetAll()) do
        if (Env.vars.isValid(v) and v:Alive() and v ~= Env.vars.me) then
            if Env.vars.esp_chams then chamz(v) end
        end
    end
end
setfenv( Env._PDE, Env )

local lerpData = {}

local function GetHealthColor(health)
    local t = health / 100
    return Color(255 * (1 - t), 255 * t, 0, 255)
end

function Env.boxcorners(v)
    if not Env.vars.isValid(v) or not v:IsPlayer() then return end

    local data = lerpData[v] or { health = v:Health(), armor = v:Armor() }
    lerpData[v] = data

    local min, max = v:GetCollisionBounds()
    local pos, pos2 = v:GetPos(), v:GetPos() + Env.vars.Vec(0, 0, max.z)
    pos, pos2 = Env.vars.tScreen(pos), Env.vars.tScreen(pos2)

    local h, w = pos.y - pos2.y, (pos.y - pos2.y) / 2
    local x, y = pos.x - w / 2, pos.y - h

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

    Env.vars.sSetDrawColor(GetEntityColor(v))
    Env.vars.sDrawOutlinedRect(x, y, w, h)

    local health = Env.vars.math_clamp(v:Health(), 0, 100)
    data.health = Lerp(FrameTime() * 10, data.health, health)
    
    local healthColor = GetHealthColor(health)
    local healthBarHeight = h * (data.health / 100)

    Env.vars.sSetDrawColor(Color(0, 0, 0))
    Env.vars.sDrawRect(x - 6, y - 1, 4, h + 2)

    Env.vars.sSetDrawColor(healthColor)
    Env.vars.sDrawRect(x - 5, y + h - healthBarHeight, 2, healthBarHeight)

    local armor = Env.vars.math_clamp(v:Armor(), 0, 100)
    data.armor = Lerp(FrameTime() * 10, data.armor, armor)
    
    local armorBarHeight = h * (data.armor / 100)

    Env.vars.sSetDrawColor(Color(0, 0, 0))
    Env.vars.sDrawRect(x + w + 2, y - 1, 4, h + 2)

    Env.vars.sSetDrawColor(Color(0, 150, 255))
    Env.vars.sDrawRect(x + w + 3, y + h - armorBarHeight, 2, armorBarHeight)
end

function Env.txtesp(v)
    local pos = Env.vars.tScreen((v:GetPos() + Env.vars.Vec(0, 0, 75)))
    
    local pName = v:Nick()
    if v:IsAdmin() then
        pName = pName .. " [STAFF]"
    end

    Env.vars.dSimpleTextOutlined(pName, Env.vars.cmdfont, pos.x, pos.y, GetEntityColor(v), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, Color(30, 30, 30, 255))
end

function Env.xhair()
    local X, Y = Env.vars.sw * 0.5, Env.vars.sh * 0.5

    if Env.vars.thirdPersonEnabled then
        local trace = util.TraceLine({
            start = Env.vars.me:EyePos(),
            endpos = Env.vars.me:EyePos() + Env.vars.fa:Forward() * 10000,
            filter = Env.vars.me
        })

        if trace.Hit then
            local screenPos = Env.vars.tScreen(trace.HitPos)
            X, Y = screenPos.x or X, screenPos.y or Y
        end
    end

    local size, thickness = 3.5, 2
    Env.vars.sSetDrawColor(255, 0, 0, 255)
    Env.vars.sDrawRect(X - size - thickness, Y - thickness * 0.5, size, thickness)
    Env.vars.sDrawRect(X + thickness, Y - thickness * 0.5, size, thickness)
    Env.vars.sDrawRect(X - thickness * 0.5, Y - size - thickness, thickness, size)
    Env.vars.sDrawRect(X - thickness * 0.5, Y + thickness, thickness, size)
end

function Env.watermark()
	---- WATERMARK ----
    Env.vars.sSetDrawColor(Env.colors.Background1)
    Env.vars.sDrawRect(10, 10, 200, 94)
    Env.vars.sSetDrawColor(Env.colors.TopBar1)
    Env.vars.sDrawRect(10, 10, 200, 3)
    Env.vars.dDrawText( "Client fps: "..  Env.vars.math_round( 1 / FrameTime()), Env.vars.cmdfont, 25, 20, Color( 255, 255, 255, 255 ) )
    Env.vars.dDrawText( "Server Tick: "..  Env.vars.math_round( 1/engine.TickInterval()) .. "" , Env.vars.cmdfont, 25, 33, Color( 255, 255, 255, 255 ) )
    Env.vars.dDrawText( "Date: "..  os.date( "%d/%m/%Y" ) .. "" , Env.vars.cmdfont, 25, 46, Color( 255, 255, 255, 255 ) )
    Env.vars.dDrawText( "Version: "..  "2.0" .. "" , Env.vars.cmdfont, 25, 58, Color( 255, 255, 255, 255 ) )

    local choke_seconds = Env.GetAvgChoke(0) / 100

    Env.vars.dDrawText( "Desync: ".. string.format("%.3f sec", choke_seconds) , Env.vars.cmdfont, 25, 78, Color( 255, 255, 255, 255 ) )
    ------------------
end

function Env._HP()
    if Env.vars.unload then
        for k,v in Env.ip(Env.player.GetAll()) do
            if not Env.vars.isValid(v) or v == Env.vars.me or not v:Alive() or v:IsDormant() then continue end
            if Env.vars.me:GetPos():Distance(v:GetPos()) > 10000 then continue end
            if not Env.vars.me:InVehicle() and not Env.vars.antiaim and Env.IsOutOfFOV(v) then continue end

            if Env.vars.esp_boxes then Env.boxcorners(v) end
            if Env.vars.esp then Env.txtesp(v) end
        end
        if Env.vars.aim_aimbot and !Env.vars.thirdPersonEnabled then
            local X1 = Env.vars.math_tan( Env.vars.math_rad( Env.vars.aim_fov ) / 1.25 )
            local X2 = Env.vars.math_tan( Env.vars.math_rad( Env.vars.me:GetFOV() / 2 ) )
            local r = X1 / X2
            local pxR = r * ( Env.vars.sw / 2 )
            Env.vars.sDrawCircle(Env.vars.sw / 2, Env.vars.sh / 2, pxR, Env.colors.red)
            if Env.vars.target and Env.shouldFire() then
                local bonePos = Env.getCenterBone(Env.vars.target)
                if not bonePos then return end
                local pos = Env.vars.tScreen(bonePos)
                Env.vars.sSetDrawColor( Env.colors.red )
                Env.vars.sDrawLine( pos.x, pos.y, Env.vars.sw / 2, Env.vars.sh / 2 )
            end
        end
        Env.xhair()
        Env.watermark()
     end
end
setfenv( Env._HP, Env )

function Env._OI(data)
    Env.vars.bulletImpacts[#Env.vars.bulletImpacts + 1] = {
        shootTime = Env.vars.CurTime(),
        pos = data.m_vOrigin,
        alpha = 255
    }
end
setfenv( Env._OI, Env )

function Env._PDOR()
    local currentTime = Env.vars.CurTime()

    for i = #Env.vars.bulletImpacts, 1, -1 do
        local impact = Env.vars.bulletImpacts[i]
        local timeLeft = 0.5 - (currentTime - impact.shootTime)

        if timeLeft <= 0 then
            Env.vars.tRemove(Env.vars.bulletImpacts, i)
        else
            local fadeFactor = timeLeft * 2
            local size = 4 * fadeFactor
            local color = Color(255 * fadeFactor, 0, 255 * (1 - fadeFactor), 255 * fadeFactor)

            Env.vars.Cam3Ds()
                Env.vars.rColorMat()
                Env.vars.rDrawBox(impact.pos, angle_zero, Env.vars.Vec(-size, -size, -size), Env.vars.Vec(size, size, size), color)
            Env.vars.Cam3De()
        end
    end
end
setfenv( Env._PDOR, Env )

Env.VARhooks("CreateMove", Env._C)
Env.VARhooks("PostCreateMove", Env._CAIM)
Env.VARhooks("CalcView", Env._CV)
Env.VARhooks("CalcViewModelView", Env._CVMV)
Env.VARhooks("PreDrawViewModel", Env._PDVM)
Env.VARhooks("PostDrawViewModel", Env._PODVM)
Env.VARhooks('PreDrawEffects', Env._PDE)
Env.VARhooks('HUDPaint', Env._HP)
Env.VARhooks("OnImpact", Env._OI)
Env.VARhooks("PostDrawOpaqueRenderables", Env._PDOR)
