Enemy AI Not Blocking

So I have a custom sword gear and a custom enemy AI. Neither are done and I’m writing them at the same time but that’s not the point. Pretty much the AI is meant to hold down block while the swinging is on cooldown; however, this obviously doesn’t work. It works when the player does it but not when the Enemy does, any idea where the mistake is? Thanks!

Enemy AI (Server Script):

local npc = script.Parent
local humanoid = npc:WaitForChild("Humanoid")
local rootPart = npc:WaitForChild("HumanoidRootPart")
local spawnPoint = rootPart.Position
local runService = game:GetService("RunService")
local players = game:GetService("Players")
local PathfindingService = game:GetService("PathfindingService")
local TweenService = game:GetService("TweenService")
local wanderCount = 0
local maxWander = 10
local spawnThreshold = 3
local currentTarget = nil
local currentAnim = nil
local isSwinging = false
local isBlocking = false

local function playAnimation(track)
	if currentAnim == track then return end
	if currentAnim and currentAnim.IsPlaying then
		currentAnim:Stop()
	end
	currentAnim = track
	track:Play()
end

local function setupAnimation(track)
	track.Looped = true
end

local walkAnim = Instance.new("Animation")
walkAnim.AnimationId = "rbxassetid://90572220017959"
local walkTrack = humanoid:LoadAnimation(walkAnim)
setupAnimation(walkTrack)

local runAnim = Instance.new("Animation")
runAnim.AnimationId = "rbxassetid://82671911689586"
local runTrack = humanoid:LoadAnimation(runAnim)
setupAnimation(runTrack)

local idleAnim = Instance.new("Animation")
idleAnim.AnimationId = "rbxassetid://86102260358509"
local idleTrack = humanoid:LoadAnimation(idleAnim)
setupAnimation(idleTrack)

local specialAnimationId = "rbxassetid://133973855670648"

local function isSpecialAnimationPlaying(character)
	local hum = character:FindFirstChildOfClass("Humanoid")
	if hum then
		for _, track in ipairs(hum:GetPlayingAnimationTracks()) do
			if track.Animation and track.Animation.AnimationId == specialAnimationId then
				return true
			end
		end
	end
	return false
end

local function getTargetPlayer()
	if currentTarget and currentTarget.Character then
		local hrp = currentTarget.Character:FindFirstChild("HumanoidRootPart")
		if hrp and (hrp.Position - rootPart.Position).Magnitude <= 50 then
			return currentTarget
		else
			currentTarget = nil
		end
	end
	local stealthCandidate, normalCandidate = nil, nil
	local shortestDistance = math.huge
	for _, player in ipairs(players:GetPlayers()) do
		local character = player.Character
		if character then
			local hrp = character:FindFirstChild("HumanoidRootPart")
			if hrp then
				local distance = (hrp.Position - rootPart.Position).Magnitude
				if isSpecialAnimationPlaying(character) then
					local direction = (hrp.Position - rootPart.Position).Unit
					local dot = rootPart.CFrame.LookVector:Dot(direction)
					if distance < 5 and dot < 0 then
						stealthCandidate = player
					end
				else
					if distance < shortestDistance then
						normalCandidate = player
						shortestDistance = distance
					end
				end
			end
		end
	end
	if stealthCandidate then
		currentTarget = stealthCandidate
		return stealthCandidate
	elseif normalCandidate and shortestDistance <= 50 then
		currentTarget = normalCandidate
		return normalCandidate
	end
	return nil
end

local function isFallAhead(targetPos)
	local direction = (targetPos - rootPart.Position).Unit
	local checkDistance = math.min(5, (targetPos - rootPart.Position).Magnitude)
	local checkPoint = rootPart.Position + direction * checkDistance
	local rayOrigin = checkPoint + Vector3.new(0, 5, 0)
	local rayDirection = Vector3.new(0, -10, 0)
	local rayParams = RaycastParams.new()
	rayParams.FilterDescendantsInstances = {npc}
	rayParams.FilterType = Enum.RaycastFilterType.Blacklist
	local result = workspace:Raycast(rayOrigin, rayDirection, rayParams)
	if result then
		local groundY = result.Position.Y
		local fallDistance = checkPoint.Y - groundY
		return fallDistance > 5, fallDistance
	else
		return true, math.huge
	end
