Npcs/Npc.Schedule.cs
namespace Sandbox.Npcs;

public partial class Npc : Component
{
	/// <summary>
	/// The current running schedule for this NPC.
	/// </summary>
	public ScheduleBase ActiveSchedule { get; private set; }

	readonly Dictionary<Type, ScheduleBase> _schedules = [];

	/// <summary>
	/// Get a schedule -- if it doesn't exist, one will be created
	/// </summary>
	protected T GetSchedule<T>() where T : ScheduleBase, new()
	{
		var type = typeof(T);
		if ( !_schedules.TryGetValue( type, out var schedule ) )
		{
			schedule = new T();
			_schedules[type] = schedule;
		}

		return (T)schedule;
	}

	public virtual ScheduleBase GetSchedule()
	{
		return null;
	}

	/// <summary>
	/// Updates a behavior, returns if there is an active schedule - this will stop lower priority behaviors from running
	/// </summary>
	void TickSchedule()
	{
		if ( !NpcConVars.Enabled )
			return;

		// If we have a schedule, keep running it 
		// until it's completely finished.
		if ( ActiveSchedule is not null )
		{
			RunActiveSchedule();
			return;
		}

		var newSchedule = GetSchedule();
		if ( newSchedule is null ) return;

		ActiveSchedule = newSchedule;
		ActiveSchedule?.InternalInit( this );
	}

	private void RunActiveSchedule()
	{
		var status = ActiveSchedule.InternalUpdate();

		if ( status != TaskStatus.Running )
		{
			EndCurrentSchedule();
		}
	}


	protected override void OnDisabled()
	{
		EndCurrentSchedule();
	}

	/// <summary>
	/// End the current schedule cleanly. Can be called by subclasses to interrupt
	/// the active schedule (e.g. when damaged).
	/// </summary>
	protected void EndCurrentSchedule()
	{
		ActiveSchedule?.InternalEnd();
		ActiveSchedule = null;
	}
}