Advertisement
Graizy

My Restaurant script

Aug 6th, 2022
668
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 52.30 KB | None | 0 0
  1. if not getconnections then return end
  2. for i,v in next, getconnections(game.Players.LocalPlayer.Idled) do
  3. v:Disable()
  4. end
  5.  
  6. local petNet = loadstring(game:HttpGet("https://rawscripts.net/raw/Pet-Simulator-X!-PSX-Safe-Networking-3732"))()
  7.  
  8. local Food = petNet:getPath("Food")
  9. local Entity = petNet:getPath("Entity")
  10. local Customer = petNet:getPath("Customer")
  11. local Waiter = petNet:getPath("Waiter")
  12. local Appliance = petNet:getPath("Appliance")
  13. local Bakery = petNet:getPath("Bakery")
  14. local player = game:GetService("Players").LocalPlayer
  15.  
  16. local _L = require(game:GetService("ReplicatedStorage"):WaitForChild("Framework",10):WaitForChild("Library",10));
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.  
  24. Food.RandomFoodChoice = function(customerOwnerUID, customerOwnerID, isRichCustomer, isPirateCustomer, isNearTree)
  25. local spoof = Food.new("45", customerOwnerUID, customerOwnerID, true, true)
  26. spoof.IsGold = true
  27. return spoof
  28. end
  29.  
  30. function Entity:FadeTransparency(targetTransparency, finishedCallback)
  31.  
  32. local processedCallback = false
  33.  
  34. for _, child in ipairs(self.model:GetDescendants()) do
  35. if child.Name == "HumanoidRootPart" or child.Name == "CenterPart" or not child:IsA("BasePart") then
  36. continue
  37. end
  38. if child.Name == "Head" and self.ID == "25" then
  39. continue
  40. end
  41. _L.Functions.FastTween(
  42. child,
  43. {Transparency = targetTransparency},
  44. {0.0000002, "Quad", "Out"}
  45. ).Completed:Connect(function()
  46. -- race condition? god I hope not
  47. if finishedCallback and not processedCallback then
  48. processedCallback = true
  49. finishedCallback()
  50. end
  51. end)
  52. end
  53.  
  54. end
  55.  
  56.  
  57. function Entity:WalkThroughWaypoints(voxelpoints, waypoints, startX, startZ)
  58. self:PlayLoadedAnimation("walking")
  59.  
  60. if #voxelpoints == 0 then
  61. return
  62. end
  63.  
  64. if not self:BelongsToMyBakery() and self.stateData.walkingThroughWaypoints then
  65. repeat wait() until self.isDeleted or not self.stateData.walkingThroughWaypoints
  66. if self.isDeleted then
  67. return
  68. end
  69. end
  70. if not self:BelongsToMyBakery() then
  71. self.stateData.walkingThroughWaypoints = true
  72. end
  73.  
  74. -- replication fix?
  75. if not self:BelongsToMyBakery() then
  76. self.model.HumanoidRootPart.Anchored = false
  77. end
  78.  
  79. for i, v in ipairs(waypoints) do
  80.  
  81. self.model.HumanoidRootPart.CFrame = CFrame.new(v)
  82. --self.humanoid.MoveToFinished:Wait()
  83. local oldX, oldZ = self.xVoxel, self.zVoxel
  84. self.xVoxel = voxelpoints[i].x
  85. self.zVoxel = voxelpoints[i].y
  86.  
  87. -- no need for position table updates if it's not my client.
  88. -- only the owner of the bakery does pathfinding calculations.
  89. -- if replication occurs, the host client sends the pathfinding
  90. -- data.... it is not recalculated
  91. if self:BelongsToMyBakery() then
  92. self:GetMyFloor():BroadcastNPCPositionChange(self, oldX, oldZ)
  93. end
  94. end
  95.  
  96. if not self:BelongsToMyBakery() then
  97. self.stateData.walkingThroughWaypoints = false
  98. end
  99.  
  100. self:StopLoadedAnimation("walking")
  101. self:PlayLoadedAnimation("idle")
  102. end
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109. function Customer:ChangeToWaitForOrderState()
  110.  
  111. if self.state ~= "WalkingToSeat" then
  112. return
  113. end
  114.  
  115. local seatLeaf = self:EntityTable()[self.stateData.seatUID]
  116. local tableLeaf = self:EntityTable()[self.stateData.tableUID]
  117.  
  118. if seatLeaf.isDeleted or tableLeaf.isDeleted then
  119. self:ForcedToLeave()
  120. return
  121. end
  122.  
  123. self:SetCustomerState("ThinkingAboutOrder")
  124.  
  125. -- make the humanoid sit
  126. self:SitInSeat(seatLeaf).Completed:Connect(function()
  127. self.humanoid:SetStateEnabled(Enum.HumanoidStateType.Seated, true)
  128.  
  129. -- change voxel position to match the seat
  130. self.xVoxel = seatLeaf.xVoxel
  131. self.zVoxel = seatLeaf.zVoxel
  132.  
  133. coroutine.wrap(function()
  134.  
  135. -- start reading the menu
  136. self:ReadMenu()
  137. if self.isDeleted or self.state ~= "ThinkingAboutOrder" then
  138. return
  139. end
  140.  
  141. -- stop reading the menu
  142. self:StopReadingMenu()
  143.  
  144. -- advance to next state
  145. self:SetCustomerState("DecidedOnOrder")
  146.  
  147. -- only set my entire group to ready to order when everybody has decided on the order
  148. local myGroup = {self}
  149. for _, partner in ipairs(self.stateData.queueGroup) do
  150. if not partner.isDeleted then
  151. table.insert(myGroup, partner)
  152. end
  153. end
  154. local foundUndecidedMember = false
  155. for _, groupMember in ipairs(myGroup) do
  156. if groupMember.state ~= "DecidedOnOrder" then
  157. foundUndecidedMember = true
  158. break
  159. end
  160. end
  161.  
  162. -- if the entire group is ready, then have them say it in sync
  163. if not foundUndecidedMember then
  164. for _, groupMember in ipairs(myGroup) do
  165. groupMember:ReadyToOrder()
  166. end
  167. end
  168.  
  169. end)()
  170. end)
  171.  
  172. end
  173.  
  174.  
  175. function Customer:ChangeToEatingState()
  176.  
  177. coroutine.wrap(function()
  178. if self.state == "EatingFood" then
  179. return
  180. end
  181.  
  182. -- first, check for silverware
  183. local myFloor = self:GetMyFloor()
  184. table.sort(myFloor.silverwareTrays, function(a, b)
  185. local aDist = math.abs(self.xVoxel - a.xVoxel) + math.abs(self.zVoxel - a.zVoxel)
  186. local bDist = math.abs(self.xVoxel - b.xVoxel) + math.abs(self.zVoxel - b.zVoxel)
  187. return aDist < bDist
  188. end)
  189. table.sort(myFloor.goldSilverwareTrays, function(a, b)
  190. local aDist = math.abs(self.xVoxel - a.xVoxel) + math.abs(self.zVoxel - a.zVoxel)
  191. local bDist = math.abs(self.xVoxel - b.xVoxel) + math.abs(self.zVoxel - b.zVoxel)
  192. return aDist < bDist
  193. end)
  194.  
  195. self:SetCustomerState("EatingFood")
  196.  
  197. -- if there's a path to me, delete it
  198. if self.stateData.pathToMe then
  199. _L.Variables.MyBakery:CleanupAnimatedPath()
  200. self.stateData.pathToMe = nil
  201. end
  202.  
  203. local didSaladCheck = false
  204. local function checkForSaladBars(isWalkingFromSilverware, doWalkBackToSeat)
  205. didSaladCheck = true
  206. local didWalkToSalad = false
  207. -- walk to salad bar sometimes
  208. local isWalkingToSaladBar = false
  209. for _, saladBar in ipairs(myFloor.saladBars) do
  210. if math.random() < 0.20 then
  211.  
  212. if not isWalkingFromSilverware then
  213. self:StandUp()
  214. end
  215.  
  216. isWalkingToSaladBar = true
  217. didWalkToSalad = true
  218. local sx, sy, sz = self.xVoxel, self.yVoxel, self.zVoxel
  219. self:WalkToPoint(saladBar.xVoxel, saladBar.yVoxel, saladBar.zVoxel, function()
  220. if saladBar.isDeleted then
  221. isWalkingToSaladBar = false
  222. self:ForcedToLeave()
  223. return
  224. end
  225.  
  226. self:FaceEntity(saladBar)
  227. _L.SFX.Play(5708685167, saladBar.model.PrimaryPart)
  228. _L.Network.Fire("AwardTipWithVerification", self.UID, saladBar.UID, self.stateData.foodOrder.ID, isWalkingFromSilverware)
  229.  
  230. if doWalkBackToSeat then
  231. self:WalkToPoint(sx, sy, sz, function()
  232. isWalkingToSaladBar = false
  233. if self.stateData.mySeat.isDeleted then
  234. self:ForcedToLeave()
  235. return
  236. end
  237. self:SitInSeat(self.stateData.mySeat)
  238. end)
  239. else
  240. isWalkingToSaladBar = false
  241. end
  242. end)
  243. break
  244. end
  245. end
  246. if isWalkingToSaladBar then
  247. repeat wait() until not isWalkingToSaladBar
  248. end
  249. return didWalkToSalad
  250. end
  251.  
  252. local didDessertCheck = false
  253. local function checkForDessertBars(isWalkingFromSilverware, doWalkBackToSeat)
  254. didDessertCheck = true
  255. local didWalkToDessert = false
  256. -- walk to salad bar sometimes
  257. local isWalkingToDessertBar = false
  258. for _, dessertBar in ipairs(myFloor.dessertBars) do
  259. if math.random() < 0.20 then
  260.  
  261. if not isWalkingFromSilverware then
  262. self:StandUp()
  263. end
  264.  
  265. isWalkingToDessertBar = true
  266. didWalkToDessert = true
  267. local sx, sy, sz = self.xVoxel, self.yVoxel, self.zVoxel
  268. self:WalkToPoint(dessertBar.xVoxel, dessertBar.yVoxel, dessertBar.zVoxel, function()
  269. if dessertBar.isDeleted then
  270. isWalkingToDessertBar = false
  271. self:ForcedToLeave()
  272. return
  273. end
  274.  
  275. self:FaceEntity(dessertBar)
  276. _L.SFX.Play(5708685167, dessertBar.model.PrimaryPart)
  277. _L.Network.Fire("AwardTipWithVerification", self.UID, dessertBar.UID, self.stateData.foodOrder.ID, isWalkingFromSilverware)
  278.  
  279. if doWalkBackToSeat then
  280. self:WalkToPoint(sx, sy, sz, function()
  281. isWalkingToDessertBar = false
  282. if self.stateData.mySeat.isDeleted then
  283. self:ForcedToLeave()
  284. return
  285. end
  286. self:SitInSeat(self.stateData.mySeat)
  287. end)
  288. else
  289. isWalkingToDessertBar = false
  290. end
  291. end)
  292. break
  293. end
  294. end
  295. if isWalkingToDessertBar then
  296. repeat wait() until not isWalkingToDessertBar
  297. end
  298. return didWalkToDessert
  299. end
  300.  
  301. -- create food model for the customer
  302. if not self.stateData.foodOrder then
  303. self:ForcedToLeave()
  304. return
  305. end
  306. local myTable = self:EntityTable()[self.stateData.tableUID]
  307. local mySeat = self:EntityTable()[self.stateData.seatUID]
  308. if not myTable or not mySeat then
  309. _L.Print("CRITICAL: COULDN'T FIND CUSTOMERS TABLE WHEN EATING", true)
  310. return
  311. end
  312. local myFloor = myTable:GetMyFloor()
  313. local worldPos = myFloor:WorldPositionFromVoxel(mySeat:GetFacePosition())
  314. local tableRoot = myTable.model.PrimaryPart
  315. local tableTop = Vector3.new(worldPos.X, tableRoot.Position.Y + tableRoot.Size.Y/2, worldPos.Z)
  316. local foodOffset = (-1.1)*mySeat:GetFaceDirection() + Vector3.new(0, self.stateData.foodOrder.data.model.PrimaryPart.Size.Y/2, 0)
  317. local foodCF = CFrame.new(tableTop + foodOffset)
  318. self:CreateMyFoodModel(foodCF)
  319.  
  320. local isWalkingToTray = false
  321. local wasWalkingToTray = false
  322. local trayUID = false
  323. local forkModel = nil
  324. local spoonModel = nil
  325. local welds = {}
  326. local function walkToTray(tray)
  327. isWalkingToTray = true
  328. wasWalkingToTray = true
  329. trayUID = tray.UID
  330. self:StandUp()
  331. local sx, sy, sz = self.xVoxel, self.yVoxel, self.zVoxel
  332. self:WalkToPoint(tray.xVoxel, tray.yVoxel, tray.zVoxel, function()
  333. if tray.isDeleted then
  334. isWalkingToTray = false
  335. self:ForcedToLeave()
  336. return
  337. end
  338. local sounds = {5601560377, 5601560515, 5601560641}
  339. _L.SFX.Play(sounds[math.random(#sounds)], tray.model.PrimaryPart)
  340. self:FaceEntity(tray)
  341.  
  342. if not checkForSaladBars(true, false) then
  343. checkForDessertBars(true, false)
  344. end
  345.  
  346. self:WalkToPoint(sx, sy, sz, function()
  347. isWalkingToTray = false
  348. if self.stateData.mySeat.isDeleted then
  349. self:ForcedToLeave()
  350. return
  351. end
  352. self:SitInSeat(self.stateData.mySeat)
  353.  
  354. -- hold silverware
  355. local isGold = tray.ID == "25"
  356. local function weldToHand(part, hand)
  357. local weld = Instance.new("Weld", part)
  358. weld.Part0 = part
  359. weld.Part1 = hand
  360. weld.C0 = CFrame.Angles(-math.pi/2, 0, 0)
  361. table.insert(welds, weld)
  362. end
  363. if isGold then
  364. forkModel = game.ReplicatedStorage.Assets.Models["Luxury Fork"]:Clone()
  365. spoonModel = game.ReplicatedStorage.Assets.Models["Luxury Spoon"]:Clone()
  366. forkModel.Parent = self.model
  367. spoonModel.Parent = self.model
  368. weldToHand(forkModel, self.model.RightHand)
  369. weldToHand(spoonModel, self.model.LeftHand)
  370. else
  371. forkModel = game.ReplicatedStorage.Assets.Models["Default Fork"]:Clone()
  372. spoonModel = game.ReplicatedStorage.Assets.Models["Default Spoon"]:Clone()
  373. forkModel.Parent = self.model
  374. spoonModel.Parent = self.model
  375. weldToHand(forkModel, self.model.RightHand)
  376. weldToHand(spoonModel, self.model.LeftHand)
  377. end
  378. end)
  379. end)
  380. end
  381.  
  382. if #myFloor.goldSilverwareTrays > 0 then
  383. walkToTray(myFloor.goldSilverwareTrays[1])
  384. elseif #myFloor.silverwareTrays > 0 then
  385. local goodRoll = false
  386. for i = 1, #myFloor.silverwareTrays do
  387. if true then
  388. goodRoll = true
  389. end
  390. end
  391. if goodRoll then
  392. walkToTray(myFloor.silverwareTrays[1])
  393. end
  394. end
  395.  
  396. if isWalkingToTray then
  397. repeat wait() until not isWalkingToTray
  398. end
  399.  
  400. if not didSaladCheck then
  401. if not checkForSaladBars(false, true) then
  402. checkForDessertBars(false, true)
  403. end
  404. end
  405.  
  406. -- play eating animation
  407. self:PlayLoadedAnimation("eating")
  408.  
  409. -- play served sound
  410. _L.SFX.Play(5205174537, self.model.PrimaryPart, nil, 0.60)
  411.  
  412. -- play eating looped sound
  413. local pitch = 1 + (math.random() - 0.50)*0.10
  414. local eatSound = math.random() < 0.50 and 5029600710 or 5029600543
  415. self.stateData.loopedEatingSound = _L.SFX.Play(eatSound, self.model.PrimaryPart, pitch, 0.85, 35, nil, true)
  416.  
  417. coroutine.wrap(function()
  418.  
  419. -- eat timing is determined by the server. //no, it's not, -bluwud
  420. local forceLeaveTip = true
  421. if not self.isDeleted and self.state == "EatingFood" then
  422. if self.stateData.loopedEatingSound then
  423. self.stateData.loopedEatingSound = self.stateData.loopedEatingSound:Destroy()
  424. end
  425. self.stateData.foodOrder:ChangeToDirtyDish()
  426. self:StopLoadedAnimation("eating")
  427. self:ChangeToReadyToExitState(forceLeaveTip)
  428.  
  429. if forkModel then
  430. forkModel:Destroy()
  431. spoonModel:Destroy()
  432. for _, weld in ipairs(welds) do
  433. weld:Destroy()
  434. end
  435. welds = {}
  436. end
  437. end
  438. end)()
  439. end)()
  440.  
  441. end
  442.  
  443.  
  444.  
  445. function Customer:ChangeToExitingState(wasForcedToLeave, forcedToLeaveTip)
  446.  
  447. if self.isDeleted then
  448. return
  449. end
  450.  
  451. self.leaving = true
  452. self:SetCustomerState("WalkingToExit")
  453.  
  454. -- remove customer from table
  455. local myTable = self:EntityTable()[self.stateData.tableUID]
  456. if myTable and not myTable.isDeleted then
  457. myTable:RemoveCustomerFromTable(self)
  458. end
  459.  
  460. local myFloor = self:GetMyFloor()
  461.  
  462. coroutine.wrap(function()
  463. if wasForcedToLeave then
  464. self:TimedEmoji("MadEmoji", 2)
  465. else
  466. if math.random() < 0.30 or _L.Variables.MyBakery.isTutorial then
  467. self:TimedEmoji("HappyEmoji", 2.5)
  468. end
  469. end
  470.  
  471. -- make humanoid stand
  472. self:StandUp()
  473.  
  474. local function goToExitAndLeave()
  475. self:WalkToNewFloor(_L.Variables.MyBakery.floors[1], function()
  476. local vx, vy, vz = _L.Variables.MyBakery:GetCustomerStartVoxel(1)
  477. self:WalkToPoint(vx, vy, vz, function()
  478. self:FadeTransparency(1, function()
  479. self:LeaveBakery()
  480. end)
  481. end, nil, true)
  482. end)
  483. end
  484.  
  485. local isLeavingTip = false
  486. local isGoingForGumball = false
  487. local isGoingForCandy = false
  488. local isGoingForArcade = false
  489. local isGoingForPopcorn = false
  490. local isGoingForSoda = false
  491. local isGoingForBowl = false
  492.  
  493. -- is there a tip jar on this floor? if so, roll to leave tip
  494. if not wasForcedToLeave then
  495. local tipJars = myFloor:GetEntitiesFromClassAndSubClass("Appliance", "Tip Jar")
  496. if #tipJars > 0 then
  497. for _, tipJar in ipairs(tipJars) do
  498. local tipChance = tipJar.ID == "14" and 0.05 or tipJar.ID == "19" and 0.50 or tipJar.ID == "26" and 0.40 or 0
  499. if true or forcedToLeaveTip or self:IsVIPCustomer() then
  500. isLeavingTip = true
  501. self:WalkToPoint(tipJar.xVoxel, tipJar.yVoxel, tipJar.zVoxel, function()
  502. if tipJar.isDeleted or self.isDeleted or not self.stateData or not self.stateData.foodOrder then
  503. goToExitAndLeave()
  504. return
  505. end
  506.  
  507. -- happy emoji at tip jar
  508. self:TimedEmoji("VeryHappyEmoji", 2.5)
  509.  
  510. _L.Network.Fire("AwardTipWithVerification", self.UID, tipJar.UID, self.stateData.foodOrder.ID)
  511. _L.SFX.Play(5839737230, tipJar.model.PrimaryPart)
  512.  
  513. self:FaceEntity(tipJar)
  514. goToExitAndLeave()
  515. end)
  516. break
  517. end
  518. end
  519. end
  520. end
  521.  
  522. if not isLeavingTip then
  523. local candyBowls = myFloor:GetEntitiesFromClassAndSubClass("Appliance", "CandyBowl")
  524. if #candyBowls > 0 then
  525. for _, bowl in ipairs(candyBowls) do
  526. if true and bowl.level and bowl.level > 0 then
  527. isGoingForBowl = true
  528. self:WalkToPoint(bowl.xVoxel, bowl.yVoxel, bowl.zVoxel, function()
  529. if bowl.isDeleted or not self.stateData or not self.stateData.foodOrder or bowl.level <= 0 then
  530. goToExitAndLeave()
  531. return
  532. end
  533.  
  534. -- happy emoji at tip jar
  535. self:TimedEmoji("VeryHappyEmoji", 2.5)
  536.  
  537. _L.Network.Fire("AwardTipWithVerification", self.UID, bowl.UID, self.stateData.foodOrder.ID)
  538. _L.SFX.Play(5057746151, bowl.model.PrimaryPart)
  539.  
  540. self:FaceEntity(bowl)
  541. goToExitAndLeave()
  542. end)
  543. break
  544. end
  545. end
  546. end
  547. end
  548.  
  549. -- only go for gumball if we're not leaving a tip
  550. if not isLeavingTip and not isGoingForBowl then
  551.  
  552. local gumballMachines = myFloor:GetEntitiesFromClassAndSubClass("Appliance", "GumballMachine")
  553. if #gumballMachines > 0 then
  554. for _, gumballMachine in ipairs(gumballMachines) do
  555. if true then
  556. isGoingForGumball = true
  557.  
  558. local fx, fy, fz = gumballMachine:GetFacePosition()
  559. if not myFloor:IsValidVoxel(fx, fy, fz) then
  560. fx, fy, fz = gumballMachine.xVoxel, gumballMachine.yVoxel, gumballMachine.zVoxel
  561. end
  562. self:WalkToPoint(fx, fy, fz, function()
  563. if gumballMachine.isDeleted or self.isDeleted then
  564. goToExitAndLeave()
  565. return
  566. end
  567.  
  568. -- gumball tip
  569. if self.stateData.foodOrder then
  570. _L.Network.Fire("AwardTipWithVerification", self.UID, gumballMachine.UID, self.stateData.foodOrder.ID)
  571. end
  572.  
  573. -- gumball sound
  574. _L.SFX.Play(5205171179, gumballMachine.model.PrimaryPart.Position)
  575.  
  576. -- gumball emoji
  577. self:TimedEmoji("VeryHappyEmoji", 2.5)
  578. self:FaceEntity(gumballMachine)
  579. goToExitAndLeave()
  580. end)
  581. break
  582. end
  583. end
  584. end
  585.  
  586. end
  587.  
  588. if not isLeavingTip and not isGoingForGumball and not isGoingForBowl then
  589. local candyMachines = myFloor:GetEntitiesFromClassAndSubClass("Appliance", "CandyMachine")
  590. if #candyMachines > 0 then
  591. for _, candyMachine in ipairs(candyMachines) do
  592. if true then
  593. isGoingForCandy = true
  594.  
  595. local fx, fy, fz = candyMachine:GetFacePosition()
  596. if not myFloor:IsValidVoxel(fx, fy, fz) then
  597. fx, fy, fz = candyMachine.xVoxel, candyMachine.yVoxel, candyMachine.zVoxel
  598. end
  599. self:WalkToPoint(fx, fy, fz, function()
  600. if candyMachine.isDeleted or self.isDeleted then
  601. goToExitAndLeave()
  602. return
  603. end
  604.  
  605. _L.SFX.Play(5601560734, candyMachine.model.PrimaryPart)
  606.  
  607. -- gumball tip
  608. if self.stateData.foodOrder then
  609. _L.Network.Fire("AwardTipWithVerification", self.UID, candyMachine.UID, self.stateData.foodOrder.ID)
  610. end
  611.  
  612. -- gumball emoji
  613. self:TimedEmoji("VeryHappyEmoji", 2.5)
  614. self:FaceEntity(candyMachine)
  615. goToExitAndLeave()
  616. end)
  617. break
  618. end
  619. end
  620. end
  621. end
  622.  
  623. -- check for popcorn machine
  624. if not isLeavingTip and not isGoingForGumball and not isGoingForCandy and not isGoingForBowl then
  625.  
  626. local popcornMachines = myFloor:GetEntitiesFromClassAndSubClass("Appliance", "PopcornMachine")
  627. if #popcornMachines > 0 then
  628. for _, popcornMachine in ipairs(popcornMachines) do
  629. if true then
  630. isGoingForPopcorn = true
  631.  
  632. local fx, fy, fz = popcornMachine:GetFacePosition()
  633. if not myFloor:IsValidVoxel(fx, fy, fz) then
  634. fx, fy, fz = popcornMachine.xVoxel, popcornMachine.yVoxel, popcornMachine.zVoxel
  635. end
  636. self:WalkToPoint(fx, fy, fz, function()
  637. if popcornMachine.isDeleted or self.isDeleted then
  638. goToExitAndLeave()
  639. return
  640. end
  641.  
  642. _L.SFX.Play(5625433552, popcornMachine.model.PrimaryPart)
  643.  
  644. -- popcorn tip
  645. if self.stateData.foodOrder then
  646. _L.Network.Fire("AwardTipWithVerification", self.UID, popcornMachine.UID, self.stateData.foodOrder.ID)
  647. end
  648.  
  649. -- gumball emoji
  650. self:TimedEmoji("VeryHappyEmoji", 2.5)
  651. self:FaceEntity(popcornMachine)
  652. goToExitAndLeave()
  653. end)
  654. break
  655. end
  656. end
  657. end
  658.  
  659. end
  660.  
  661. -- check for soda machine
  662. if not isLeavingTip and not isGoingForGumball and not isGoingForCandy and not isGoingForPopcorn and not wasForcedToLeave and not isGoingForBowl then
  663. local sodaMachines = myFloor:GetEntitiesFromClassAndSubClass("Appliance", "SodaMachine")
  664. if #sodaMachines > 0 then
  665. for _, sodaMachine in ipairs(sodaMachines) do
  666. if true then
  667. isGoingForSoda = true
  668.  
  669. local fx, fy, fz = sodaMachine:GetFacePosition()
  670. if not myFloor:IsValidVoxel(fx, fy, fz) then
  671. fx, fy, fz = sodaMachine.xVoxel, sodaMachine.yVoxel, sodaMachine.zVoxel
  672. end
  673. self:WalkToPoint(fx, fy, fz, function()
  674. if sodaMachine.isDeleted or self.isDeleted then
  675. goToExitAndLeave()
  676. return
  677. end
  678.  
  679. _L.SFX.Play(5708685354, sodaMachine.model.PrimaryPart)
  680.  
  681. -- soda tip
  682. if self.stateData.foodOrder then
  683. _L.Network.Fire("AwardTipWithVerification", self.UID, sodaMachine.UID, self.stateData.foodOrder.ID)
  684. end
  685.  
  686. -- gumball emoji
  687. self:TimedEmoji("VeryHappyEmoji", 2.5)
  688. self:FaceEntity(sodaMachine)
  689. goToExitAndLeave()
  690. end)
  691. break
  692. end
  693. end
  694. end
  695. end
  696.  
  697. -- check for arcade machine
  698. if not isLeavingTip and not isGoingForGumball and not isGoingForCandy and not isGoingForPopcorn and not isGoingForSoda and not wasForcedToLeave and not isGoingForBowl then
  699. local arcadeMachines = myFloor:GetEntitiesFromClassAndSubClass("Furniture", "ArcadeMachine")
  700. if #arcadeMachines > 0 then
  701. local indices = _L.Functions.RandomIndices(arcadeMachines)
  702. for _, index in ipairs(indices) do
  703. local arcadeMachine = arcadeMachines[index]
  704. if arcadeMachine.arcadeState ~= "Highscore" then
  705. continue
  706. end
  707. if arcadeMachine.busy then
  708. continue
  709. end
  710. arcadeMachine.busy = true
  711. isGoingForArcade = true
  712. local fx, fy, fz = arcadeMachine:GetFacePosition()
  713. if not myFloor:IsValidVoxel(fx, fy, fz) then
  714. fx, fy, fz = arcadeMachine.xVoxel, arcadeMachine.yVoxel, arcadeMachine.zVoxel
  715. end
  716. self:WalkToPoint(fx, fy, fz, function()
  717.  
  718. if arcadeMachine.isDeleted or self.isDeleted then
  719. goToExitAndLeave()
  720. return
  721. end
  722.  
  723. self:FaceEntity(arcadeMachine)
  724.  
  725. -- play game (halts thread until done)
  726. arcadeMachine:PlayGameWithCustomer(self)
  727.  
  728. arcadeMachine.busy = false
  729.  
  730. goToExitAndLeave()
  731.  
  732. end)
  733. break
  734. end
  735. end
  736. end
  737.  
  738. -- check for celebrity customer
  739. local isGoingForCelebrity = false
  740. (function()
  741. if isLeavingTip or isGoingForGumball or isGoingForCandy or isGoingForPopcorn or isGoingForArcade or isGoingForSoda or isGoingForBowl then
  742. return
  743. end
  744. if _L.Variables.MyBakery.nameCounters["Celebrity Customer"] == 0 then
  745. return
  746. end
  747.  
  748. local celebrity = _L.Variables.MyBakery:SearchForCelebrity()
  749. if not celebrity or celebrity.isDeleted or celebrity.stateData.celebrityApproachCount >= 3 then
  750. return
  751. end
  752.  
  753. local function isValidCelebState()
  754. local validCelebStates = {
  755. ThinkingAboutOrder = true,
  756. DecidedOnOrder = true,
  757. WaitingToOrder = true,
  758. WaitingForFood = true,
  759. EatingFood = true
  760. }
  761. return not celebrity.isDeleted and validCelebStates[celebrity.state]
  762. end
  763.  
  764. if not isValidCelebState() then
  765. return
  766. end
  767.  
  768. isGoingForCelebrity = true
  769. celebrity.stateData.celebrityApproachCount += 1
  770.  
  771. self:WalkToNewFloor(celebrity:GetMyFloor(), function()
  772. if not isValidCelebState() then
  773. if not celebrity.isDeleted then
  774. celebrity.stateData.celebrityApproachCount -= 1
  775. end
  776. goToExitAndLeave()
  777. return
  778. end
  779.  
  780. self:WalkToPoint(celebrity.xVoxel, celebrity.yVoxel, celebrity.zVoxel, function()
  781. if not isValidCelebState() then
  782. if not celebrity.isDeleted then
  783. celebrity.stateData.celebrityApproachCount -= 1
  784. end
  785. goToExitAndLeave()
  786. return
  787. end
  788.  
  789. celebrity.stateData.celebrityApproachCount -= 1
  790.  
  791. _L.SFX.Play(5278932469, celebrity.model.PrimaryPart.Position)
  792. self:FaceEntity(celebrity)
  793. self:TimedEmoji("Starstruck", 2.5)
  794. self:PlayLoadedAnimation("wave")
  795. goToExitAndLeave()
  796. end)
  797. end)
  798. end)()
  799. if not isLeavingTip and not isGoingForGumball and not isGoingForCelebrity and not isGoingForCandy and not isGoingForArcade and not isGoingForPopcorn and not isGoingForBowl then
  800. goToExitAndLeave()
  801. end
  802. end)()
  803. end
  804.  
  805.  
  806. function Waiter:StartActionLoop()
  807. coroutine.wrap(function()
  808. while not self.isDeleted do
  809. self:PerformAction()
  810. wait()
  811. end
  812. end)()
  813. end
  814.  
  815.  
  816. function Waiter:CheckForDishPickup()
  817.  
  818. local myFloor = self:GetMyFloor()
  819. local selectedDishChair, selectedDishChairFloor = nil
  820.  
  821. -- check other floors for dishes
  822. local indices = _L.Functions.RandomIndices(_L.Variables.MyBakery.floors)
  823.  
  824. --check my floor first
  825. if true then
  826. for i, index in ipairs(indices) do
  827. if index == myFloor.floorLevel then
  828. table.remove(indices, i)
  829. table.insert(indices, 1, myFloor.floorLevel)
  830. break
  831. end
  832. end
  833. end
  834.  
  835. for _, index in ipairs(indices) do
  836. local thisFloor = _L.Variables.MyBakery.floors[index]
  837. local dishIndices = _L.Functions.RandomIndices(thisFloor.dishChairs)
  838. for _, dishIndex in ipairs(dishIndices) do
  839. local dishChair = thisFloor.dishChairs[dishIndex]
  840. if dishChair.isDeleted or dishChair.stateData.flaggedByWaiterForDishPickup or not dishChair.stateData.dish or dishChair.stateData.dish.isDeleted then
  841. continue
  842. end
  843. selectedDishChair = dishChair
  844. selectedDishChairFloor = dishChair:GetMyFloor()
  845. break
  846. end
  847. if selectedDishChair then
  848. break
  849. end
  850. end
  851.  
  852. if not selectedDishChair then
  853. return false
  854. end
  855.  
  856. local dishwashers = myFloor:GatherDishwashersOnAnyFloor()
  857. if #dishwashers == 0 then
  858. return false
  859. end
  860.  
  861. -- chair that has an attached dish to go to
  862. local dishChair = selectedDishChair
  863. dishChair.stateData.flaggedByWaiterForDishPickup = true
  864.  
  865. local dishwasher = dishwashers[math.random(#dishwashers)]
  866. dishwasher.stateData.dishWasherTargetCount += 1
  867.  
  868. -- flag the dish with the targeted dishwasher
  869. dishChair.stateData.dish.flaggedDishwasherUID = dishwasher.UID
  870.  
  871. self.state = "WalkingToPickupDish"
  872.  
  873. self:WalkToNewFloor(dishChair:GetMyFloor(), function()
  874.  
  875. if dishChair.isDeleted or not dishChair.stateData.dish then
  876. dishwasher.stateData.dishWasherTargetCount -= 1
  877. self.state = "Idle"
  878. return
  879. end
  880.  
  881. self:WalkToPoint(dishChair.xVoxel, dishChair.yVoxel, dishChair.zVoxel, function()
  882.  
  883. if dishChair.isDeleted or not dishChair.stateData.dish then
  884. dishwasher.stateData.dishWasherTargetCount -= 1
  885. self.state = "Idle"
  886. return
  887. end
  888.  
  889. dishChair.stateData.flaggedByWaiterForDishPickup = false
  890.  
  891. if not dishChair.stateData.dish or dishChair.stateData.dish.isDeleted then
  892. dishwasher.stateData.dishWasherTargetCount -= 1
  893. self.state = "Idle"
  894. return
  895. end
  896.  
  897. -- dish is good. delete it and remove
  898. if dishChair.stateData.dish and dishChair.stateData.dish.model then
  899.  
  900. -- remove dishChair from available
  901. for i, dishChairEntry in ipairs(selectedDishChairFloor.dishChairs) do
  902. if dishChairEntry == selectedDishChair then
  903. table.remove(selectedDishChairFloor.dishChairs, i)
  904. break
  905. end
  906. end
  907.  
  908. -- stop the interact
  909. dishChair.stateData.dish:CleanupInteract()
  910.  
  911. -- play dish sound
  912. if dishChair.stateData.dish.model and dishChair.stateData.dish.model.PrimaryPart then
  913. local dishSounds = {5205173686, 5205173942}
  914. _L.SFX.Play(dishSounds[math.random(#dishSounds)], dishChair.stateData.dish.model:GetPrimaryPartCFrame().p)
  915. end
  916.  
  917. -- pick up the money and dish (if necessary)
  918. dishChair.stateData.dish:MoneyPickedUp()
  919. dishChair.stateData.dish:DestroyModel()
  920. dishChair.stateData.dish = nil
  921.  
  922. -- hold the dish I'm delivering
  923. self:HoldDirtyDish()
  924.  
  925. end
  926.  
  927. self:FaceEntity(dishChair)
  928.  
  929. if dishwasher.isDeleted then
  930. self:StopLoadedAnimation("hold")
  931. if self.stateData.heldDish then
  932. self.stateData.heldDish = self.stateData.heldDish:Destroy()
  933. end
  934. self.state = "Idle"
  935. return
  936. end
  937.  
  938. -- walk to the dishwasher to deposit
  939. -- TODO face direction
  940. self:WalkToNewFloor(dishwasher:GetMyFloor(), function()
  941.  
  942. if dishwasher.isDeleted then
  943. self:StopLoadedAnimation("hold")
  944. if self.stateData.heldDish then
  945. self.stateData.heldDish = self.stateData.heldDish:Destroy()
  946. end
  947. self.state = "Idle"
  948. return
  949. end
  950.  
  951. self:WalkToPoint(dishwasher.xVoxel, dishwasher.yVoxel, dishwasher.zVoxel, function()
  952.  
  953. -- put down the dish
  954. self:DropFood()
  955.  
  956. if dishwasher.isDeleted then
  957. self.state = "Idle"
  958. return
  959. end
  960. dishwasher:AddDish()
  961.  
  962. self:FaceEntity(dishwasher)
  963.  
  964. self:ResetAllStates()
  965.  
  966. end)
  967. end)
  968. end)
  969. end)
  970.  
  971. return true
  972.  
  973. end
  974.  
  975.  
  976. function Waiter:WalkToNewFloor(targetFloor, finishedCallback)
  977.  
  978. local currentFloor = self:GetMyFloor()
  979.  
  980. if not targetFloor or currentFloor.floorLevel == targetFloor.floorLevel then
  981. if finishedCallback then finishedCallback() end
  982. return
  983. end
  984.  
  985.  
  986. self:TransitionToDifferentFloor(targetFloor)
  987. if finishedCallback then
  988. finishedCallback()
  989. end
  990.  
  991. end
  992.  
  993. function Waiter:CheckForFoodDelivery()
  994.  
  995. -- gather all order stands
  996. local myFloor = self:GetMyFloor()
  997. local orderStands = myFloor:GatherOrderStandsWithDeliveryReady()
  998.  
  999. if #orderStands == 0 then
  1000.  
  1001. -- if there are no order stands on my floor, search for floors that might need help
  1002. local indices = _L.Functions.RandomIndices(_L.Variables.MyBakery.floors)
  1003. for _, index in ipairs(indices) do
  1004. local floor = _L.Variables.MyBakery.floors[index]
  1005. if floor ~= myFloor then
  1006. if not floor:HasAtLeastOneIdleStateOfClass("Waiter") then
  1007. -- gather order stands on this floor
  1008. orderStands = floor:GatherOrderStandsWithDeliveryReady()
  1009. if #orderStands > 0 then
  1010. break
  1011. end
  1012. end
  1013. end
  1014. end
  1015.  
  1016. -- STILL nothing? abort
  1017. if #orderStands == 0 then
  1018. return false
  1019. end
  1020. end
  1021.  
  1022. -- select a random order stand to deliver from
  1023. local orderStand = orderStands[math.random(#orderStands)]
  1024. if not orderStand then
  1025. return false
  1026. end
  1027.  
  1028. orderStand.stateData.foodReadyTargetCount = orderStand.stateData.foodReadyTargetCount + 1
  1029.  
  1030. self.state = "WalkingToPickupFood"
  1031.  
  1032. -- walk to the order stand
  1033. self:WalkToNewFloor(orderStand:GetMyFloor(), function()
  1034.  
  1035. -- no need to kick out the customer, they've already been removed.
  1036. -- just reset the waiter back to idle
  1037. if orderStand.isDeleted then
  1038. self.state = "Idle"
  1039. return
  1040. end
  1041.  
  1042. self:WalkToPoint(orderStand.xVoxel, orderStand.yVoxel, orderStand.zVoxel, function()
  1043.  
  1044. if orderStand.isDeleted then
  1045. self.state = "Idle"
  1046. return
  1047. end
  1048.  
  1049. orderStand.stateData.foodReadyTargetCount = orderStand.stateData.foodReadyTargetCount - 1
  1050.  
  1051. -- it's possible that the user already cleared the queue...
  1052. if #orderStand.stateData.foodReadyList == 0 then
  1053. self.state = "Idle"
  1054. return
  1055. end
  1056.  
  1057. -- grab some food off of the top of the queue
  1058. local selectedFoodOrder = orderStand.stateData.foodReadyList[1]
  1059. selectedFoodOrder.isGold = orderStand:IsGoldOrderStand() and math.random() < 0.05
  1060. table.remove(orderStand.stateData.foodReadyList, 1)
  1061. if selectedFoodOrder.isGold then
  1062. _L.SFX.Play(5370840758, orderStand.model.PrimaryPart)
  1063. end
  1064.  
  1065. -- delete this list item
  1066. selectedFoodOrder:DestroyPopupListItemUI()
  1067.  
  1068. -- the customer that I should deliver to...
  1069. local customerOfOrder = self:EntityTable()[selectedFoodOrder.customerOwnerUID]
  1070. if not customerOfOrder then
  1071. _L.Print("CRITICAL: customer owner of food not found", true)
  1072. self.state = "Idle"
  1073. return false
  1074. end
  1075.  
  1076.  
  1077. -- pause to face the order stand for a little bit
  1078. self:FaceEntity(orderStand)
  1079. -- hold the dish I'm delivering
  1080. self:HoldFood(selectedFoodOrder.ID, selectedFoodOrder.isGold)
  1081.  
  1082. self.state = "WalkingToDeliverFood"
  1083.  
  1084. if customerOfOrder.isDeleted then
  1085. self.state = "Idle"
  1086. self.stateData.heldDish = self.stateData.heldDish:Destroy()
  1087. return
  1088. end
  1089.  
  1090. -- walk to the customer to deliver...
  1091. self:WalkToNewFloor(customerOfOrder:GetMyFloor(), function()
  1092. self:WalkToPoint(customerOfOrder.xVoxel, customerOfOrder.yVoxel, customerOfOrder.zVoxel, function()
  1093.  
  1094. self:DropFood()
  1095.  
  1096. if customerOfOrder.isDeleted then
  1097. _L.Print("CRITICAL: walked to customer, but they were forced to leave. aborting", true)
  1098. self.state = "Idle"
  1099. return
  1100. end
  1101.  
  1102. customerOfOrder:ChangeToEatingState()
  1103.  
  1104. -- face the customer
  1105. self:FaceEntity(customerOfOrder)
  1106.  
  1107. -- award XP for delivering food
  1108. _L.Network.Fire("AwardWaiterExperienceForDeliveringOrderWithVerification", self.UID)
  1109. -- free the waiter back up
  1110. self.state = "Idle"
  1111. end)
  1112. end)
  1113. end)
  1114. end)
  1115.  
  1116. return true
  1117. end
  1118.  
  1119.  
  1120. function Waiter:CheckForCustomerOrder()
  1121.  
  1122. local myFloor = self:GetMyFloor()
  1123.  
  1124. -- find a customer that is waiting to order
  1125. local waitingCustomer = myFloor:GetCustomerWaitingToOrder()
  1126.  
  1127. if not waitingCustomer then
  1128.  
  1129. -- if there's no customer on my current floor, check if other floors need help
  1130. local indices = _L.Functions.RandomIndices(_L.Variables.MyBakery.floors)
  1131. for _, index in ipairs(indices) do
  1132. local floor = _L.Variables.MyBakery.floors[index]
  1133. if floor ~= myFloor then
  1134. if not floor:HasAtLeastOneIdleStateOfClass("Waiter") then
  1135. waitingCustomer = floor:GetCustomerWaitingToOrder()
  1136. if waitingCustomer then
  1137. break
  1138. end
  1139. end
  1140. end
  1141. end
  1142.  
  1143. -- still nothing? abort
  1144. if not waitingCustomer then
  1145. return false
  1146. end
  1147. end
  1148.  
  1149. self.state = "WalkingToTakeOrder"
  1150.  
  1151. -- find the entire customer group
  1152. local customerGroup = {waitingCustomer}
  1153. for _, customerPartner in ipairs(waitingCustomer.stateData.queueGroup) do
  1154. if customerPartner.state == "WaitingToOrder" and not customerPartner.waiterIsAttendingToFoodOrder then
  1155. table.insert(customerGroup, customerPartner)
  1156. end
  1157. end
  1158.  
  1159. -- tag debounce, not allowing other waiters to interfere
  1160. for _, seatedCustomer in ipairs(customerGroup) do
  1161. seatedCustomer.waiterIsAttendingToFoodOrder = true
  1162. end
  1163.  
  1164. local function untagGroup()
  1165. for _, seatedCustomer in ipairs(customerGroup) do
  1166. seatedCustomer.waiterIsAttendingToFoodOrder = false
  1167. end
  1168. end
  1169.  
  1170. -- walk to the seated group
  1171. local firstCustomer = customerGroup[1]
  1172. local groupTable = self:EntityTable()[firstCustomer.stateData.tableUID]
  1173. if not groupTable or groupTable.isDeleted then
  1174. self.state = "Idle"
  1175. return
  1176. end
  1177. local tx, ty, tz = groupTable.xVoxel, groupTable.yVoxel, groupTable.zVoxel
  1178.  
  1179. local customerFloor = firstCustomer:GetMyFloor()
  1180. self:WalkToNewFloor(customerFloor, function()
  1181. if firstCustomer.leaving or firstCustomer.isDeleted then
  1182. self.state = "Idle"
  1183. return
  1184. end
  1185. self:WalkToPoint(tx, ty, tz, function()
  1186.  
  1187. if firstCustomer.isDeleted or firstCustomer.leaving then
  1188. self.state = "Idle"
  1189. return
  1190. end
  1191.  
  1192. -- order stand to deposit the orders in
  1193. local orderStand = customerFloor:FindOrderStandOnAnyFloor()
  1194. if not orderStand then
  1195. _L.Print("CRITICAL: NO ORDER STAND FOUND!", true)
  1196. untagGroup()
  1197. self.state = "Idle"
  1198. self:TimedEmoji("ConcernedEmoji", 2)
  1199. return
  1200. end
  1201.  
  1202. -- stop interacting
  1203. local firstCustomer = customerGroup[1]
  1204. if firstCustomer then
  1205. firstCustomer:StopGroupEmoji()
  1206. firstCustomer:CleanupGroupInteract()
  1207. end
  1208.  
  1209. -- check for customers in the group still waiting to have their
  1210. -- order taken. it's possible that the user took one or
  1211. -- more of their orders
  1212. local groupOrder = {}
  1213. local tookOrdersFrom = {}
  1214. for _, seatedCustomer in ipairs(customerGroup) do
  1215. if seatedCustomer.state == "WaitingToOrder" then
  1216. table.insert(tookOrdersFrom, seatedCustomer)
  1217. groupOrder[seatedCustomer.UID] = _L.Food.RandomFoodChoice(seatedCustomer.UID, seatedCustomer.ID, seatedCustomer:IsRichCustomer(), seatedCustomer:IsPirateCustomer(), seatedCustomer.isNearTree)
  1218. seatedCustomer.state = "WaitingForFood"
  1219. seatedCustomer:StopChat()
  1220. end
  1221. end
  1222.  
  1223. -- if no orders are taken, abort
  1224. if #tookOrdersFrom == 0 then
  1225. self.state = "Idle"
  1226. return
  1227. end
  1228.  
  1229. -- take order animation
  1230. self:PlayLoadedAnimation("write")
  1231. for _, customer in ipairs(customerGroup) do
  1232. self:FaceEntity(customer)
  1233. end
  1234. self:StopLoadedAnimation("write")
  1235.  
  1236. self.state = "WalkingToDropoffOrder"
  1237.  
  1238. self:WalkToNewFloor(orderStand:GetMyFloor(), function()
  1239.  
  1240. if orderStand.isDeleted then
  1241. for _, customer in ipairs(customerGroup) do
  1242. customer:ForcedToLeave()
  1243. end
  1244. self.state = "Idle"
  1245. return
  1246. end
  1247.  
  1248. self:WalkToPoint(orderStand.xVoxel, orderStand.yVoxel, orderStand.zVoxel, function()
  1249.  
  1250. if orderStand.isDeleted then
  1251. for _, customer in ipairs(customerGroup) do
  1252. customer:ForcedToLeave()
  1253. end
  1254. self.state = "Idle"
  1255. return
  1256. end
  1257.  
  1258. -- deposit each of the orders
  1259. for _, orderedCustomer in ipairs(tookOrdersFrom) do
  1260. if orderedCustomer.isDeleted then
  1261. continue
  1262. end
  1263. orderedCustomer:ChangeToWaitingForFoodState(groupOrder[orderedCustomer.UID])
  1264. orderStand:AddFoodToQueue(groupOrder[orderedCustomer.UID])
  1265. end
  1266.  
  1267. -- award XP for taking an order
  1268. _L.Network.Fire("AwardWaiterExperienceForTakingOrderWithVerification", self.UID)
  1269.  
  1270. -- face deposit location
  1271. self:FaceEntity(orderStand)
  1272.  
  1273. -- free up the waiter for more actions
  1274. self.state = "Idle"
  1275.  
  1276. end)
  1277. end)
  1278.  
  1279. end)
  1280. end)
  1281.  
  1282. return true
  1283.  
  1284. end
  1285.  
  1286. function Waiter:CheckForQueuedCustomers()
  1287.  
  1288. if not _L.Variables.MyBakery.isOpen then
  1289. return false
  1290. end
  1291.  
  1292.  
  1293. local myFloor = self:GetMyFloor()
  1294.  
  1295. -- if I'm not on the first floor, only go to help if there is nobody
  1296. -- idle on the first floor
  1297. if myFloor.floorLevel ~= 1 then
  1298. if _L.Variables.MyBakery.floors[1]:HasAtLeastOneIdleStateOfClass("Waiter") then
  1299. return false
  1300. end
  1301.  
  1302. -- only allow myself to go de-queue a customer if there are 5 or less waiters
  1303. -- on the first floor. no need to overdo it.
  1304. if #_L.Variables.MyBakery.floors[1].waiters > 5 then
  1305. return false
  1306. end
  1307. end
  1308.  
  1309. -- search for the top of the queue customer group that is ready
  1310. -- to be seated
  1311. local readyCustomerGroup = nil
  1312. for _, customerGroup in ipairs(_L.Variables.MyBakery.customerQueue) do
  1313. if customerGroup[1].state == "WaitingForSeat" and not customerGroup[1].waiterIsAttendingToInQueue then
  1314. readyCustomerGroup = customerGroup
  1315. break
  1316. end
  1317. end
  1318.  
  1319. if not readyCustomerGroup then
  1320. return false
  1321. end
  1322.  
  1323. -- tag each customer as attended to
  1324. for _, customer in ipairs(readyCustomerGroup) do
  1325. customer.waiterIsAttendingToInQueue = true
  1326. end
  1327. local firstCustomer = readyCustomerGroup[1]
  1328.  
  1329. -- waiter is attending to me but I still haven't been seated? timeout
  1330. coroutine.wrap(function()
  1331. wait()
  1332. if #readyCustomerGroup == 0 then
  1333. return
  1334. end
  1335. if readyCustomerGroup[1].waiterIsAttendingToInQueue and readyCustomerGroup[1].state == "WaitingForSeat" then
  1336. --_L.Print("timeout successful")
  1337. for _, customer in ipairs(readyCustomerGroup) do
  1338. customer.waiterIsAttendingToInQueue = false
  1339. end
  1340. end
  1341. end)()
  1342.  
  1343. self.state = "WalkingToQueuedCustomerGroup"
  1344.  
  1345. -- walk to one of the customers in the queue group
  1346.  
  1347.  
  1348.  
  1349. -- it's possible that the user sends the customers to their
  1350. -- seat before we get there. if so, abort
  1351. if firstCustomer.state ~= "WaitingForSeat" or firstCustomer.stateData.busyWalking then
  1352. -- untag attending
  1353. for _, customer in ipairs(readyCustomerGroup) do
  1354. customer.waiterIsAttendingToInQueue = false
  1355. end
  1356. self:ResetAllStates()
  1357. return
  1358. end
  1359.  
  1360. -- stop user pings
  1361. firstCustomer:CleanupGroupInteract()
  1362. firstCustomer:StopGroupEmoji()
  1363.  
  1364. -- seat the customer group
  1365. _L.Variables.MyBakery:SeatQueuedCustomerGroup(firstCustomer)
  1366.  
  1367. -- update positioning
  1368. _L.Variables.MyBakery:UpdateCustomerQueuePositioning()
  1369.  
  1370. -- face the group
  1371. self:FaceEntity(firstCustomer)
  1372.  
  1373. -- free the waiter up
  1374. self.state = "Idle"
  1375.  
  1376. return true
  1377.  
  1378. end
  1379.  
  1380.  
  1381.  
  1382.  
  1383.  
  1384.  
  1385.  
  1386.  
  1387. local rng = Random.new()
  1388.  
  1389.  
  1390. function Bakery:AddCustomersToQueueIfNecessary(kickCustomerIfNecessary, UIDBatch)
  1391.  
  1392. -- helper function
  1393. local function goToSeat(customer, doNotPlaySound)
  1394. if customer.state ~= "WaitingForSeat" then
  1395. -- error sound
  1396. if not doNotPlaySound then
  1397. _L.Audio.Play(5074110087, player.PlayerGui)
  1398. end
  1399. return
  1400. end
  1401. customer:StopGroupEmoji()
  1402. customer:CleanupGroupInteract()
  1403.  
  1404. self:SeatQueuedCustomerGroup(customer)
  1405. self:UpdateCustomerQueuePositioning()
  1406.  
  1407. -- click sound
  1408. if not doNotPlaySound then
  1409. _L.Audio.Play(5074101610, player.PlayerGui)
  1410. end
  1411. end
  1412.  
  1413. -- max queue size of 4
  1414. if #self.customerQueue >= 4 then
  1415. return 0
  1416. end
  1417.  
  1418. -- every customer is initially on the first floor
  1419. local firstFloor = self.floors[1]
  1420.  
  1421. -- grab all available seats. search floors at random until a seat group is found
  1422. local selectedTable, selectedSeatGroup
  1423. local indices = _L.Functions.RandomIndices(_L.Variables.MyBakery.floors)
  1424. for _, index in ipairs(indices) do
  1425. local floor = self.floors[index]
  1426. selectedTable, selectedSeatGroup = floor:GetAvailableSeatGroupings()
  1427. if selectedTable and selectedSeatGroup then
  1428. break
  1429. end
  1430. end
  1431.  
  1432. if not (selectedTable and selectedSeatGroup) then
  1433.  
  1434. -- if we didn't find a seat and kickCustomerIfNecessary (for VIP customers), then
  1435. -- kick a random customer for the VIP customer
  1436. if kickCustomerIfNecessary then
  1437. local didKickCustomer = false
  1438. for _, floor in ipairs(self.floors) do
  1439. for _, customer in ipairs(floor.customers) do
  1440. if customer.state ~= "ReadyToExit" then
  1441. customer:ForcedToLeave()
  1442. didKickCustomer = true
  1443. break
  1444. end
  1445. end
  1446. if didKickCustomer then
  1447. break
  1448. end
  1449. end
  1450.  
  1451. end
  1452.  
  1453. return 0
  1454. end
  1455. local queueEntry = {}
  1456.  
  1457. local didPlayVIPCustomerSound = false
  1458.  
  1459. -- if a vip is forced (royal set), let the server know
  1460. local vipOverride = {}
  1461. local johnDoeOverride = {}
  1462. local pirateOverride = {}
  1463. local youtuberOverride = {}
  1464. local shadowOverride = {}
  1465. local corruptedVIPOverride = {}
  1466. local santaOverride = {}
  1467. local elfOverride = {}
  1468. local treeTable = {}
  1469.  
  1470. -- create customers to fill this seat grouping
  1471. local containsGhostOrSpecial = false
  1472. for i, seatGroup in pairs(selectedSeatGroup) do
  1473. local seat = seatGroup
  1474. local tabl = selectedTable
  1475.  
  1476. local forceVIPCustomer = false
  1477. local forceShadowCustomer = false
  1478. local forceJohnDoeCustomer = false
  1479. local forcePirateCustomer = false
  1480. local forceYoutuberCustomer = false
  1481. local forceSantaCustomer = false
  1482. local forceElfCustomer = false
  1483.  
  1484. -- look for a nearby christmas tree
  1485. local floor = self.floors[seat.floorLevel]
  1486. for _, entity in ipairs(floor:GetEntitiesFromClassAndSubClass("Furniture", "ChristmasTree")) do
  1487. local dist = math.sqrt(math.pow(entity.xVoxel - seat.xVoxel, 2) + math.pow(entity.zVoxel - seat.zVoxel, 2))
  1488. if dist < 4*math.sqrt(2)+0.1 then
  1489. treeTable[i] = true
  1490. break
  1491. end
  1492. end
  1493.  
  1494. -- royal table logic
  1495. local overrideUID = nil
  1496. if seat.ID == "43" and tabl.ID == "44" then
  1497. forceVIPCustomer = true
  1498. overrideUID = seat.UID
  1499. elseif seat.ID == "43" then
  1500. forceVIPCustomer = true
  1501. overrideUID = seat.UID
  1502. elseif tabl.ID == "44" then
  1503. forceVIPCustomer = true
  1504. overrideUID = tabl.UID
  1505. end
  1506.  
  1507. if forceVIPCustomer then
  1508. UIDBatch[i].ID = "13"
  1509. vipOverride[i] = overrideUID
  1510. end
  1511.  
  1512. -- royal halloween table logic
  1513. if not forceVIPCustomer then
  1514. if seat.ID == "98" and tabl.ID == "99" then
  1515. forceShadowCustomer = true
  1516. overrideUID = seat.UID
  1517. elseif seat.ID == "98" then
  1518. forceShadowCustomer = true
  1519. overrideUID = seat.UID
  1520. elseif tabl.ID == "99" then
  1521. forceShadowCustomer = true
  1522. overrideUID = tabl.UID
  1523. end
  1524. -- 1% chance for haunted customer, otherwise corrupted VIP
  1525. if forceShadowCustomer then
  1526. if true then
  1527. UIDBatch[i].ID = "25"
  1528. shadowOverride[i] = overrideUID
  1529. else
  1530. UIDBatch[i].ID = "26"
  1531. corruptedVIPOverride[i] = overrideUID
  1532. end
  1533. end
  1534. end
  1535.  
  1536. -- John Doe Table Logic
  1537. if not forceVIPCustomer then
  1538. if seat.ID == "216" and tabl.ID == "217" then
  1539. forceJohnDoeCustomer = true
  1540. overrideUID = seat.UID
  1541. elseif seat.ID == "216" then
  1542. forceJohnDoeCustomer = true
  1543. overrideUID = seat.UID
  1544. elseif tabl.ID == "217" then
  1545. forceJohnDoeCustomer = true
  1546. overrideUID = tabl.UID
  1547. end
  1548. --Force John Doe
  1549. if forceJohnDoeCustomer then
  1550. -- if math.random() < 0.005 then
  1551. UIDBatch[i].ID = "29"
  1552. johnDoeOverride[i] = overrideUID
  1553. -- else
  1554. --UIDBatch[i].ID = "26"
  1555. --corruptedVIPOverride[i] = overrideUID
  1556. end
  1557. end
  1558. -- end
  1559.  
  1560. -- pirate table logic
  1561. if not forceVIPCustomer and not forceShadowCustomer then
  1562. if seat.ID == "74" and tabl.ID == "75" then
  1563. forcePirateCustomer = true
  1564. overrideUID = seat.UID
  1565. elseif seat.ID == "74" then
  1566. forcePirateCustomer = true
  1567. overrideUID = seat.UID
  1568. elseif tabl.ID == "75" then
  1569. forcePirateCustomer = true
  1570. overrideUID = tabl.UID
  1571. end
  1572.  
  1573. if forcePirateCustomer then
  1574. UIDBatch[i].ID = "21"
  1575. pirateOverride[i] = overrideUID
  1576. end
  1577. end
  1578.  
  1579. -- gamer table logic
  1580. if not forceVIPCustomer and not forcePirateCustomer and not forceShadowCustomer then
  1581. if seat.ID == "84" and tabl.ID == "85" then
  1582. forceYoutuberCustomer = true
  1583. overrideUID = seat.UID
  1584. elseif seat.ID == "84" then
  1585. forceYoutuberCustomer = true
  1586. overrideUID = seat.UID
  1587. elseif tabl.ID == "85" then
  1588. forceYoutuberCustomer = true
  1589. overrideUID = tabl.UID
  1590. end
  1591.  
  1592. if forceYoutuberCustomer then
  1593. UIDBatch[i].ID = "22"
  1594. youtuberOverride[i] = overrideUID
  1595. end
  1596. end
  1597.  
  1598. -- santa table logic
  1599. if not forceVIPCustomer and not forcePirateCustomer and not forceShadowCustomer and not forceYoutuberCustomer then
  1600. if seat.ID == "108" and true then
  1601. forceSantaCustomer = true
  1602. overrideUID = seat.UID
  1603. UIDBatch[i].ID = "27"
  1604. santaOverride[i] = overrideUID
  1605. end
  1606. end
  1607.  
  1608. -- elf table logic
  1609. if not forceVIPCustomer and not forcePirateCustomer and not forceShadowCustomer and not forceYoutuberCustomer and not forceSantaCustomer then
  1610. if seat.ID == "110" and tabl.ID == "111" then
  1611. forceElfCustomer = true
  1612. overrideUID = seat.UID
  1613. elseif seat.ID == "110" then
  1614. forceElfCustomer = true
  1615. overrideUID = seat.UID
  1616. elseif tabl.ID == "111" then
  1617. forceElfCustomer = true
  1618. overrideUID = tabl.UID
  1619. end
  1620.  
  1621. if forceElfCustomer then
  1622. UIDBatch[i].ID = "28"
  1623. elfOverride[i] = overrideUID
  1624. end
  1625. end
  1626.  
  1627. local sx, sy, sz = self:GetCustomerStartVoxel(i, #selectedSeatGroup)
  1628. local fx, fy, fz = self:GetCustomerQueueVoxel(i, -5, #selectedSeatGroup)
  1629. local createdCustomer = _L.Customer.CreateRandomCustomer(UIDBatch[i], sx, sy, sz)
  1630. local worldStart = firstFloor:WorldPositionFromVoxel(sx, sy, sz)
  1631. local queueFront = firstFloor:WorldPositionFromVoxel(fx, fy, fz)
  1632. createdCustomer.stateData.seatUID = seat.UID
  1633. createdCustomer.stateData.tableUID = tabl.UID
  1634. createdCustomer.stateData.queuePosition = #self.customerQueue + 1
  1635. createdCustomer.isNearTree = treeTable[i] ~= nil
  1636. createdCustomer:SetVoxelPosition(self:GetCustomerStartVoxel(i, #selectedSeatGroup))
  1637.  
  1638. -- center the customer group...... remember that max group size is 4
  1639. if createdCustomer:BelongsToMyBakery() then
  1640. if #selectedSeatGroup % 2 == 0 then
  1641. createdCustomer.model:SetPrimaryPartCFrame(CFrame.new(worldStart + Vector3.new(0, 2, 0), queueFront))
  1642. elseif #selectedSeatGroup == 1 then
  1643. local startCFrame = CFrame.new(worldStart + Vector3.new(0, 2, 0)) * CFrame.Angles(0, self.baseAngle, 0) * CFrame.new(2, 0, 0)
  1644. local faceCFrame = CFrame.new(queueFront) * CFrame.Angles(0, self.baseAngle, 0) * CFrame.new(2, 0, 0)
  1645. createdCustomer.model:SetPrimaryPartCFrame(CFrame.new(startCFrame.p, faceCFrame.p))
  1646. elseif #selectedSeatGroup == 3 then
  1647. local startCFrame = CFrame.new(worldStart + Vector3.new(0, 2, 0)) * CFrame.Angles(0, self.baseAngle, 0) * CFrame.new(-2, 0, 0)
  1648. local faceCFrame = CFrame.new(queueFront) * CFrame.Angles(0, self.baseAngle, 0) * CFrame.new(-2, 0, 0)
  1649. createdCustomer.model:SetPrimaryPartCFrame(CFrame.new(startCFrame.p, faceCFrame.p))
  1650. end
  1651. end
  1652.  
  1653. -- special customer notifications
  1654. if _L.PlayerSettings.GetSetting("Notifications") == "Enabled" then
  1655. -- Haunted Horseman
  1656. if createdCustomer.ID == "25" and not didPlayVIPCustomerSound then
  1657. didPlayVIPCustomerSound = true
  1658. _L.SFX.Play(5839736886, player.PlayerGui, nil, 1)
  1659. _L.Alert.Message("The Headless Horseman has entered your Restaurant!")
  1660. end
  1661.  
  1662. -- Santa
  1663. if createdCustomer.ID == "27" and not didPlayVIPCustomerSound then
  1664. didPlayVIPCustomerSound = true
  1665. _L.SFX.Play("6106142958", player.PlayerGui)
  1666. _L.Alert.Message("Santa has entered your Restaurant!")
  1667. end
  1668.  
  1669. -- VIP customer? play sound for at least one
  1670. if createdCustomer.ID == "13" and not didPlayVIPCustomerSound then
  1671. didPlayVIPCustomerSound = true
  1672. _L.SFX.Play(5174014731, player.PlayerGui)
  1673. _L.Alert.Message("A VIP Customer has entered your Restaurant!")
  1674. end
  1675.  
  1676. -- celebrity customer?
  1677. if createdCustomer.ID == "20" and not didPlayVIPCustomerSound then
  1678. didPlayVIPCustomerSound = true
  1679. _L.SFX.Play(5278932246, player.PlayerGui)
  1680. _L.Alert.Message("A Celebrity Customer has entered your Restaurant!")
  1681. end
  1682.  
  1683. -- pirate customer
  1684. if createdCustomer.ID == "21" and not didPlayVIPCustomerSound then
  1685. didPlayVIPCustomerSound = true
  1686. _L.SFX.Play(5601560215, player.PlayerGui, nil, 0.25)
  1687. _L.Alert.Message("A Pirate Customer has entered your Restaurant!")
  1688. end
  1689.  
  1690. -- youtuber customer
  1691. if createdCustomer.ID == "22" and not didPlayVIPCustomerSound then
  1692. didPlayVIPCustomerSound = true
  1693. _L.SFX.Play(5625433365, player.PlayerGui, nil, 0.25)
  1694. _L.Alert.Message("A Youtuber Customer has entered your Restaurant!")
  1695. end
  1696.  
  1697. -- corrupted VIP
  1698. if createdCustomer.ID == "26" and not didPlayVIPCustomerSound then
  1699. didPlayVIPCustomerSound = true
  1700. _L.SFX.Play(5839737683, player.PlayerGui, nil, 0.25)
  1701. _L.Alert.Message("A Haunted VIP Customer has entered your Restaurant!")
  1702. end
  1703.  
  1704. --John Doe
  1705. if createdCustomer.ID == "29" and not didPlayVIPCustomerSound then
  1706. didPlayVIPCustomerSound = true
  1707. _L.SFX.Play(5839737683, player.PlayerGui, nil, 0.25)
  1708. _L.Alert.Message("John Doe has entered your Restaurant!")
  1709. end
  1710. end
  1711.  
  1712. if createdCustomer.ID == "14" or createdCustomer.ID == "15" then
  1713. containsGhostOrSpecial = true
  1714. end
  1715.  
  1716. -- finally give the customer a parent (prevents weird teleporting from corner thing)
  1717. createdCustomer.model.Parent = createdCustomer.cachedParent
  1718. createdCustomer:FadeTransparency(createdCustomer:GetMyTransparency())
  1719.  
  1720. -- replication event.. customer created
  1721. _L.Replication.SendEvent("CustomerCreated", createdCustomer:ToUIDData())
  1722.  
  1723. -- tutorial table + flag
  1724. if self.isTutorial then
  1725. table.insert(self.tutorial.firstCustomerWave, createdCustomer)
  1726. self.tutorial.hasAllowedFirstWaveOfCustomers = true
  1727. end
  1728.  
  1729. seat:SetIsOccupied(createdCustomer)
  1730. tabl:AddCustomerAtTable(createdCustomer)
  1731.  
  1732. createdCustomer:Emoji("WaitingForSeat", true)
  1733.  
  1734. createdCustomer:Interact(function()
  1735. goToSeat(createdCustomer)
  1736. end)
  1737.  
  1738. -- celebrity customer flag
  1739. if createdCustomer.ID == "20" then
  1740. _L.Variables.MyBakery.activeCelebrity = true
  1741. end
  1742.  
  1743. table.insert(queueEntry, createdCustomer)
  1744.  
  1745. end
  1746.  
  1747. -- initialize each customer's queue group. the customer can NOT be
  1748. -- inside of their own queue group, since cyclic tables are not permitted
  1749. for _, customer0 in ipairs(queueEntry) do
  1750. customer0.stateData.queueGroup = {}
  1751. for _, customer1 in ipairs(queueEntry) do
  1752. if customer0 ~= customer1 then
  1753. table.insert(customer0.stateData.queueGroup, customer1)
  1754. end
  1755. end
  1756. end
  1757.  
  1758. table.insert(self.customerQueue, queueEntry)
  1759.  
  1760. if not containsGhostOrSpecial then
  1761. self:UpdateCustomerQueuePositioning()
  1762. else
  1763. goToSeat(queueEntry[1], true)
  1764. end
  1765.  
  1766. return #selectedSeatGroup, vipOverride, pirateOverride, youtuberOverride, shadowOverride, corruptedVIPOverride, santaOverride, elfOverride, johnDoeOverride, treeTable
  1767.  
  1768. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement