Why does my script NPC become dumber over time?

I want the script to work as smoothly as it can
Over time my NPC attacker script becomes slower and starts walking closer and then away from me over and over.
I’ve tried check if it was a memory leak and stuff but it didn’t fix it.
I’ll also take any suggestions to impove my code since I know it’s a little messy.

--//CODED BY TRUNGNHAN11!

local BasicEnemyAI = {}
BasicEnemyAI.__index = BasicEnemyAI

local MovementAnimations = game.ReplicatedStorage.ServerAnimations.SprintWalkAnimations
local UIS = game:GetService("UserInputService")
local RS = game:GetService("RunService")
local tweenservice = game:GetService("TweenService")
local playerlist = game.Players:GetPlayers()
local ReplicatedStorage = game.ReplicatedStorage

local MovementAnimations = game.ReplicatedStorage.ServerAnimations.SprintWalkAnimations
local RagdollService = require(game:GetService("ServerScriptService").RagdollStuff.RagdollService)
local Remotes: Folder = ReplicatedStorage:WaitForChild("Remotes")
local Server_Motors2 = Remotes:WaitForChild("ServertoServer_Motors")
local characterfolder = workspace:WaitForChild("Characters")
local BlockingNpcEvent = game:GetService("ServerStorage").NPCAttackRelated.BlockEvent

function BasicEnemyAI.new(character)
	local self = setmetatable({}, BasicEnemyAI)
	
	self.character = character
	self.Weapon = character:FindFirstChildOfClass("Tool")
	self.Weapontype = self.Weapon.Name
	self.equipped = false
	self.isBlocking = self.character:GetAttribute("IsBlocking")
	self.IsDashing = false
	self.Humanoid = character:WaitForChild("Humanoid")
	if self.Humanoid.Health == 100 then
	self.Humanoid.Health = math.random(100,150)
	end
	self.Humanoid.MaxHealth = self.Humanoid.Health
	self.HumanoidRootPart = character:WaitForChild("HumanoidRootPart")
	self.Alarmed = false
	self.AlarmedFlag = false
	self.Walkdistance = 20
	self.Rundistance = 60
	self.stopdistance = nil
	if self.Weapontype == "Fist" then
	self.stopdistance = 6
	elseif self.Weapontype == "WoodSword" then
	self.stopdistance = 6.5
	end
	self.noticedistance = 120
	self.UniqueID = character:GetAttribute("UniqueID")
	self.CurrentAnimations = nil
	self.BlockAniTrack = nil
	self.DashCooldown = 4.5
	self.CJ = nil
	self.Hflag = true
	self.flag = true
	self.flag1 = true
	self.flag2 = false
	self.BlockFlag = false
	self.ChaseRagdoll = false
	self.speed = nil
	self.attackflag = false
	
	self.Humanoid:UnequipTools(self.Weapon)
	
	self:loadAnimations()
	
	self:connectEvents()
	
	self.alignorientation = Instance.new("AlignOrientation")
	self.alignorientation.Parent = self.HumanoidRootPart
	self.alignorientation.Mode = Enum.OrientationAlignmentMode.OneAttachment
	self.alignorientation.Attachment0 = self.HumanoidRootPart.RootAttachment
	self.alignorientation.PrimaryAxisOnly = true
	self.alignorientation.Responsiveness = 75
	self.alignorientation.MaxTorque = 1000000
	
	self.Humanoid.StateChanged:Connect(function(OldState, NewState)
		if NewState == Enum.HumanoidStateType.Running then
			self.CJ = true
		else
			self.CJ = false
		end
	end)
	
	return self
	
end

function BasicEnemyAI:isIdleAnimationPlaying(humanoid)

	local animator = humanoid:FindFirstChildOfClass("Animator")
	if not animator then
		warn("Animator not found in humanoid.")
		return false
	end


	local tracks = animator:GetPlayingAnimationTracks()


	for _, track in ipairs(tracks) do
		if track.Name == "Idle" then
			return true
		end
	end

	return false
end

function BasicEnemyAI:attack(Atype)
	local NPCATTACK = game:GetService("ServerStorage").NPCAttackRelated.AttackingEvent
	if self.attackflag == false then
		BlockingNpcEvent:Fire(self.character, false)
		self.attackflag = true
		if self.Weapontype == "Fist" then
			if Atype == 1 then
				NPCATTACK:Fire(self.character, 1, self.Weapontype)
			elseif Atype == 2 then
				NPCATTACK:Fire(self.character, 2, self.Weapontype)
			end
		elseif self.Weapontype == "WoodSword" then
			if Atype == 1 then
				NPCATTACK:Fire(self.character, 1, self.Weapontype)
			elseif Atype == 2 then
				NPCATTACK:Fire(self.character, 2, self.Weapontype)
			end
		end
		self.attackflag = false
	end
end

function BasicEnemyAI:StunCheck()
	for _, accessory in ipairs(self.character:GetChildren()) do
		if accessory:IsA("Accessory") and accessory.Name == "Stun" then
			return true
		end
	end
	return false
end

function BasicEnemyAI:ParryCheck()
	for _, accessory in ipairs(self.character:GetChildren()) do
		if accessory:IsA("Accessory") and accessory.Name == "ParriedStun" then
			return true
		end
	end
	return false
end

function BasicEnemyAI:M1Check()
	for _, accessory in ipairs(self.character:GetChildren()) do
		if accessory:IsA("Accessory") and accessory.Name == "LightAttack" then
			return true
		end
	end
	return false
end

function BasicEnemyAI:HeavyCheck()
	for _, accessory in ipairs(self.character:GetChildren()) do
		if accessory:IsA("Accessory") and accessory.Name == "HeavyAttack" then
			return true
		end
	end
	return false
end

function BasicEnemyAI:EnemyAttackCheck(target)
	for _, Highlight in ipairs(target:GetChildren()) do
		if Highlight:IsA("Highlight") then
			return true
		end
	end
	return false
end

function BasicEnemyAI:Dash(Direction)
	
local RollingNpcEvent = game:GetService("ServerStorage").NPCAttackRelated.RollingEvent
	
if self.CJ == true then
		if self.IsDashing == false and not self:M1Check() and not self:StunCheck() and not self:ParryCheck() and not self:HeavyCheck() then
			self.IsDashing = true
			RollingNpcEvent:Fire(self.character, self.IsDashing)
			local linearVelocity = Instance.new("LinearVelocity")
				linearVelocity.Attachment0 = self.HumanoidRootPart.RootAttachment
				linearVelocity.MaxForce = 25000
				linearVelocity.RelativeTo = Enum.ActuatorRelativeTo.Attachment0
				linearVelocity.Parent = self.HumanoidRootPart
						
				if Direction == "Forward" then
					self.AniDashForward:Play()
						linearVelocity.VectorVelocity = Vector3.new(0, 1, -45)
				elseif Direction == "Backward" then
					self.AniDashBackward:Play()
						linearVelocity.VectorVelocity = Vector3.new(0, 1, 45)
				elseif Direction == "Right" then
						linearVelocity.VectorVelocity = Vector3.new(30, 0, 0)
				elseif Direction == "Left" then
					linearVelocity.VectorVelocity = Vector3.new(-30, 0, 0)
				end
						
				task.wait(0.35)
				linearVelocity:Destroy()
				task.wait(self.DashCooldown)
			self.IsDashing = false	
		end
	end
end

function BasicEnemyAI:loadAnimations()
local MovementAnimations = ReplicatedStorage.ServerAnimations.SprintWalkAnimations
local DashAnimations = ReplicatedStorage.ServerAnimations.DashingAnimations
	
	self.AniDashForward = self.Humanoid:LoadAnimation(DashAnimations.RollAnimation)
	self.AniDashBackward = self.Humanoid:LoadAnimation(DashAnimations.RollAnimation)

	self.AniWalk = self.Humanoid:LoadAnimation(MovementAnimations.Walk)
	self.AniSprint = self.Humanoid:LoadAnimation(MovementAnimations.Sprint)

	if self.Weapontype == "Fist" then
		self.CurrentAnimations = ReplicatedStorage.ServerAnimations.FistAnimations
	elseif self.Weapontype == "WoodSword" then
		self.CurrentAnimations = ReplicatedStorage.ServerAnimations.WoodSwordAnimations
	end
	
	self.Idle = self.Humanoid:LoadAnimation(self.CurrentAnimations.Idle)
	self.BlockAniTrack = self.Humanoid:LoadAnimation(self.CurrentAnimations.Blocking)
	
