Further enhance, and add a toggle to turn it on and off (KEY: R).
```
-- Enhanced Roblox Script with Advanced Dynamic Slap Blocking System

-- 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")

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

-- Settings
local Settings = {
    BlockDistance = 15,
    AutoCounterEnabled = false,
    AutoSlapDistance = 10,
    ReactionTimeThreshold = 0.15, -- Base reaction time
    BlockDuration = 0.3,
    Cooldown = 1.0,
    SlapAnimations = {
        ["Slap"] = 12625891544,
        ["SlappedLegs"] = 12671715182,
        ["SlappedArms"] = 12625896358
    }
}

-- State Management
local blockingPlayers = {} -- Tracks blocking state per 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")
    
    local blockIndicator = Instance.new("Frame")
    blockIndicator.Size = UDim2.new(0, 200, 0, 100)
    blockIndicator.Position = UDim2.new(0.5, -100, 0, 10)
    blockIndicator.BackgroundColor3 = Color3.new(0, 0, 0)
    blockIndicator.BackgroundTransparency = 0.5
    blockIndicator.Visible = false
    blockIndicator.Parent = screenGui
    
    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 against:\nNone"
    blockText.TextColor3 = Color3.new(1, 1, 1)
    blockText.TextScaled = true
    blockText.TextWrapped = true
    blockText.Parent = blockIndicator
    
    return blockIndicator, blockText
end

local blockIndicator, blockText = setupGUI()

-- Tween for Smooth Appearance/Disappearance
local tweenInfo = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
local showTween = TweenService:Create(blockIndicator, tweenInfo, {BackgroundColor3 = Color3.new(0, 0, 0), Visible = true})
local hideTween = TweenService:Create(blockIndicator, tweenInfo, {BackgroundColor3 = Color3.new(0, 0, 0), Visible = false})

local function showBlockIndicator(opponentNames)
    if not blockIndicator.Visible then
        blockIndicator.Visible = true
        showTween:Play()
    end
    blockText.Text = "Blocking against:\n" .. table.concat(opponentNames, ", ")
end

local function hideBlockIndicator(opponentNames)
    if blockIndicator.Visible and #opponentNames == 0 then
        hideTween:Play()
        task.delay(tweenInfo.Time, function()
            blockIndicator.Visible = false
            blockText.Text = "Blocking against:\nNone"
        end)
    else
        blockText.Text = "Blocking against:\n" .. (opponentNames[1] or "None")
    end
end

-- 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 Update GUI Indicators based on Blocking State
local function updateGUI()
    local blockingNames = {}
    for opponentName, _ in pairs(blockingPlayers) do
        table.insert(blockingNames, opponentName)
    end
    showBlockIndicator(blockingNames)
    hideBlockIndicator(blockingNames)
end

-- Handle Slap Animation with Advanced Blocking Logic
local function handleSlapAnimation(opponent, animTrack)
    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 distance = (character.HumanoidRootPart.Position - opponentRoot.Position).Magnitude

    if distance > Settings.BlockDistance then return end

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

    if timeSinceLastBlock < Settings.Cooldown then
        print("Block on cooldown for:", opponent.Name, "Time left:", 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.AnimationId == "rbxassetid://" .. Settings.SlapAnimations[animName] then
            shouldBlock = true
            break
        end
    end

    if shouldBlock then
        blockingPlayers[opponent.Name] = currentTime
        BlockRemote:FireServer()
        print("Blocking initiated against:", opponent.Name)

        updateGUI()

        -- Schedule Unblock
        task.delay(Settings.BlockDuration, function()
            UnblockRemote:FireServer()
            blockingPlayers[opponent.Name] = nil
            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)
            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)

-- Optimize GUI Updates with Heartbeat
RunService.Heartbeat:Connect(function()
    -- You can add additional logic here if needed
    -- For now, GUI updates are handled within the blocking functions
end)