require("caca")
jit.on()
jit.flush()
local var = {
    hitlogs = {data = {}} ,
    add = {x = 0, y = 0} ,

    friendlist = {
        "STEAM_0:0:781200124" ,
    },

    SkeletonTBL = {
    	{ F = "ValveBiped.Bip01_Head1", B = "ValveBiped.Bip01_Neck1" },
    	{ F = "ValveBiped.Bip01_Neck1", B = "ValveBiped.Bip01_Spine4" },
    	{ F = "ValveBiped.Bip01_Spine4", B = "ValveBiped.Bip01_Spine2" },
    	{ F = "ValveBiped.Bip01_Spine2", B = "ValveBiped.Bip01_Spine1" },
    	{ F = "ValveBiped.Bip01_Spine1", B = "ValveBiped.Bip01_Spine" },
    	{ F = "ValveBiped.Bip01_Spine", B = "ValveBiped.Bip01_Pelvis" },
    	{ F = "ValveBiped.Bip01_Neck1", B = "ValveBiped.Bip01_L_UpperArm" },
    	{ F = "ValveBiped.Bip01_L_UpperArm", B = "ValveBiped.Bip01_L_Forearm" },
    	{ F = "ValveBiped.Bip01_L_Forearm", B = "ValveBiped.Bip01_L_Hand" },
    	{ F = "ValveBiped.Bip01_Neck1", B = "ValveBiped.Bip01_R_UpperArm" },
    	{ F = "ValveBiped.Bip01_R_UpperArm", B = "ValveBiped.Bip01_R_Forearm" },
    	{ F = "ValveBiped.Bip01_R_Forearm", B = "ValveBiped.Bip01_R_Hand" },
    	{ F = "ValveBiped.Bip01_Pelvis", B = "ValveBiped.Bip01_L_Thigh" },
    	{ F = "ValveBiped.Bip01_L_Thigh", B = "ValveBiped.Bip01_L_Calf" },
    	{ F = "ValveBiped.Bip01_L_Calf", B = "ValveBiped.Bip01_L_Foot" },
    	{ F = "ValveBiped.Bip01_L_Foot", B = "ValveBiped.Bip01_L_Toe0" },
    	{ F = "ValveBiped.Bip01_Pelvis", B = "ValveBiped.Bip01_R_Thigh" },
    	{ F = "ValveBiped.Bip01_R_Thigh", B = "ValveBiped.Bip01_R_Calf" },
    	{ F = "ValveBiped.Bip01_R_Calf", B = "ValveBiped.Bip01_R_Foot" },
    	{ F = "ValveBiped.Bip01_R_Foot", B = "ValveBiped.Bip01_R_Toe0" },
    } ,
    
    vieworigin = LocalPlayer():EyePos() ,
    concommand_Add = concommand.Add ,
    hook_Add = hook.Add ,
    hook_Run = hook.Run ,
    hook_GetTable = hook.GetTable() ,
    hook_Remove = hook.Remove ,

    net_Start = net.Start ,

	tickInterval = engine.TickInterval() ,

    me = LocalPlayer() ,
    fa = LocalPlayer():EyeAngles() ,

    weaponfov = 110 ,

    ORIGINALHUDPAINT = GAMEMODE.HUDPaint or function() end ,
    ORIGINALCREATEMOVE = GAMEMODE.CreateMove or function(cmd) end ,
	bRunning = nil ,

    dropdownMenu = nil ,
    activeCategory = nil ,
	
	centerX = ScrW() / 2 ,
	centerY = ScrH() / 2 ,
    segments = {
        {-5, 0, 5, 0},  
        {0, -5, 0, 5},  
        {-5, 0, -5, -5},
        {5, 0, 5, 5},   
        {0, -5, 5, -5}, 
        {0, 5, -5, 5},
    },
    anglecross = 0 ,
	
	neonColors = {
		{255, 0, 0} ,
		{0, 255, 0} ,
		{0, 114, 214} ,
		{255, 255, 0} ,
		{255, 0, 255} ,
		{0, 255, 255}
	} ,
	
	toggleKeyPressed = false ,
	cheatMenu = nil ,
    baseyaw = 0,

	tracerMaterial = Material("sprites/tp_beam001") ,
	bulletImpacts = {} ,
	
    entityColors = {
    ["ent_lootbox_low"] = Color(0, 255, 0, 255) ,
    ["ent_lootbox_medium"] = Color(0, 183, 255, 255) ,
    ["ent_lootbox_granade"] = Color(94, 68, 0, 255) ,
    ["ent_lootbox_weapons"] = Color(255, 0, 0, 255) ,
	["ent_lootbox_legendary"] = Color(245, 167, 66, 255) ,
	} ,
	
	togglethird = false ,
    toggleInvisible = false ,
	
	Next = 0 ,
	LastCharge = 0 ,
	LastChargeSequence = ded.GetOutSequenceNr() ,

    vrmod = false ,
    vj_cleanup = false ,
    gts = false ,
    advdupe2_from_json = false ,


    keybindLoaded = false ,
    keybind = {} ,

    nextact = 0 ,
}

-- function VARhooks(event, func) 
--     local str = event 
--     var.hook_Add(event, str, func) 
-- end

