local ReplicatedStorage = game:GetService("ReplicatedStorage") local Players = game:GetService("Players") local Workspace = game:GetService("Workspace") local AbilityEvent = ReplicatedStorage.Remotes.AbilityEvent local LocalPlayer = Players.LocalPlayer local DEFAULT_DISTANCE = 14 local DEFAULT_DELAY = 0.18 local MAX_HEIGHT_DIFF = 3 local ATTACKS = { -- Default Zombie ["rbxassetid://131057554784102"] = "Default Zombie Attack", -- Warrior Zombie ["rbxassetid://108041731225218"] = "Warrior Zombie Slash", ["rbxassetid://125437242735574"] = "Warrior Zombie Lunge", -- Shielder Zombie ["rbxassetid://129506999094960"] = "Shielder Zombie Punch", ["rbxassetid://77588863691464"] = "Shielder Zombie Bash", ["rbxassetid://123074144179609"] = "Shielder Zombie Shoot", -- Heavy Zombie ["rbxassetid://121876202477528"] = "Heavy Zombie Overhead", -- Frostbitten Zombie ["rbxassetid://82301323029298"] = "Frostbitten Zombie Ice Cannon", ["rbxassetid://92117909785463"] = "Frostbitten Zombie Ice Spit", -- Fast Zombie ["rbxassetid://96246924672044"] = "Fast Zombie Punch", -- Charger Zombie ["rbxassetid://133014997958959"] = "Charger Zombie Charge Start", ["rbxassetid://123917107950291"] = "Charger Zombie Upstrike", -- Brutal Zombie ["rbxassetid://71991484785794"] = "Brutal Zombie Bat Strike", -- Bomber ["rbxassetid://78370109861978"] = "Bomber Attack", -- Scripter ["rbxassetid://101311358142810"] = "Scripter M1", ["rbxassetid://70486957731291"] = "Scripter Move 1", ["rbxassetid://120438552410980"] = "Scripter Move 2", -- Crosswalker ["rbxassetid://99251628957425"] = "Crosswalker Slam", -- Frostborne ["rbxassetid://130471571956863"] = "Frostborne M1", ["rbxassetid://119457368102139"] = "Frostborne M2", -- Ellernate ["rbxassetid://131301950844942"] = "Ellernate M1", ["rbxassetid://101792283397169"] = "Ellernate Move 1", ["rbxassetid://137865611397955"] = "Ellernate Move 4", ["rbxassetid://120005408192265"] = "Ellernate Slash (old)", ["rbxassetid://95411977177318"] = "Ellernate Slash", ["rbxassetid://138267905274628"] = "Ellernate Flames of Vengeance", ["rbxassetid://112428071621675"] = "Ellernate Burnout", ["rbxassetid://86035725516389"] = "Ellernate Dash", -- 1x1x1x1 ["rbxassetid://83897946662289"] = "Twin Slash", ["rbxassetid://134017370471458"] = "Twin Slash Clone", ["rbxassetid://96818151041944"] = "Gushing Scourge", ["rbxassetid://87885580461373"] = "Death Penalty", ["rbxassetid://126153486813271"] = "Cross Convergence", ["rbxassetid://95423315579104"] = "Breakthrough", ["rbxassetid://96747052141209"] = "Warping Streak", } local CUSTOM_DISTANCES = { ["Warrior Zombie Lunge"] = 12, } local CUSTOM_DELAYS = { ["Ellernate Burnout"] = 0.32, ["Heavy Zombie Overhead"] = 2.0, ["Death Penalty"] = 0.35, ["Cross Convergence"] = 0.30, ["Gushing Scourge"] = 0.25, -- No delay ["Shielder Zombie Punch"] = 0, ["Shielder Zombie Bash"] = 0, ["Shielder Zombie Shoot"] = 0, ["Bomber Attack"] = 0, -- fast attack } local function normalizeId(id) if typeof(id) ~= "string" then return nil end return id:gsub("rbxassetid://", "") end local normalizedAttacks = {} for id, name in pairs(ATTACKS) do normalizedAttacks[normalizeId(id)] = name normalizedAttacks[id] = name end local function isCloseEnough(character, attackName) local myChar = LocalPlayer.Character if not myChar or not myChar:FindFirstChild("HumanoidRootPart") then return false end if not character or not character:FindFirstChild("HumanoidRootPart") then return false end local myHRP = myChar.HumanoidRootPart local theirHRP = character.HumanoidRootPart -- Don't parry if you are above them if myHRP.Position.Y > theirHRP.Position.Y + MAX_HEIGHT_DIFF then return false end local maxDist = CUSTOM_DISTANCES[attackName] or DEFAULT_DISTANCE local distance = (myHRP.Position - theirHRP.Position).Magnitude return distance <= maxDist end local function onAttackDetected(animationId, character) local name = normalizedAttacks[animationId] or normalizedAttacks[normalizeId(animationId)] if not name then return end if not isCloseEnough(character, name) then return end local delayTime = CUSTOM_DELAYS[name] or DEFAULT_DELAY print("Matched:", name, "| Delay:", delayTime) task.delay(delayTime, function() AbilityEvent:FireServer("AbilityQ", false) local pos = character and character:FindFirstChild("HumanoidRootPart") and character.HumanoidRootPart.Position if pos then AbilityEvent:FireServer("AbilityQ", true, pos) end print("Fired AbilityQ") end) end local connected = {} local function setupAnimator(animator, character) if connected[animator] then return end connected[animator] = true animator.AnimationPlayed:Connect(function(track) if track.Animation then onAttackDetected(track.Animation.AnimationId, character) end end) end local function setupCharacter(character) if not character:IsA("Model") then return end if connected[character] then return end connected[character] = true local humanoid = character:FindFirstChildOfClass("Humanoid") if humanoid then local animator = humanoid:FindFirstChildOfClass("Animator") if animator then setupAnimator(animator, character) else humanoid.ChildAdded:Connect(function(child) if child:IsA("Animator") then setupAnimator(child, character) end end) end end local animController = character:FindFirstChildOfClass("AnimationController") if animController then local animator = animController:FindFirstChildOfClass("Animator") if animator then setupAnimator(animator, character) end end end local function scan(container) for _, child in ipairs(container:GetDescendants()) do if child:IsA("Model") and (child:FindFirstChildOfClass("Humanoid") or child:FindFirstChildOfClass("AnimationController")) then setupCharacter(child) end end end scan(Workspace) Workspace.DescendantAdded:Connect(function(desc) if desc:IsA("Model") then task.defer(setupCharacter, desc) elseif desc:IsA("Animator") then local character = desc:FindFirstAncestorOfClass("Model") if character then setupAnimator(desc, character) end end end) print("Script loaded - Bomber added (0 delay)")