Further enhance, and add more anti-slap features that can make it block slaps consistently:

```
-- Enhanced Roblox Script with Advanced Anti-Slap Features, Slap Prediction, 360 Slap Detection, and Advanced Auto-Counters

-- Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local VirtualInputManager = game:GetService("VirtualInputManager")
local TweenService = game:GetService("TweenService")
local UserInputService = game:GetService("UserInputService")

-- Remotes
local LightsaberRemotes = ReplicatedStorage:WaitForChild("LightsaberRemotes")
local BlockRemote = LightsaberRemotes:WaitForChild("Block")
local UnblockRemote = LightsaberRemotes:WaitForChild("Unblock")

-- Settings
local Settings = {
    BlockDistance = 15,
    AutoCounterEnabled = true,
    AutoSlapDistance = 10,
    ReactionTimeThreshold = 0.15, -- Base reaction time in seconds
    BlockDuration = 0.3, -- Duration to block in seconds
    Cooldown = 1.0, -- Cooldown period between blocks in seconds
    SlapAnimations = {
        ["Slap"] = 12625891544,
        ["SlappedLegs"] = 12671715182,
        ["SlappedArms"] = 12625896358,
        ["RightSwing"] = 12625891545,
        ["LeftSwing"] = 12625891546,
        ["OverheadSwing"] = 12625891547,
        ["DoubleSlap"] = 12625891548
    },
    GUI = {
        BlockIndicatorSize = UDim2.new(0, 250, 0, 120),
        BlockIndicatorPosition = UDim2.new(0.5, -125, 0, 10),
        ToggleIndicatorSize = UDim2.new(0, 200, 0, 50),
        ToggleIndicatorPosition = UDim2.new(0.5, -100, 0, 140),
        IndicatorColors = {
            Enabled = Color3.fromRGB(0, 255, 0),
            Disabled = Color3.fromRGB(255, 0, 0)
        }
    },
    AdvancedFeatures = {
        SlapPredictionEnabled = true,
        CharacterRotationEnabled = true,
        AntiSlapEnabled = true,
        PredictionDecay = 0.3, -- Decay rate for prediction accuracy
    },
    Animations = {
        -- Add any additional animations here
    }
}

-- State Management
local blockingPlayers = {} -- Tracks blocking state per opponent
local isBlockingEnabled = true -- Toggle state
local predictions = {} -- Slap predictions for each opponent

-- GUI Setup for Visual Feedback
local function setupGUI()
    local screenGui = Instance.new("ScreenGui")
    screenGui.Name = "AdvancedAntiSlapIndicator"
    screenGui.ResetOnSpawn = false
    screenGui.Parent = Players.LocalPlayer:WaitForChild("PlayerGui")

    -- Block Indicator Frame
    local blockIndicator = Instance.new("Frame")
    blockIndicator.Size = Settings.GUI.BlockIndicatorSize
    blockIndicator.Position = Settings.GUI.BlockIndicatorPosition
    blockIndicator.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
    blockIndicator.BackgroundTransparency = 0.5
    blockIndicator.BorderSizePixel = 0
    blockIndicator.Visible = false
    blockIndicator.Parent = screenGui

    -- Block Text Label
    local blockText = Instance.new("TextLabel")
    blockText.Size = UDim2.new(1, 0, 1, 0)
    blockText.Position = UDim2.new(0, 0, 0, 0)
    blockText.BackgroundTransparency = 1
    blockText.Text = "Blocking System:\nEnabled\nAgainst: None"
    blockText.TextColor3 = Settings.GUI.IndicatorColors.Enabled
    blockText.TextScaled = true
    blockText.TextWrapped = true
    blockText.Parent = blockIndicator

    -- Directional Indicators
    local directions = {"Top", "Bottom", "Left", "Right", "TopLeft", "TopRight", "BottomLeft", "BottomRight"}
    local directionIndicators = {}
    for _, dir in ipairs(directions) do
        local indicator = Instance.new("Frame")
        indicator.Size = UDim2.new(0, 20, 0, 20)
        indicator.BackgroundColor3 = Color3.fromRGB(255, 0, 0)
        indicator.BackgroundTransparency = 0.7
        indicator.BorderSizePixel = 0
        indicator.Visible = false
        indicator.Name = dir .. "Indicator"
        indicator.Parent = blockIndicator

        -- Position indicators around the blockIndicator
        local posX, posY
        if dir == "Top" then
            posX, posY = 0.5, -25
        elseif dir == "Bottom" then
            posX, posY = 0.5, 100 + 5
        elseif dir == "Left" then
            posX, posY = -25, 0.5
        elseif dir == "Right" then
            posX, posY = 250 + 5, 0.5
        elseif dir == "TopLeft" then
            posX, posY = -15, -15
        elseif dir == "TopRight" then
            posX, posY = 250 - 5, -15
        elseif dir == "BottomLeft" then
            posX, posY = -15, 100 - 5
        elseif dir == "BottomRight" then
            posX, posY = 250 - 5, 100 - 5
        end
        indicator.Position = UDim2.new(posX, 0, posY < 0 and 0 or (posY > 0 and 1 or 0.5), posY < 0 and posY or (posY > 0 and posY) or -10)
        directionIndicators[dir] = indicator
    end

    -- Toggle Indicator Frame
    local toggleIndicator = Instance.new("Frame")
    toggleIndicator.Size = Settings.GUI.ToggleIndicatorSize
    toggleIndicator.Position = Settings.GUI.ToggleIndicatorPosition
    toggleIndicator.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
    toggleIndicator.BackgroundTransparency = 0.5
    toggleIndicator.BorderSizePixel = 0
    toggleIndicator.Visible = false
    toggleIndicator.Parent = screenGui

    -- Toggle Text Label
    local toggleText = Instance.new("TextLabel")
    toggleText.Size = UDim2.new(1, 0, 1, 0)
    toggleText.Position = UDim2.new(0, 0, 0, 0)
    toggleText.BackgroundTransparency = 1
    toggleText.Text = "Blocking System Disabled"
    toggleText.TextColor3 = Settings.GUI.IndicatorColors.Disabled
    toggleText.TextScaled = true
    toggleText.TextWrapped = true
    toggleText.Parent = toggleIndicator

    return blockIndicator, blockText, toggleIndicator, toggleText, directionIndicators
end

local blockIndicator, blockText, toggleIndicator, toggleText, directionIndicators = setupGUI()

-- Tween for Smooth Appearance/Disappearance
local tweenInfoVisible = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
local tweenInfoHidden = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.In)

local showTweenBlock = TweenService:Create(blockIndicator, tweenInfoVisible, {BackgroundTransparency = 0.3, Visible = true})
local hideTweenBlock = TweenService:Create(blockIndicator, tweenInfoHidden, {BackgroundTransparency = 0.5, Visible = false})

local showTweenToggle = TweenService:Create(toggleIndicator, tweenInfoVisible, {BackgroundTransparency = 0.3, Visible = true})
local hideTweenToggle = TweenService:Create(toggleIndicator, tweenInfoHidden, {BackgroundTransparency = 0.5, Visible = false})

-- Utility Function to Get Current Time
local function getCurrentTime()
    return tick()
end

-- Function to Get Closest Players within BlockDistance
local function getClosestPlayers()
    local players = {}
    local localPlayer = Players.LocalPlayer
    local localCharacter = localPlayer.Character

    if localCharacter and localCharacter:FindFirstChild("HumanoidRootPart") then
        local localPosition = localCharacter.HumanoidRootPart.Position

        for _, player in ipairs(Players:GetPlayers()) do
            if player ~= localPlayer and player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
                local playerPosition = player.Character.HumanoidRootPart.Position
                local distance = (playerPosition - localPosition).Magnitude

                if distance <= Settings.BlockDistance then
                    table.insert(players, {Player = player, Distance = distance})
                end
            end
        end
    end

    table.sort(players, function(a, b) return a.Distance < b.Distance end)
    return players
end

-- Function to Determine Direction from LocalPlayer to Opponent
local function getDirection(localPos, opponentPos)
    local directionVector = (opponentPos - localPos).Unit
    local angle = math.deg(math.atan2(directionVector.Z, directionVector.X)) -- Y is up

    -- Determine direction based on angle
    if angle >= -22.5 and angle < 22.5 then
        return "Right"
    elseif angle >= 22.5 and angle < 67.5 then
        return "TopRight"
    elseif angle >= 67.5 and angle < 112.5 then
        return "Top"
    elseif angle >= 112.5 and angle < 157.5 then
        return "TopLeft"
    elseif (angle >= 157.5 and angle <= 180) or (angle >= -180 and angle < -157.5) then
        return "Left"
    elseif angle >= -157.5 and angle < -112.5 then
        return "BottomLeft"
    elseif angle >= -112.5 and angle < -67.5 then
        return "Bottom"
    elseif angle >= -67.5 and angle < -22.5 then
        return "BottomRight"
    end
end

-- Function to Update GUI Indicators based on Blocking State and Directions
local function updateGUI()
    local blockingNames = {}
    for opponentName, info in pairs(blockingPlayers) do
        blockingNames[#blockingNames + 1] = opponentName
        -- Show directional indicator
        if directionIndicators[info.Direction] then
            directionIndicators[info.Direction].Visible = true
        end
    end

    if isBlockingEnabled and #blockingNames > 0 then
        blockIndicator.Visible = true
        blockText.Text = "Blocking System:\nEnabled\nAgainst:\n" .. table.concat(blockingNames, ", ")
        blockText.TextColor3 = Settings.GUI.IndicatorColors.Enabled
    else
        blockIndicator.Visible = false
        blockText.Text = "Blocking System:\nEnabled\nAgainst:\nNone"
        blockText.TextColor3 = Settings.GUI.IndicatorColors.Enabled
    end
end

-- Function to Clear Directional Indicators
local function clearDirectionalIndicators()
    for _, indicator in pairs(directionIndicators) do
        indicator.Visible = false
    end
end

-- Function to Toggle Blocking System
local function toggleBlockingSystem()
    isBlockingEnabled = not isBlockingEnabled
    if isBlockingEnabled then
        -- Enable Blocking System
        hideTweenToggle:Play()
        toggleIndicator.Visible = false
        print("Blocking System Enabled")
    else
        -- Disable Blocking System
        showTweenToggle:Play()
        toggleIndicator.Visible = true
        blockingPlayers = {} -- Clear any existing blocking states
        UnblockRemote:FireServer()
        print("Blocking System Disabled")
        clearDirectionalIndicators()
    end
    updateGUI()
end

-- Key Binding for Toggle (R Key)
UserInputService.InputBegan:Connect(function(input, gameProcessed)
    if gameProcessed then return end
    if input.KeyCode == Enum.KeyCode.R then
        toggleBlockingSystem()
    end
end)

-- Function to Rotate Character Towards Direction
local function rotateCharacter(direction)
    local character = Players.LocalPlayer.Character
    if character and character:FindFirstChild("HumanoidRootPart") then
        local humanoid = character:FindFirstChildOfClass("Humanoid")
        if humanoid then
            local orientation
            if direction == "Top" then
                orientation = Vector3.new(0, 0, 0)
            elseif direction == "TopRight" then
                orientation = Vector3.new(0, 45, 0)
            elseif direction == "Right" then
                orientation = Vector3.new(0, 90, 0)
            elseif direction == "BottomRight" then
                orientation = Vector3.new(0, 135, 0)
            elseif direction == "Bottom" then
                orientation = Vector3.new(0, 180, 0)
            elseif direction == "BottomLeft" then
                orientation = Vector3.new(0, -135, 0)
            elseif direction == "Left" then
                orientation = Vector3.new(0, -90, 0)
            elseif direction == "TopLeft" then
                orientation = Vector3.new(0, -45, 0)
            else
                orientation = Vector3.new(0, 0, 0)
            end
            humanoid.RootPart.CFrame = CFrame.new(humanoid.RootPart.Position) * CFrame.Angles(math.rad(orientation.X), math.rad(orientation.Y), math.rad(orientation.Z))
        end
    end
end

-- Function to Predict Incoming Slap
local function predictSlap(opponent)
    if not Settings.AdvancedFeatures.SlapPredictionEnabled then return end
    -- Simple prediction based on recent movement and animation
    local lastPos = opponent.Character and opponent.Character:FindFirstChild("HumanoidRootPart") and opponent.Character.HumanoidRootPart.Position
    if not lastPos then return end
    predictions[opponent.Name] = {LastPosition = lastPos, Time = getCurrentTime()}
end

-- Function to Handle Anti-Slap
local function handleAntiSlap(opponent, direction)
    if not Settings.AdvancedFeatures.AntiSlapEnabled then return end
    -- Implement logic to reduce or negate the slap impact
    -- This can be customized based on game mechanics
    -- For demonstration, we'll simply print a message
    print("Anti-Slap activated against:", opponent.Name, "from direction:", direction)
    -- Example: Reduce health or apply resistance here
end

-- Function to Handle Slap Animation with Advanced Blocking Logic
local function handleSlapAnimation(opponent, animTrack)
    if not isBlockingEnabled then return end

    local localPlayer = Players.LocalPlayer
    local character = localPlayer.Character
    if not character or not character:FindFirstChild("HumanoidRootPart") then return end

    local opponentRoot = opponent.Character:FindFirstChild("HumanoidRootPart")
    if not opponentRoot then return end

    local localPos = character.HumanoidRootPart.Position
    local opponentPos = opponentRoot.Position
    local distance = (localPos - opponentPos).Magnitude

    if distance > Settings.BlockDistance then return end

    local currentTime = getCurrentTime()
    local lastBlockInfo = blockingPlayers[opponent.Name]
    local lastBlock = lastBlockInfo and lastBlockInfo.LastBlock or 0
    local timeSinceLastBlock = currentTime - lastBlock

    if timeSinceLastBlock < Settings.Cooldown then
        print("Block on cooldown for:", opponent.Name, "Time left:", string.format("%.2f", Settings.Cooldown - timeSinceLastBlock))
        return
    end

    -- Dynamic Reaction Time based on distance (closer opponents require faster reaction)
    local dynamicReactionTime = Settings.ReactionTimeThreshold * (Settings.BlockDistance / distance)
    dynamicReactionTime = math.clamp(dynamicReactionTime, 0.05, Settings.ReactionTimeThreshold)

    -- Determine if block should be initiated based on animation
    local shouldBlock = false
    local reactiveAnims = {"Slap", "RightSwing", "LeftSwing", "OverheadSwing", "DoubleSlap"}

    for _, animName in ipairs(reactiveAnims) do
        if animTrack.Animation and animTrack.Animation.AnimationId == "rbxassetid://" .. Settings.SlapAnimations[animName] then
            shouldBlock = true
            break
        end
    end

    if shouldBlock then
        local direction = getDirection(localPos, opponentPos)
        blockingPlayers[opponent.Name] = {
            LastBlock = currentTime,
            Direction = direction
        }
        BlockRemote:FireServer()
        print("Blocking initiated against:", opponent.Name, "from direction:", direction)

        updateGUI()

        -- Rotate Character to Face Slap Direction
        if Settings.AdvancedFeatures.CharacterRotationEnabled then
            rotateCharacter(direction)
        end

        -- Anti-Slap Activation
        handleAntiSlap(opponent, direction)

        -- Schedule Unblock
        task.delay(Settings.BlockDuration, function()
            blockingPlayers[opponent.Name] = nil
            UnblockRemote:FireServer()
            print("Blocking ended for:", opponent.Name)
            updateGUI()
        end)

        -- Auto Counter Slap if enabled and within AutoSlapDistance
        if Settings.AutoCounterEnabled and distance <= Settings.AutoSlapDistance then
            task.delay(dynamicReactionTime, function()
                VirtualInputManager:SendKeyEvent(true, Enum.KeyCode.E, false, game)
                task.wait(0.1)
                VirtualInputManager:SendKeyEvent(false, Enum.KeyCode.E, false, game)
                print("Automatic counter-slap performed against:", opponent.Name)
            end)
        end
    end
end

-- Monitor Opponent's Animations
local function onOpponentAnimationPlayed(opponent, animTrack)
    for animName, animId in pairs(Settings.SlapAnimations) do
        if animTrack.Animation and animTrack.Animation.AnimationId == "rbxassetid://" .. animId then
            print("Detected slap animation:", animName, "from:", opponent.Name)
            handleSlapAnimation(opponent, animTrack)
            -- Predict future slaps based on animation
            if Settings.AdvancedFeatures.SlapPredictionEnabled then
                predictSlap(opponent)
            end
            break
        end
    end
end

-- Setup Character Connections
local function onCharacterAdded(character, player)
    local humanoid = character:WaitForChild("Humanoid")
    humanoid.AnimationPlayed:Connect(function(animTrack)
        onOpponentAnimationPlayed(player, animTrack)
    end)
end

-- Setup Player Connections
local function setupPlayer(player)
    if player == Players.LocalPlayer then return end
    if player.Character then
        onCharacterAdded(player.Character, player)
    end
    player.CharacterAdded:Connect(function(character)
        onCharacterAdded(character, player)
    end)
end

-- Initialize Existing Players
for _, player in ipairs(Players:GetPlayers()) do
    setupPlayer(player)
end

-- Listen for New Players
Players.PlayerAdded:Connect(setupPlayer)

-- Listen for Player Removing
Players.PlayerRemoving:Connect(function(player)
    if blockingPlayers[player.Name] then
        blockingPlayers[player.Name] = nil
        updateGUI()
    end
    predictions[player.Name] = nil
end)

-- Initial GUI Update
updateGUI()

-- Periodically Clear Directional Indicators to Avoid Stale Indicators
RunService.RenderStepped:Connect(function()
    if not isBlockingEnabled then return end
    -- Hide all directional indicators if no active blocking
    if next(blockingPlayers) == nil then
        clearDirectionalIndicators()
    end

    -- Update Predictions (Optional: Enhance Prediction Accuracy)
    if Settings.AdvancedFeatures.SlapPredictionEnabled then
        for playerName, prediction in pairs(predictions) do
            if getCurrentTime() - prediction.Time > Settings.AdvancedFeatures.PredictionDecay then
                predictions[playerName] = nil
                -- Additional prediction handling can be implemented here
            end
        end
    end
end)

-- Function to Turn Character Towards Closest Slap
local function turnTowardsClosestSlap()
    if not Settings.AdvancedFeatures.CharacterRotationEnabled then return end
    local closestSlap = nil
    local shortestDistance = math.huge
    local localPlayer = Players.LocalPlayer
    local localCharacter = localPlayer.Character

    if localCharacter and localCharacter:FindFirstChild("HumanoidRootPart") then
        local localPosition = localCharacter.HumanoidRootPart.Position

        for _, info in pairs(blockingPlayers) do
            local distance = info.Distance or (info.LastBlock and (localPosition - (Players[info.PlayerName].Character and Players[info.PlayerName].Character.HumanoidRootPart.Position or localPosition)).Magnitude) or 0
            if distance < shortestDistance then
                closestSlap = info.Direction
                shortestDistance = distance
            end
        end

        if closestSlap then
            rotateCharacter(closestSlap)
        end
    end
end

-- Enhanced Logic to Turn Character Towards Closest Slap
RunService.Stepped:Connect(function()
    if isBlockingEnabled then
        turnTowardsClosestSlap()
    end
end)

-- Optional: Display Instructions in the Output
print("Advanced Dynamic Universal Slap Blocking System Initialized.")
print("Press 'R' to toggle the blocking system on and off.")
```