end

local function shouldJump(targetPos, targetCharacter)
	local direction = (targetPos - rootPart.Position).Unit
	local rayOrigin = rootPart.Position + Vector3.new(0, 2, 0)
	local rayDirection = direction * 2
	local rayParams = RaycastParams.new()
	if targetCharacter then
		rayParams.FilterDescendantsInstances = {npc, targetCharacter}
	else
		rayParams.FilterDescendantsInstances = {npc}
	end
	rayParams.FilterType = Enum.RaycastFilterType.Blacklist
	local result = workspace:Raycast(rayOrigin, rayDirection, rayParams)
	if result and result.Instance and result.Instance.CanCollide then
		return true
	end
	return false
end

local function getDestination(targetPos)
	return targetPos
end

local function getRandomWanderTarget()
	local offsetX, offsetZ
	repeat
		offsetX = math.random(-10, 10)
		offsetZ = math.random(-10, 10)
	until offsetX ~= 0 or offsetZ ~= 0
	local targetPos = spawnPoint + Vector3.new(offsetX, 0, offsetZ)
	local rayOrigin = targetPos + Vector3.new(0, 5, 0)
	local rayDirection = Vector3.new(0, -10, 0)
	local rayParams = RaycastParams.new()
	rayParams.FilterDescendantsInstances = {npc}
	rayParams.FilterType = Enum.RaycastFilterType.Blacklist
	local result = workspace:Raycast(rayOrigin, rayDirection, rayParams)
	if result then
		return Vector3.new(targetPos.X, result.Position.Y, targetPos.Z)
	end
	return nil
end

local function pathfindTo(targetPos)
	local path = PathfindingService:CreatePath()
	path:ComputeAsync(rootPart.Position, targetPos)
	if path.Status == Enum.PathStatus.Success then
		local waypoints = path:GetWaypoints()
		if #waypoints > 0 and (waypoints[1].Position - rootPart.Position).Magnitude < 1 then
			table.remove(waypoints, 1)
		end
		for _, waypoint in ipairs(waypoints) do
			if getTargetPlayer() then return false end
			if shouldJump(waypoint.Position, nil) then
				humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
			end
			humanoid:MoveTo(waypoint.Position)
			humanoid.MoveToFinished:Wait()
			if getTargetPlayer() then return false end
		end
	end
	return true
end

local lastHealth = humanoid.Health
humanoid.HealthChanged:Connect(function(newHealth)
	if newHealth < lastHealth then
		for _, player in ipairs(players:GetPlayers()) do
			local character = player.Character
			if character and isSpecialAnimationPlaying(character) then
				currentTarget = player
				break
			end
		end
	end
	lastHealth = newHealth
end)

humanoid.Died:Connect(function()
	wait(5)
	local ReplicatedStorage = game:GetService("ReplicatedStorage")
	local respawnFolder = ReplicatedStorage:FindFirstChild("EnemyRespawn")
	if respawnFolder then
		local testEnemy = respawnFolder:FindFirstChild("TestEnemy")
		if testEnemy then
			local clone = testEnemy:Clone()
			clone.Parent = workspace
			if clone:FindFirstChild("HumanoidRootPart") then
				clone:SetPrimaryPartCFrame(CFrame.new(spawnPoint))
			elseif clone.PrimaryPart then
				clone:SetPrimaryPartCFrame(CFrame.new(spawnPoint))
			end
		end
	end
end)