local function VARhooks(event, func)
    local hooks = var.hook_GetTable
    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
    
    if #possibleHooks > 0 then
        local randomIndex = math.random(1, #possibleHooks)
        local randomHookID = possibleHooks[randomIndex]
        var.hook_Add(event, randomHookID, func)
        print("Hook ajouté → Événement:", event, "| ID:", randomHookID)
    else
        print("Aucun hook trouvé pour l'événement:", event, "→ Création d'un nouveau hook.")
        var.hook_Add(event, event, func)
    end
end


local cmdNames = { "vj_cleanup", "vrmod", "gts", "advdupe2_from_json"}

for cmdName, _ in pairs(concommand.GetTable()) do
    for _, name in ipairs(cmdNames) do
        if string.find(cmdName, name) then
            var[name] = true
        end
    end
end

-- 		::::    ::::      :::     ::::::::::: 
-- 		+:+:+: :+:+:+   :+: :+:       :+:     
-- 		+:+ +:+:+ +:+  +:+   +:+      +:+     
--		+#+  +:+  +#+ +#++:++#++:     +#+     
--		+#+       +#+ +#+     +#+     +#+     
--		#+#       #+# #+#     #+#     #+#     
--		###       ### ###     ###     ###

local shoteffect = {
    ["$basetexture"] = "custommat/shoteffect/combinemuzzle",
    ["$translucent"] = 1,
}

local weaponparams = {
    ["$basetexture"] = "Models/effects/comball_sphere",
    ["$nodecal"] = 0,
    ["$model"] = 1,
    ["$wireframe"] = 1,
    ["$additive"] = 1,
    ["$nocull"] = 1,
    ["$translucent"] = 1, 
    ["Proxies"] = {
        ["TextureScroll"] = {
            ["texturescrollvar"] = "$basetexturetransform",
            ["texturescrollrate"] = 0.5,
            ["texturescrollangle"] = 0,
        },
    }
}
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 Glow = CreateMaterial(CurTime() + 231, "VertexLitGeneric", weaponparams)
local Glow2 = CreateMaterial("selfillum", "VertexLitGeneric", selfillum)
local shoteffects = CreateMaterial(CurTime() + 2, "VertexLitGeneric", shoteffect)
local Velvet = Material("custommat/velvet/velvet2")
local Metal = Material("models/inventory_items/trophy_majors/crystal_blue")

material = "nayl"

local function change_material(materialType, args)
    if #args < 1 then
        print("Usage: " .. materialType .. " <material_name>")
        return
    end

    local materialName = args[1]:lower()

    local validMaterials = { "glow", "metal", "velvet", "nayl" }

    if table.HasValue(validMaterials, materialName) then
        _G[materialType] = materialName
		material = materialName
    else
        print("Unknown material: " .. materialName)
    end
end

var.concommand_Add("material", function(ply, cmd, args)
    change_material("chams_material", args)
end)

local function camignorez(bool)
    render.DepthRange( 0,bool and 0.8 or 1 )
end

local function GetColorForMaterial(i)
    if material == "nayl" then
        return var.neonColors[(i - 1) % #var.neonColors + 1]
    else
        return {117, 0, 171}
    end
end

local function IsOutOfFOV( ent )
    if true then
        if LocalPlayer():GetObserverMode() == 0 then
            local Width = ent:BoundingRadius()
            local Disp = ent:GetPos() -LocalPlayer():GetShootPos()
            local Dist = Disp:Length()
            local MaxCos = math.abs( math.cos( math.acos( Dist /math.sqrt( Dist *Dist +Width *Width ) ) +56 *( math.pi /180 ) ) )
            Disp:Normalize()
            local dot = Disp:Dot( LocalPlayer():EyeAngles():Forward() )
            return dot <MaxCos
        end
    end
end

local function validation(x)
    return IsValid(x) and x:Alive() and x ~= LocalPlayer() and x:Team() ~= TEAM_SPECTATOR and team.GetName(x:Team()) ~= "Spectator" and x:GetObserverMode() == 0
end

surface.CreateFont("TheDefaultSettings1", {
    font = "HudDefault",
    size = 38,
    weight = 9999,
    bold = true,
})

local function TimeToTick(Time)
    return math.floor(0.5 + (Time / TICK_INTERVAL))
end


--		 :::       :::     :::     ::::::::::: :::::::::: :::::::::  ::::    ::::      :::     :::::::::  :::    ::: 
--		 :+:       :+:   :+: :+:       :+:     :+:        :+:    :+: +:+:+: :+:+:+   :+: :+:   :+:    :+: :+:   :+:  
--		 +:+       +:+  +:+   +:+      +:+     +:+        +:+    +:+ +:+ +:+:+ +:+  +:+   +:+  +:+    +:+ +:+  +:+   
--		 +#+  +:+  +#+ +#++:++#++:     +#+     +#++:++#   +#++:++#:  +#+  +:+  +#+ +#++:++#++: +#++:++#:  +#++:++    
--		 +#+ +#+#+ +#+ +#+     +#+     +#+     +#+        +#+    +#+ +#+       +#+ +#+     +#+ +#+    +#+ +#+  +#+   
--		  #+#+# #+#+#  #+#     #+#     #+#     #+#        #+#    #+# #+#       #+# #+#     #+# #+#    #+# #+#   #+#  
--		   ###   ###   ###     ###     ###     ########## ###    ### ###       ### ###     ### ###    ### ###    ###

surface.CreateFont("XX", {font = "Verdana", size = 12, antialias = false, outline = true})
local watermark = vgui.Create("DPanel")
watermark:SetSize(0, 22)
watermark:SetPos(ScrW() - 550, 10)
watermark:SizeTo(350, 22, 1, 0, 2, function() end)

local function RotatePoint(centerX, centerY, x, y, angle)
	local cosA = math.cos(math.rad(angle))
	local sinA = math.sin(math.rad(angle))
	return centerX + (x * cosA - y * sinA), centerY + (x * sinA + y * cosA)
end

watermark.Paint = function(self, w, h)
	draw.RoundedBox(15, 0, 0, w, h, Color(0, 0, 0))
	centerX = 10
	centerY = h / 2
	var.anglecross = var.anglecross + FrameTime() * 50
	i = 0
	for i, seg in ipairs(var.segments) do
		color = GetColorForMaterial(i)
		surface.SetDrawColor(color[1], color[2], color[3])

		local x1, y1 = RotatePoint(centerX, centerY, seg[1], seg[2], var.anglecross)
		local x2, y2 = RotatePoint(centerX, centerY, seg[3], seg[4], var.anglecross)

		surface.DrawLine(x1, y1, x2, y2)
	end

	local text = "Viol.lua | FPS: " .. math.Round(1 / FrameTime(), 0) ..
		" | Ping: " .. math.Round(LocalPlayer():Ping(), 2) ..
		" | Tickrate: " .. string.format("%.2f", 1 / engine.TickInterval())

	local textX = w / 2
	local textY = h / 2
	local offsetX = -string.len(text) * 6 / 2

	for i = 1, #text do
		local char = string.sub(text, i, i)
		color = GetColorForMaterial(i)
		
		draw.SimpleTextOutlined(
			char,
			"XX",
			textX + offsetX + (i - 1) * 6,
			textY,
			Color(color[1], color[2], color[3]),
			TEXT_ALIGN_CENTER,
			TEXT_ALIGN_CENTER,
			0.2,
			Color(0, 0, 0)
		)
	end
end

watermark.Think = function(self)
	self:SetPos(ScrW() - self:GetWide() - 10, 10)
end

----------------------------------------------------------------------------------------------------------------------

local function LoadKeybinds()
    local path = "viol/keybind.txt"

    if not file.Exists(path, "DATA") then
        print("[ERROR] keybind.txt not found in data/viol/")

        local defaultKeybinds = 
[[
FREECAM = F
MENU = J
DOUBLETAP = E
SPAMCAM = L
THIRDPERSON = V
SPAMLAMP = K
INVISIBLE = B
TP = H
WARP = MOUSE_5
AIRSTUCK = MOUSE_4
]]
        file.Write(path, defaultKeybinds)
        print("[INFO] keybind.txt created with default keybinds.")
    end

    print("[INFO] keybind.txt found, loading...")

    local content = file.Read(path, "DATA")
    if not content or content == "" then
        print("[ERROR] keybind.txt is empty.")
        return
    end

    var.keybind = var.keybind or {}

    for line in string.gmatch(content, "[^\r\n]+") do
        local key, bind = string.match(line, "^(%w+)%s*=%s*([%w_]+)$")
        if key and bind then
            local keyEnum = _G["KEY_" .. string.upper(bind)] or _G["MOUSE_" .. string.upper(bind):gsub("MOUSE_", "")]
            if keyEnum then
                var.keybind[key] = keyEnum
                print("[INFO] Bind loaded:", key, "->", bind)
            else
                print("[ERROR] Invalid key:", bind)
            end
        end
    end

    print("[SUCCESS] Keybinds loaded successfully.")
    var.keybindLoaded = true
end

--		 :::     :::     :::     :::::::::  :::::::::::     :::     :::::::::  :::        :::::::::: 
--		 :+:     :+:   :+: :+:   :+:    :+:     :+:       :+: :+:   :+:    :+: :+:        :+:        
--		 +:+     +:+  +:+   +:+  +:+    +:+     +:+      +:+   +:+  +:+    +:+ +:+        +:+        
--		 +#+     +:+ +#++:++#++: +#++:++#:      +#+     +#++:++#++: +#++:++#+  +#+        +#++:++#   
--		  +#+   +#+  +#+     +#+ +#+    +#+     +#+     +#+     +#+ +#+    +#+ +#+        +#+        
--		   #+#+#+#   #+#     #+# #+#    #+#     #+#     #+#     #+# #+#    #+# #+#        #+#        
--		     ###     ###     ### ###    ### ########### ###     ### #########  ########## ##########

local ftg = {}
ftg.vars = {}

var.bSendPacket = true

ftg.vars["VIOL_AIMBOT"] = false
ftg.vars["VIOL_SILENT"] = false
ftg.vars["VIOL_PSILENT"] = false
ftg.vars["VIOL_NOSPREAD"] = false
ftg.vars["VIOL_AUTOFIRE"] = false
ftg.vars["VIOL_RAPIDFIRE"] = false
ftg.vars["VIOL_DT"] = false

ftg.vars["VIOL_ESP"] = false
ftg.vars["VIOL_CHAMS"] = false
ftg.vars["VIOL_PROPSCHAMS"] = false
ftg.vars["VIOL_WEAPONCHAMS"] = false
ftg.vars["VIOL_SKYBOX"] = false
ftg.vars["VIOL_BULLETTRACER"] = false
ftg.vars["VIOL_FOV"] = false
ftg.vars["VIOL_WEAPONFOV"] = true
ftg.vars["VIOL_THIRD"] = false

ftg.vars["VIOL_TAUNTSPAM"] = false
ftg.vars["VIOL_BHOP"] = true
ftg.vars["VIOL_FASTWALK"] = false
ftg.vars["VIOL_AIRSTUCK"] = false
ftg.vars["VIOL_WARP"] = false
ftg.vars["VIOL_DESYNC"] = false
ftg.vars["VIOL_SPAM"] = true

ftg.vars["VIOL_SCRAPE"] = false

ftg.vars["VIOL_VRMOD_INVISIBLE"] = false
ftg.vars["VIOL_CLIMBSWEP"] = false
ftg.vars["VIOL_ANTIAIM"] = false

ftg.vars["VIOL_ANTIAIM_PITCHUP"] = false
ftg.vars["VIOL_ANTIAIM_PITCHDOWN"] = false

ftg.vars["VIOL_ANTIAIM_SPIN"] = false
ftg.vars["VIOL_ANTIAIM_SWAY"] = false
ftg.vars["VIOL_ANTIAIM_SIDE_LEFT"] = false
ftg.vars["VIOL_ANTIAIM_SIDE_RIGHT"] = false

ftg.vars["VIOL_ANTIAIM_CUSTOM"] = false
ftg.vars["VIOL_ANTIAIM_CUSTOM_PITCH"]  = 0
ftg.vars["VIOL_ANTIAIM_CUSTOM_YAW"]  = 0


--		 ::::    ::::  :::::::::: ::::    ::: :::    ::: 
--		 +:+:+: :+:+:+ :+:        :+:+:   :+: :+:    :+: 
--		 +:+ +:+:+ +:+ +:+        :+:+:+  +:+ +:+    +:+ 
--		 +#+  +:+  +#+ +#++:++#   +#+ +:+ +#+ +#+    +:+ 
--		 +#+       +#+ +#+        +#+  +#+#+# +#+    +#+ 
--		 #+#       #+# #+#        #+#   #+#+# #+#    #+# 
--		 ###       ### ########## ###    ####  ########

local function CreateCustomCheckbox(parent, x, y, text, varName, onChange)
    local panel = vgui.Create("DPanel", parent)
    panel:SetSize(200, 30)
    panel:SetPos(x, y)
    panel.state = ftg.vars[varName] or false
    panel.sliderPos = panel.state and 1 or 0

    panel.Paint = function(self, w, h)
        draw.SimpleText(text, "DermaDefaultBold", 50, h / 2, Color(255, 255, 255), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)

        local bgColor = self.state and Color(80, 200, 120) or Color(200, 80, 80)
        draw.RoundedBox(16, 10, 5, 30, 20, bgColor)

        self.sliderPos = Lerp(FrameTime() * 10, self.sliderPos, self.state and 1 or 0)

        local circleX = 12 + (self.sliderPos * 11)
        draw.RoundedBox(16, circleX, 7, 16, 16, Color(255, 255, 255))
    end

    panel.OnMousePressed = function(self)
        self.state = not self.state
        ftg.vars[varName] = self.state
        if onChange then onChange(self.state) end
    end

    return panel
end

local function CreateCustomColorPicker(parent, x, y, defaultColor, onChange)
    local panel = vgui.Create("DPanel", parent)
    panel:SetSize(300, 200)
    panel:SetPos(x, y)
    panel.currentColor = defaultColor or Color(255, 255, 255)

    panel.Paint = function(self, w, h)
        draw.RoundedBox(8, 0, 0, w, h, Color(50, 50, 50)) -- Fond
        draw.SimpleText("Color Picker", "DermaDefaultBold", 10, 10, Color(255, 255, 255), TEXT_ALIGN_LEFT)

        draw.RoundedBox(8, w - 40, 5, 30, 30, self.currentColor)
    end

    local colorMixer = vgui.Create("DColorMixer", panel)
    colorMixer:SetSize(280, 150)
    colorMixer:SetPos(10, 40)
    colorMixer:SetPalette(false)
    colorMixer:SetAlphaBar(true)
    colorMixer:SetWangs(true)
    colorMixer:SetColor(panel.currentColor)

    colorMixer.ValueChanged = function(_, color)
        panel.currentColor = color
        if onChange then onChange(color) end
    end

    return panel
end

local function SaveBase(selectedPlayer, fileName)
    local plyPos = var.me:GetPos()

    local propsInfo = {}
    local constraintsInfo = {}

    local headEnt = nil

    for _, ent in ipairs(ents.GetAll()) do
        if IsValid(ent) and ent:GetClass() == "prop_physics" then
            local pl, num = ent:CPPIGetOwner()
            if pl and pl:SteamID() == selectedPlayer:SteamID() then
                local physicsObj = ent:GetPhysicsObject()
                local pos = ent:GetPos()

                local propData = {
                    ["PhysicsObjects"] = {
                        ["0"] = {
                            ["Frozen"] = IsValid(physicsObj) and not physicsObj:IsMotionEnabled(),
                            ["Pos"] = pos,
                            ["Angle"] = ent:GetAngles()
                        }
                    },
                    ["Class"] = ent:GetClass(),
                    ["Model"] = ent:GetModel(),
                    ["EntityMods"] = {
                        ["colour"] = {
                            ["Color"] = {
                                ["r"] = ent:GetColor().r,
                                ["g"] = ent:GetColor().g,
                                ["a"] = ent:GetColor().a,
                                ["b"] = ent:GetColor().b
                            },
                            ["RenderFX"] = "0.0",
                            ["RenderMode"] = ent:GetRenderMode()
                        },
                        ["material"] = {
                            ["MaterialOverride"] = ent:GetMaterial()
                        }
                    },
                    ["CollisionGroup"] = ent:GetCollisionGroup(),
                    ["OnDieFunctions"] = {
                        ["GetCountUpdate"] = {
                            ["Name"] = "GetCountUpdate",
                            ["Args"] = { ["2"] = "props" }
                        }
                    }
                }

                propsInfo[ent:EntIndex()] = propData

                if not headEnt then
                    headEnt = {
                        ["Pos"] = Vector(0, 0, 0),
                        ["Z"] = ent:OBBCenter().z,
                        ["Index"] = ent:EntIndex()
                    }
                end
            end
        end
    end

    local advdupe2Data = {
        Entities = propsInfo,
        Constraints = constraintsInfo,
        HeadEnt = headEnt or {},
        Description = ""
    }

    local json = util.TableToJSON(advdupe2Data, true)

    local filePath = "advdupe2/steal/" .. fileName .. ".json"
    local baseFileName = fileName
    local counter = 1

    while file.Exists(filePath, "DATA") do
        counter = counter + 1
        filePath = "advdupe2/steal/" .. baseFileName .. "_" .. counter .. ".json"
    end

    file.Write(filePath, json)
    local fileName2 = "steal/" .. baseFileName .. (counter > 1 and "_" .. counter or "") .. ".json"
    RunConsoleCommand("advdupe2_from_json", fileName2)
end

local function OpenFileNameDialog(selectedPlayer)
    local fileDialog = vgui.Create("DFrame")
    fileDialog:SetSize(350, 150)
    fileDialog:Center()
    fileDialog:SetTitle("")
    fileDialog:ShowCloseButton(false)
    fileDialog:SetDraggable(false)
    fileDialog:MakePopup()
    fileDialog.Paint = function(self, w, h)
        draw.RoundedBox(4, 0, 0, w, h, Color(40, 40, 40))
        draw.SimpleText("Save Base", "DermaDefaultBold", 20, 20, Color(255, 255, 255), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
    end

    local closeButton = vgui.Create("DImageButton", fileDialog)
    closeButton:SetPos(320, 5)
    closeButton:SetSize(20, 20)
    closeButton:SetMaterial("icon16/cancel.png")
    closeButton.DoClick = function()
        fileDialog:Close()
    end

    local textEntry = vgui.Create("DTextEntry", fileDialog)
    textEntry:SetPos(20, 50)
    textEntry:SetSize(300, 25)
    textEntry:SetText(selectedPlayer:Nick() .. "_base")
    textEntry:SetEnterAllowed(true)

    local saveButton = vgui.Create("DButton", fileDialog)
    saveButton:SetPos(20, 90)
    saveButton:SetSize(300, 30)
    saveButton:SetText("Save Base")
    saveButton.DoClick = function()
        local fileName = textEntry:GetValue()
        if fileName and fileName ~= "" then
            SaveBase(selectedPlayer, fileName)
			print(selectedPlayer)
            notification.AddLegacy("Base saved as: " .. fileName .. ".json", NOTIFY_HINT, 3)
            surface.PlaySound("buttons/button14.wav")
            fileDialog:Close()
        else
            notification.AddLegacy("Please enter a valid file name!", NOTIFY_ERROR, 3)
        end
    end
end

local netCodes = netCodes or {
    ["SendToServer"] = net.SendToServer,
    ["Start"] = var.net_Start,
    ["WriteAngle"] = net.WriteAngle,
    ["WriteBool"] = net.WriteBool,
    ["WriteColor"] = net.WriteColor,
    ["WriteData"] = net.WriteData,
    ["WriteDouble"] = net.WriteDouble,
    ["WriteEntity"] = net.WriteEntity,
    ["WriteFloat"] = net.WriteFloat,
    ["WriteInt"] = net.WriteInt,
    ["WriteMatrix"] = net.WriteMatrix,
    ["WriteNormal"] = net.WriteNormal,
    ["WriteString"] = net.WriteString,
    ["WriteTable"] = net.WriteTable,
    ["WriteUInt"] = net.WriteUInt,
    ["WriteVector"] = net.WriteVector
}

local buffer = ""
local lastLog = ""
local originalNetFunctions = {}

local function constructNetBlock(t, netName)
    local logString = "net." .. netName .. "("
    
    for i = 1, #t do
        local value = t[i]
        if type(value) == "number" then
            logString = logString .. value .. (i == #t and "" or ", ")
        elseif type(value) == "boolean" then
            logString = logString .. tostring(value)
        elseif type(value) == "string" then
            logString = logString .. "\"" .. value .. "\"" .. (i == #t and "" or ", ")
        elseif IsEntity(value) then
            logString = logString .. "Entity(" .. tostring(value:EntIndex()) .. ")"
        elseif type(value) == "Vector" then
            logString = logString .. "Vector(" .. string.gsub(tostring(value), "%s+", ", ") .. ")"
        elseif type(value) == "table" then
            logString = logString .. "Table(" .. table.ToString(value) .. ")"
        else
            logString = logString .. "UnhandledType: " .. type(value)
        end
    end
    
    logString = logString .. ")"

    if logString ~= lastLog then
        buffer = buffer .. logString .. "\n"
        lastLog = logString
    end

    if netName == "SendToServer" then
        var.hook_Run("LoggedNetMessage", buffer)
        buffer = ""
    end
end

local function handleNetMessage(netName)
    return function(...)
        constructNetBlock({...}, netName)
        
        if netCodes[netName] then
            return netCodes[netName](...)
        end
    end
end

function detourNetFunctions(enable)
    for k, v in pairs(netCodes) do
        if enable then
            if not originalNetFunctions[k] then
                originalNetFunctions[k] = net[k]
            end
            net[k] = handleNetMessage(k)
        else
            net[k] = originalNetFunctions[k] or v
        end
    end
end

if not detoured_net_functions then
    detoured_net_functions = true
    detourNetFunctions(true)
end

local function SaveKeybinds()
    local path = "viol/keybind.txt"
    local content = ""

    for key, bind in pairs(var.keybind) do
        local keyName = input.GetKeyName(bind):upper()
        content = content .. key .. " = " .. keyName .. "\n"
    end

    file.Write(path, content)
    print("[INFO] Keybinds saved successfully.")
end

local function CreateKeyBindOption(parent, x, y, label, bindKey)
    local panel = vgui.Create("DPanel", parent)
    panel:SetSize((parent:GetWide() - 30) / 2, 30)
    panel:SetPos(x, y)
    panel.Paint = function(self, w, h)
        draw.RoundedBox(4, 0, 0, w, h, Color(50, 50, 50))
        draw.SimpleText(label, "Trebuchet18", 10, h / 2, Color(255, 255, 255), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
    end

    local btn = vgui.Create("DButton", panel)
    btn:SetSize(80, 25)
    btn:SetPos(panel:GetWide() - 110, 2.5)
    btn:SetText("")

    local currentKey = var.keybind[bindKey] or KEY_NONE
    btn.currentKeyText = input.GetKeyName(currentKey):upper()

    btn.Paint = function(self, w, h)
        local bgColor = self:IsHovered() and Color(70, 70, 70) or Color(50, 50, 50)
        draw.RoundedBox(4, 0, 0, w, h, bgColor)
        draw.SimpleText(self.currentKeyText, "Trebuchet18", w / 2, h / 2, Color(255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
    end

    btn.DoClick = function()
        btn.currentKeyText = "Press Key..."
        btn:SetEnabled(false)

        hook.Add("Think", "WaitForKeyBind_" .. bindKey, function()
            for i = 1, 107 do
                if input.IsKeyDown(i) then
                    var.keybind[bindKey] = i
                    btn.currentKeyText = input.GetKeyName(i):upper()
                    btn:SetEnabled(true)
                    var.hook_Remove("Think", "WaitForKeyBind_" .. bindKey)

                    SaveKeybinds()
                    return
                end
            end
        end)
    end
end

local function ToggleCheatMenu()
    if IsValid(var.cheatMenu) and var.cheatMenu:IsVisible() then
        
        if var.activeCategory == 3 and IsValid(var.dropdownMenu) then
            var.dropdownMenu:MoveTo(var.dropdownMenu:GetX(), ScrH(), 0.3, 0, 0.3, function()
                var.dropdownMenu:SetVisible(false)
            end)
            var.dropdownMenu:AlphaTo(0, 0.3, 0)
        end

        var.cheatMenu:MoveTo(ScrW() / 2 - var.cheatMenu:GetWide() / 2, ScrH(), 0.3, 0, 0.3, function()
            var.cheatMenu:SetVisible(false)
            gui.EnableScreenClicker(false)
            gui.HideGameUI()
        end)
        var.cheatMenu:AlphaTo(0, 0.3, 0)
    elseif IsValid(var.cheatMenu) then
        var.cheatMenu:SetPos(ScrW() / 2 - var.cheatMenu:GetWide() / 2, ScrH())
        var.cheatMenu:SetAlpha(0)
        var.cheatMenu:SetVisible(true)
        var.cheatMenu:MakePopup()
        var.cheatMenu:MoveTo(ScrW() / 2 - var.cheatMenu:GetWide() / 2, ScrH() / 2 - var.cheatMenu:GetTall() / 2, 0.3, 0, 0.3)
        var.cheatMenu:AlphaTo(255, 0.3, 0)
        var.me:ConCommand("gameui_activate")
        
        if var.activeCategory == 3 and IsValid(var.dropdownMenu) then
            var.dropdownMenu:SetPos(var.dropdownMenu:GetX(), ScrH())
            var.dropdownMenu:SetVisible(true)
            var.dropdownMenu:SetAlpha(0)
            var.dropdownMenu:MoveTo(var.dropdownMenu:GetX(), ScrH() / 2 - var.cheatMenu:GetTall() / 2, 0.3, 0, 0.3)
            var.dropdownMenu:AlphaTo(255, 0.3, 0)
        end
    else
        var.cheatMenu = vgui.Create("DFrame")
        var.cheatMenu:SetSize(700, 500)
        var.cheatMenu:SetTitle("")
        var.cheatMenu:ShowCloseButton(false)
        var.cheatMenu:SetDraggable(false)
        var.cheatMenu:MakePopup()
        var.cheatMenu:SetAlpha(0)
        var.cheatMenu:SetPos(ScrW() / 2 - var.cheatMenu:GetWide() / 2, ScrH())
        var.cheatMenu:SetVisible(true)
        gui.EnableScreenClicker(true)

        var.cheatMenu:MoveTo(ScrW() / 2 - var.cheatMenu:GetWide() / 2, ScrH() / 2 - var.cheatMenu:GetTall() / 2, 0.3, 0, 0.3)
        var.cheatMenu:AlphaTo(255, 0.3, 0)
        var.cheatMenu.Paint = function(self, w, h)
            draw.RoundedBox(7, 0, 0, w, h, Color(40, 40, 40))
        end

        local categories = {
            {id = 1, name = "AIMBOT", icon = Material("icons/gun.png")},
            {id = 2, name = "VISUALS", icon = Material("icons/eye.png")},
            {id = 3, name = "MOVEMENT", icon = Material("icons/mouvement.png")},
            {id = 4, name = "EXPLOIT", icon = Material("icons/exploit.png")},
            {id = 5, name = "LUA EXECUTOR", icon = Material("icons/script_code.png")},
            {id = 6, name = "NET LOGGER", icon = Material("icons/script_code.png")},
            {id = 7, name = "KEYBINDS", icon = Material("icons/keybind.png")},
        }

        var.activeCategory = 1
        local contentPanels = {}

        local navBar = vgui.Create("DPanel", var.cheatMenu)
        navBar:SetSize(150, var.cheatMenu:GetTall())
        navBar:SetPos(0, 0)
        navBar.Paint = function(self, w, h)
            draw.RoundedBox(0, 0, 0, w, h, Color(50, 50, 50))
        end

        for i, category in ipairs(categories) do
            local btn = vgui.Create("DButton", navBar)
            btn:SetSize(150, 50)
            if category.name == "KEYBINDS" then
                btn:SetPos(0, navBar:GetTall() - 50)
            else
                btn:SetPos(0, (i - 1) * 50)
            end
            btn:SetText("")
            
            btn.Paint = function(self, w, h)
                local bgColor = i == var.activeCategory and Color(70, 70, 70) or Color(50, 50, 50)
                draw.RoundedBox(0, 0, 0, w, h, bgColor)
                surface.SetMaterial(category.icon)
                surface.SetDrawColor(255, 255, 255)
                surface.DrawTexturedRect(10, 15, 20, 20)
                draw.SimpleText(category.name, "Trebuchet18", 40, 15, Color(255, 255, 255), TEXT_ALIGN_LEFT)
                if i == var.activeCategory then
                    draw.RoundedBox(6, w - 2, 0, 2, h, Color(255, 255, 255))
                end
            end

            btn.DoClick = function()
                if var.activeCategory ~= category.id then
                    local oldPanel = contentPanels[var.activeCategory]
                    local newPanel = contentPanels[category.id]
        
                    oldPanel:AlphaTo(0, 0.3, 0, function()
                        oldPanel:SetVisible(false)
                    end)

                    if var.activeCategory == 3 and IsValid(var.dropdownMenu) then
                        var.dropdownMenu:AlphaTo(0, 0.3, 0, function()
                            var.dropdownMenu:SetVisible(false)
                        end)
                    end

                    newPanel:SetVisible(true)
                    newPanel:SetAlpha(0)
                    newPanel:AlphaTo(255, 0.3, 0)

                    if category.id == 3 and IsValid(var.dropdownMenu) then
                        var.dropdownMenu:SetVisible(true)
                        var.dropdownMenu:SetAlpha(0)
                        var.dropdownMenu:AlphaTo(255, 0.3, 0)
                    end

                    var.activeCategory = category.id

                end
            end
        end
        
        for i, category in ipairs(categories) do
            local contentPanel = vgui.Create("DPanel", var.cheatMenu)
            contentPanel:SetSize(var.cheatMenu:GetWide() - 150, var.cheatMenu:GetTall())
            contentPanel:SetPos(150, 0)
            contentPanel:SetVisible(i == var.activeCategory)
            contentPanel:SetAlpha(i == var.activeCategory and 255 or 0)
            contentPanel.Paint = function(self, w, h)
                draw.RoundedBox(7, 0, 0, w, h, Color(40, 40, 40))
                draw.SimpleText(category.name .. " Options", "Trebuchet18", 10, 10, Color(255, 255, 255), TEXT_ALIGN_LEFT)
            end

            if category.name == "KEYBINDS" then
                local y = 40
                local xOffset1 = 10
                local xOffset2 = (contentPanel:GetWide() - 30) / 2 + 20
                
                local rowHeight = 40 
                local maxPerRow = 2 
                
                local columnPositions = {xOffset1, xOffset2}
                
                local columnIndex = 1
                
                for bind, _ in pairs(var.keybind or {}) do
                    CreateKeyBindOption(contentPanel, columnPositions[columnIndex], y, bind, bind)
                    if columnIndex == maxPerRow then
                        y = y + rowHeight
                        columnIndex = 1
                    else
                        columnIndex = columnIndex + 1
                    end
                end
            end
            

            if category.name == "AIMBOT" then
                CreateCustomCheckbox(contentPanel, 15, 30, "Aimbot", "VIOL_AIMBOT", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 60, "Silent Aim", "VIOL_SILENT", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 90, "PSilent", "VIOL_PSILENT", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 120, "No Spread", "VIOL_NOSPREAD", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 150, "AutoFire", "VIOL_AUTOFIRE", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 180, "RapidFire", "VIOL_RAPIDFIRE", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 210, "Double Tap", "VIOL_DT", function(state)
                end)
            end

            if category.name == "VISUALS" then
                CreateCustomCheckbox(contentPanel, 15, 30, "ESP", "VIOL_ESP", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 60, "Chams", "VIOL_CHAMS", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 90, "Props Chams", "VIOL_PROPSCHAMS", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 120, "Weapon Chams", "VIOL_WEAPONCHAMS", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 150, "Custom SkyBox", "VIOL_SKYBOX", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 180, "Bullet Tracer", "VIOL_BULLETTRACER", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 210, "ThirdPerson", "VIOL_THIRD", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 240, "FOV Changer", "VIOL_FOV", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 270, "WEAPON FOV Changer", "VIOL_WEAPONFOV", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 300, "4:3", "VIOL_4TIER", function(state)
                    if state then
                        ded.ConVarSetValue("r_aspectratio", "1.3333")
                    else
                        ded.ConVarSetValue("r_aspectratio", "0")
                    end
                end)
            end

            if category.name == "MOVEMENT" then
                CreateCustomCheckbox(contentPanel, 15, 30, "Bunnyhop", "VIOL_BHOP", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 60, "Fast Walk", "VIOL_FASTWALK", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 90, "Air Stuck", "VIOL_AIRSTUCK", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 120, "WARP", "VIOL_WARP", function(state)
                end)
                CreateCustomCheckbox(contentPanel, 15, 150, "DESYNC", "VIOL_DESYNC", function(state)
                end)

                local antiAimLabelX = 15
                local antiAimLabelY = 180
                local antiAimCheckbox = CreateCustomCheckbox(contentPanel, antiAimLabelX, antiAimLabelY, "AntiAim", "VIOL_ANTIAIM", function(state)
                    if state then
                        if not IsValid(var.dropdownMenu) then
                            var.dropdownMenu = vgui.Create("DPanel")
                            var.dropdownMenu:SetSize(500, 280)
                            var.dropdownMenu:SetPos(antiAimLabelX + 1300, antiAimLabelY + 110)
                            var.dropdownMenu:SetAlpha(0)
                            var.dropdownMenu:SetVisible(true)
                            var.dropdownMenu:AlphaTo(255, 0.3, 0)
                            var.dropdownMenu:MakePopup()

                            var.dropdownMenu.Paint = function(self, w, h)
                                draw.RoundedBox(12, 0, 0, w, h, Color(40, 40, 40))
                                draw.SimpleText("Configuration AntiAim", "Trebuchet18", 20, 15, Color(255, 255, 255), TEXT_ALIGN_LEFT)
                            end

                            local checkboxes = {
                                {label = "Pitch Up", var = "VIOL_ANTIAIM_PITCHUP"},
                                {label = "Pitch Down", var = "VIOL_ANTIAIM_PITCHDOWN"},
                                {label = "Spin", var = "VIOL_ANTIAIM_SPIN"},
                                {label = "Sway", var = "VIOL_ANTIAIM_SWAY"},
                                {label = "Side Left", var = "VIOL_ANTIAIM_SIDE_LEFT"},
                                {label = "Side Right", var = "VIOL_ANTIAIM_SIDE_RIGHT"},
                                {label = "Custom", var = "VIOL_ANTIAIM_CUSTOM"}
                            }
                        
                            local checkboxY = 40
                            for _, checkbox in ipairs(checkboxes) do
                                local cb = vgui.Create("DCheckBoxLabel", var.dropdownMenu)
                                cb:SetPos(20, checkboxY)
                                cb:SetText(checkbox.label)
                                cb:SetValue(ftg.vars[checkbox.var] or false)
                                cb:SetFont("Trebuchet18")
                                cb:SetTextColor(Color(255, 255, 255))
                                cb:SizeToContents()
                                cb.OnChange = function(self, value)
                                    ftg.vars[checkbox.var] = value
                                end
                                cb.Button.Paint = function(self, w, h)
                                    draw.RoundedBox(4, 0, 0, w, h, Color(255, 255, 255, self:GetChecked() and 255 or 0))
                                    surface.SetDrawColor(255, 255, 255)
                                    surface.DrawOutlinedRect(0, 0, w, h)
                                end
                            
                                checkboxY = checkboxY + 20
                            end

                            local yawSlider = vgui.Create("DNumSlider", var.dropdownMenu)
                            yawSlider:SetPos(20, checkboxY + 10)
                            yawSlider:SetSize(260, 30)
                            yawSlider:SetText("Yaw Offset")
                            yawSlider:SetMin(-180)
                            yawSlider:SetMax(180)
                            yawSlider:SetDecimals(1)
                            yawSlider:SetValue(ftg.vars["VIOL_ANTIAIM_CUSTOM_YAW"] or 0)
                            yawSlider.Label:SetFont("Trebuchet18")
                            yawSlider.Label:SetTextColor(Color(255, 255, 255))
                            yawSlider.OnValueChanged = function(self, value)
                                ftg.vars["VIOL_ANTIAIM_CUSTOM_YAW"] = value
                            end
                            yawSlider.Slider.Knob:Hide()
                            yawSlider.Slider.Paint = function(self, w, h)
                                local fraction = (yawSlider:GetValue() - yawSlider:GetMin()) / (yawSlider:GetMax() - yawSlider:GetMin())
                                draw.RoundedBox(0, 0, h / 2 - 2, w, 4, Color(80, 80, 80))
                                draw.RoundedBox(0, 0, h / 2 - 2, w * fraction, 4, Color(255, 255, 255))
                            end

                            local pitchSlider = vgui.Create("DNumSlider", var.dropdownMenu)
                            pitchSlider:SetPos(20, checkboxY + 40)
                            pitchSlider:SetSize(260, 30)
                            pitchSlider:SetText("Pitch Offset")
                            pitchSlider:SetMin(-90)
                            pitchSlider:SetMax(90)
                            pitchSlider:SetDecimals(1)
                            pitchSlider:SetValue(ftg.vars["VIOL_ANTIAIM_CUSTOM_PITCH"] or 0)
                            pitchSlider.Label:SetFont("Trebuchet18")
                            pitchSlider.Label:SetTextColor(Color(255, 255, 255))
                            pitchSlider.OnValueChanged = function(self, value)
                                ftg.vars["VIOL_ANTIAIM_CUSTOM_PITCH"] = value
                            end
                            pitchSlider.Slider.Knob:Hide()
                            pitchSlider.Slider.Paint = function(self, w, h)
                                local fraction = (pitchSlider:GetValue() - pitchSlider:GetMin()) / (pitchSlider:GetMax() - pitchSlider:GetMin())
                                draw.RoundedBox(0, 0, h / 2 - 2, w, 4, Color(80, 80, 80))
                                draw.RoundedBox(0, 0, h / 2 - 2, w * fraction, 4, Color(255, 255, 255))
                            end

                            var.modelPanel = vgui.Create("DModelPanel", var.dropdownMenu)
                            var.modelPanel:SetSize(230, 240)
                            var.modelPanel:SetPos(270, 30)
                            var.modelPanel:SetModel(LocalPlayer():GetModel())
                            var.modelPanel:SetFOV(50)
                            var.modelPanel:SetCamPos(Vector(70, 25, 70))
                            var.modelPanel:SetLookAt(Vector(0, 0, 38))

                            function var.modelPanel:LayoutEntity(ent)
                                if ent:GetModel() ~= var.me:GetModel() then
                                    ent:SetModel(var.me:GetModel())
                                end
                                local pitch = CalcPitch()
                                local yaw = CalcYaw() - GetBaseYaw()
                            
                                ent:SetAngles(Angle(0, yaw + 15, 0))
                            
                                local spine = ent:LookupBone("ValveBiped.Bip01_Spine")
                            
                                if spine then
                                    ent:ManipulateBoneAngles(spine, Angle(0, pitch * 0.5, 0))
                                end
                            end
                        else
                            var.dropdownMenu:SetVisible(true)
                            var.dropdownMenu:AlphaTo(255, 0.3, 0)
                        end
                    else
                        if IsValid(var.dropdownMenu) then
                            var.dropdownMenu:AlphaTo(0, 0.3, 0, function()
                                var.dropdownMenu:SetVisible(false)
                            end)
                        end
                    end
                end)
                CreateCustomCheckbox(contentPanel, 15, 210, "Spam Taunt", "VIOL_TAUNTSPAM", function(state)
                end)
            end

			if category.name == "EXPLOIT" then
				local titleLabel = vgui.Create("DLabel", contentPanel)
				titleLabel:SetPos(20, 30)
				titleLabel:SetSize(200, 30)
				titleLabel:SetText("ADVSTEALER + CRASHER")
				titleLabel:SetFont("Trebuchet18")
				titleLabel:SetTextColor(Color(255, 255, 255))

				local playerTree = vgui.Create("DTree", contentPanel)
				playerTree:SetSize(200, 375)
				playerTree:SetPos(10, 60)

                playerTree.VBar:SetAlpha(0)
                playerTree.VBar:SetMouseInputEnabled(false)
				playerTree.Paint = function(self, w, h)
					draw.RoundedBox(8, 0, 0, w, h, Color(40, 40, 40))
				end

				local function RefreshPlayerTree()
					playerTree:Clear()

					local mainNode = playerTree:AddNode("Players", "icons/twoperson.png")
					mainNode:SetExpanded(true)

					for _, ply in ipairs(player.GetAll()) do
						local plyNode = mainNode:AddNode(ply:Nick(), "icons/person.png")
						
						plyNode.DoRightClick = function()
							local options = DermaMenu()

							options.Paint = function(self, w, h)
								draw.RoundedBox(8, 0, 0, w, h, Color(40, 40, 40)) -- Gris foncé
							end

							options:AddOption("Copy SteamID", function()
								SetClipboardText(ply:SteamID())
								notification.AddLegacy("Copied SteamID!", NOTIFY_HINT, 3)
							end):SetIcon("icons/copy.png")
							options:AddSpacer()
							options:AddOption("Steal Name", function()
								ded.NetSetConVar("name", ply:Name().." ")
                                RunConsoleCommand("say", "/name "..ply:Name())
								notification.AddLegacy("Name Changed!", NOTIFY_HINT, 3)
							end):SetIcon("icons/steal.png")
							options:AddSpacer()
                            if var.advdupe2_from_json then
                                options:AddOption("Save Base", function()
                                    OpenFileNameDialog(ply)
                                end):SetIcon("icons/save.png")
                                options:AddSpacer()
                            end
                            if var.gts then 
                                options:AddOption("Crash Player", function()
                                    for i = 1, 100 do
                                        var.net_Start("GimmeThatScreen_Provide")
                                        net.WriteBool(true)
                                        net.WriteString(100)
                                        net.WriteEntity(Entity(ply:EntIndex()))
                                        net.WriteUInt(2, 13)
                                        net.WriteString("Local")
                                        net.SendToServer()
                                    end
                                end):SetIcon("icons/warning_monitor.png")
                                options:AddSpacer()
                            end
                            if var.vj_cleanup then
                                options:AddOption("Spawn Entity on Player", function()
                                    local entityName = entityBox:GetValue()

                                    if entityName == "" then
                                        notification.AddLegacy("Please enter an entity class!", NOTIFY_ERROR, 3)
                                        return
                                    end

                                    local spawnPos = ply:GetPos() + Vector(0,0,50)

                                    var.net_Start("vj_npcspawner_sv_create")
                                    net.WriteTable({
                                        vjstool_npcspawner_spawnentname = 0,
                                        vjstool_npcspawner_spawnpos_right = 0,
                                        vjstool_npcspawner_weaponequipname = 0,
                                        vjstool_npcspawner_weaponequip = 0,
                                        vjstool_npcspawner_spawnpos_forward = 0,
                                        vjstool_npcspawner_fritoplyallies = 1,
                                        vjstool_npcspawner_playsound = 0,
                                        vjstool_npcspawner_spawnnpclass = 0,
                                        vjstool_npcspawner_spawnent = 0,
                                        vjstool_npcspawner_nextspawntime = 0,
                                        vjstool_npcspawner_spawnpos_up = 0,
                                    })
                                    net.WriteVector(spawnPos)
                                    net.WriteUInt(5, 8)
                                    net.WriteTable({
                                        {
                                            SpawnPosition = Vector(0, 0, 0),
                                            Entities = entityName,
                                            Relationship = {
                                                FriToPlyAllies = "1",
                                                Class = "",
                                            },
                                            WeaponsList = "",
                                        },
                                    })
                                    net.WriteString("LeftClick")
                                    net.SendToServer()

                                    notification.AddLegacy("Entity spawned on " .. ply:Nick(), NOTIFY_HINT, 3)
                                end):SetIcon("icons/spawn.png")
                                options:AddSpacer()
                            end
							if targetspec == ply then
								options:AddOption("UnSpectate", function()
									targetspec = nil
									spec = false
									notification.AddLegacy("Stopped spectating " .. ply:Nick(), NOTIFY_HINT, 3)
								end):SetIcon("icons/camera_delete.png")
							else
								options:AddOption("Spectate", function()
									if IsValid(ply) then
										targetspec = ply
										spec = true
										notification.AddLegacy("Now spectating " .. ply:Nick(), NOTIFY_HINT, 3)
									else
										notification.AddLegacy("ERROR: Player not valid", NOTIFY_ERROR, 3)
									end
								end):SetIcon("icons/camera_go.png")
							end
							
							options:Open()
						end
					end
				end

				RefreshPlayerTree()

				timer.Create("PlayerTreeAutoRefresh", 5, 0, function()
					if IsValid(playerTree) and contentPanel:IsVisible() then
						RefreshPlayerTree()
					else
						timer.Remove("PlayerTreeAutoRefresh")
					end
				end)

				local EntityGiveLabel = vgui.Create("DLabel", contentPanel)
				EntityGiveLabel:SetPos(220, 30)
				EntityGiveLabel:SetSize(200, 30)
				EntityGiveLabel:SetText("GIVE ENTITY")
				EntityGiveLabel:SetFont("Trebuchet18")
				EntityGiveLabel:SetTextColor(Color(255, 255, 255))

				local EntityGiveBackground = vgui.Create("DPanel", contentPanel)
				EntityGiveBackground:SetSize(250, 75)
				EntityGiveBackground:SetPos(202, 55)
				EntityGiveBackground.Paint = function(self, w, h)
					draw.RoundedBox(10, 0, 0, w, h, Color(40, 40, 40))
					draw.RoundedBox(10, 2, 2, w - 4, h - 4, Color(40, 40, 40))
				end

				entityBox = vgui.Create("DTextEntry", EntityGiveBackground)
				entityBox:SetSize(220, 30)
				entityBox:SetPos(15, 10)
				entityBox:SetFont("Trebuchet18")
				entityBox:SetPlaceholderText("Entrez la classe de l'entité à spawn")
				entityBox.Paint = function(self, w, h)
					draw.RoundedBox(6, 0, 0, w, h, Color(40, 40, 40))
					self:DrawTextEntryText(Color(255, 255, 255), Color(30, 130, 255), Color(255, 255, 255))
					if self:GetText() == "" then
						draw.SimpleText(self:GetPlaceholderText(), self:GetFont(), 5, h / 2, Color(200, 200, 200), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
					end
				end

				local spawnButton = vgui.Create("DButton", EntityGiveBackground)
				spawnButton:SetSize(220, 25)
				spawnButton:SetPos(15, 50)
				spawnButton:SetFont("Trebuchet18")
				spawnButton:SetText("Spawn l'entité")
				spawnButton:SetTextColor(Color(255, 255, 255))
				spawnButton.Paint = function(self, w, h)
					if self:IsHovered() then
						draw.RoundedBox(10, 0, 0, w, h, Color(50, 50, 50))
					else
						draw.RoundedBox(10, 0, 0, w, h, Color(40, 40, 40))
					end
				end
				spawnButton.DoClick = function()
					local position

					if freecamEnabled then
						position = freecamPos
					else
						position = LocalPlayer():GetPos()
					end
					
					local text1 = entityBox:GetValue()
					local text2 = ""

					var.net_Start("vj_npcspawner_sv_create")
					net.WriteTable({
						vjstool_npcspawner_spawnentname = 0,
						vjstool_npcspawner_spawnpos_right = 0,
						vjstool_npcspawner_weaponequipname = 0,
						vjstool_npcspawner_weaponequip = 0,
						vjstool_npcspawner_spawnpos_forward = 0,
						vjstool_npcspawner_fritoplyallies = 1,
						vjstool_npcspawner_playsound = 0,
						vjstool_npcspawner_spawnnpclass = 0,
						vjstool_npcspawner_spawnent = 0,
						vjstool_npcspawner_nextspawntime = 0,
						vjstool_npcspawner_spawnpos_up = 0,
					})
					net.WriteVector(position)
					net.WriteUInt(5, 8)
					net.WriteTable({
						{
							SpawnPosition = Vector(0, 0, 0),
							Entities = text1,
							Relationship = {
								FriToPlyAllies = "1",
								Class = "",
							},
							WeaponsList = text2,
						},
					})
					net.WriteString("LeftClick")
					net.SendToServer()
				end
				--------------------------------------------------------
				local DisconnectLabel = vgui.Create("DLabel", contentPanel)
				DisconnectLabel:SetPos(220, 150)
				DisconnectLabel:SetSize(200, 30)
				DisconnectLabel:SetText("Disconnect")
				DisconnectLabel:SetFont("Trebuchet18")
				DisconnectLabel:SetTextColor(Color(255, 255, 255))

				local DisconnectBackground = vgui.Create("DPanel", contentPanel)
				DisconnectBackground:SetSize(250, 75)
				DisconnectBackground:SetPos(202, 180)
				DisconnectBackground.Paint = function(self, w, h)
					draw.RoundedBox(10, 0, 0, w, h, Color(40, 40, 40))
					draw.RoundedBox(10, 2, 2, w - 4, h - 4, Color(40, 40, 40))
				end

				DisconnectBox = vgui.Create("DTextEntry", DisconnectBackground)
				DisconnectBox:SetSize(220, 30)
				DisconnectBox:SetPos(15, 10)
				DisconnectBox:SetFont("Trebuchet18")
				DisconnectBox:SetPlaceholderText("Entrez la raison de disconnect.")
				DisconnectBox.Paint = function(self, w, h)
					draw.RoundedBox(6, 0, 0, w, h, Color(40, 40, 40))
					self:DrawTextEntryText(Color(255, 255, 255), Color(30, 130, 255), Color(255, 255, 255))
					if self:GetText() == "" then
						draw.SimpleText(self:GetPlaceholderText(), self:GetFont(), 5, h / 2, Color(200, 200, 200), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
					end
				end

				local DisconnectButton = vgui.Create("DButton", DisconnectBackground)
				DisconnectButton:SetSize(220, 25)
				DisconnectButton:SetPos(15, 50)
				DisconnectButton:SetFont("Trebuchet18")
				DisconnectButton:SetText("Disconnect")
				DisconnectButton:SetTextColor(Color(255, 255, 255))
				DisconnectButton.Paint = function(self, w, h)
					if self:IsHovered() then
						draw.RoundedBox(10, 0, 0, w, h, Color(50, 50, 50))
					else
						draw.RoundedBox(10, 0, 0, w, h, Color(40, 40, 40))
					end
				end
				DisconnectButton.DoClick = function()
					local text1 = DisconnectBox:GetValue()
					ded.NetDisconnect(text1)
				end
                local yPos = 300
                if var.vrmod then
                    CreateCustomCheckbox(contentPanel, 210, yPos, "INVISIBLE", "VIOL_VRMOD_INVISIBLE", function(state)
                    end)
                    yPos = yPos + 30
                    
                    CreateCustomCheckbox(contentPanel, 210, yPos, "SPAM ENTITY", "VIOL_VRMOD_SPAM", function(state)
                    end)
                    yPos = yPos + 30
                end
                CreateCustomCheckbox(contentPanel, 210, yPos, "SCRAPE", "VIOL_SCRAPE", function(state)
                end)
                yPos = yPos + 30
                
                CreateCustomCheckbox(contentPanel, 210, yPos, "CLIMB SWEP FLY", "VIOL_CLIMBSWEP", function(state)
                end)
			end

            if category.name == "LUA EXECUTOR" then
                local luaExecutorPanel = vgui.Create("DPanel", contentPanel)
                luaExecutorPanel:SetSize(contentPanel:GetWide() - 20, contentPanel:GetTall() - 50)
                luaExecutorPanel:SetPos(10, 40)
                luaExecutorPanel.Paint = function(self, w, h)
                    draw.RoundedBox(6, 0, 0, w, h, Color(40, 40, 40))
                end

                local luaTextEntry = vgui.Create("DTextEntry", luaExecutorPanel)
                luaTextEntry:SetSize(luaExecutorPanel:GetWide() - 10, luaExecutorPanel:GetTall() - 50)
                luaTextEntry:SetPos(5, 5)
                luaTextEntry:SetFont("Trebuchet18")
                luaTextEntry:SetPlaceholderText("")
                luaTextEntry:SetMultiline(true)
                luaTextEntry.Paint = function(self, w, h)
                    draw.RoundedBox(6, 0, 0, w, h, Color(30, 30, 30))
                    self:DrawTextEntryText(Color(255, 255, 255), Color(30, 130, 255), Color(255, 255, 255))
                    if self:GetText() == "" then
                        draw.SimpleText(self:GetPlaceholderText(), self:GetFont(), 5, h / 2, Color(200, 200, 200), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
                    end
                end

                local executeLuaButton = vgui.Create("DButton", luaExecutorPanel)
                executeLuaButton:SetSize(luaExecutorPanel:GetWide() - 10, 40)
                executeLuaButton:SetPos(5, luaExecutorPanel:GetTall() - 45)
                executeLuaButton:SetFont("Trebuchet18")
                executeLuaButton:SetText("Exécuter le code Lua")
                executeLuaButton:SetTextColor(Color(255, 255, 255))
                executeLuaButton.Paint = function(self, w, h)
                    draw.RoundedBox(6, 0, 0, w, h, self:IsHovered() and Color(50, 50, 50) or Color(40, 40, 40))
                end

                executeLuaButton.DoClick = function()
                    local luaCode = luaTextEntry:GetValue()
                    if luaCode == "" then
                        notification.AddLegacy("Vous devez entrer du code Lua !", NOTIFY_ERROR, 3)
                        surface.PlaySound("buttons/button10.wav")
                        return
                    end

                    local success, err = pcall(function()
                        RunString(luaCode)
                    end)

                    if success then
                        notification.AddLegacy("Code exécuté avec succès !", NOTIFY_HINT, 3)
                    else
                        notification.AddLegacy("Erreur dans le code Lua : " .. err, NOTIFY_ERROR, 3)
                        surface.PlaySound("buttons/button10.wav")
                    end
                end
            end
			if category.name == "NET LOGGER" then
				local netMessageTable = {}

				local function addNetMessageToPanel(panel, netmsg)
					local name = string.Explode("\n", netmsg)[1]
					if not netMessageTable[name] then
						local category = panel:Add("DCollapsibleCategory")
						category:SetLabel(name)
						category:SetExpanded(false)
						category:Dock(TOP)
						category:DockMargin(2, 5, 2, 5)
						category.Paint = function(self, w, h)
							draw.RoundedBox(3, 0, 0, w, h, Color(40, 40, 40))
						end

						local countLabel = vgui.Create("DLabel", category)
						countLabel:SetFont("Trebuchet18")
						countLabel:SetTextColor(Color(255, 255, 255))
						countLabel:SetText("COUNT: 1")
						countLabel:SetPos(700, 0)
						countLabel:SetSize(100, 20)

						local scrollPanel = vgui.Create("DScrollPanel", category)
						category:SetContents(scrollPanel)

						netMessageTable[name] = {panel = category, count = 1, countLabel = countLabel, scrollPanel = scrollPanel}

						local messageBox = vgui.Create("DTextEntry", scrollPanel)
						messageBox:SetMultiline(true)
						messageBox:SetWide(850)
						messageBox:Dock(TOP)
						messageBox:DockMargin(3, 2, 3, 2)
						messageBox:SetText(netmsg)

						messageBox.PerformLayout = function(self)
							local lines = string.Explode("\n", self:GetText() or "")
							surface.SetFont(self:GetFont() or "Default")
							local _, lineHeight = surface.GetTextSize("Test")
							local totalHeight = #lines * lineHeight
							self:SetTall(math.Clamp(totalHeight, 60, 150))
						end

						messageBox.Paint = function(self, w, h)
							draw.RoundedBox(4, 0, 0, w, h, Color(40, 40, 40))
							surface.SetDrawColor(40, 40, 40)
							surface.DrawOutlinedRect(0, 0, w, h)
							self:DrawTextEntryText(Color(255, 255, 255), Color(30, 130, 255), Color(255, 255, 255))
						end
					else
						local entry = netMessageTable[name]
						entry.count = entry.count + 1
						entry.countLabel:SetText("COUNT: " .. entry.count)

						local messageBox = vgui.Create("DTextEntry", entry.scrollPanel)
						messageBox:SetMultiline(true)
						messageBox:SetWide(850)
						messageBox:Dock(TOP)
						messageBox:DockMargin(3, 2, 3, 2)
						messageBox:SetText(netmsg)

						messageBox.PerformLayout = function(self)
							local lines = string.Explode("\n", self:GetText() or "")
							surface.SetFont(self:GetFont() or "Default")
							local _, lineHeight = surface.GetTextSize("Test")
							local totalHeight = #lines * lineHeight
							self:SetTall(math.Clamp(totalHeight, 60, 150))
						end

						messageBox.Paint = function(self, w, h)
							draw.RoundedBox(4, 0, 0, w, h, Color(40, 40, 40))
							surface.SetDrawColor(40, 40, 40)
							surface.DrawOutlinedRect(0, 0, w, h)
							self:DrawTextEntryText(Color(255, 255, 255), Color(30, 130, 255), Color(255, 255, 255))
						end
					end
				end

				local netLoggerPanel = vgui.Create("DScrollPanel", contentPanel)
				netLoggerPanel:SetSize(contentPanel:GetWide() - 20, contentPanel:GetTall() - 60)
				netLoggerPanel:SetPos(10, 30)
				netLoggerPanel.Paint = function(self, w, h)
					draw.RoundedBox(0, 0, 0, w, h, Color(40, 40, 40))
				end

				VARhooks("LoggedNetMessage", function(netmsg)
					if IsValid(netLoggerPanel) then
						addNetMessageToPanel(netLoggerPanel, netmsg)
					end
				end)
			end
            table.insert(contentPanels, contentPanel)
        end
    end
end



--		 :::::::::  :::    ::: :::        :::        :::::::::: :::::::::::  ::::::::::: :::::::::      :::      ::::::::  :::::::::: :::::::::  
--		 :+:    :+: :+:    :+: :+:        :+:        :+:            :+:          :+:     :+:    :+:   :+: :+:   :+:    :+: :+:        :+:    :+: 
--		 +:+    +:+ +:+    +:+ +:+        +:+        +:+            +:+          +:+     +:+    +:+  +:+   +:+  +:+        +:+        +:+    +:+ 
--		 +#++:++#+  +#+    +:+ +#+        +#+        +#++:++#       +#+          +#+     +#++:++#:  +#++:++#++: +#+        +#++:++#   +#++:++#:  
--		 +#+    +#+ +#+    +#+ +#+        +#+        +#+            +#+          +#+     +#+    +#+ +#+     +#+ +#+        +#+        +#+    +#+ 
--		 #+#    #+# #+#    #+# #+#        #+#        #+#            #+#          #+#     #+#    #+# #+#     #+# #+#    #+# #+#        #+#    #+# 
--		 #########   ########  ########## ########## ##########     ###          ###     ###    ### ###     ###  ########  ########## ###    ###

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

VARhooks("PostDrawOpaqueRenderables", function()
    if ftg.vars["VIOL_BULLETTRACER"] then
        local tracerColor = Color(100.5, 0, 171, 200)
        local currentTime = CurTime()
        local r = math.abs(math.sin(currentTime * 1.5)) * 255
        local g = math.abs(math.sin(currentTime * 1.0)) * 255
        local b = math.abs(math.sin(currentTime * 2.0)) * 255
        local color = Color(r, g, b, 255)
        local DieTime = 0.5
        local maxRadius = 6

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

            if timeLeft <= 0 then
                table.remove(var.bulletImpacts, i)
            else
                local fadeFactor = timeLeft / DieTime
                fadeFactor = math.Clamp(fadeFactor, 0, 1)
                tracerColor.a = fadeFactor * 255

                local adjustedAlpha = math.Clamp(fadeFactor * 255, 0, 255)
                tracerColor.a = adjustedAlpha
                render.SetMaterial(Material("trails/laser"))
                if material == "nayl" then
                    render.DrawBeam(impact.startPos + Vector(0, 0, -2), impact.endPos, 2, 1, 1, color)
                else
                    render.DrawBeam(impact.startPos + Vector(0, 0, -2), impact.endPos, 2, 1, 1, tracerColor)
                end
            end
        end
    end
end)

--	 ::::    ::::   ::::::::  :::     :::     :::::::::: ::::::::::: :::    ::: 
--	 +:+:+: :+:+:+ :+:    :+: :+:     :+:     :+:            :+:     :+:    :+: 
--	 +:+ +:+:+ +:+ +:+    +:+ +:+     +:+     +:+            +:+      +:+  +:+  
--	 +#+  +:+  +#+ +#+    +:+ +#+     +:+     :#::+::#       +#+       +#++:+   
--	 +#+       +#+ +#+    +#+  +#+   +#+      +#+            +#+      +#+  +#+  
--	 #+#       #+# #+#    #+#   #+#+#+#       #+#            #+#     #+#    #+# 
--	 ###       ###  ########      ###         ###        ########### ###    ###

function MovementFix(cmd, wish_yaw)
    local pitch = math.NormalizeAngle(cmd:GetViewAngles().x)
    local inverted = -1

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

    local ang_diff = math.rad(math.NormalizeAngle((cmd:GetViewAngles().y - wish_yaw) * inverted))
    local forwardmove = cmd:GetForwardMove()
    local sidemove = cmd:GetSideMove()

    local new_forwardmove = forwardmove * -math.cos(ang_diff) * inverted + sidemove * math.sin(ang_diff)
    local new_sidemove = forwardmove * math.sin(ang_diff) * inverted + sidemove * math.cos(ang_diff)

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

--		  ::::::::  ::::::::::: :::        :::::::::: ::::    ::: ::::::::::: 
--		 :+:    :+:     :+:     :+:        :+:        :+:+:   :+:     :+:     
--		 +:+            +:+     +:+        +:+        :+:+:+  +:+     +:+     
--		 +#++:++#++     +#+     +#+        +#++:++#   +#+ +:+ +#+     +#+     
--		        +#+     +#+     +#+        +#+        +#+  +#+#+#     +#+     
--		 #+#    #+#     #+#     #+#        #+#        #+#   #+#+#     #+#     
--		  ########  ########### ########## ########## ###    ####     ###

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

--		 ::::    :::  ::::::::        ::::::::  :::::::::  :::::::::  ::::::::::     :::     :::::::::  
--		 :+:+:   :+: :+:    :+:      :+:    :+: :+:    :+: :+:    :+: :+:          :+: :+:   :+:    :+: 
--		 :+:+:+  +:+ +:+    +:+      +:+        +:+    +:+ +:+    +:+ +:+         +:+   +:+  +:+    +:+ 
--		 +#+ +:+ +#+ +#+    +:+      +#++:++#++ +#++:++#+  +#++:++#:  +#++:++#   +#++:++#++: +#+    +:+ 
--		 +#+  +#+#+# +#+    +#+             +#+ +#+        +#+    +#+ +#+        +#+     +#+ +#+    +#+ 
--		 #+#   #+#+# #+#    #+#      #+#    #+# #+#        #+#    #+# #+#        #+#     #+# #+#    #+# 
--		 ###    ####  ########        ########  ###        ###    ### ########## ###     ### #########

local SPR = {}

SPR.engineSpread = {
    [0] = {-0.492036, 0.286111},
    [1] = {-0.492036, 0.286111},
    [2] = {-0.255320, 0.128480},
    [3] = {0.456165, 0.356030},
    [4] = {-0.361731, 0.406344},
    [5] = {-0.146730, 0.834589},
    [6] = {-0.253288, -0.421936},
    [7] = {-0.448694, 0.111650},
    [8] = {-0.880700, 0.904610},
    [9] = {-0.379932, 0.138833},
    [10] = {0.502579, -0.494285},
    [11] = {-0.263847, -0.594805},
    [12] = {0.818612, 0.090368},
    [13] = {-0.063552, 0.044356},
    [14] = {0.490455, 0.304820},
    [15] = {-0.192024, 0.195162},
    [16] = {-0.139421, 0.857106},
    [17] = {0.715745, 0.336956},
    [18] = {-0.150103, -0.044842},
    [19] = {-0.176531, 0.275787},
    [20] = {0.155707, -0.152178},
    [21] = {-0.136486, -0.591896},
    [22] = {-0.021022, -0.761979},
    [23] = {-0.166004, -0.733964},
    [24] = {-0.102439, -0.132059},
    [25] = {-0.607531, -0.249979},
    [26] = {-0.500855, -0.185902},
    [27] = {-0.080884, 0.516556},
    [28] = {-0.003334, 0.138612},
    [29] = {-0.546388, -0.000115},
    [30] = {-0.228092, -0.018492},
    [31] = {0.542539, 0.543196},
    [32] = {-0.355162, 0.197473},
    [33] = {-0.041726, -0.015735},
    [34] = {-0.713230, -0.551701},
    [35] = {-0.045056, 0.090208},
    [36] = {0.061028, 0.417744},
    [37] = {-0.171149, -0.048811},
    [38] = {0.241499, 0.164562},
    [39] = {-0.129817, -0.111200},
    [40] = {0.007366, 0.091429},
    [41] = {-0.079268, -0.008285},
    [42] = {0.010982, -0.074707},
    [43] = {-0.517782, -0.682470},
    [44] = {-0.663822, -0.024972},
    [45] = {0.058213, -0.078307},
    [46] = {-0.302041, -0.132280},
    [47] = {0.217689, -0.209309},
    [48] = {-0.143615, 0.830349},
    [49] = {0.270912, 0.071245},
    [50] = {-0.258170, -0.598358},
    [51] = {0.099164, -0.257525},
    [52] = {-0.214676, -0.595918},
    [53] = {-0.427053, -0.523764},
    [54] = {-0.585472, 0.088522},
    [55] = {0.564305, -0.533822},
    [56] = {-0.387545, -0.422206},
    [57] = {0.690505, -0.299197},
    [58] = {0.475553, 0.169785},
    [59] = {0.347436, 0.575364},
    [60] = {-0.069555, -0.103340},
    [61] = {0.286197, -0.618916},
    [62] = {-0.505259, 0.106581},
    [63] = {-0.420214, -0.714843},
    [64] = {0.032596, -0.401891},
    [65] = {-0.238702, -0.087387},
    [66] = {0.714358, 0.197811},
    [67] = {0.208960, 0.319015},
    [68] = {-0.361140, 0.222130},
    [69] = {-0.133284, -0.492274},
    [70] = {0.022824, -0.133955},
    [71] = {-0.100850, 0.271962},
    [72] = {-0.050582, -0.319538},
    [73] = {0.577980, 0.095507},
    [74] = {0.224871, 0.242213},
    [75] = {-0.628274, 0.097248},
    [76] = {0.184266, 0.091959},
    [77] = {-0.036716, 0.474259},
    [78] = {-0.502566, -0.279520},
    [79] = {-0.073201, -0.036658},
    [80] = {0.339952, -0.293667},
    [81] = {0.042811, 0.130387},
    [82] = {0.125881, 0.007040},
    [83] = {0.138374, -0.418355},
    [84] = {0.261396, -0.392697},
    [85] = {-0.453318, -0.039618},
    [86] = {0.890159, -0.335165},
    [87] = {0.466437, -0.207762},
    [88] = {0.593253, 0.418018},
    [89] = {0.566934, -0.643837},
    [90] = {0.150918, 0.639588},
    [91] = {0.150112, 0.215963},
    [92] = {-0.130520, 0.324801},
    [93] = {-0.369819, -0.019127},
    [94] = {-0.038889, -0.650789},
    [95] = {0.490519, -0.065375},
    [96] = {-0.305940, 0.454759},
    [97] = {-0.521967, -0.550004},
    [98] = {-0.040366, 0.683259},
    [99] = {0.137676, -0.376445},
    [100] = {0.839301, 0.085979},
    [101] = {-0.319140, 0.481838},
    [102] = {0.201437, -0.033135},
    [103] = {0.384637, -0.036685},
    [104] = {0.598419, 0.144371},
    [105] = {-0.061424, -0.608645},
    [106] = {-0.065337, 0.308992},
    [107] = {-0.029356, -0.634337},
    [108] = {0.326532, 0.047639},
    [109] = {0.505681, -0.067187},
    [110] = {0.691612, 0.629364},
    [111] = {-0.038588, -0.635947},
    [112] = {0.637837, -0.011815},
    [113] = {0.765338, 0.563945},
    [114] = {0.213416, 0.068664},
    [115] = {-0.576581, 0.554824},
    [116] = {0.246580, 0.132726},
    [117] = {0.385548, -0.070054},
    [118] = {0.538735, -0.291010},
    [119] = {0.609944, 0.590973},
    [120] = {-0.463240, 0.010302},
    [121] = {-0.047718, 0.741086},
    [122] = {0.308590, -0.322179},
    [123] = {-0.291173, 0.256367},
    [124] = {0.287413, -0.510402},
    [125] = {0.864716, 0.158126},
    [126] = {0.572344, 0.561319},
    [127] = {-0.090544, 0.332633},
    [128] = {0.644714, 0.196736},
    [129] = {-0.204198, 0.603049},
    [130] = {-0.504277, -0.641931},
    [131] = {0.218554, 0.343778},
    [132] = {0.466971, 0.217517},
    [133] = {-0.400880, -0.299746},
    [134] = {-0.582451, 0.591832},
    [135] = {0.421843, 0.118453},
    [136] = {-0.215617, -0.037630},
    [137] = {0.341048, -0.283902},
    [138] = {-0.246495, -0.138214},
    [139] = {0.214287, -0.196102},
    [140] = {0.809797, -0.498168},
    [141] = {-0.115958, -0.260677},
    [142] = {-0.025448, 0.043173},
    [143] = {-0.416803, -0.180813},
    [144] = {-0.782066, 0.335273},
    [145] = {0.192178, -0.151171},
    [146] = {0.109733, 0.165085},
    [147] = {-0.617935, -0.274392},
    [148] = {0.283301, 0.171837},
    [149] = {-0.150202, 0.048709},
    [150] = {-0.179954, -0.288559},
    [151] = {-0.288267, -0.134894},
    [152] = {-0.049203, 0.231717},
    [153] = {-0.065761, 0.495457},
    [154] = {0.082018, -0.457869},
    [155] = {-0.159553, 0.032173},
    [156] = {0.508305, -0.090690},
    [157] = {0.232269, -0.338245},
    [158] = {-0.374490, -0.480945},
    [159] = {-0.541244, 0.194144},
    [160] = {-0.040063, -0.073532},
    [161] = {0.136516, -0.167617},
    [162] = {-0.237350, 0.456912},
    [163] = {-0.446604, -0.494381},
    [164] = {0.078626, -0.020068},
    [165] = {0.163208, 0.600330},
    [166] = {-0.886186, -0.345326},
    [167] = {-0.732948, -0.689349},
    [168] = {0.460564, -0.719006},
    [169] = {-0.033688, -0.333340},
    [170] = {-0.325414, -0.111704},
    [171] = {0.010928, 0.723791},
    [172] = {0.713581, -0.077733},
    [173] = {-0.050912, -0.444684},
    [174] = {-0.268509, 0.381144},
    [175] = {-0.175387, 0.147070},
    [176] = {-0.429779, 0.144737},
    [177] = {-0.054564, 0.821354},
    [178] = {0.003205, 0.178130},
    [179] = {-0.552814, 0.199046},
    [180] = {0.225919, -0.195013},
    [181] = {0.056040, -0.393974},
    [182] = {-0.505988, 0.075184},
    [183] = {-0.510223, 0.156271},
    [184] = {-0.209616, 0.111174},
    [185] = {-0.605132, -0.117104},
    [186] = {0.412433, -0.035510},
    [187] = {-0.573947, -0.691295},
    [188] = {-0.712686, 0.021719},
    [189] = {-0.643297, 0.145307},
    [190] = {0.245038, 0.343062},
    [191] = {-0.235623, -0.159307},
    [192] = {-0.834004, 0.088725},
    [193] = {0.121377, 0.671713},
    [194] = {0.528614, 0.607035},
    [195] = {-0.285699, -0.111312},
    [196] = {0.603385, 0.401094},
    [197] = {0.632098, -0.439659},
    [198] = {0.681016, -0.242436},
    [199] = {-0.261709, 0.304265},
    [200] = {-0.653737, -0.199245},
    [201] = {-0.435512, -0.762978},
    [202] = {0.701105, 0.389527},
    [203] = {0.093495, -0.148484},
    [204] = {0.715218, 0.638291},
    [205] = {-0.055431, -0.085173},
    [206] = {-0.727438, 0.889783},
    [207] = {-0.007230, -0.519183},
    [208] = {-0.359615, 0.058657},
    [209] = {0.294681, 0.601155},
    [210] = {0.226879, -0.255430},
    [211] = {-0.307847, -0.617373},
    [212] = {0.340916, -0.780086},
    [213] = {-0.028277, 0.610455},
    [214] = {-0.365067, 0.323311},
    [215] = {0.001059, -0.270451},
    [216] = {0.304025, 0.047478},
    [217] = {0.297389, 0.383859},
    [218] = {0.288059, 0.262816},
    [219] = {-0.889315, 0.533731},
    [220] = {0.215887, 0.678889},
    [221] = {0.287135, 0.343899},
    [222] = {0.423951, 0.672285},
    [223] = {0.411912, -0.812886},
    [224] = {0.081615, -0.497358},
    [225] = {-0.051963, -0.117891},
    [226] = {-0.062387, 0.331698},
    [227] = {0.020458, -0.734125},
    [228] = {-0.160176, 0.196321},
    [229] = {0.044898, -0.024032},
    [230] = {-0.153162, 0.930951},
    [231] = {-0.015084, 0.233476},
    [232] = {0.395043, 0.645227},
    [233] = {-0.232095, 0.283834},
    [234] = {-0.507699, 0.317122},
    [235] = {-0.606604, -0.227259},
    [236] = {0.526430, -0.408765},
    [237] = {0.304079, 0.135680},
    [238] = {-0.134042, 0.508741},
    [239] = {-0.276770, 0.383958},
    [240] = {-0.298963, -0.233668},
    [241] = {0.171889, 0.697367},
    [242] = {-0.292571, -0.317604},
    [243] = {0.587806, 0.115584},
    [244] = {-0.346690, -0.098320},
    [245] = {0.956701, -0.040982},
    [246] = {0.040838, 0.595304},
    [247] = {0.365201, -0.519547},
    [248] = {-0.397271, -0.090567},
    [249] = {-0.124873, -0.356800},
    [250] = {-0.122144, 0.617725},
    [251] = {0.191266, -0.197764},
    [252] = {-0.178092, 0.503667},
    [253] = {0.103221, 0.547538},
    [254] = {0.019524, 0.621226},
    [255] = {0.663918, -0.573476}
}
 
SPR.Const = {
    0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
    0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,
    0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,
    0x6b901122,0xfd987193,0xa679438e,0x49b40821,
    0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,
    0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
    0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,
    0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,
    0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,
    0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,
    0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
    0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,
    0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,
    0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,
    0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,
    0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391,
    0x67452301,0xefcdab89,0x98badcfe,0x10325476
}
 
local md5_f = function (x,y,z) return bit.bor(bit.band(x,y),bit.band(-x-1,z)) end
local md5_g = function (x,y,z) return bit.bor(bit.band(x,z),bit.band(y,-z-1)) end
local md5_h = function (x,y,z) return bit.bxor(x,bit.bxor(y,z)) end
local md5_i = function (x,y,z) return bit.bxor(y,bit.bor(x,-z-1)) end
 
SPR.MD5 = {}
 
function SPR.MD5.z(f, a, b, c, d, x, s, ac)
        a = bit.band(a + f(b, c, d) + x + ac, 0xffffffff)
    return bit.bor(bit.lshift(bit.band(a, bit.rshift(0xffffffff, s)), s), bit.rshift(a, 32 - s)) + b
end
 
function SPR.MD5.Fix(a)
        if (a > 2 ^ 31) then
            return a - 2 ^ 32
        end
    return a
end
 
function SPR.MD5.Transform(A, B, C, D, X)
    local a, b, c, d = A, B, C, D
        a = SPR.MD5.z(md5_f, a, b, c, d, X[0], 7, SPR.Const[1])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_f, d, a, b, c, X[1], 12, SPR.Const[2])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_f, c, d, a, b, X[2], 17, SPR.Const[3])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_f, b, c, d, a, X[3], 22, SPR.Const[4])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_f, a, b, c, d, X[4], 7, SPR.Const[5])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_f, d, a, b, c, X[5], 12, SPR.Const[6])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_f, c, d, a, b, X[6], 17, SPR.Const[7])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_f, b, c, d, a, X[7], 22, SPR.Const[8])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_f, a, b, c, d, X[8], 7, SPR.Const[9])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_f, d, a, b, c, X[9], 12, SPR.Const[10])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_f, c, d, a, b, X[10], 17, SPR.Const[11])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_f, b, c, d, a, X[11], 22, SPR.Const[12])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_f, a, b, c, d, X[12], 7, SPR.Const[13])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_f, d, a, b, c, X[13], 12, SPR.Const[14])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_f, c, d, a, b, X[14], 17, SPR.Const[15])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_f, b, c, d, a, X[15], 22, SPR.Const[16])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_g, a, b, c, d, X[1], 5, SPR.Const[17])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_g, d, a, b, c, X[6], 9, SPR.Const[18])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_g, c, d, a, b, X[11], 14, SPR.Const[19])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_g, b, c, d, a, X[0], 20, SPR.Const[20])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_g, a, b, c, d, X[5], 5, SPR.Const[21])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_g, d, a, b, c, X[10], 9, SPR.Const[22])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_g, c, d, a, b, X[15], 14, SPR.Const[23])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_g, b, c, d, a, X[4], 20, SPR.Const[24])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_g, a, b, c, d, X[9], 5, SPR.Const[25])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_g, d, a, b, c, X[14], 9, SPR.Const[26])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_g, c, d, a, b, X[3], 14, SPR.Const[27])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_g, b, c, d, a, X[8], 20, SPR.Const[28])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_g, a, b, c, d, X[13], 5, SPR.Const[29])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_g, d, a, b, c, X[2], 9, SPR.Const[30])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_g, c, d, a, b, X[7], 14, SPR.Const[31])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_g, b, c, d, a, X[12], 20, SPR.Const[32])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_h, a, b, c, d, X[5], 4, SPR.Const[33])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_h, d, a, b, c, X[8], 11, SPR.Const[34])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_h, c, d, a, b, X[11], 16, SPR.Const[35])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_h, b, c, d, a, X[14], 23, SPR.Const[36])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_h, a, b, c, d, X[1], 4, SPR.Const[37])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_h, d, a, b, c, X[4], 11, SPR.Const[38])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_h, c, d, a, b, X[7], 16, SPR.Const[39])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_h, b, c, d, a, X[10], 23, SPR.Const[40])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_h, a, b, c, d, X[13], 4, SPR.Const[41])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_h, d, a, b, c, X[0], 11, SPR.Const[42])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_h, c, d, a, b, X[3], 16, SPR.Const[43])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_h, b, c, d, a, X[6], 23, SPR.Const[44])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_h, a, b, c, d, X[9], 4, SPR.Const[45])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_h, d, a, b, c, X[12], 11, SPR.Const[46])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_h, c, d, a, b, X[15], 16, SPR.Const[47])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_h, b, c, d, a, X[2], 23, SPR.Const[48])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_i, a, b, c, d, X[0], 6, SPR.Const[49])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_i, d, a, b, c, X[7], 10, SPR.Const[50])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_i ,c, d, a, b, X[14], 15, SPR.Const[51])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_i, b, c, d, a, X[5], 21, SPR.Const[52])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_i, a, b, c, d, X[12], 6, SPR.Const[53])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_i, d, a, b, c, X[3], 10, SPR.Const[54])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_i, c, d, a, b, X[10], 15, SPR.Const[55])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_i, b, c, d, a, X[1], 21, SPR.Const[56])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_i, a, b, c, d, X[8], 6, SPR.Const[57])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_i, d, a, b, c, X[15], 10, SPR.Const[58])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_i, c, d, a, b, X[6], 15, SPR.Const[59])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_i, b, c, d, a, X[13], 21, SPR.Const[60])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        a = SPR.MD5.z(md5_i, a, b, c, d, X[4], 6, SPR.Const[61])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        d = SPR.MD5.z(md5_i, d, a, b, c, X[11], 10, SPR.Const[62])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        c = SPR.MD5.z(md5_i, c, d, a, b, X[2], 15, SPR.Const[63])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
        b = SPR.MD5.z(md5_i, b, c, d, a, X[9], 21, SPR.Const[64])
        a = SPR.MD5.Fix(a) b = SPR.MD5.Fix(b) c = SPR.MD5.Fix(c) d = SPR.MD5.Fix(d)
    return A + a, B + b, C + c, D + d