Reference Script:

```
local animIDs = {
    ["RightSwing"] = 12625839385,
    ["OverheadSwing"] = 12625841878,
    ["LeftSwing"] = 12625843823,
    ["BackLeftSwing"] = 12625846167,
    ["FrontRightSwing"] = 12625848489,
    ["BackRightSwing"] = 12625851115,
    ["FrontLeftSwing"] = 12625853257,
    ["RightBlock"] = 12625856098,
    ["LeftBlock"] = 12625858434,
    ["FrontLeftBlock"] = 12625860439,
    ["FrontRightBlock"] = 12625862519,
    ["FrontBlock"] = 12625864413,
    ["BackLeftBlock"] = 12625866538,
    ["BackRightBlock"] = 12625868684,
    ["Grab"] = 12625870437,
    ["Slap"] = 12625891544,
    ["SlappedLegs"] = 12671715182,
    ["SlappedArms"] = 12625896358,
    ["KickUp"] = 12625897944,
    ["KickBack"] = 12625899752,
    ["LeftRoll"] = 12625901874,
    ["RightRoll"] = 12625904322,
    ["Aerial"] = 12625908201,
    ["Idle"] = 13956175510,
    ["Throw"] = 12626569448,
    ["ForcePush"] = 12645928786,
    ["CrouchWalkRight"] = 12699256551,
    ["CrouchWalkLeft"] = 12699989478,
    ["CrouchWalkBack"] = 12699390244,
    ["CrouchWalkForward"] = 12699464592,
    ["FrontRoll"] = 12708915962,
    ["RightCrouchRoll"] = 12713661639,
    ["LeftCrouchRoll"] = 12713663289,
    ["Kata"] = 12735531097,
    ["Choking"] = 12814275189,
    ["Choke"] = 12815930160,
}

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local VirtualInputManager = game:GetService("VirtualInputManager")

local LightsaberRemotes = ReplicatedStorage:WaitForChild("LightsaberRemotes")
local BlockRemote = LightsaberRemotes:WaitForChild("Block")
local UnblockRemote = LightsaberRemotes:WaitForChild("Unblock")

local ESP_COLOR = Color3.new(1, 0, 0)
local OUTLINE_THICKNESS = 3

local Rayfield = loadstring(game:HttpGet('https://raw.githubusercontent.com/shlexware/Rayfield/main/source'))()

local Window = Rayfield:CreateWindow({
    Name = "Saber Showdown GUI",
    LoadingTitle = "Saber Showdown Auto Block",
    LoadingSubtitle = "Created By xenon9012",
})

local ESPTab = Window:CreateTab("ESP Settings", 4483362458)
local AutoBlockTab = Window:CreateTab("Auto Block", 4483362458)
local AutoCounterTab = Window:CreateTab("Auto Counter", 4483362458)
local creditsTab = Window:CreateTab("Credits", 4483362458)

local Section = ESPTab:CreateSection("ESP Config")

local espEnabled = true
local autoBlockEnabled = true
local autoCounterEnabled = true
local autoHalfSwingEnabled = true
local autoFastSwingEnabled = true
local espOutlineColor = Color3.new(1, 1, 1)
local espNameColor = Color3.new(1, 0, 0)
local espDistance = 100
local blockDistance = 20
local autoSlapDistance = 10
local rainbowESPEnabled = false
local highlightThickness = 0.5
local slapTimerEnabled = true
local slapTimerColor = Color3.new(0, 1, 0)
local autoHalfSwingDelay = 0.3
local autoFastSwingDelay = 0.15
local autoHalfSwingEnabled = false
local autoFastSwingEnabled = false
local autoHalfSwingDelay = 0.3
local autoFastSwingDelay = 0.15
local swingCooldown = 0.1 -- Cooldown between swings
local lastSwingTime = 0

local function updateESPColors()
    for _, player in ipairs(Players:GetPlayers()) do
        if player ~= Players.LocalPlayer and player.Character then
            local espObjects = player.Character:FindFirstChild("ESPObjects")
            if espObjects then
                local highlight = espObjects:FindFirstChild("Highlight")
                local nameESP = espObjects:FindFirstChild("NameESP")
                if highlight then
                    highlight.OutlineColor = espOutlineColor
                    highlight.OutlineTransparency = 1 - highlightThickness
                end
                if nameESP then
                    nameESP.Color = espNameColor
                end
            end
        end
    end
end

local Toggle = ESPTab:CreateToggle({
    Name = "Enable ESP",
    CurrentValue = espEnabled,
    Flag = "ESPToggle",
    Callback = function(Value)
        espEnabled = Value
    end,
})

local RainbowToggle = ESPTab:CreateToggle({
    Name = "Rainbow Outline ESP",
    CurrentValue = rainbowESPEnabled,
    Flag = "RainbowESPToggle",
    Callback = function(Value)
        rainbowESPEnabled = Value
    end,
})

local SlapTimerToggle = ESPTab:CreateToggle({
    Name = "Enable Slap Timer",
    CurrentValue = slapTimerEnabled,
    Flag = "SlapTimerToggle",
    Callback = function(Value)
        slapTimerEnabled = Value
    end,
})

local ColorPicker1 = ESPTab:CreateColorPicker({
    Name = "ESP Outline Color",
    Color = espOutlineColor,
    Flag = "ESPOutlineColor",
    Callback = function(Value)
        espOutlineColor = Value
        updateESPColors()
    end,
})

local ColorPicker2 = ESPTab:CreateColorPicker({
    Name = "ESP Name Color",
    Color = espNameColor,
    Flag = "ESPNameColor",
    Callback = function(Value)
        espNameColor = Value
        updateESPColors()
    end,
})

local Slider1 = ESPTab:CreateSlider({
    Name = "ESP Distance",
    Range = {0, 500},
    Increment = 10,
    Suffix = "studs",
    CurrentValue = espDistance,
    Flag = "ESPDistance",
    Callback = function(Value)
        espDistance = Value
    end,
})

local Slider3 = ESPTab:CreateSlider({
    Name = "Highlight Thickness",
    Range = {0, 1},
    Increment = 0.1,
    Suffix = "",
    CurrentValue = highlightThickness,
    Flag = "HighlightThickness",
    Callback = function(Value)
        highlightThickness = Value
        updateESPColors()
    end,
})

local SlapTimerColorPicker = ESPTab:CreateColorPicker({
    Name = "Slap Timer Color",
    Color = slapTimerColor,
    Flag = "SlapTimerColor",
    Callback = function(Value)
        slapTimerColor = Value
    end,
})

local Toggle2 = AutoBlockTab:CreateToggle({
    Name = "Enable Auto Block",
    CurrentValue = autoBlockEnabled,
    Flag = "AutoBlockToggle",
    Callback = function(Value)
        autoBlockEnabled = Value
    end,
})

local Slider2 = AutoBlockTab:CreateSlider({
    Name = "Block Distance",
    Range = {0, 100},
    Increment = 1,
    Suffix = "studs",
    CurrentValue = blockDistance,
    Flag = "BlockDistance",
    Callback = function(Value)
        blockDistance = Value
    end,
})

local AutoCounterToggle = AutoCounterTab:CreateToggle({
    Name = "Enable Auto Slap",
    CurrentValue = autoCounterEnabled,
    Flag = "AutoCounterToggle",
    Callback = function(Value)
        autoCounterEnabled = Value
    end,
})

local AutoHalfSwingToggle = AutoCounterTab:CreateToggle({
    Name = "Auto Half Swing",
    CurrentValue = autoHalfSwingEnabled,
    Flag = "AutoHalfSwingToggle",
    Callback = function(Value)
        autoHalfSwingEnabled = Value
    end,
})

local AutoHalfSwingSlider = AutoCounterTab:CreateSlider({
    Name = "Auto Half Swing Delay",
    Range = {0.1, 1},
    Increment = 0.05,
    Suffix = "secs",
    CurrentValue = autoHalfSwingDelay,
    Flag = "AutoHalfSwingDelay",
    Callback = function(Value)
        autoHalfSwingDelay = Value
    end,
})

local AutoFastSwingToggle = AutoCounterTab:CreateToggle({
    Name = "Auto Fast Swing",
    CurrentValue = autoFastSwingEnabled,
    Flag = "AutoFastSwingToggle",
    Callback = function(Value)
        autoFastSwingEnabled = Value
    end,
})

local AutoFastSwingSlider = AutoCounterTab:CreateSlider({
    Name = "Auto Fast Swing Delay",
    Range = {0.05, 0.5},
    Increment = 0.05,
    Suffix = "secs",
    CurrentValue = autoFastSwingDelay,
    Flag = "AutoFastSwingDelay",
    Callback = function(Value)
        autoFastSwingDelay = Value
    end,
})

local SwingCooldownSlider = AutoCounterTab:CreateSlider({
    Name = "Swing Cooldown",
    Range = {0, 0.5},
    Increment = 0.01,
    Suffix = "secs",
    CurrentValue = swingCooldown,
    Flag = "SwingCooldown",
    Callback = function(Value)
        swingCooldown = Value
    end,
})

local AutoSlapDistanceSlider = AutoCounterTab:CreateSlider({
    Name = "Auto Slap Distance",
    Range = {0, 50},
    Increment = 1,
    Suffix = "studs",
    CurrentValue = autoSlapDistance,
    Flag = "AutoSlapDistance",
    Callback = function(Value)
        autoSlapDistance = Value
    end,
})

local function createPlayerESP(player)
    local espFolder = Instance.new("Folder")
    espFolder.Name = "ESPObjects"
    espFolder.Parent = player.Character

    local highlight = Instance.new("Highlight")
    highlight.FillColor = Color3.new(1, 0, 0)
    highlight.OutlineColor = espOutlineColor
    highlight.FillTransparency = 1
    highlight.OutlineTransparency = 1 - highlightThickness
    highlight.Adornee = player.Character
    highlight.Parent = espFolder

    local nameESP = Drawing.new("Text")
    nameESP.Visible = false
    nameESP.Center = true
    nameESP.Outline = true
    nameESP.Font = 2
    nameESP.Size = 13
    nameESP.Color = espNameColor

    local healthBar = Drawing.new("Line")
    healthBar.Visible = false
    healthBar.Thickness = 2
    healthBar.Color = Color3.new(0, 1, 0)

    local slapTimerESP = Drawing.new("Text")
    slapTimerESP.Visible = false
    slapTimerESP.Center = true
    slapTimerESP.Outline = true
    slapTimerESP.Font = 2
    slapTimerESP.Size = 13
    slapTimerESP.Color = slapTimerColor

    RunService.RenderStepped:Connect(function()
        if player.Character and player.Character:FindFirstChild("HumanoidRootPart") and player.Character:FindFirstChild("Humanoid") then
            local rootPart = player.Character.HumanoidRootPart
            local humanoid = player.Character.Humanoid
            local vector, onScreen = workspace.CurrentCamera:WorldToViewportPoint(rootPart.Position)
            local distance = (rootPart.Position - workspace.CurrentCamera.CFrame.Position).Magnitude
            
            if onScreen and distance <= espDistance and espEnabled then
                nameESP.Text = string.format("%s [%.1f]", player.Name, distance)
                nameESP.Position = Vector2.new(vector.X, vector.Y - 40)
                nameESP.Visible = true

                local healthPercentage = humanoid.Health / humanoid.MaxHealth
                healthBar.From = Vector2.new(vector.X + 50, vector.Y - 20)
                healthBar.To = Vector2.new(vector.X + 50, vector.Y - 20 + 40 * healthPercentage)
                healthBar.Color = Color3.new(1 - healthPercentage, healthPercentage, 0)
                healthBar.Visible = true

                highlight.Enabled = true

                if rainbowESPEnabled then
                    local hue = (tick() % 5) / 5
                    local rainbowColor = Color3.fromHSV(hue, 1, 1)
                    highlight.OutlineColor = rainbowColor
                    nameESP.Color = rainbowColor
                else
                    highlight.OutlineColor = espOutlineColor
                    nameESP.Color = espNameColor
                end
                highlight.OutlineTransparency = 1 - highlightThickness

                if slapTimerEnabled then
                    slapTimerESP.Position = Vector2.new(vector.X, vector.Y + 20)
                    slapTimerESP.Visible = true
                else
                    slapTimerESP.Visible = false
                end
            else
                nameESP.Visible = false
                healthBar.Visible = false
                highlight.Enabled = false
                slapTimerESP.Visible = false
            end
        else
            nameESP.Visible = false
            healthBar.Visible = false
            highlight.Enabled = false
            slapTimerESP.Visible = false
        end
    end)

    return {nameESP, healthBar, highlight, slapTimerESP}
end

local function getClosestPlayer()
    local closestPlayer = nil
    local shortestDistance = math.huge
    local localPlayer = Players.LocalPlayer
    local localCharacter = localPlayer.Character

    if localCharacter then
        local localPosition = localCharacter.PrimaryPart.Position

        for _, player in ipairs(Players:GetPlayers()) do
            if player ~= localPlayer and player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
                local playerPosition = player.Character.PrimaryPart.Position
                local distance = (playerPosition - localPosition).Magnitude

                if distance < shortestDistance then
                    closestPlayer = player
                    shortestDistance = distance
                end
            end
        end
    end

    return closestPlayer
end

local function performSwing()
    local currentTime = tick()
    if currentTime - lastSwingTime >= swingCooldown then
        mouse1click()
        lastSwingTime = currentTime
    end
end

local function onCharacterAdded(character)
    local humanoid = character:WaitForChild("Humanoid")
    local player = Players:GetPlayerFromCharacter(character)
    
    local espObjects = createPlayerESP(player)
    local slapTimerESP = espObjects[4]
    local canSlap = true
    local blockEndTime = 0
    
    humanoid.AnimationPlayed:Connect(function(animTrack)
        for animName, animId in pairs(animIDs) do
            if animTrack.Animation.AnimationId == "rbxassetid://" .. animId then
                print(player.Name .. " used animation: " .. animName)
                
                if animName == "Slap" and slapTimerEnabled then
                    canSlap = false
                    local startTime = tick()
                    
                    task.spawn(function()
                        while tick() - startTime < 3 and slapTimerEnabled do
                            local timeLeft = math.ceil(3 - (tick() - startTime))
                            slapTimerESP.Text = string.format("%d cannot slap", timeLeft)
                            slapTimerESP.Color = slapTimerColor
                            slapTimerESP.Visible = true
                            task.wait(0.1)
                        end
                        
                        canSlap = true
                        slapTimerESP.Text = "Can slap"
                        slapTimerESP.Color = Color3.new(1, 0, 0)
                        slapTimerESP.Visible = true
                    end)
                end
                
                if animName == "Slap" then
                    local localPlayer = Players.LocalPlayer
                    local localCharacter = localPlayer.Character
                    if localCharacter then
                        local localPosition = localCharacter.PrimaryPart.Position
                        local playerPosition = player.Character.PrimaryPart.Position
                        local distance = (playerPosition - localPosition).Magnitude
                        
                        if distance < blockDistance then 
                            BlockRemote:FireServer()
                            
                            -- Block for the duration of the slap animation
                            task.wait(animTrack.Length)
                            
                            UnblockRemote:FireServer()
                            
                            -- Auto Counter Slap if enabled
                            if autoCounterEnabled and distance < autoSlapDistance then
                                VirtualInputManager:SendKeyEvent(true, Enum.KeyCode.E, false, game)
                                task.wait(0.1)
                                VirtualInputManager:SendKeyEvent(false, Enum.KeyCode.E, false, game)
                            end
                        end
                    end
                end
                
                -- Auto Half Swing or Fast Swing
                if animName:find("Swing") and player == Players.LocalPlayer then
                    if autoHalfSwingEnabled then
                        task.spawn(function()
                            task.wait(autoHalfSwingDelay)
                            performSwing()
                        end)
                    end
                    if autoFastSwingEnabled then
                        task.spawn(function()
                            for i = 1, 3 do -- Perform multiple fast swings
                                task.wait(autoFastSwingDelay)
                                performSwing()
                            end
                        end)
                    end
                end
                
                break
            end
        end
    end)
end

local function monitorClosestPlayer()
    local closestPlayer = getClosestPlayer()
    if closestPlayer and closestPlayer.Character then
        local humanoid = closestPlayer.Character:FindFirstChild("Humanoid")
        if humanoid then
            humanoid.AnimationPlayed:Connect(function(animTrack)
                for animName, animId in pairs(animIDs) do
                    if animTrack.Animation.AnimationId == "rbxassetid://" .. animId then
                        if animName:find("Block") then
                            blockEndTime = tick() + 0.5
                        end
                    end
                end
            end)
        end
    end
end

local function handleSlapAnimation(player, animTrack, slapTimerESP)
    if slapTimerEnabled then
        updateSlapTimer(slapTimerESP)
    end

    local localCharacter = localPlayer.Character
    if localCharacter then
        local distance = (localCharacter.PrimaryPart.Position - player.Character.PrimaryPart.Position).Magnitude
        
        if distance < blockDistance then 
            BlockRemote:FireServer()
            task.wait(animTrack.Length)
            UnblockRemote:FireServer()
            
            if autoCounterEnabled and distance < autoSlapDistance then
                counterSlap()
            end
        end
    end
end

local function updateSlapTimer(slapTimerESP)
    local canSlap = false
    local startTime = tick()
    
    task.spawn(function()
        while tick() - startTime < 3 and slapTimerEnabled do
            local timeLeft = math.ceil(3 - (tick() - startTime))
            slapTimerESP.Text = string.format("%d cannot slap", timeLeft)
            slapTimerESP.Color = slapTimerColor
            slapTimerESP.Visible = true
            task.wait(0.1)
        end
        
        canSlap = true
        slapTimerESP.Text = "Can slap"
        slapTimerESP.Color = Color3.new(1, 0, 0)
        slapTimerESP.Visible = true
    end)
end

local function counterSlap()
    VirtualInputManager:SendKeyEvent(true, Enum.KeyCode.E, false, game)
    task.wait(0.1)
    VirtualInputManager:SendKeyEvent(false, Enum.KeyCode.E, false, game)
end

local function handleSwingAnimation(animTrack)
    if autoHalfSwingEnabled then
        task.spawn(function()
            task.wait(autoHalfSwingDelay)
            performSwing()
        end)
    end
    if autoFastSwingEnabled then
        task.spawn(function()
            for i = 1, 3 do
                task.wait(autoFastSwingDelay)
                performSwing()
            end
        end)
    end
end

RunService.RenderStepped:Connect(function()
    local closestPlayer = getClosestPlayer()
    if closestPlayer and closestPlayer.Character then
        local humanoid = closestPlayer.Character:FindFirstChild("Humanoid")
        if humanoid and tick() > blockEndTime then
            local localPlayer = Players.LocalPlayer
            local localCharacter = localPlayer.Character
            if localCharacter then
                local localPosition = localCharacter.PrimaryPart.Position
                local playerPosition = closestPlayer.Character.PrimaryPart.Position
                local distance = (playerPosition - localPosition).Magnitude
                
                if distance < autoSlapDistance then
                    VirtualInputManager:SendKeyEvent(true, Enum.KeyCode.E, false, game)
                    task.wait(0.1)
                    VirtualInputManager:SendKeyEvent(false, Enum.KeyCode.E, false, game)
                end
            end
        end
    end
end)

for _, player in ipairs(Players:GetPlayers()) do
    if player ~= Players.LocalPlayer then
        if player.Character then
            onCharacterAdded(player.Character)
        end
        player.CharacterAdded:Connect(onCharacterAdded)
    end
end

Players.PlayerAdded:Connect(function(player)
    if player ~= Players.LocalPlayer then
        player.CharacterAdded:Connect(onCharacterAdded)
    end
end)

local creditsSection = creditsTab:CreateSection("Credits")

local creditsText = {
    "Created by xenon90 on discord",
    "If any other comissions are needed then feel free to contact me",
    "Most of my scripts are free that i make due to it being for experience",
}

for _, text in ipairs(creditsText) do
    creditsTab:CreateLabel(text)
end

monitorClosestPlayer()