Need help with npc shop system

I need help making this look it works once but when a new npc spawns it does not work like it stop at the points for a little bit Here’s the script local plot = script.Parent
local npcSpawn = plot.Steps:WaitForChild(“NPCSpawn”)
local shopPoint = plot.Steps:WaitForChild(“ShopPoint”)
local stopPoint = plot.Steps:WaitForChild(“StopPoint”)
local WalkPoint1 = plot.Steps:WaitForChild(“WalkPoint1”)
local WalkPoint2 = plot.Steps:WaitForChild(“WalkPoint2”)
local WalkPoint3 = plot.Steps:WaitForChild(“WalkPoint3”)
local WalkPoint4 = plot.Steps:WaitForChild(“WalkPoint4”)
local WalkPoint5 = plot.Steps:WaitForChild(“WalkPoint5”)
local WalkPoint6 = plot.Steps:WaitForChild(“WalkPoint6”)
local WalkPoint7 = plot.Steps:WaitForChild(“WalkPoint7”)
local WalkPoint8 = plot.Steps:WaitForChild(“WalkPoint8”)
local cashPad = plot:WaitForChild(“CashPad”)
local npcFolderRoot = game.ReplicatedStorage:WaitForChild(“CustomerNPCs”)
local moneyPopupTemplate = game.ReplicatedStorage:WaitForChild(“MoneyPopup”)

local isSpawning = false

– Ensure CashPad attribute exists
if cashPad:GetAttribute(“MoneyStored”) == nil then
cashPad:SetAttribute(“MoneyStored”, 0)
end

– ===== NPC Configuration =====
local npcConfig = {
NormalNPCs = {chance = 0.7, min = 10, max = 25},
VIPNPCs = {chance = 0.25, min = 100, max = 250},
SuperVIPNPCs = {chance = 0.01, min = 500, max = 750}
}

– ===== NPC Pools =====
local npcPool = {}
local preloadedNPCs = {}

for folderName, cfg in pairs(npcConfig) do
npcPool[folderName] = {}
local folder = npcFolderRoot:FindFirstChild(folderName)
if folder then
preloadedNPCs[folderName] = {}
for _, npcModel in pairs(folder:GetChildren()) do
table.insert(preloadedNPCs[folderName], npcModel)
for i = 1, 2 do
local clone = npcModel:Clone()
clone.Parent = nil
table.insert(npcPool[folderName], clone)
end
end
end
end

– ===== Choose a customer =====
local function chooseCustomer()
local totalWeight = 0
for _, cfg in pairs(npcConfig) do
totalWeight += cfg.chance
end

local roll = math.random() * totalWeight
local cumulative = 0
local chosenFolder

for folderName, cfg in pairs(npcConfig) do
	cumulative += cfg.chance
	if roll <= cumulative then
		chosenFolder = folderName
		break
	end
end

if not chosenFolder or not preloadedNPCs[chosenFolder] then
	return nil, 0, nil
end

local npcModels = preloadedNPCs[chosenFolder]
if #npcModels == 0 then
	return nil, 0, nil
end

