Npcs/Diner/DinerMillSchedule.cs
using Sandbox.Npcs.Tasks;

namespace Sandbox.Npcs.Schedules;

/// <summary>
/// Mill around the home area complaining, periodically checking for a free chair.
/// The DinerNpc's GetSchedule() will interrupt this and switch to DinerSitSchedule
/// as soon as a chair becomes available.
/// </summary>
public class DinerMillSchedule : ScheduleBase
{
	private static readonly string[] MillingLines =
	[
		"Where am I supposed to sit?!",
		"This is unacceptable.",
		"I paid for a full breakfast!",
		"*mutters furiously*",
		"There had better be compensation.",
		"I'm going to stand here until there's a seat.",
		"Does anyone work here?",
		"My table is destroyed.",
		"I'm writing a strongly worded letter.",
		"Has anyone seen my hat? It was on the table.",
		"The eggs are everywhere.",
		"That car came from NOWHERE.",
		"First the service, now THIS.",
		"I just wanted a quiet breakfast.",
		"This city, I swear.",
	];

	protected override void OnStart()
	{
		var diner = Npc as Sandbox.Npcs.Diner.DinerNpc;

		// Wander to a random point within the home area
		var randomDir    = Vector3.Random.WithZ( 0 ).Normal;
		var wanderRadius = diner?.MillRadius ?? 300f;
		var home         = diner?.HomeArea ?? Npc.WorldPosition;
		var target       = home + randomDir * Game.Random.Float( 80f, wanderRadius * 0.6f );

		if ( Npc.Scene.NavMesh.GetClosestPoint( target ) is { } navPoint )
			AddTask( new MoveTo( navPoint, 20f ) );
		else
			AddTask( new MoveTo( target, 20f ) );

		// Stop and complain
		AddTask( new Wait( Game.Random.Float( 0.5f, 1.5f ) ) );

		if ( Npc.Speech.CanSpeak && Game.Random.Float() < 0.65f )
		{
			var line = MillingLines[Game.Random.Int( 0, MillingLines.Length - 1 )];
			AddTask( new Say( line, 3f ) );
		}

		AddTask( new Wait( Game.Random.Float( 0.5f, 2f ) ) );
	}
}