end

function BasicEnemyAI:BlockAttack()
	local IsCurrentlyblocking = self.character:GetAttribute("IsBlocking")

	if self.equipped then
		if IsCurrentlyblocking then 
			self.BlockAniTrack:play()
		else
			self.BlockAniTrack:stop()
		end
	end
end


function BasicEnemyAI:FindNearestCharacter()

	local nearestcharacter = nil
	local distance = nil
	local direction = nil

	for I, character in pairs(characterfolder:GetChildren()) do
		
		local rootPart = character:FindFirstChild("HumanoidRootPart")
		
		local character = character
		if character and character ~= self.character and character:GetAttribute("IsEnemy") ~= self.character:GetAttribute("IsEnemy") and character.Humanoid.Health > 0 and character:GetAttribute("testing") == false then
			if rootPart ~= nil then
				local distanceVector = (character.HumanoidRootPart.Position - self.HumanoidRootPart.Position)
				if not nearestcharacter then
					nearestcharacter = character
					distance = distanceVector.Magnitude
					direction = distanceVector.Unit
				elseif distanceVector.Magnitude < distance then
					nearestcharacter = character
					distance = distanceVector.Magnitude
					direction = distanceVector.Unit
				end
			
			else
			
			end
		end
	end
	return nearestcharacter, distance, direction
end

function BasicEnemyAI:NoticedEvent()

	local nearestcharacter, distance, direction = self:FindNearestCharacter()
	
	if nearestcharacter:GetAttribute("IsEnemy") == self.character:GetAttribute("IsEnemy") or self.Humanoid:GetState() == Enum.HumanoidStateType.Jumping or self.Humanoid:GetState() == Enum.HumanoidStateType.Freefall or self.Humanoid:GetState() == Enum.HumanoidStateType.PlatformStanding then return end

	local Hrp = nearestcharacter.HumanoidRootPart

	local targetPosition = Hrp.Position
	local direction = (targetPosition - self.HumanoidRootPart.Position).unit
	local lookAtCFrame = CFrame.new(self.HumanoidRootPart.Position, targetPosition)


	local tweenInfo = TweenInfo.new(1)
	local tween = tweenservice:Create(self.HumanoidRootPart, tweenInfo, { CFrame = lookAtCFrame })


	tween:Play()
	tween.Completed:Wait()
end

function BasicEnemyAI:FINDANDCHASECharacter()

local nearestcharacter, distance, direction = self:FindNearestCharacter()

local head = self.character:FindFirstChild("Head")