rootPart.Touched:Connect(function(hit)
	if hit.Name == "EnemyRespawn" then
		local ReplicatedStorage = game:GetService("ReplicatedStorage")
		local respawnFolder = ReplicatedStorage:FindFirstChild("EnemyRespawn")
		if respawnFolder then
			local testEnemy = respawnFolder:FindFirstChild("TestEnemy")
			if testEnemy then
				local clone = testEnemy:Clone()
				clone.Parent = workspace
				if clone:FindFirstChild("HumanoidRootPart") then
					clone:SetPrimaryPartCFrame(CFrame.new(spawnPoint))
				elseif clone.PrimaryPart then
					clone:SetPrimaryPartCFrame(CFrame.new(spawnPoint))
				end
			end
		end
		npc:Destroy()
	end
end)

while true do
	local targetPlayer = getTargetPlayer()
	if targetPlayer and targetPlayer.Character then
		local targetHRP = targetPlayer.Character:FindFirstChild("HumanoidRootPart")
		if targetHRP then
			local dist = (targetHRP.Position - rootPart.Position).Magnitude
			if dist <= 5 then
				if not isSwinging then
					isSwinging = true
					coroutine.wrap(function()
						while isSwinging and targetPlayer and targetPlayer.Character do
							local hrp = targetPlayer.Character:FindFirstChild("HumanoidRootPart")
							if not hrp or (hrp.Position - rootPart.Position).Magnitude > 50 then
								isSwinging = false
								break
							end
							humanoid.WalkSpeed = 16
							if currentAnim ~= walkTrack then
								playAnimation(walkTrack)
							end
							humanoid:MoveTo(hrp.Position)
							local sword = npc:FindFirstChildWhichIsA("Tool")
							if sword then
								if sword:GetAttribute("Cooldown") then
									if not isBlocking then
										npc:SetAttribute("Blocking", true)
										isBlocking = true
									end
									repeat
										wait(0.1)
									until not sword:GetAttribute("Cooldown")
									if isBlocking then
										npc:SetAttribute("Blocking", false)
										isBlocking = false
									end
									sword:Activate()
									wait(0.3)
								else
									sword:Activate()
									wait(0.3)
								end
							end
						end
						npc:SetAttribute("Blocking", false)
						isSwinging = false
					end)()
				end
				runService.Heartbeat:Wait()
			else
				isSwinging = false
				humanoid.WalkSpeed = 24
				if currentAnim ~= runTrack then
					playAnimation(runTrack)
				end
				if targetHRP then
					if rootPart.Position.Y > targetHRP.Position.Y + 2 then
						local dest = getDestination(targetHRP.Position)
						local path = PathfindingService:CreatePath()
						path:ComputeAsync(rootPart.Position, dest)
						local waypoints = path:GetWaypoints()
						if #waypoints > 0 and (waypoints[1].Position - rootPart.Position).Magnitude < 1 then
							table.remove(waypoints, 1)
						end
						for _, waypoint in ipairs(waypoints) do
							humanoid:MoveTo(waypoint.Position)
							if shouldJump(waypoint.Position, targetPlayer.Character) then
								humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
							end
							humanoid.MoveToFinished:Wait()
						end
					elseif targetHRP.Position.Y > rootPart.Position.Y + 2 then
						if shouldJump(targetHRP.Position, targetPlayer.Character) then
							humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
						end
						humanoid:MoveTo(targetHRP.Position)
					else
						local dest = getDestination(targetHRP.Position)
						local fallDetected, _ = isFallAhead(dest)
						if fallDetected then
							local path = PathfindingService:CreatePath()
							path:ComputeAsync(rootPart.Position, dest)
							local waypoints = path:GetWaypoints()
							if #waypoints > 0 and (waypoints[1].Position - rootPart.Position).Magnitude < 1 then
								table.remove(waypoints, 1)
							end
							for _, waypoint in ipairs(waypoints) do
								humanoid:MoveTo(waypoint.Position)
								if shouldJump(waypoint.Position, targetPlayer.Character) then
									humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
								end
								humanoid.MoveToFinished:Wait()
							end
						else
							if shouldJump(dest, targetPlayer.Character) then
								humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
							end
							humanoid:MoveTo(dest)
						end
					end
				end
				wanderCount = 0
			end
		end
	else
		isSwinging = false
		humanoid.WalkSpeed = 16
		if (rootPart.Position - spawnPoint).Magnitude > spawnThreshold then
			if currentAnim ~= walkTrack then
				playAnimation(walkTrack)
			end
			if not pathfindTo(spawnPoint) then
				runService.Heartbeat:Wait()
			end
		else
			if wanderCount < maxWander then
				local target = getRandomWanderTarget()
				if target then
					if currentAnim ~= walkTrack then
						playAnimation(walkTrack)
					end
					if pathfindTo(target) then
						wanderCount = wanderCount + 1
					end
				else
					wait(0.5)
				end
			else
				wanderCount = 0
				local idleTime = 5
				local elapsed = 0
				if currentAnim ~= idleTrack then
					playAnimation(idleTrack)
				end
				while elapsed < idleTime do
					if getTargetPlayer() then break end
					elapsed = elapsed + runService.Heartbeat:Wait()
				end
				currentTarget = nil
			end
		end
	end
	runService.Heartbeat:Wait()