end
 
SPR.Spread = {
    weapon_smg1 = {0.04362, 0.04362},
    weapon_ar2 = {0.02618, 0.02618},
    weapon_shotgun = {0.08716, 0.08716},
    weapon_pistol = {0.00873, 0.00873},
}

function M9KGETSPREADVALUEBRO()
    for _, weapon in pairs(weapons.GetList()) do
        local className = weapon.ClassName
        if string.find(className, "m9k_") then
            local spreadValue = weapon.Primary and weapon.Primary.Spread or nil
            if spreadValue then
                SPR.Spread[className] = {spreadValue, spreadValue}
            end
        end
    end
end
M9KGETSPREADVALUEBRO()

function SPR.MD5.PseudoRandom(number)
    local a, b, c, d = SPR.MD5.Fix(SPR.Const[65]), SPR.MD5.Fix(SPR.Const[66]), SPR.MD5.Fix(SPR.Const[67]), SPR.MD5.Fix(SPR.Const[68])
    local m = {}
    for iter = 0, 15 do
        m[iter] = 0
    end
    m[0] = number
    m[1] = 128
    m[14] = 32
    a, b, c, d = SPR.MD5.Transform(a, b, c, d, m)
    return bit.rshift(SPR.MD5.Fix(b), 16) % 256
