local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage"):WaitForChild("ReplicatedStorage", 5) or game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")
local pcall = pcall
local TouchEnabled = UserInputService.TouchEnabled
local player = Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui", 5)
-- Wait for character and handle respawns
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid", 5)
local rootPart = character:WaitForChild("HumanoidRootPart", 5)
player.CharacterAdded:Connect(function(newChar)
character = newChar
humanoid = newChar:WaitForChild("Humanoid", 5)
rootPart = newChar:WaitForChild("HumanoidRootPart", 5)
end)
-- Create or get RemoteEvent with safety
local counterRemote
pcall(function()
counterRemote = ReplicatedStorage:WaitForChild("CounterAttack", 3)
if not counterRemote then
counterRemote = Instance.new("RemoteEvent")
counterRemote.Name = "CounterAttack"
counterRemote.Parent = ReplicatedStorage
end
end)
-- Config: Move-specific ranges
local DETECTION_RANGES = {
ChargeGrab = 15,
MeleeSwing = 8,
GodsTrickery = 12,
Default = 10
}
-- Known attack keywords
local ATTACK_KEYWORDS = {"attack", "swing", "charge", "grab", "punch", "slash", "trick", "hit", "strike", "melee", "god"}
local COOLDOWN = 2
local isBlocking = false
local lastCounter = 0
local frameCounter = 0 -- For throttling
-- Per-enemy debounce
local enemyDebounce = {}
-- Auto-Tag Common Executioners (shallower recursion for Delta perf)
local possibleEnemyNames = {"_2011X", "Fleetway", "V1", "Chaos", "Executioner", "Killer"}
local function findAndTagEnemies(parent, depth)
if depth > 3 then return end -- Limit depth
pcall(function()
for _, obj in ipairs(parent:GetChildren()) do
if obj:IsA("Model") and table.find(possibleEnemyNames, obj.Name) and obj:FindFirstChild("Humanoid") and not CollectionService:HasTag(obj, "EnemyAttacker") then
CollectionService:AddTag(obj, "EnemyAttacker")
end
findAndTagEnemies(obj, depth + 1)
end
end)
end
local function autoTagEnemies()
pcall(findAndTagEnemies, workspace, 0)
end
autoTagEnemies()
task.spawn(function()
while task.wait(10) do -- Slower poll for Delta
autoTagEnemies()
end
end)
-- GUI Setup (Delta-safe)
local screenGui = Instance.new("ScreenGui")
screenGui.Name = "KnucklesCounterGUI"
screenGui.ResetOnSpawn = false
screenGui.Parent = playerGui
local mainFrame = Instance.new("Frame")
mainFrame.Size = UDim2.new(0, 220, 0, 120)
mainFrame.Position = UDim2.new(0, 10, 0, 10)
mainFrame.BackgroundColor3 = Color3.new(0, 0, 0)
mainFrame.BackgroundTransparency = 0.5
mainFrame.BorderSizePixel = 2
mainFrame.BorderColor3 = Color3.new(1, 0, 0)
mainFrame.Parent = screenGui
local titleLabel = Instance.new("TextLabel")
titleLabel.Size = UDim2.new(1, 0, 0.3, 0)
titleLabel.BackgroundTransparency = 1
titleLabel.Text = "Knuckles Auto-Counter"
titleLabel.TextColor3 = Color3.new(1, 0, 0)
titleLabel.TextScaled = true
titleLabel.Font = Enum.Font.SourceSansBold
titleLabel.Parent = mainFrame
local statusLabel = Instance.new("TextLabel")
statusLabel.Size = UDim2.new(1, 0, 0.3, 0)
statusLabel.Position = UDim2.new(0, 0, 0.3, 0)
statusLabel.BackgroundTransparency = 1
statusLabel.Text = TouchEnabled and "Tap Button to Toggle Block" or "Hold E to Block"
statusLabel.TextColor3 = Color3.new(1, 1, 1)
statusLabel.TextScaled = true
statusLabel.Font = Enum.Font.SourceSansItalic
statusLabel.Parent = mainFrame
local instructLabel = Instance.new("TextLabel")
instructLabel.Size = UDim2.new(1, 0, 0.2, 0)
instructLabel.Position = UDim2.new(0, 0, 0.6, 0)
instructLabel.BackgroundTransparency = 1
instructLabel.Text = "Auto-tags & detects attacks!"
instructLabel.TextColor3 = Color3.new(0, 1, 0)
instructLabel.TextScaled = true
instructLabel.Font = Enum.Font.SourceSans
instructLabel.Parent = mainFrame
-- Toggle Button (Mobile)
local toggleButton = Instance.new("TextButton")
toggleButton.Size = UDim2.new(0.9, 0, 0.2, 0)
toggleButton.Position = UDim2.new(0.05, 0, 0.8, 0)
toggleButton.BackgroundColor3 = Color3.new(1, 0, 0)
toggleButton.Text = "Toggle Block (Off)"
toggleButton.TextColor3 = Color3.new(1, 1, 1)
toggleButton.TextScaled = true
toggleButton.Font = Enum.Font.SourceSansBold
toggleButton.Visible = TouchEnabled
toggleButton.Parent = mainFrame
local function setBlocking(state)
isBlocking = state
if humanoid then
humanoid.WalkSpeed = state and 8 or 16
end
toggleButton.Text = "Toggle Block (" .. (state and "On" or "Off") .. ")"
toggleButton.BackgroundColor3 = state and Color3.new(0, 1, 0) or Color3.new(1, 0, 0)
updateStatusGUI()
end
toggleButton.MouseButton1Click:Connect(function()
setBlocking(not isBlocking)
end)
-- Input: Use ContextActionService for better Delta support
local blockAction = "BlockAction"
ContextActionService:BindAction(blockAction, function(actionName, inputState, inputObj)
if actionName == blockAction then
if inputState == Enum.UserInputState.Begin then
setBlocking(true)
elseif inputState == Enum.UserInputState.End then
setBlocking(false)
end
return Enum.ContextActionResult.Sink
end
end, false, Enum.KeyCode.E)
if TouchEnabled then
ContextActionService:BindAction(blockAction, function() end, true, Enum.KeyCode.ButtonA) -- Fallback for mobile
end
-- Update GUI (throttled)
local function updateStatusGUI()
if not statusLabel then return end
local baseText = isBlocking and "Blocking... Scanning attacks!" or (TouchEnabled and "Tap Button to Toggle Block" or "Hold E to Block")
statusLabel.Text = baseText
local cooldownLeft = COOLDOWN - (tick() - lastCounter)
if cooldownLeft > 0 then
statusLabel.Text = baseText .. "\nCooldown: " .. string.format("%.1f", cooldownLeft) .. "s"
statusLabel.TextColor3 = Color3.new(1, 1, 0)
else
statusLabel.TextColor3 = isBlocking and Color3.new(0, 1, 0) or Color3.new(1, 1, 1)
end
end
-- Punch effect (non-blocking)
local function playPunchEffect(moveType)
pcall(function()
local punchSound = Instance.new("Sound")
punchSound.SoundId = "rbxassetid://156894510"
punchSound.Volume = 1
if rootPart then punchSound.Parent = rootPart end
punchSound:Play()
game:GetService("Debris"):AddItem(punchSound, 5)
local camera = workspace.CurrentCamera
local originalFOV = camera.FieldOfView
local shake = TweenService:Create(camera, TweenInfo.new(0.1, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, 5, true), {FieldOfView = originalFOV + math.random(-5, 5)})
shake:Play()
task.spawn(function()
shake.Completed:Wait()
camera.FieldOfView = originalFOV
end)
local flash = TweenService:Create(mainFrame, TweenInfo.new(0.2), {BackgroundTransparency = 0.2})
flash:Play()
task.spawn(function()
flash.Completed:Wait()
TweenService:Create(mainFrame, TweenInfo.new(0.2), {BackgroundTransparency = 0.5}):Play()
end)
end)
end
-- Infer move type
local function inferMoveType(name)
if not name then return "Default" end
name = name:lower()
if name:find("charge") or name:find("grab") then return "ChargeGrab"
elseif name:find("melee") or name:find("swing") or name:find("punch") or name:find("slash") then return "MeleeSwing"
elseif name:find("god") or name:find("trick") then return "GodsTrickery"
end
return "Default"
end
-- Is attack
local function isAttackName(name)
if not name then return false end
name = name:lower()
for _, keyword in ipairs(ATTACK_KEYWORDS) do
if name:find(keyword) then return true end
end
return false
end
-- Connections cache
local animConnections = {}
local soundConnections = {}
-- Connect to enemy
local function connectEnemyDetection(enemy)
if animConnections[enemy] then return end
local hum = enemy:FindFirstChild("Humanoid")
if not hum then return end
pcall(function()
local animConn = hum.AnimationPlayed:Connect(function(track)
if track.IsPlaying and track.Animation and isAttackName(track.Animation.Name) then
local moveType = inferMoveType(track.Animation.Name)
performCounterIfInRange(enemy, moveType)
end
end)
animConnections[enemy] = animConn
local root = enemy:FindFirstChild("HumanoidRootPart") or enemy
local soundConn = root.ChildAdded:Connect(function(child)
if child:IsA("Sound") and child.IsPlaying and isAttackName(child.Name) then
local moveType = inferMoveType(child.Name)
performCounterIfInRange(enemy, moveType)
end
end)
soundConnections[enemy] = soundConn
end)
end
-- Shared counter logic with debounce
local function performCounterIfInRange(enemy, moveType)
if not isBlocking or tick() - lastCounter < COOLDOWN then return end
local now = tick()
if enemyDebounce[enemy] and now - enemyDebounce[enemy] < 0.5 then return end -- Per-enemy debounce
enemyDebounce[enemy] = now
local enemyRoot = enemy:FindFirstChild("HumanoidRootPart")
if enemyRoot and rootPart then
local distance = (rootPart.Position - enemyRoot.Position).Magnitude
local range = DETECTION_RANGES[moveType] or DETECTION_RANGES.Default
if distance <= range then
pcall(function()
counterRemote:FireServer(enemy.Name, moveType) -- Send name instead of instance for safety
playPunchEffect(moveType)
lastCounter = now
updateStatusGUI()
end)
end
end
end
-- Main Detection Loop (throttled)
RunService.Heartbeat:Connect(function()
frameCounter = frameCounter + 1
if frameCounter % 2 ~= 0 then return end -- Every 2nd frame
updateStatusGUI()
if not isBlocking then return end
local myPos = rootPart and rootPart.Position
if not myPos then return end
pcall(function()
for _, enemy in ipairs(CollectionService:GetTagged("EnemyAttacker")) do
if enemy and enemy:FindFirstChild("HumanoidRootPart") and enemy:FindFirstChild("Humanoid") and enemy.Humanoid.Health > 0 then
connectEnemyDetection(enemy)
-- Proactive checks
local hum = enemy.Humanoid
for _, track in ipairs(hum:GetPlayingAnimationTracks()) do
if track.IsPlaying and track.Animation and isAttackName(track.Animation.Name) then
local moveType = inferMoveType(track.Animation.Name)
performCounterIfInRange(enemy, moveType)
end
end
local root = enemy:FindFirstChild("HumanoidRootPart") or enemy
for _, child in ipairs(root:GetChildren()) do
if child:IsA("Sound") and child.IsPlaying and isAttackName(child.Name) then
local moveType = inferMoveType(child.Name)
performCounterIfInRange(enemy, moveType)
end
end
end
end
end)
end)
-- Cleanup
CollectionService:GetInstanceRemovedSignal("EnemyAttacker"):Connect(function(enemy)
if animConnections[enemy] then
animConnections[enemy]:Disconnect()
animConnections[enemy] = nil
end
if soundConnections[enemy] then
soundConnections[enemy]:Disconnect()
soundConnections[enemy] = nil
end
enemyDebounce[enemy] = nil
end)