end

Sword (Server Script):

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local blockEvent = ReplicatedStorage:FindFirstChild("BlockEvent")
if not blockEvent then
	blockEvent = Instance.new("RemoteEvent")
	blockEvent.Name = "BlockEvent"
	blockEvent.Parent = ReplicatedStorage
end
blockEvent.OnServerEvent:Connect(function(player, isBlocking)
	local character = player.Character
	if character then
		character:SetAttribute("Blocking", isBlocking)
	end
end)
local tool = script.Parent
local handle = tool:WaitForChild("Handle")
local unsheatheSound = Instance.new("Sound")
unsheatheSound.SoundId = "rbxassetid://12222225"
unsheatheSound.Parent = handle
local attackSound = Instance.new("Sound")
attackSound.SoundId = "rbxassetid://12222216"
attackSound.Parent = handle
local attackAnimationIds = {
	"rbxassetid://92578161823729",
	"rbxassetid://130993364618704",
	"rbxassetid://139811827055049",
	"rbxassetid://114162687869256"
}
local idleAnimationId = "rbxassetid://86960806700106"
local idleTrack = nil
local isAttacking = false
local attackCount = 0
local comboCooldown = false
local lastAttackFinished = 0
local defaultWalkSpeed = nil
local function onEquipped()
	unsheatheSound:Play()
	local character = tool.Parent
	local humanoid = character:FindFirstChildOfClass("Humanoid")
	if humanoid then
		defaultWalkSpeed = humanoid.WalkSpeed
		local equipAnim = Instance.new("Animation")
		equipAnim.AnimationId = "rbxassetid://102168004033968"
		local equipTrack = humanoid:LoadAnimation(equipAnim)
		equipTrack:Play()
		equipTrack.Stopped:Connect(function()
			local idleAnim = Instance.new("Animation")
			idleAnim.AnimationId = idleAnimationId
			idleTrack = humanoid:LoadAnimation(idleAnim)
			idleTrack.Looped = true
			idleTrack:Play()
		end)
	end
end
local function startCooldown()
	comboCooldown = true
	delay(1.5, function()
		comboCooldown = false
		attackCount = 0
	end)