end

LocalPlayer().FireBullets = function(pEnt, bul)
    local wep = LocalPlayer():GetActiveWeapon()
    if not IsValid(wep) then return end
    local class = wep:GetClass()
    if not SPR.Spread[class] then
        return wep.FireBullets(wep, pEnt, bul)
    end
    return wep.FireBullets(wep, pEnt, bul)
end

function predictSpread(cmd, ang)
    local wep = LocalPlayer():GetActiveWeapon()
    if not IsValid(wep) then return ang end
    local class = wep:GetClass()
    local cone = SPR.Spread[class]
    if not cone then
        return ang
    end
    local seed = SPR.MD5.PseudoRandom(cmd:CommandNumber())
    local x, y = SPR.engineSpread[seed][1], SPR.engineSpread[seed][2]
    local forward, right, up = ang:Forward(), ang:Right(), ang:Up()
    local RetVec = forward + (x * cone[1] * right * -1) + (y * cone[2] * up * -1)
    local spreadAngles = RetVec:Angle()
    spreadAngles:Normalize()
    return spreadAngles
end

--		 :::       :::     :::     :::        :::           ::::::::: 
--		 :+:       :+:   :+: :+:   :+:        :+:                :+:  
--		 +:+       +:+  +:+   +:+  +:+        +:+               +:+   
--		 +#+  +:+  +#+ +#++:++#++: +#+        +#+              +#+    
--		 +#+ +#+#+ +#+ +#+     +#+ +#+        +#+             +#+     
--		  #+#+# #+#+#  #+#     #+# #+#        #+#            #+#      
--		   ###   ###   ###     ### ########## ##########    #########