if head ~= nil then

	local vector1 = (nearestcharacter.Head.Position - head.Position).Unit
	local elook = self.character.HumanoidRootPart.CFrame.LookVector
	local dot = elook:Dot(vector1)

	if nearestcharacter then

		local Hrp = nearestcharacter.HumanoidRootPart
		if self.AlarmedFlag == false then
			if self.Humanoid.Health ~= self.Humanoid.MaxHealth or dot > 0.3 then
				if distance <= self.Rundistance then
					self.Humanoid:EquipTool(self.Weapon)
					self.Alarmed = true
					self.AlarmedFlag = true
				elseif distance <= self.noticedistance then
					self:NoticedEvent()
					self.Humanoid:EquipTool(self.Weapon)
					self.Humanoid:MoveTo(Hrp.Position)
					self.Alarmed = true
					self.AlarmedFlag = true
				end
			end
		end
		local CharacterIsCurrentlyRagdoll = self.character:GetAttribute("Ragdolled")	
		if self.Humanoid.Health > 0 and nearestcharacter.Humanoid.Health > 0 and CharacterIsCurrentlyRagdoll == false then
			local TargetIsCurrentlyRagdoll = nearestcharacter:GetAttribute("Ragdolled")
			local TargetIsCurrentlyStaggered = nearestcharacter:GetAttribute("Staggered")
			local IsStaggered = self.character:GetAttribute("Staggered")
				if not self:StunCheck() and not IsStaggered and not self:ParryCheck() and not self:M1Check() and not self:HeavyCheck() and self.Alarmed and self.equipped == true and ((self.ChaseRagdoll == true) or (TargetIsCurrentlyRagdoll == false and self.ChaseRagdoll == false)) then
					self:BlockAttack()
					if self:isIdleAnimationPlaying(self.Humanoid) == false then
						self.Idle:play()
					end
				if distance <= self.Rundistance and not self:M1Check() and not IsStaggered and not self:StunCheck() and not self:ParryCheck() and not self:HeavyCheck() and not self.character:GetAttribute("Staggered") and not self.character:GetAttribute("IsBlocking") then
					local diff = nearestcharacter.HumanoidRootPart.Position - self.HumanoidRootPart.Position
					local angle = math.atan2(-diff.X, -diff.Z)

					self.alignorientation.CFrame = CFrame.Angles(0, angle, 0)
				end
				if distance <= (self.stopdistance - (self.stopdistance / 4)) and not IsStaggered then
					self.Humanoid:Move(-direction)
				elseif distance < self.stopdistance and not IsStaggered and dot > 0.8 and TargetIsCurrentlyStaggered == true and not self:HeavyCheck() and not self:M1Check() then
					if self.Weapontype == "Fist" then
						if self.Hflag == true then
							self.Hflag = false
							task.wait(0.5)
							self:attack(2)
							task.wait(0.5)
							self.Hflag = true
						end
				elseif self.Weapontype == "WoodSword" then
						if self.Hflag == true then
							self.Hflag = false
							task.wait(0.5)
							self:attack(2)
							self.ChaseRagdoll = true
							task.wait(1.5)
							self:attack(2)
							task.wait(0.5)
							self.ChaseRagdoll = false
							self.Hflag = true
						end
					end
					
				elseif distance < 50 and dot > 0.8 and self:EnemyAttackCheck(nearestcharacter) and not IsStaggered then
					self.Humanoid:Move(Vector3.new(0,0,0))
						if self.BlockFlag == false then
							self.BlockFlag = true
							if self.IsDashing == false and not self:M1Check() and not IsStaggered and not self:StunCheck() and not self:ParryCheck() and not self:HeavyCheck() and not self.character:GetAttribute("Staggered") and not self.character:GetAttribute("IsBlocking") and not nearestcharacter:GetAttribute("Ragdolled") and 2 == 2 then
								self.Humanoid:Move(Vector3.new(0, 0, 0)) 
								if math.random(1,2) == 2 then
									BlockingNpcEvent:Fire(self.character , true)
								else
									task.wait(0.1)
									BlockingNpcEvent:Fire(self.character , true)
								end
							else
								self.Humanoid:Move(Vector3.new(0, 0, 0)) 
									task.wait(0.4)
									BlockingNpcEvent:Fire(self.character , false)
								end
							self.BlockFlag = false
						end
				elseif distance < self.stopdistance and dot > 0.8 and self.flag1 and not self:HeavyCheck() and not IsStaggered and not self:M1Check() and not self.IsBlocking and not self.BlockFlag and not self.character:GetAttribute("CantBlock") and self.character:GetAttribute("CanAttack") then
					self.Humanoid:Move(Vector3.new(0, 0, 0)) 
						if self.flag == true then
							self.flag = false
							if not self.IsBlocking then
							self:attack(1)
							end
								if math.random(1, 20) == 5 then
									self.Humanoid:Move(Vector3.new(0, 0, 0)) 
									self.flag1 = false
									self.flag2 = true
									self.flag = false
								end
							self.flag = true
						end
				elseif distance < self.stopdistance and dot > 0.8 and self.flag2 and not self:M1Check() and not IsStaggered and not self:HeavyCheck() and not self.IsBlocking and not self.BlockFlag and not self.character:GetAttribute("CantBlock") and self.character:GetAttribute("CanAttack") then
					self.Humanoid:Move(Vector3.new(0, 0, 0))
						if self.flag == true then
							self.Humanoid:Move(Vector3.new(0, 0, 0)) 
							self.flag = false
							if not self.IsBlocking then
								--self:attack(2)
							end
							self.flag2 = false
							self.flag1 = true
							self.flag = false
							task.wait(0.1)
							self.flag = true
						end
				elseif distance <= self.Walkdistance and not self.IsBlocking and not self:M1Check() and not IsStaggered and not self:HeavyCheck() and not self.character:GetAttribute("CantBlock") and self.character:GetAttribute("CanAttack") then
					if self.BlockFlag == false then
						self.BlockFlag = true
						task.wait(0.3)
						BlockingNpcEvent:Fire(self.character , false)
						self.BlockFlag = false
					end
					self.Humanoid.WalkSpeed = 15
					self.Humanoid:Move(direction)
				elseif distance <= self.Rundistance and not self.IsBlocking and not self:M1Check() and not IsStaggered and not self:HeavyCheck() and not self.character:GetAttribute("CantBlock") and self.character:GetAttribute("CanAttack") then
					if self.BlockFlag == false then
						self.BlockFlag = true
						task.wait(0.3)
						BlockingNpcEvent:Fire(self.character, false)
						self.BlockFlag = false
					end
					if math.random(1,5) == 5 then
						self:Dash("Forward")
					end
					self.Humanoid.WalkSpeed = 20
					self.Humanoid:Move(direction)
				else
					self.Humanoid.WalkSpeed = 15
					self.Humanoid:Move(Vector3.new(0,0,0))
				end
			else
				self.Humanoid.WalkSpeed = 15
				self.Humanoid:Move(Vector3.new(0,0,0))
			end
		end
	end
	else
