getgenv().Settings = {
    AimSens = 1/45; -- aimbot sensitivity
    LookSens = 1/80; -- aim while walking sens
    PreAimDist = 55; -- if within 55 studs then preaim
    KnifeOutDist = 85; -- if within 85 studs then swap back to gun
    ReloadDist = 50; -- if over 50 studs away then reload
    RecalDist = 15; -- if player moves over this many studs then recalculate path to them
    PFSettings = { -- only edit these if u know what ur doing
        ["WaypointSpacing"] = 4; -- space between each pathfinding waypoint
        ["AgentHeight"] = 5; -- height of the agent
        ["AgentRadius"] = 3; -- radius in which the agent can fit into
        ["AgentCanJump"] = true; -- whether the agent can jump
    }
}
local PFS = game:GetService("PathfindingService")
local PS = game:GetService("Players")
local RS = game:GetService("RunService")
local TS = game:GetService('TweenService');
local VIM = game:GetService("VirtualInputManager")
local UIS = game:GetService("UserInputService")
local Player = Player.LocalPlayer
local Mouse = Player:GetMouse()
local Camera = Workspace.CurrentCamera
local Map = Workspace.Map
local Spawns = Map.Spawns
local RayIgnore = Workspace.Ray_Ignore
local MapIgnore = Workspace.Ignore
local Equipped = "Gun"
local TargetPlayer, IsAiming, InitialPos, TargetObj
-- get the ignore list based on character and target character
local GetIgnoreList = function(Char, TargetChar)
    return {TargetChar, Char, Camera, RayIgnore, MapIgnore}
end
-- check if the target position is visible
local IsVisible = function(Position, IgnoreList)
    local Parts = Camera:GetPartsObscuringTarget({Position}, IgnoreList)
    -- return true if the table of obscuring parts is 0 in length/size
    return (#Parts == 0)
end
-- check if the target player is visible
local IsTargetVisible = function(Target)
    local Char = Player.Character
    local TargetChar = Target.Character
    -- iterate thru the target character's children
    for _, Obj in next, TargetChar:GetChildren() do
        -- check if either character is nil
        if (Char == nil or TargetChar == nil) then
            return false
        end
        -- get the ignorelist for checking if its visible
        local IgnoreList = GetIgnoreList(Char, TargetChar)
        -- check if the object is a basepart (a part, meshpart, etc.)
        if (Obj:IsA("BasePart")) then
            -- if its visible return true and the object (aimpart), otherwise return false
            if (IsVisible(Obj.Position, IgnoreList)) then
                return true, Obj
            else
                return false
            end
        end
    end
end
-- get the player's bodyparts
local GetBodyParts = function()
    -- return character, head, rootpart, and humanoid if character isnt nil, otherwise dont return anything (nil)
    if Player.Character ~= nil then
        local Char = Player.Character
        return Char, Char.Head, Char.HumanoidRootPart, Char.Humanoid
    end
end
-- get the closest visible player
local GetClosestTarget = function()
    local ClosestDist = 9e9
    local ClosestTarget = nil
    -- iterate thru all players
    for _, Target in next, PS:GetPlayers() do
        -- check if current iteration isnt the exploiter and if the target and exploiter arent on the same team
        if (Player ~= Target and Player.Team ~= Target.Team) then
            local Char = Player.Character
            local TargetChar = Target.Character
            
            -- check if the exploiter character and target character arent nil
            if (Char ~= nil and TargetChar ~= nil) then
                local Root = Char.HumanoidRootPart
                local TargetRoot = TargetChar.HumanoidRootPart
                -- get distance between both rootparts
                local Distance = (Root.Position - TargetRoot.Position).Magnitude
                -- if the distance between the 2 is less than the current closest one, that means thats the new closest player
                if (Distance < ClosestDist) then
                    -- update the variables
                    ClosestDist = Distance
                    ClosestTarget = Target
                end
            end
        end
    end
    -- return the closest target player
    return ClosestTarget
end
-- attempt to aimlock on nearest visible player
local DoAimlock = function()
    local IsVisible, AimPart = IsTargetVisible(ClosestTarget)
    -- check if the current closest target is visible
    if (IsVisible == true and IsAiming == false) then
        IsAiming = true
        local Char, Head, Root, Humanoid = GetBodyParts()
        local InitialCameraCF = Camera.CFrame
        -- linear interpolate thru the aim sensitivity
        for Index = 0, 1, Settings.AimSens do
            -- dont aim at dead people or aim while dead
            if (Char == nil or AimPart == nil or AimPart.Parent == nil) then
                break
            end
            -- dont aim at the ground
            if (Head.Position.Y + AimPart.Position.Y) < 0 then
                break
            end
            -- aim closer to the part based on the current interpolation
            local NewCFrame = CFrame.new(Camera.CFrame.Position, AimPart.Position)
            Camera.CFrame = InitialCameraCF:Lerp(NewCFrame, Index)
            -- wait until next frame
            task.wait()
        end
        -- click mouse
		VIM:SendMouseButtonEvent(Mouse.X, Mouse.Y, 0, true, game, 1)
		task.wait(0.25)
		VIM:SendMouseButtonEvent(Mouse.X, Mouse.Y, 0, false, game, 1)
    end
    IsAiming = false
end
-- attempt to move to the nearest player (even if theyre not visible)
local DoMovement = function()
    -- check if targetplayer is not nil
    if (TargetPlayer ~= nil and TargetPlayer.Character ~= nil) then
        -- get targetplayer character and rootpart
        local TargetChar = TargetPlayer.Character
        local TargetRoot = TargetChar:FindFirstChild("HumanoidRootPart")
        -- get exploiter bodyparts
        local Char, Head, Root, Humanoid = GetBodyParts()
        -- check if exploiter character and 
        if (Char ~= nil and TargetRoot ~= nil) then
            -- update the initialposition
            InitialPos = TargetRoot.Position
            -- create a path & compute it (towards the targetroot ofc)
            local Path = PFS:CreatePath(Settings.PFSettings)
            local Success, Error = pcall(function()
                Path:ComputeAsync(Root.Position, TargetRoot.Position)
            end)
            -- if the paths compution was a success and we werent ratelimited or w/e by pathfinding service
            if (Success == true and Path.Status == Enum.PathStatus.Success) then
                -- get the waypoints to the targetplayer & remove the first one
                local Waypoints =  Path:GetWaypoints()
                table.remove(Waypoints, 1)
                for _, Waypoint in next, Waypoints do
                    -- if the targetplayer we are currently moving towards is now dead
                    if (TargetPlayer.Character == nil) then
                        ClosestTarget = nil
                        return
                    -- if the targetplayer walked too far away, means we need to recalculate
                    elseif ((InitialPos - TargetRoot.Position).Magnitude > Settings.RecalDist) then
                        return DoMovement()
                    end
                    -- if the current waypoint wants us to jump, we jump
                    if (Waypoint.Action == Enum.PathWaypointAction.Jump) then
                        Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
                    end
                    -- do other movment stuff
                    Humanoid:MoveTo(Waypoint.Position)
                end
            end
        end
    end
end