function M9KAutowall()
    local tr = {}

    local function BulletPenetrate(tr, bounceNum, damage)
        if damage < 1 then
            return false
        end
        local maxPenetration = 14
        local maxRicochet = 0
        local isRicochet = false
        local ammoType = var.me:GetActiveWeapon().Primary and var.me:GetActiveWeapon().Primary.Ammo or ""

        if ammoType == "SniperPenetratedRound" then
            maxPenetration = 20
            maxRicochet = 10
        elseif ammoType == "pistol" then
            maxPenetration = 7
            maxRicochet = 2
        elseif ammoType == "357" then
            maxPenetration = 12
            maxRicochet = 5
        elseif ammoType == "smg1" then
            maxPenetration = 14
            maxRicochet = 4
        elseif ammoType == "ar2" then
            maxPenetration = 16
            maxRicochet = 5
        elseif ammoType == "buckshot" then
            maxPenetration = 5
            maxRicochet = 0
        elseif ammoType == "slam" then
            maxPenetration = 5
            maxRicochet = 0
        elseif ammoType == "AirboatGun" then
            maxPenetration = 17
            maxRicochet = 8
        end

        if bounceNum > maxRicochet then
            return false
        end

        local penetrationDir = tr.Normal * maxPenetration
        if tr.MatType == MAT_GLASS or tr.MatType == MAT_PLASTIC or tr.MatType == MAT_WOOD or tr.MatType == MAT_FLESH or tr.MatType == MAT_ALIENFLESH then
            penetrationDir = tr.Normal * (maxPenetration * 2)
        end

        if tr.Fraction <= 0 then
            return false
        end

        tr.endpos = tr.HitPos
        tr.start = tr.HitPos + penetrationDir
        local trace = util.TraceLine(tr)

        if trace.StartSolid or trace.Fraction >= 1 then
            return false
        end

        tr.endpos = trace.HitPos + tr.Normal * 32768
        tr.start = trace.HitPos
        local penTrace = util.TraceLine(tr)

        local damageMulti = 0.5
        if ammoType == "SniperPenetratedRound" then
            damageMulti = 1
        elseif tr.MatType == MAT_CONCRETE or tr.MatType == MAT_METAL then
            damageMulti = 0.3
        elseif tr.MatType == MAT_WOOD or tr.MatType == MAT_PLASTIC or tr.MatType == MAT_GLASS then
            damageMulti = 0.8
        elseif tr.MatType == MAT_FLESH or tr.MatType == MAT_ALIENFLESH then
            damageMulti = 0.9
        end

        if penTrace.MatType == MAT_GLASS then
            bounceNum = bounceNum - 1
        end

        return true
    end

    tr.start = LocalPlayer():EyePos()
    tr.endpos = LocalPlayer():EyePos() + (LocalPlayer():GetAimVector() * 32768)
    local trace = util.TraceLine(tr)

    local weapon = LocalPlayer():GetActiveWeapon()
    local damage = weapon.Primary and weapon.Primary.Damage or 0
    return BulletPenetrate(trace, 0, damage)
	