local npcModel = npcModels[math.random(1, #npcModels)]
local cfg = npcConfig[chosenFolder]
local earned = math.random(cfg.min, cfg.max)

return npcModel, earned, chosenFolder

end

– ===== Get NPC from pool =====
local function getNPC(model, folderName)
local npc
if #npcPool[folderName] > 0 then
npc = table.remove(npcPool[folderName])
npc.Parent = plot.CustomerFolder
else
npc = model:Clone()
npc.Parent = plot.CustomerFolder
end

npc:SetPrimaryPartCFrame(CFrame.new(npcSpawn.Position) * CFrame.Angles(0, math.rad(180), 0))

local humanoid = npc:FindFirstChildOfClass("Humanoid")
if humanoid then
	humanoid.Health = humanoid.MaxHealth
	humanoid.WalkSpeed = 9
end

return npc

end

– ===== Recycle NPC =====
local function recycleNPC(npc, folderName)
npc.Parent = nil
table.insert(npcPool[folderName], npc)
end

– ===== Spawn a single customer =====
local function spawnCustomer()

if not plot:GetAttribute("Occipied") then return end
if isSpawning then return end
isSpawning = true

local npcModel, earned, folderName = chooseCustomer()
if not npcModel then
	isSpawning = false
	return
end

local npc = getNPC(npcModel, folderName)
local humanoid = npc:FindFirstChildOfClass("Humanoid")

local animator = humanoid:FindFirstChildOfClass("Animator")

local walkAnim = Instance.new("Animation")
walkAnim.AnimationId = "rbxassetid://100621370842384"

local walkTrack
if animator then
	walkTrack = animator:LoadAnimation(walkAnim)
end

local function playWalk()
	if walkTrack and not walkTrack.IsPlaying then
		walkTrack:Play()
	end
end

local function stopWalk()
	if walkTrack and walkTrack.IsPlaying then
		walkTrack:Stop()
	end
end

--================================
-- idle animation
-- ===============================

local IdleAnim = Instance.new("Animation")
IdleAnim.AnimationId = "rbxassetid://120677824080558"

local idleTrack
if animator then
	idleTrack = animator:LoadAnimation(IdleAnim)
end

local function PlayIdle()
	if idleTrack and not idleTrack.IsPlaying then
		idleTrack:Play()
	end
end

local function StopIdle()
	if idleTrack and idleTrack.IsPlaying then
		idleTrack:Stop()
	end
end


if humanoid then
	-- Walk to shop
	
	wait(9)
	
	playWalk()
	humanoid:MoveTo(WalkPoint1.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint2.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint3.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint4.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint5.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint6.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint7.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint8.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint8.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint8.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint8.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint8.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint8.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(shopPoint.Position)
	humanoid.MoveToFinished:Wait()
	stopWalk()
	PlayIdle()

	-- PAY AT SHOP
	cashPad:SetAttribute("MoneyStored", cashPad:GetAttribute("MoneyStored") + earned)
	print(`"Earned From:", [{npc}] amount [{earned}]`)

	-- Floating money popup
	local popup = moneyPopupTemplate:Clone()
	popup.Adornee = npc.PrimaryPart
	popup.TextLabel.Text = "+" .. earned
	popup.Parent = workspace

	spawn(function()
		local duration = 2
		local startPos = popup.StudsOffset
		local endPos = startPos + Vector3.new(0, 2, 0)
		local steps = 20
		local textLabel = popup.TextLabel

		for i = 1, steps do
			local alpha = i / steps
			popup.StudsOffset = startPos:Lerp(endPos, alpha)
			textLabel.TextTransparency = alpha
			task.wait(duration / steps)
		end

		wait(7)
		popup:Destroy()
	end)

	-- Wait at shop (simulate shopping)
	task.wait(7)
	
	StopIdle()
	playWalk()
	humanoid:MoveTo(WalkPoint8.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint7.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint6.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint5.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint4.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint3.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint2.Position)
	humanoid.MoveToFinished:Wait()
	
	humanoid:MoveTo(WalkPoint1.Position)
	humanoid.MoveToFinished:Wait()
	
	-- Walk to exit
	humanoid:MoveTo(stopPoint.Position)
	humanoid.MoveToFinished:Wait()
	stopWalk()

	-- Recycle NPC
	recycleNPC(npc, folderName)
end

task.wait(math.random(2, 6))
isSpawning = false

end

– ===== Main loop =====
task.spawn(function()
task.wait(math.random(13, 25))
while true do
if plot:GetAttribute(“Occipied”) then
spawnCustomer()
end
task.wait(math.random(2, 6))
end
end) also heres the recording https://youtu.be/qXXIJy_OWcs

  1. Put this in Help and Feedback > Scripting Support ]

  2. If you want people to actually help you, format your code correctly using the “Preformatted Text” button. No one is reasonably going to read this.

1 Like