AI/ActionSystem/Actions/EnterParkAction.cs
namespace HC3;

public partial class EnterParkAction : AgentAction
{
	private ParkEntrance _cachedEntrance;

	private ParkEntrance entrance
	{
		get
		{
			_cachedEntrance ??= Scene.GetAll<ParkEntrance>().FirstOrDefault();
			return _cachedEntrance;
		}
	}

	private bool _hasStarted;
	private Vector3 _target;

	public override void StopAction()
	{
		if ( Agent is Guest guest && BuildingZone.Instance.IsOwned( WorldPosition ) )
		{
			GuestManager.Instance.RegisterGuest( guest, true );
		}

		IParkEvents.PostToGameObject( Agent.GameObject.Root, x => x.OnAgentEnter( Agent ) );
	}

	public override float Score()
	{
		if ( entrance == null || BuildingZone.Instance.IsOwned( WorldPosition ) )
		{
			return 0f;
		}

		return 1005f;
	}

	public override void StartAction()
	{
		if ( entrance == null || Controller == null )
			return;

		_hasStarted = true;

		Controller.ClearNavigation();

		var flags = NavFlags.Default;
		flags = flags.WithFlag( NavFlags.Owned, false );

		_target = entrance.WorldPosition + entrance.WorldRotation.Forward * GridManager.GridSize;
		Controller.Navigate( _target, flags );
	}

	public override Status TickAction()
	{
		if ( !_hasStarted || Controller == null )
			return Status.Failure;

		if ( WorldPosition.Distance( _target ) < 10f )
			return Status.Success;

		// Re-navigate if path was lost (e.g. after save load)
		if ( !Controller.IsNavigating )
		{
			var flags = NavFlags.Default;
			flags = flags.WithFlag( NavFlags.Owned, false );
			Controller.Navigate( _target, flags );
		}

		return Status.Running;
	}

	public override ActionDisplayInfo? GetDisplay()
	{
		if ( entrance == null ) return null;

		var maxDistance = 2000f; // Define a sane max range for normalization
		var currentDistance = WorldPosition.Distance( _target );
		var progress = 1f - (currentDistance / maxDistance).Clamp( 0f, 1f );

		return new ActionDisplayInfo(
			"login",
			"Walking to the park entrance...",
			progress
		);
	}
}