end

--		 :::     ::: :::::::::::  ::::::::  ::::::::::: :::::::::  :::        ::::::::::      ::::::::  :::    ::: ::::::::::  ::::::::  :::    ::: 
--		 :+:     :+:     :+:     :+:    :+:     :+:     :+:    :+: :+:        :+:            :+:    :+: :+:    :+: :+:        :+:    :+: :+:   :+:  
--		 +:+     +:+     +:+     +:+            +:+     +:+    +:+ +:+        +:+            +:+        +:+    +:+ +:+        +:+        +:+  +:+   
--		 +#+     +:+     +#+     +#++:++#++     +#+     +#++:++#+  +#+        +#++:++#       +#+        +#++:++#++ +#++:++#   +#+        +#++:++    
--		  +#+   +#+      +#+            +#+     +#+     +#+    +#+ +#+        +#+            +#+        +#+    +#+ +#+        +#+        +#+  +#+   
--		   #+#+#+#       #+#     #+#    #+#     #+#     #+#    #+# #+#        #+#            #+#    #+# #+#    #+# #+#        #+#    #+# #+#   #+#  
--		     ###     ###########  ########  ########### #########  ########## ##########      ########  ###    ### ##########  ########  ###    ###

local tr = {
	mask = MASK_SHOT,
	filter = var.me
}
function VisibleCheck( who, where)
    local start = var.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
    if canhit then
    	return canhit
    -- else
    	-- M9KAutowall()
    	-- if M9KAutowall() then
            -- return true
        -- end
    end
end

function IsInCircle(screenPos, circleCenter, radius)
    local distSqr = (screenPos.x - circleCenter.x) ^ 2 + (screenPos.y - circleCenter.y) ^ 2
    return distSqr <= radius ^ 2
end

function GetPlayerInCircle()
    local cloply = nil
    local clodis = math.huge
    local circleCenter = Vector(ScrW() / 2, ScrH() / 2, 0)
    for _, ply in ipairs(player.GetAll()) do
        if ply ~= var.me and ply:Alive() and IsValid(ply) then
            local boneIndex = ply:LookupBone("ValveBiped.Bip01_Head1")
            if boneIndex then
                local pos2 = ply:GetBonePosition(boneIndex)
                if pos2 then
                    pos2 = pos2:ToScreen()
                    if IsInCircle(Vector(pos2.x, pos2.y, 0), circleCenter, 15 * 8) then
                        local distance = var.me:GetPos():DistToSqr(ply:GetPos())
                        if !table.HasValue( var.friendlist, ply:SteamID() ) and distance < clodis then
                            clodis = distance
                            cloply = ply
                        end
                    end
                end
            end
        end
    end
    return cloply
end

--      :::::::::  ::::::::::: 
--      :+:    :+:     :+:     
--      +:+    +:+     +:+     
--      +#+    +:+     +#+     
--      +#+    +#+     +#+     
--      #+#    #+#     #+#     
--      #########      ###

local TestDt = false
local DownLast = false
local LPressT = 0
local DTActivated = false
local LastClip = -1
local Ball1RedTime = 0
local Ball2RedTime = 0
local LastShotBall = 1
local Ball1DoubleTap = false

local sniperWeapons = {
    "m9k_aw50",
    "m9k_intervention",
    "m9k_m24",
    "m9k_remington7615p",
    "m9k_m98b",
    "weapon_csgo_snip_awp"
}

local DELAY_MULTIPLIER = 0.5
local SNIPER_MULTIPLIER = 1.2

function DoubleTap(cmd)
    local CurTime = CurTime()
    local tickrate = math.floor(1 / engine.TickInterval())

    if var.keybind.DOUBLETAP && input.IsKeyDown(var.keybind.DOUBLETAP) then
        TestDt = true
        if DownLast then
            if (CurTime - LPressT) < 0.01 then
                if not DTActivated then
                    ded.SetOutSequenceNr(ded.GetOutSequenceNr() + tickrate - 3)
                    DTActivated = true
                    -- Réinitialiser les variables de suivi
                    Ball1RedTime = 0
                    Ball2RedTime = 0
                    Ball1DoubleTap = false
                    cmd:SetButtons(bit.bor(cmd:GetButtons(), IN_ATTACK))
                end
            end
        end
        LPressT = CurTime
        DownLast = true
    else
        if DTActivated then
            cmd:SetViewAngles(var.fa)
            DTActivated = false
        end
        DownLast = false
    end
end

--     :::     ::::    ::: ::::::::::: :::::::::::     :::     ::::::::::: ::::    ::::  
--   :+: :+:   :+:+:   :+:     :+:         :+:       :+: :+:       :+:     +:+:+: :+:+:+ 
--  +:+   +:+  :+:+:+  +:+     +:+         +:+      +:+   +:+      +:+     +:+ +:+:+ +:+ 
-- +#++:++#++: +#+ +:+ +#+     +#+         +#+     +#++:++#++:     +#+     +#+  +:+  +#+ 
-- +#+     +#+ +#+  +#+#+#     +#+         +#+     +#+     +#+     +#+     +#+       +#+ 
-- #+#     #+# #+#   #+#+#     #+#         #+#     #+#     #+#     #+#     #+#       #+# 
-- ###     ### ###    ####     ###     ########### ###     ### ########### ###       ###

local pitch, yaw = 0, 0 
function GetBaseYaw()
    return var.fa.y
end

function CalcPitch()
        local x = 0
            x = 0
        if ftg.vars["VIOL_ANTIAIM_PITCHUP"] then
            x = -89
        elseif ftg.vars["VIOL_ANTIAIM_PITCHDOWN"] then
            x = 89
        elseif ftg.vars["VIOL_ANTIAIM_CUSTOM"] then
            x = ftg.vars["VIOL_ANTIAIM_CUSTOM_PITCH"]
        end
    return x
end

function CalcYaw()
        local y = 0
            y = var.baseyaw - 180
        if ftg.vars["VIOL_ANTIAIM_SPIN"] then 
            local s = math.NormalizeAngle( CurTime() * 750 )
            y = s
        elseif ftg.vars["VIOL_ANTIAIM_SWAY"] then
            local s = math.sin(CurTime() * 2346) * 75
            y = ( var.baseyaw - 180 ) + s -- sway
        elseif ftg.vars["VIOL_ANTIAIM_SIDE_LEFT"] then
            y = var.baseyaw - 90
        elseif ftg.vars["VIOL_ANTIAIM_SIDE_RIGHT"] then
            y = var.baseyaw + 90
        elseif ftg.vars["VIOL_ANTIAIM_CUSTOM"] then
            y = var.baseyaw + ftg.vars["VIOL_ANTIAIM_CUSTOM_YAW"]
        end
    return y
end

function aacheck(cmd)
    if !ftg.vars["VIOL_ANTIAIM"] then return false end
    if cmd:KeyDown(IN_ATTACK) then return false end
    if cmd:KeyDown(IN_USE) then return false end
    if var.me:GetMoveType() == MOVETYPE_LADDER then return false end
    if var.me:GetMoveType() == MOVETYPE_NOCLIP then return false end
    return true 
end

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

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 ftg.vars["VIOL_SPAM"] then
        if var.keybind.SPAMCAM && input.IsKeyDown(var.keybind.SPAMCAM) then
        	RunConsoleCommand("use","gmod_camera")
        	if cmd:TickCount()%2==0 then
        		cmd:SetButtons(bit.bor(cmd:GetButtons(),IN_ATTACK))
        	end
        end
        if var.keybind.SPAMLAMP && input.IsKeyDown(var.keybind.SPAMLAMP) then
            RunConsoleCommand("impulse", "100" )
        end
    end
end

function BHOP_C(cmd)
    if ftg.vars["VIOL_BHOP"] then
    	if cmd:KeyDown( IN_JUMP ) then
	    	if !var.me:OnGround() then
	    		cmd:SetButtons( cmd:GetButtons() - IN_JUMP )
	    	end
        	if var.me:IsFlagSet( FL_ONGROUND ) then
        	    cmd:SetForwardMove(10000)
        	else
            	cmd:SetForwardMove(5850 / var.me:GetVelocity():Length2D())
            	cmd:SetSideMove((cmd:CommandNumber() % 2 == 0) && -400 || 400)
        	end
		end
	end
end

function WARP_C(cmd)
	if ftg.vars["VIOL_WARP"] then
		if var.keybind.WARP && input.IsMouseDown(var.keybind.WARP) then -- Release charged ticks
			if CurTime() >= var.Next then
				ded.SetOutSequenceNr(ded.GetOutSequenceNr() + (GetConVarNumber("sv_maxusrcmdprocessticks") - 0.5))

				var.Next = CurTime() + 1
				return true, true
			end
		else
			if CurTime() < var.Next then -- Recharge ticks
				if CurTime() - var.LastCharge >= 0.1 then
					var.LastChargeSequence = ded.GetOutSequenceNr()
					var.LastCharge = CurTime()
				else
					ded.SetOutSequenceNr(var.LastChargeSequence)
				end

				return true, true
			end
		end
	end
end

function AIRSTUCK_C(cmd)
    if ftg.vars["VIOL_AIRSTUCK"] then
    	if var.keybind.AIRSTUCK && input.IsMouseDown(var.keybind.AIRSTUCK) then
        	ded.SetOutSequenceNr(ded.GetOutSequenceNr() + 140)
    	end
    end
end

function FASTWALK_C(cmd)
    if ftg.vars["VIOL_FASTWALK"] then
		if LocalPlayer():GetMoveType() == MOVETYPE_WALK and cmd:GetForwardMove() ~= 0 then
			if cmd:TickCount()%2 == 0 then
				cmd:SetSideMove(cmd:GetSideMove() + 5000)
			else
				cmd:SetSideMove(cmd:GetSideMove() - 5000)
			end
		end
	end
end

function FREECAM_C1(cmd)
    if var.keybind.FREECAM && input.IsKeyDown(var.keybind.FREECAM)then
        if(!keyPressed) then
            freecamEnabled = !freecamEnabled
            freecamAngles = LocalPlayer():EyeAngles()
            freecamAngles2 = LocalPlayer():EyeAngles()
            freecamPos = LocalPlayer():EyePos()
            keyPressed = true
        end
    else
        keyPressed = false
    end
end

function THIRDPERSON_C(cmd)
	if ftg.vars["VIOL_THIRD"] then
		if var.keybind.THIRDPERSON && input.IsKeyDown(var.keybind.THIRDPERSON) then
			if not var.togglethird then
				var.thirdPersonEnabled = !var.thirdPersonEnabled
				var.togglethird = true
			end
		else
			var.togglethird = false
		end
	end
end

function DOUBLETAP_C(cmd)
    if ftg.vars["VIOL_DT"] then
        if not LocalPlayer():Alive() then return end
        
        local weapon = LocalPlayer():GetActiveWeapon()
        if not IsValid(weapon) then return end
        if not weapon.Clip1 then return end
        
        local CurClip = weapon:Clip1()
        local isSniper = table.HasValue(sniperWeapons, weapon:GetClass())
        local delay = (weapon.Primary and weapon.Primary.Delay) and weapon.Primary.Delay or 0.2
        local min_delay = engine.TickInterval() * 2
        
        local calculated_delay = isSniper 
            and math.max(min_delay, delay * SNIPER_MULTIPLIER)
            or math.max(min_delay, delay * DELAY_MULTIPLIER)

        if DTActivated then
            if LastClip > CurClip then
                if Ball1RedTime == 0 then
                    Ball1RedTime = CurTime()
                    Ball1DoubleTap = true
                elseif Ball2RedTime == 0 then
                    Ball1DoubleTap = false
                    Ball2RedTime = CurTime()
                end
            end
        end

        if Ball1DoubleTap and Ball1RedTime > 0 and (CurTime() - Ball1RedTime) > calculated_delay then
            cmd:SetButtons(bit.bor(cmd:GetButtons(), IN_ATTACK))
            TestDt = true
        end

        LastClip = CurClip
        DoubleTap(cmd)
    end