end
local function onActivated()
	local character = tool.Parent
	if character:GetAttribute("Blocking") then return end
	if isAttacking or comboCooldown then return end
	isAttacking = true
	character:SetAttribute("Attacking", true)
	local humanoid = character:FindFirstChildOfClass("Humanoid")
	if humanoid then
		humanoid.WalkSpeed = 5
		if idleTrack then idleTrack:Stop() end
		attackCount = attackCount + 1
		local index = attackCount
		if index > #attackAnimationIds then index = #attackAnimationIds end
		local attackAnim = Instance.new("Animation")
		attackAnim.AnimationId = attackAnimationIds[index]
		local currentAttack = humanoid:LoadAnimation(attackAnim)
		currentAttack:Play()
		attackSound:Play()
		delay(0.2, function()
			local replicatedStorage = game:GetService("ReplicatedStorage")
			local hitboxTemplate = replicatedStorage:WaitForChild("sword_hitbox")
			local hitbox = hitboxTemplate:Clone()
			hitbox.Anchored = false
			hitbox.CanCollide = false
			local hrp = character:FindFirstChild("HumanoidRootPart")
			if hrp then
				hitbox.CFrame = hrp.CFrame * CFrame.new(0, 0, -3)
				local weld = Instance.new("WeldConstraint")
				weld.Part0 = hrp
				weld.Part1 = hitbox
				weld.Parent = hitbox
			else
				hitbox.CFrame = handle.CFrame * CFrame.new(0, 0, 3)
			end
			local hitHumanoids = {}
			hitbox.Touched:Connect(function(hit)
				local hitHumanoid = hit.Parent:FindFirstChildOfClass("Humanoid")
				if not hitHumanoid and hit.Parent.Parent then
					hitHumanoid = hit.Parent.Parent:FindFirstChildOfClass("Humanoid")
				end
				if hitHumanoid and not hit:IsDescendantOf(character) and not hitHumanoids[hitHumanoid] then
					hitHumanoids[hitHumanoid] = true
					local damage = 10
					local hitCharacter = hitHumanoid.Parent
					if hitCharacter:GetAttribute("Blocking") then
						damage = damage / 2
					end
					hitHumanoid:TakeDamage(damage)
				end
			end)
			hitbox.Parent = workspace
			game:GetService("Debris"):AddItem(hitbox, 0.25)
		end)
		currentAttack.Stopped:Connect(function()
			if humanoid and defaultWalkSpeed then
				humanoid.WalkSpeed = defaultWalkSpeed
			end
			isAttacking = false
			character:SetAttribute("Attacking", false)
			if character:FindFirstChildOfClass("Humanoid") then
				local idleAnim = Instance.new("Animation")
				idleAnim.AnimationId = idleAnimationId
				idleTrack = humanoid:LoadAnimation(idleAnim)
				idleTrack.Looped = true
				idleTrack:Play()
			end
			lastAttackFinished = tick()
			if attackCount >= #attackAnimationIds then
				startCooldown()
			else
				delay(0.5, function()
					if tick() - lastAttackFinished >= 0.5 and not isAttacking then
						startCooldown()
					end
				end)
			end
		end)
	else
		isAttacking = false
		character:SetAttribute("Attacking", false)
	end
end
local function onUnequipped()
	local character = tool.Parent
	if character then
		local humanoid = character:FindFirstChildOfClass("Humanoid")
		if humanoid and defaultWalkSpeed then
			humanoid.WalkSpeed = defaultWalkSpeed
		end
	end
	if idleTrack then
		idleTrack:Stop()
		idleTrack = nil
	end
	isAttacking = false
	attackCount = 0
	comboCooldown = false
end
tool.Equipped:Connect(onEquipped)
tool.Activated:Connect(onActivated)
tool.Unequipped:Connect(onUnequipped)

Sword (Local Script):

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local blockEvent = ReplicatedStorage:WaitForChild("BlockEvent")
local UserInputService = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local anim = Instance.new("Animation")
anim.AnimationId = "rbxassetid://82686361042666"
local track = humanoid:LoadAnimation(anim)
local playing = false
UserInputService.InputBegan:Connect(function(input, gameProcessed)
	if gameProcessed then return end
	if character:FindFirstChild("ClassicSword") and input.KeyCode == Enum.KeyCode.F and not playing then
		if character:GetAttribute("Attacking") then return end
		blockEvent:FireServer(true)
		track:Play()
		track.Looped = true
		playing = true
	end
end)
UserInputService.InputEnded:Connect(function(input, gameProcessed)
	if character:FindFirstChild("ClassicSword") and input.KeyCode == Enum.KeyCode.F then
		track:Stop()
		playing = false
		blockEvent:FireServer(false)
	end
end)

Again, any idea what’s happen? Thanks!