Introduction
Hello fellow scripters! I am making a simple customer system for my (bad) game.
How it’s supposed to work
When the npc spawns in the map, it will loop through all the seats and check if they are available, if it does then it proceeds, if it doesn’t then the NPC gets :Destroyed() and the selected seated will be set to nil.
The Issue
Sometimes, the checks do pass, but the NPC just spawns and stays there, no movement at all
Things you should know
I would like to note that this pathfinding system uses the SimplePath module made by Wicked_Wizard.
The Code
local ServerStorage = game:GetService("ServerStorage")
local SimplePath = require(ServerStorage.SimplePath)
local TweenService = game:GetService("TweenService")
local ChatService = game:GetService("Chat")
local MenuItems = {"Burger", "Hot Dog", "Soda", "Water", "Coffee", "Soup", "Cooked Chicken"}
local ChatOptions = {"Hurry up!", "I'm gonna fall asleep waiting for my food!", "Tell the cooks to hurry up before I leave!", "Can you cook any faster!", "My food is still not here!", "I knew I should have ordered food from ChatGPT!", "Who let these guys cook, because they are doing a terrible job right now!"}
local RateMin = script:WaitForChild("Min")
local RateMax = script:WaitForChild("Max")
for i,v in pairs(game:GetService("Workspace"):WaitForChild("NPC Pathfinding"):GetChildren()) do
if v:IsA("BasePart") then
local Value = Instance.new("BoolValue")
Value.Name = "Taken"
Value.Value = false
Value.Parent = v
end
end
local function SpawnCar()
local CarCoroutine = coroutine.create(function()
wait(math.random(4,8))
local Cars = ServerStorage:WaitForChild("Cars"):GetChildren()
local Selected_Car = Cars[math.random(1,#Cars)]:Clone()
Selected_Car.Parent = game:GetService("Workspace"):WaitForChild("NPCS")
local Tween = TweenService:Create(Selected_Car.PrimaryPart, TweenInfo.new(10), {CFrame = Selected_Car.PrimaryPart.CFrame - Vector3.new(1000,0,0)})
Tween:Play()
Tween.Completed:Wait()
Selected_Car:Destroy()
end)
coroutine.resume(CarCoroutine)
end
local function SpawnCustomer()
local NPCS = ServerStorage:WaitForChild("NPCS"):GetChildren()
local Selected_NPC = NPCS[math.random(1,#NPCS)]:Clone()
local Selected_Item = MenuItems[math.random(1,#MenuItems)]
local Billboard = ServerStorage:WaitForChild("BillboardGui"):Clone()
local ProximityPrompt = Instance.new("ProximityPrompt")
ProximityPrompt.RequiresLineOfSight = false
ProximityPrompt.Enabled = false
ProximityPrompt.HoldDuration = 0.5
ProximityPrompt.ActionText = "Give Item"
ProximityPrompt.ObjectText = "Customer"
ProximityPrompt.Parent = Selected_NPC
Billboard.Enabled = false
Billboard:WaitForChild("Frame"):WaitForChild("TextLabel").Text = Selected_Item
Billboard.Parent = Selected_NPC:WaitForChild("Head")
local Entrance = game:GetService("Workspace"):WaitForChild("Map"):WaitForChild("NPC Start")
local function GetSeat()
local NPC_Seats = game:GetService("Workspace"):WaitForChild("NPC Pathfinding"):GetChildren()
local availableSeats = {}
for i, seat in ipairs(NPC_Seats) do
if not seat.Taken.Value then
table.insert(availableSeats, seat)
end
end
if #availableSeats > 0 then
local selectedSeat = availableSeats[math.random(1, #availableSeats)]
selectedSeat.Taken.Value = true
Current_Seat = selectedSeat
else
Current_Seat = nil
return
end
end
GetSeat()
for i,v in pairs(Selected_NPC:GetChildren()) do
if v:IsA("BasePart") then
v.CollisionGroup = "Players"
end
end
-- || NPC Spawns ||
if Current_Seat == nil then Selected_NPC:Destroy() return end
local Customer_Seat = Current_Seat
Selected_NPC:PivotTo(Entrance.CFrame)
Selected_NPC.Parent = workspace.NPCS
local Seat_Path = SimplePath.new(Selected_NPC)
Seat_Path:Run(Customer_Seat)
Seat_Path.Reached:Wait()
task.wait(0.5)
Selected_NPC:PivotTo(Customer_Seat.Seat.CFrame)
Selected_NPC:FindFirstChildOfClass("Humanoid").Sit = true
Selected_NPC.HumanoidRootPart.Anchored = true
local HasWarned = false
local WarnedTwice = false
local NPC_Patience_Timer = 0
local NPC_Max_Time = 5
ProximityPrompt.Enabled = true
Billboard.Enabled = true
local function NPC_Leave()
if Current_Seat == nil then Selected_NPC:Destroy() return end
ProximityPrompt.Enabled = false
Billboard.Enabled = false
wait(0.5)
Selected_NPC:PivotTo(Customer_Seat.Seat.CFrame)
Selected_NPC.HumanoidRootPart.Anchored = false
Selected_NPC.Humanoid.Sit = false
local NPC_Leave_Path = SimplePath.new(Selected_NPC)
NPC_Leave_Path:Run(Entrance)
NPC_Leave_Path.Blocked:Connect(function()
NPC_Leave_Path:Run(Entrance)
end)
NPC_Leave_Path.Error:Connect(function()
NPC_Leave_Path:Run(Entrance)
end)
NPC_Leave_Path.Reached:Connect(function()
Selected_NPC:Destroy()
Current_Seat.Taken.Value = false
end)
end
ProximityPrompt.Triggered:Connect(function(Player)
local Character = Player.Character or Player.CharacterAdded:Wait()
local Tool = Character:FindFirstChildOfClass("Tool")
if Tool and Tool.Name == Selected_Item then
ChatService:Chat(Selected_NPC.Head, "Thank you!", Enum.ChatColor.White)
Player.leaderstats.Money.Value += 15
Tool:Destroy()
NPC_Leave()
else
local Failed_Snd = ServerStorage:WaitForChild("Failed"):Clone()
Failed_Snd.Parent = Selected_NPC:WaitForChild("HumanoidRootPart")
Failed_Snd:Play()
ChatService:Chat(Selected_NPC.Head, "That's not what I wanted", Enum.ChatColor.White)
NPC_Leave()
end
end)
local NPC_Timer_Thread = coroutine.create(function()
while task.wait(1) do
NPC_Patience_Timer += 1
if NPC_Patience_Timer == NPC_Max_Time / 2 and not HasWarned then
HasWarned = true
local Selected_Message = ChatOptions[math.random(1,#ChatOptions)]
ChatService:Chat(Selected_NPC:WaitForChild("Head"), Selected_Message, Enum.ChatColor.White)
elseif NPC_Patience_Timer >= NPC_Max_Time and not WarnedTwice then
WarnedTwice = true
ChatService:Chat(Selected_NPC:WaitForChild("Head"), "I'm leaving!", Enum.ChatColor.White)
NPC_Leave()
break
end
end
end)
coroutine.resume(NPC_Timer_Thread)
end
while task.wait(math.random(RateMin.Value, RateMax.Value)) do
RateMin.Value = script.Min.Value
RateMax.Value = script.Max.Value
SpawnCustomer()
SpawnCar()
end