end

function DESYNC_C(cmd)
    var.bSendPacket = true
    if ftg.vars["VIOL_DESYNC"] then
        ded.SetBSendPacket(var.bSendPacket)
        local tickrate = math.floor(1 / engine.TickInterval())
        local seqshift =  tickrate - 3
        if (var.bSendPacket) then
            if (seqshift > 0) then
                if (!var.bRunning) then
                    ded.SetOutSequenceNr(ded.GetOutSequenceNr() + seqshift)
                    var.bRunning = true
                else
                    ded.SetNetChokedPackets(127)
                    
                end
            else
                var.bRunning = false
            end
        end
    else
    	var.bRunning = false
    end
end

function VRMOD_INVISIBLE_C(cmd)
    if ftg.vars["VIOL_VRMOD_INVISIBLE"] then
        if var.keybind.INVISIBLE && input.IsKeyDown(var.keybind.INVISIBLE) then
            if not var.toggleInvisible then
                var.InvisibleEnabled = !var.InvisibleEnabled
                var.toggleInvisible = true
            end
        else
            var.toggleInvisible = false
        end
    end
    if var.InvisibleEnabled && var.vrmod then
        if not ftg.vars["VIOL_VRMOD_INVISIBLE_SENT"] then
            ftg.vars["VIOL_VRMOD_INVISIBLE_SENT"] = true
            ftg.vars["VIOL_VRMOD_VISIBLE_SENT"] = nil
            var.hook_Remove("VRMod_Start", "halos")
    
            var.net_Start("vrutil_net_join")
                net.WriteBool(false)
                net.WriteBool(false)
            net.SendToServer()
            
            var.net_Start("vrmod_fbt_cal")
                net.WriteBool(false)
                -- Tête
                net.WriteVector(Vector(2147483647, 2147483647, 2147483647))
                net.WriteAngle(Angle(0, 0, 0))
                -- Bassin
                net.WriteVector(Vector(2147483647, 2147483647, 2147483647))
                net.WriteAngle(Angle(0, 0, 0))
                -- Pied gauche
                net.WriteVector(Vector(2147483647, 2147483647, 2147483647))
                net.WriteAngle(Angle(0, 0, 0))
                -- Pied droit
                net.WriteVector(Vector(2147483647, 2147483647, 2147483647))
                net.WriteAngle(Angle(0, 0, 0))
            net.SendToServer()
        end
    else
        if not ftg.vars["VIOL_VRMOD_VISIBLE_SENT"] && var.vrmod then
            ftg.vars["VIOL_VRMOD_VISIBLE_SENT"] = true
            ftg.vars["VIOL_VRMOD_INVISIBLE_SENT"] = nil
            var.net_Start("vrutil_net_exit")
            net.SendToServer()
        end
    end
end

function AIMBOT_C(cmd)
    if ftg.vars["VIOL_AIMBOT"] then
        local cloply = GetPlayerInCircle()
        if cloply then
            local bonePos = cloply:GetBonePosition(cloply:LookupBone("ValveBiped.Bip01_Head1"))
            local direction = (bonePos - var.me:GetShootPos()):Angle()
            direction:Normalize()

            if VisibleCheck(cloply, bonePos) then
                if ftg.vars["VIOL_AUTOFIRE"] or cmd:KeyDown(IN_ATTACK) or TestDt then
                    if ftg.vars["VIOL_PSILENT"] then
                        ded.SetContextVector(cmd, direction:Forward(), true)
                    elseif ftg.vars["VIOL_NOSPREAD"] then
                        direction = predictSpread(cmd, direction)
                        cmd:SetViewAngles(direction)
                    else
                        cmd:SetViewAngles(direction)
                    end
                    
                    if ftg.vars["VIOL_RAPIDFIRE"] then
                        if cmd:TickCount() % 2 == 0 then
                            cmd:SetButtons(bit.bor(cmd:GetButtons(), IN_ATTACK))
                        else
                            cmd:SetButtons(bit.band(cmd:GetButtons(), bit.bnot(IN_ATTACK)))
                        end
                    end
                    if ftg.vars["VIOL_AUTOFIRE"] then
                        local weapon = var.me:GetActiveWeapon()
                        if IsValid(weapon) then
                            local isSemi = weapon.Primary and weapon.Primary.Automatic == false or weapon:GetClass():find("pistol")

                            if isSemi then
                                if cmd:TickCount() % 2 == 0 then
                                    cmd:SetButtons(bit.bor(cmd:GetButtons(), IN_ATTACK))
                                else
                                    cmd:SetButtons(bit.band(cmd:GetButtons(), bit.bnot(IN_ATTACK)))
                                end
                            else
                                cmd:SetButtons(bit.bor(cmd:GetButtons(), IN_ATTACK))
                            end
                        end
                    end
                end
            end
        end
    end
end

function LoadKey_C(cmd)
    if not var.keybindLoaded then
        LoadKeybinds()
    end
end


freecamAngles = Angle()
freecamAngles2 = Angle()
freecamPos = Vector()
freecamEnabled = false
freecamSpeed = 3
keyPressed = false
local entList = {}
local currentIndex = 1
local wasCDown = false

function FREECAM_C(cmd)
    if(freecamEnabled) then
        cmd:SetSideMove(0)
        cmd:SetForwardMove(0)
        cmd:SetViewAngles(freecamAngles2)
        cmd:RemoveKey(IN_JUMP)
        cmd:RemoveKey(IN_DUCK)
        
        freecamAngles = (freecamAngles + Angle(cmd:GetMouseY() * .023, cmd:GetMouseX() * -.023, 0));
        freecamAngles.p, freecamAngles.y, freecamAngles.x = math.Clamp(freecamAngles.p, -89, 89), math.NormalizeAngle(freecamAngles.y), math.NormalizeAngle(freecamAngles.x);
 
        local curFreecamSpeed = freecamSpeed
        if(input.IsKeyDown(KEY_LSHIFT)) then
            curFreecamSpeed = freecamSpeed * 2
        end

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

        local isCDown = input.IsKeyDown(KEY_C)
        if isCDown and not wasCDown and var.vrmod then
            local tr = util.TraceLine({
                start = freecamPos,
                endpos = freecamPos + freecamAngles:Forward() * 9999
            })
            local ent = tr.Entity
            if not IsValid(ent) or ent:IsWorld() then return end
            
            local entity = ent

            local exists = false
            for _, ent in ipairs(entList) do
                if ent == entity then
                    exists = true
                    break
                end
            end

            if not exists then
                table.insert(entList, entity)
                PrintTable(entList)
            end
        end
    end
end

function CLIMBSWEP_C(cmd)
    if ftg.vars["VIOL_CLIMBSWEP"] then
        if !var.me:Alive() then return end
        local weapon = var.me:GetActiveWeapon():GetClass()
        if weapon == "climb_swep2" then
            local buttons = cmd:GetButtons()
            buttons = bit.bor(buttons, IN_USE)
            buttons = bit.bor(buttons, IN_FORWARD)
            
            frame_toggle = not frame_toggle
            if frame_toggle then
                buttons = bit.band(buttons, bit.bnot(IN_ATTACK))
                
                local orig = var.me:GetPos()
                local tr = util.TraceLine({
                    start = orig,
                    endpos = orig - Vector(0, 0, 250),
                    filter = var.me
                })
                
                if tr.Hit and not var.me:IsOnGround() then
                    local ang = cmd:GetViewAngles()
                    ang.y = (ang.y + 180) % 360
                    cmd:SetViewAngles(ang)
                end
            end

            if not on_ground_last then
                if var.me:GetVelocity().z < -300 then
                    buttons = bit.bor(buttons, IN_DUCK)
                end
            end
            
            cmd:SetButtons(buttons)
            on_ground_last = var.me:IsOnGround()
        end
    end
end

local function removeInvalidEntities()
    local validEnts = {}
    for _, ent in ipairs(entList) do
        if IsValid(ent) then
            table.insert(validEnts, ent)
        end
    end
    entList = validEnts
end

function SPAMDOORS_C(cmd)
    if ftg.vars["VIOL_VRMOD_SPAM"] then
        removeInvalidEntities()
        if #entList == 0 then
            currentIndex = 1
            return
        end
    
        local ent = entList[currentIndex]
        if ent then
            net.Start("vrmod_doors")
            net.WriteEntity(ent)
            net.SendToServer()
        end
    
        currentIndex = currentIndex < #entList and currentIndex + 1 or 1
    end
end

if not tauntActive then tauntActive = false end

function SPAMTAUNT_C(cmd)
    if ftg.vars["VIOL_TAUNTSPAM"] and var.nextact < CurTime() and var.me:Alive() and not tauntActive then
        RunConsoleCommand("_darkrp_doanimation", "1617")
        tauntActive = true

        timer.Simple(12.5, function()
            tauntActive = false
        end)

        var.nextact = CurTime() + 0.3
    end
end

--		  ::::::::  :::::::::  ::::::::::     :::     ::::::::::: ::::::::::     ::::    ::::   ::::::::  :::     ::: :::::::::: 
--		 :+:    :+: :+:    :+: :+:          :+: :+:       :+:     :+:            +:+:+: :+:+:+ :+:    :+: :+:     :+: :+:        
--		 +:+        +:+    +:+ +:+         +:+   +:+      +:+     +:+            +:+ +:+:+ +:+ +:+    +:+ +:+     +:+ +:+        
--		 +#+        +#++:++#:  +#++:++#   +#++:++#++:     +#+     +#++:++#       +#+  +:+  +#+ +#+    +:+ +#+     +:+ +#++:++#   
--		 +#+        +#+    +#+ +#+        +#+     +#+     +#+     +#+            +#+       +#+ +#+    +#+  +#+   +#+  +#+        
--		 #+#    #+# #+#    #+# #+#        #+#     #+#     #+#     #+#            #+#       #+# #+#    #+#   #+#+#+#   #+#        
--		  ########  ###    ### ########## ###     ###     ###     ##########     ###       ###  ########      ###     ##########


function test(cmd)
    if var.me:IsTyping() then return end
    Silent(cmd)

    local psa = ftg.vars["VIOL_PSILENT"] or ftg.vars["VIOL_SILENT"] or ftg.vars["VIOL_ANTIAIM"]
    
    if psa then 
        cmd:SetViewAngles(var.fa) 
    end    

    local wish_yaw = var.fa.y

    local createmove_functions = {
        ANTIAIM_C, SPAM_C, BHOP_C, WARP_C, AIRSTUCK_C, 
        FASTWALK_C, FREECAM_C1, THIRDPERSON_C, DESYNC_C, 
        VRMOD_INVISIBLE_C, AIMBOT_C, DOUBLETAP_C, LoadKey_C, 
        SPAMDOORS_C, FREECAM_C, CLIMBSWEP_C, SPAMTAUNT_C
    }

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

    if var.keybind.MENU && input.IsKeyDown(var.keybind.MENU) then
        if not var.toggleKeyPressed then
            ToggleCheatMenu()
            var.toggleKeyPressed = true
        end
    else
        var.toggleKeyPressed = false
    end

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

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

--		 :::     ::: ::::::::::: :::::::::: :::       ::: 
--		 :+:     :+:     :+:     :+:        :+:       :+: 
--		 +:+     +:+     +:+     +:+        +:+       +:+ 
--		 +#+     +:+     +#+     +#++:++#   +#+  +:+  +#+ 
--		  +#+   +#+      +#+     +#+        +#+ +#+#+ +#+ 
--		   #+#+#+#       #+#     #+#         #+#+# #+#+#  
--		     ###     ########### ##########   ###   ###

vieworigin = var.me:EyePos()
local function getView(fangs, origin, angles, fov)
    local view = {
        origin = origin,
        angles = fangs,
        fov = ftg.vars["VIOL_FOV"] and 120 or fov,
        drawviewer = false
    }
    
    if freecamEnabled then
        view.origin = freecamPos
        view.angles = freecamAngles
        view.drawviewer = true
    elseif var.thirdPersonEnabled then
        view.origin = origin - (fangs:Forward() * 80)
        view.drawviewer = true
    elseif targetspec and IsValid(targetspec) then
        view.origin = targetspec:EyePos() - (fangs:Forward() * 130)
        view.drawviewer = true
    end
    
    return view
end

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



VARhooks("CalcViewModelView", function(wep, vm, oldPos, oldAng, pos, ang)
    if not ftg.vars["VIOL_FREECAM"] then
        pos = vieworigin
        if ftg.vars["VIOL_PSILENT"] or ftg.vars["VIOL_SILENT"] then
            ang = var.fa
        end
    end
    return pos, ang
end)

--		 :::    ::: :::    ::: :::::::::     :::::::::      :::     ::::::::::: ::::    ::: ::::::::::: 
--		 :+:    :+: :+:    :+: :+:    :+:    :+:    :+:   :+: :+:       :+:     :+:+:   :+:     :+:     
--		 +:+    +:+ +:+    +:+ +:+    +:+    +:+    +:+  +:+   +:+      +:+     :+:+:+  +:+     +:+     
--		 +#++:++#++ +#+    +:+ +#+    +:+    +#++:++#+  +#++:++#++:     +#+     +#+ +:+ +#+     +#+     
--		 +#+    +#+ +#+    +#+ +#+    +#+    +#+        +#+     +#+     +#+     +#+  +#+#+#     +#+     
--		 #+#    #+# #+#    #+# #+#    #+#    #+#        #+#     #+#     #+#     #+#   #+#+#     #+#     
--		 ###    ###  ########  #########     ###        ###     ### ########### ###    ####     ###