end
end

function BasicEnemyAI:connectEvents()
	
	self.Humanoid.Running:Connect(function(speed)
		self.speed = speed
		if speed >= 17.5 then
			self.AniWalk:Stop()
			self.AniSprint:Play()
		elseif speed > 5 then
			self.AniSprint:Stop()
			self.AniWalk:Play()
		else
			self.AniWalk:Stop()
			self.AniSprint:Stop()
		end
	end)
	
	self.Weapon.Equipped:Connect(function()
		self:motor6d()
		self.equipped = true
		self.isBlocking = false
		self.Idle:play()
	end)
	
	self.Weapon.Unequipped:Connect(function()
		self.equipped = false
		self.isBlocking = false
		self.Idle:stop()
	end)
	
	RS.Heartbeat:Connect(function()
		self:FINDANDCHASECharacter()
	end)
end

function BasicEnemyAI:motor6d()
	if self.Weapon:FindFirstChildOfClass("Configuration") and self.Weapon:FindFirstChildOfClass("Configuration").Name == "6D_Config" then
		local Configuration: Configuration = self.Weapon:WaitForChild("6D_Config")

			for _, Motor_Config: Configuration in Configuration:GetChildren() do

				if Motor_Config:IsA("Configuration") then
						Server_Motors2:Fire(nil ,self.character ,self.Weapon)
				end

			end
	end
end

function BasicEnemyAI:Clear_Traces(Tool)

	if Tool:FindFirstChildOfClass("Configuration") and Tool:FindFirstChildOfClass("Configuration").Name == "6D_Config" then

		local Configuration: Configuration = Tool:WaitForChild("6D_Config")

		for _, Motor_Config: Configuration in Configuration:GetChildren() do

			if Motor_Config:IsA("Configuration") then

				for _, Old_Motor: Motor6D in Motor_Config:GetChildren() do

					Old_Motor:Destroy()

				end

			end

		end

	end

end



return BasicEnemyAI

^ What I want it to be all the time

^ What happens after like 3 minutes

2 Likes