Need help fixing the Pathfinding script

I’m making a game that involves interaction with NPCs. and one of the NPC types is “Neutral”
all they are doing basically wandering around aimlessly and then reacting to the surrounding event

Now back to my problem. Normally I could just use MoveTo() + math.Random to just make them wander around but with my fascination with pathfinding and from my experience it is not as good as using PathFindingService

Another problem is that I don’t want to copy and paste the script into every copy of the NPC I wish to have pathfinding because of the optimization issue

So I make sure to pack all NPC into a folder called “NPC” with each of them having Tags corresponding to their type (in this case “Neutral”)

With the help of the amazing Tutorial by notzeussz I manage to implement the code into something like a cheap version of OOP script but at the moment it only controls one NPC which is the reason I made this post

Summary of my goal

  1. single Server script (if possible) that control all the npc with Tag “Neutral”
  2. Each npc having random time they’ll start “Wandering” if they all start walking at the same time It will just look weird and too robotic to my liking
  3. Each npc having their own random path and not just go at the same point

The Script
local pfs = game:GetService("PathfindingService")
local cs = game:GetService("CollectionService")

local MAX_RETRIES = 5
local RETRY_COOLDOWN = 5
local YIELDING = false

local Agent = {
	AgentRadius = 3,
	AgentHeight = 6,
	AgentCanJump = true,
	AgentCanClimb = true,
	Costs = {
		Danger = math.huge
	}
}

local model
local humanoid
local humanoidRootPart

local path = pfs:CreatePath(Agent)
local reachedConnection
local pathBlockedConnection

function GetNPC()
	for _, npc in pairs(workspace.NPC:GetChildren()) do
		if npc:WaitForChild("Humanoid") and npc.Humanoid.Health > 0 and npc:HasTag("Neutral") then
			return npc
		end
	end
end

local function CreateRandomGoal()
	return GetNPC():WaitForChild("HumanoidRootPart").Position + Vector3.new(math.random(-30,30), math.random(-3,3), math.random(-30,30))
end

function walkTo(targetPosition, yieldable)
	local RETRY_NUM = 0
	local success, errorMessage
	humanoid = GetNPC():WaitForChild("Humanoid")
	humanoidRootPart = GetNPC():WaitForChild("HumanoidRootPart")

	repeat
		RETRY_NUM += 1
		success, errorMessage = pcall(path.ComputeAsync, path, humanoidRootPart.Position, targetPosition)
		if not success then
			warn("Pathfind compute path error: "..errorMessage)
			task.wait(RETRY_COOLDOWN)
		end
	until success == true or RETRY_NUM > MAX_RETRIES

	if success then
		if path.Status == Enum.PathStatus.Success then
			local waypoints = path:GetWaypoints()
			local currentWaypointIndex = 2

			if not reachedConnection then
				reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
					if reached and currentWaypointIndex < #waypoints then
						currentWaypointIndex += 1

						humanoid:MoveTo(waypoints[currentWaypointIndex].Position)
						if waypoints[currentWaypointIndex].Action == Enum.PathWaypointAction.Jump then
							humanoid.Jump = true
						end
					else
						reachedConnection:Disconnect()
						pathBlockedConnection:Disconnect()
						reachedConnection = nil
						pathBlockedConnection = nil
						YIELDING = false
					end
				end)
			end

			pathBlockedConnection = path.Blocked:Connect(function(waypointNumber)
				if waypointNumber > currentWaypointIndex then
					reachedConnection:Disconnect()
					pathBlockedConnection:Disconnect()
					reachedConnection = nil
					pathBlockedConnection = nil
					walkTo(workspace.EndGoal.Position, true)
				end
			end)

			humanoid:MoveTo(waypoints[currentWaypointIndex].Position)
			if waypoints[currentWaypointIndex].Action == Enum.PathWaypointAction.Jump then
				humanoid.Jump = true
			end

			if yieldable then
				YIELDING = true
				repeat 
					task.wait()
				until YIELDING == false
			end
		else
			return 
		end
	else
		warn("Pathfind compute retry maxed out, error: "..errorMessage)
		return
	end

end

while task.wait(math.random(10,20)) do
	local Goal = CreateRandomGoal()
	walkTo(Goal, true)
end