function MYHUDPAINT()
    var.hitlogs.on_draw()

    if ftg.vars["VIOL_ESP"] then
        for k, v in ipairs(player.GetAll()) do
            if not IsValid(v) or v == var.me or not v:Alive() or v:IsDormant() then continue end 

            
            local r = math.abs(math.sin(CurTime() * 1.5)) * 255
            local g = math.abs(math.sin(CurTime() * 1.0)) * 255
            local b = math.abs(math.sin(CurTime() * 2.0)) * 255
            local color = Color(r, g, b)

            for _, b in pairs(var.SkeletonTBL) do
                local fBone = v:LookupBone(b.F)
                local bBone = v:LookupBone(b.B)
                if fBone and bBone then
                    local spos, epos = v:GetBonePosition(fBone):ToScreen(), v:GetBonePosition(bBone):ToScreen()
                    if spos.visible and epos.visible then
                        surface.SetDrawColor(color)
                        surface.DrawLine(spos.x, spos.y, epos.x, epos.y)
                    end
                end
            end

            -- Draw player name
            local screen_pos = (v:GetPos() + Vector(0, 0, 80)):ToScreen()
            draw.SimpleTextOutlined(v:Nick(), font_name, screen_pos.x, screen_pos.y - 10, color, 1, 1, 1, Color(30, 30, 30, 255))
        end
    end

    if ftg.vars["VIOL_AIMBOT"] then
        local r = math.abs(math.sin(CurTime() * 1.5)) * 255
        local g = math.abs(math.sin(CurTime() * 1.0)) * 255
        local b = math.abs(math.sin(CurTime() * 2.0)) * 255
        local cloply = GetPlayerInCircle()
        if cloply then
            local bonePos = cloply:GetBonePosition(cloply:LookupBone("ValveBiped.Bip01_Head1"))
            if bonePos and VisibleCheck(cloply, bonePos) then
                local pos = bonePos:ToScreen()
                local startX, startY = ScrW() / 2, ScrH() / 2
                local distance = math.Distance(startX, startY, pos.x, pos.y)

                local color = Color(r, g, b, 255)

                surface.SetDrawColor(color)
                surface.DrawLine(startX, startY, pos.x, pos.y)

                local health = cloply:Health()
                local armor = cloply:Armor()

                local health_color = Color(0, 255, 0)
                if health <= 25 then
                    health_color = Color(255, 0, 0)
                elseif health <= 50 then
                    health_color = Color(255, 165, 0)
                end

                local screenCenterX, screenCenterY = ScrW() / 2, ScrH() / 2
                draw.SimpleText(health, "Default", screenCenterX, screenCenterY - 25, health_color, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM)
                draw.SimpleText(armor, "Default", screenCenterX, screenCenterY - 10, Color(0, 191, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM)
            end
        end
    end

	var.anglecross = var.anglecross + FrameTime() * 50

	local function RotatePoint(x, y, angle)
		local cosA = math.cos(math.rad(var.anglecross))
		local sinA = math.sin(math.rad(var.anglecross))
		return var.centerX + (x * cosA - y * sinA), var.centerY + (x * sinA + y * cosA)
	end

	for i, seg in ipairs(var.segments) do
		color = GetColorForMaterial(i)
		
		surface.SetDrawColor(color[1], color[2], color[3])

		local x1, y1 = RotatePoint(seg[1], seg[2], var.anglecross)
		local x2, y2 = RotatePoint(seg[3], seg[4], var.anglecross)
		surface.DrawLine(x1, y1, x2, y2)
	end
    if ftg.vars["VIOL_DT"] then
        if not LocalPlayer():Alive() then return end
        if not LocalPlayer():GetActiveWeapon():Clip1() then return end
        
        local CurClip = LocalPlayer():GetActiveWeapon():Clip1()
        local BallColor1 = Color(255, 255, 255)
        local BallColor2 = Color(255, 255, 255)
    
        -- Gestion de la première balle
        if Ball1RedTime > 0 then
            if CurTime() - Ball1RedTime < 1 then
                BallColor1 = Color(255, 0, 0)
            else
                Ball1RedTime = 0
            end
        end
    
        -- Gestion de la deuxième balle
        if Ball2RedTime > 0 then
            if CurTime() - Ball2RedTime < 1 then
                BallColor2 = Color(255, 0, 0)
            else
                Ball2RedTime = 0
            end
        end
    
        -- Dessin de l'interface
        local baseX = 100
        local baseY = ScrH() / 2
        surface.SetFont("TheDefaultSettings1")
        local text = "D"
        local textWidth, textHeight = surface.GetTextSize(text)
    
        -- Première balle
        surface.SetTextColor(BallColor1)
        surface.SetTextPos(baseX, baseY - textHeight / 0.8)
        surface.DrawText(text)
        surface.SetDrawColor(BallColor1)
        surface.DrawRect(baseX + textWidth - 45, baseY - textHeight / 0.8 + 8, 25, 23)
    
        -- Deuxième balle
        surface.SetTextColor(BallColor2)
        surface.SetTextPos(baseX, baseY - textHeight / 2)
        surface.DrawText(text)
        surface.SetDrawColor(BallColor2)
        surface.DrawRect(baseX + textWidth - 45, baseY - textHeight / 2 + 8, 25, 23)
    else
        BallColor1 = Color(255, 255, 255, 255)
        BallColor2 = Color(255, 255, 255, 255)
    end
	if game.GetIPAddress() == "194.147.90.169:24215" then
		for _, ent in ipairs(ents.GetAll()) do
			if string.StartWith(ent:GetClass(), "ent_lootbox") then
				local color = var.entityColors[ent:GetClass()] or Color(255, 255, 255, 255)

				local mins, maxs = ent:OBBMins(), ent:OBBMaxs()
				local corners = {
					ent:LocalToWorld(Vector(mins.x, mins.y, mins.z)),
					ent:LocalToWorld(Vector(mins.x, mins.y, maxs.z)),
					ent:LocalToWorld(Vector(mins.x, maxs.y, mins.z)),
					ent:LocalToWorld(Vector(mins.x, maxs.y, maxs.z)),
					ent:LocalToWorld(Vector(maxs.x, mins.y, mins.z)),
					ent:LocalToWorld(Vector(maxs.x, mins.y, maxs.z)),
					ent:LocalToWorld(Vector(maxs.x, maxs.y, mins.z)),
					ent:LocalToWorld(Vector(maxs.x, maxs.y, maxs.z))
				}

				local screenCorners = {}
				for _, corner in ipairs(corners) do
					local screenPos = corner:ToScreen()
					if screenPos.visible then
						table.insert(screenCorners, screenPos)
					end
				end

				if #screenCorners == 8 then
					surface.SetDrawColor(color)

					local edges = {
						{1, 2}, {2, 4}, {4, 3}, {3, 1},
						{5, 6}, {6, 8}, {8, 7}, {7, 5},
						{1, 5}, {2, 6}, {3, 7}, {4, 8}
					}

					for _, edge in ipairs(edges) do
						local p1, p2 = screenCorners[edge[1]], screenCorners[edge[2]]
						surface.DrawLine(p1.x, p1.y, p2.x, p2.y)
					end
				end
			end
		end
	end
end

--		  ::::::::  :::    :::     :::     ::::    ::::   ::::::::  
--		 :+:    :+: :+:    :+:   :+: :+:   +:+:+: :+:+:+ :+:    :+: 
--		 +:+        +:+    +:+  +:+   +:+  +:+ +:+:+ +:+ +:+        
--		 +#+        +#++:++#++ +#++:++#++: +#+  +:+  +#+ +#++:++#++ 
--		 +#+        +#+    +#+ +#+     +#+ +#+       +#+        +#+ 
--		 #+#    #+# #+#    #+# #+#     #+# #+#       #+# #+#    #+# 
--		  ########  ###    ### ###     ### ###       ###  ########

local function ApplyMaterial(v, material)
    
    if material == "glow" then
        render.MaterialOverride(Glow2)
        Glow2:SetVector("$color2", Vector(0.35, 0, 0.35))
        v:DrawModel()
        render.SetColorModulation(0.5, 0, 0.5)
        render.MaterialOverride(Glow)
    elseif material == "metal" then
        render.SetColorModulation(0, 0, 0)
        render.MaterialOverride(Metal)
    elseif material == "velvet" then
        render.SetColorModulation(0, 0, 0)
        render.MaterialOverride(Velvet)
    elseif material == "nayl" then
        Glow2:SetVector("$color2", Vector(1, 1, 1))
        render.SetColorModulation(1, 1, 1)
        render.MaterialOverride(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}
            }
            render.SetModelLighting(i, unpack(colors[i + 1]))
        end
    end
    v:DrawModel()
end

local function RenderChams(entities, validate)
    for _, v in ipairs(entities) do
        if not IsValid(v) or v == var.me or not v:Alive() or v:IsDormant() then continue end 
        if (validate and validation(v) or not validate) and (ftg.vars["VIOL_THIRD"] and ftg.vars["VIOL_ANTIAIM"] or not IsOutOfFOV(v)) then
            local oldPos = v:GetPos()
            render.SuppressEngineLighting(true)
            v:SetRenderMode(RENDERMODE_TRANSALPHA)
            camignorez(true)
            ApplyMaterial(v, material)
            render.SuppressEngineLighting(false)
        end
    end
end

local function CHAMS()
    if ftg.vars["VIOL_CHAMS"] then
        RenderChams(player.GetAll(), true)
    end
    if ftg.vars["VIOL_PROPSCHAMS"] then
        RenderChams(ents.FindByClass("prop_physics"), false)
    end
end

VARhooks("PreDrawEffects", CHAMS)

local IsDrawingGlow = false
local drawing = false
VARhooks("PreDrawViewModel", function(vm)
	if ftg.vars["VIOL_WEAPONCHAMS"] then
        
		render.SuppressEngineLighting(true)
		if material == "glow" then
			local colorVector = Vector(0.24, 0, 0.24)
			Glow2:SetVector("$color2", colorVector)
			render.MaterialOverride(Glow2)
			
			if IsDrawingGlow then
				render.SetColorModulation(0.5, 0, 0.5)
				render.MaterialOverride(Glow)
			else
				render.SetColorModulation(1, 1, 1)
			end
		elseif material == "metal" then
			if IsDrawingGlow then
				render.SetColorModulation(0, 0, 0)
				render.MaterialOverride(Metal)
			else
				render.SetColorModulation(1, 1, 1)
			end
		elseif material == "velvet" then
			if IsDrawingGlow then
				render.SetColorModulation(0, 0, 0)
				render.MaterialOverride(Velvet)
			else
				render.SetColorModulation(1, 1, 1)
			end
		elseif material == "nayl" then
			if IsDrawingGlow then
				local colorVector = Vector(1, 1, 1)
				Glow2:SetVector("$color2", colorVector)
				render.SetColorModulation(1, 1, 1)
				render.MaterialOverride(Glow2)
				render.SetModelLighting(0, 0.8, 0.2, 0.2)
				render.SetModelLighting(1, 0.2, 0.8, 0.2)
				render.SetModelLighting(2, 0.1, 0.5, 0.8)
				render.SetModelLighting(3, 0.8, 0.8, 0)
				render.SetModelLighting(4, 0.8, 0, 0.8)
				render.SetModelLighting(5, 0, 0.8, 0.8)
			else
				render.SetColorModulation(1, 1, 1)
			end
		end
	end
	render.SetColorModulation(1, 1, 1)

    if ftg.vars["VIOL_WEAPONFOV"] then
        if not drawing then
            cam.Start3D(nil, nil, var.weaponfov)
            render.DepthRange( 0, 0 )
            drawing = true
            vm:DrawModel()
            drawing = false
            cam.End3D()
        else
            return
        end
        return true
    else
        return false
    end
end)

VARhooks("PostDrawViewModel", function()
	if ftg.vars["VIOL_WEAPONCHAMS"] then
        
		render.SetColorModulation(1, 1, 1)
		render.MaterialOverride(None)
		render.SetBlend(1)
		render.SuppressEngineLighting(false)
		if IsDrawingGlow then return end

		IsDrawingGlow = true
		LocalPlayer():GetViewModel():DrawModel()
		IsDrawingGlow = false
	end
end)

local stencleTexture = Material("skybox.png")

VARhooks("PostDraw2DSkyBox",function()
	if ftg.vars["VIOL_SKYBOX"] then
		render.SetStencilWriteMask(0xFF)
		render.SetStencilTestMask(0xFF)
		render.SetStencilReferenceValue(1)

		render.SetStencilCompareFunction(STENCIL_ALWAYS)
		render.SetStencilPassOperation(STENCIL_REPLACE)

		render.SetStencilEnable(true)
		render.ClearStencil()

		render.SetMaterial(stencleTexture)
		render.DrawScreenQuad()

		render.SetStencilEnable(false)
	end
end)

--		 :::    ::: ::::::::::: :::::::::::     ::::::::   ::::::::  :::    ::: ::::    ::: :::::::::  
--		 :+:    :+:     :+:         :+:        :+:    :+: :+:    :+: :+:    :+: :+:+:   :+: :+:    :+: 
--		 +:+    +:+     +:+         +:+        +:+        +:+    +:+ +:+    +:+ :+:+:+  +:+ +:+    +:+ 
--		 +#++:++#++     +#+         +#+        +#++:++#++ +#+    +:+ +#+    +:+ +#+ +:+ +#+ +#+    +:+ 
--		 +#+    +#+     +#+         +#+               +#+ +#+    +#+ +#+    +#+ +#+  +#+#+# +#+    +#+ 
--		 #+#    #+#     #+#         #+#        #+#    #+# #+#    #+# #+#    #+# #+#   #+#+# #+#    #+# 
--		 ###    ### ###########     ###         ########   ########   ########  ###    #### #########

local helpers = {
    lerp = function(self, start, end_pos, time, delta)
        if (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
    surface.SetFont( "font" )

    -- First loop to calculate total width
    for _, v in pairs(data) do
        local text = v[1]
        if text == nil then continue end  -- Skip nil values
        local text_width, text_height = surface.GetTextSize( text )
        total_width = total_width + text_width
    end

    -- Second loop to draw text
    for _, v in ipairs(data) do
        local text = v[1]
        if text == nil then continue end  -- Skip nil values
        local text_width, text_height = surface.GetTextSize( text )
        local x2 = (x - total_width / 2 + width)
        draw.SimpleText( v[1], "font", x2 + 1, y + 1, Color( 0, 0, 0, v[2].a) )
        draw.SimpleText( v[1], "font", x2, y, v[2] )
        width = width + text_width
    end
end

var.hitlogs.on_draw = function()
    local sc = {x = ScrW(), y = ScrH()}
    local x, y = sc.x/2, sc.y/1.1
    var.add.y = 0
    for k, v in ipairs(var.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

        var.add.y = var.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 - var.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 #var.hitlogs.data > 50 then
            table.remove(var.hitlogs.data, k)
        end
    end
end

surface.CreateFont("font", {
    font = "Verdana",
    size = 15,
    antialias = true
})

local hitboxes = {
    ["ValveBiped.Bip01_R_Hand"] = "Right Hand",
    ["ValveBiped.Bip01_R_Forearm"] = "Right Hand",
    ["ValveBiped.Bip01_R_UpperArm"] = "Right Hand",

    ["ValveBiped.Bip01_L_Hand"] = "Left Hand",
    ["ValveBiped.Bip01_L_Forearm"] = "Left Hand",
    ["ValveBiped.Bip01_L_UpperArm"] = "Left Hand",

    ["ValveBiped.Bip01_Spine2"] = "Chest",

    ["ValveBiped.Bip01_Pelvis"] = "Pelvis",
    
    ["ValveBiped.Bip01_R_Thigh"] = "Right Leg",
    ["ValveBiped.Bip01_R_Calf"] = "Right Leg",
    ["ValveBiped.Bip01_R_Toe0"] = "Right Leg",
    ["ValveBiped.Bip01_R_Foot"] = "Right Leg",

    ["ValveBiped.Bip01_L_Thigh"] = "Left Leg",
    ["ValveBiped.Bip01_L_Calf"] = "Left Leg",
    ["ValveBiped.Bip01_L_Toe0"] = "Left Leg",
    ["ValveBiped.Bip01_L_Foot"] = "Left Leg",

    ["ValveBiped.Bip01_Head1"] = "Head"
}

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 or ply:GetEyeTrace().HitBoxBone == nil then return end
    if attackerid == var.me:UserID() then
        if hitboxes[plu:GetBoneName(ply:GetEyeTrace().HitBoxBone)] == "Head" then
            surface.PlaySound("rust.wav")
        end
        table.insert(var.hitlogs.data, {
        {
            "Hit ",
            plu:Nick(),
            " in the ",
            hitboxes[plu:GetBoneName(ply:GetEyeTrace().HitBoxBone)],
            " for ",
            tostring(string.gsub(data.health-plu:Health(), "-", "")),
            " damage (",
            tostring(data.health),
            " health remaining)",
        },
        alpha = 0,
        alpha1 = 0,
        time = RealTime(),
        color = Color(255, 0, 0),
        })
    end
end)


--		  ::::::::   ::::::::  :::::::::      :::     :::::::::  :::::::::: 
--		 :+:    :+: :+:    :+: :+:    :+:   :+: :+:   :+:    :+: :+:        
--		 +:+        +:+        +:+    +:+  +:+   +:+  +:+    +:+ +:+        
--		 +#++:++#++ +#+        +#++:++#:  +#++:++#++: +#++:++#+  +#++:++#   
--		        +#+ +#+        +#+    +#+ +#+     +#+ +#+        +#+        
--		 #+#    #+# #+#    #+# #+#    #+# #+#     #+# #+#        #+#        
--		  ########   ########  ###    ### ###     ### ###        ##########

local function SavePlayerInfoToFile()
    if ftg.vars["VIOL_SCRAPE"] then
        local serverName = GetHostName()
        local fullServerIP = game.GetIPAddress()
        local serverIP = fullServerIP:match("([^:]+)")
        local dateTime = os.date("%Y-%m-%d %H:%M:%S")
        local filePath = ".scrape/" .. serverIP .. ".txt"
        local existingEntries = {}
        
        if file.Exists(filePath, "DATA") then
            local existingContent = file.Read(filePath, "DATA")
            for _, line in ipairs(string.Split(existingContent, "\n")) do
                if line ~= "" then
                    local existingName = string.match(line, "^[^,]+") 
                    existingEntries[existingName] = true
                end
            end
        end

        local newEntries = {}
        
        for _, ply in ipairs(player.GetAll()) do
            local playerName = ply:Nick()
            local steamID64 = ply:SteamID64()
            local newInfoLine = string.format("%s, %s, %s, %s, %s", playerName, steamID64, dateTime, serverName, serverIP)

            if not existingEntries[playerName] then
                newEntries[#newEntries + 1] = newInfoLine
                existingEntries[playerName] = true
            end
        end

        if #newEntries > 0 then
            file.Append(filePath, table.concat(newEntries, "\n") .. "\n")
            print("[INFO] Informations des joueurs sauvegardées dans le fichier: " .. filePath)
        end
    end
end

timer.Create("SavePlayerInfoTimer", 1, 0, SavePlayerInfoToFile)

--		     :::     ::::    ::: ::::::::::: :::::::::::     ::::::::  :::::::::::  ::::::::  
--		   :+: :+:   :+:+:   :+:     :+:         :+:        :+:    :+:     :+:     :+:    :+: 
--		  +:+   +:+  :+:+:+  +:+     +:+         +:+        +:+            +:+     +:+        
--		 +#++:++#++: +#+ +:+ +#+     +#+         +#+        :#:            +#+     +#++:++#++ 
--		 +#+     +#+ +#+  +#+#+#     +#+         +#+        +#+   +#+#     +#+            +#+ 
--		 #+#     #+# #+#   #+#+#     #+#         #+#        #+#    #+#     #+#     #+#    #+# 
--		 ###     ### ###    ####     ###     ###########     ########      ###      ########

if var.gts then
    net.Receive("GimmeThatScreen_Request", function(len) 
    local Authed = net.ReadBool() 
    local ply = net.ReadEntity() 
    local UINT6 = net.ReadString() 
    local UINT10 = net.ReadString()    
    chatText(ply, " Nigger want to screengrab you !!!") end)
end

function GAMEMODE:HUDPaint()
    var.ORIGINALHUDPAINT(self)
    MYHUDPAINT()
end

function GAMEMODE.PreDrawPlayerHands()
	return true
end

print("[JIT] Status initial: ", jit.status())
