AI/Guests/Guest.cs
using HC3.UI;

namespace HC3;

/// <summary>
/// A guest.
/// </summary>
public partial class Guest : Agent, IInspectable, IParkEvents
{
	/// <summary>
	/// Moves the guest around
	/// </summary>
	[RequireComponent]
	public new GuestController Controller { get; set; }

	/// <summary>
	/// Guest's needs system
	/// </summary>
	[RequireComponent]
	public NeedSystem Needs { get; set; }

	/// <summary>
	/// Guest inventory
	/// </summary>
	[Property]
	public Inventory.Inventory Inventory { get; set; }

	public override void Tick()
	{
		DecaySuspicionLevel();
		UpdateAnimation();

		if ( IInspectable.Current == this )
		{
			UpdateSelected();
		}
		else if ( Line.Enabled )
		{
			Line.Enabled = false;
		}
	}

	public override void FixedTick()
	{
		Needs?.Tick();
	}

	protected override void OnAwake()
	{
		if ( !Networking.IsHost )
			return;

		// Setup the guest's identity on awake so that it's already
		// done before it gets network spawned.
		SetupStats();
		SetupIdentity();

		base.OnAwake();
	}

	protected override void OnStart()
	{
		var isInPark = BuildingZone.Instance.IsOwned( WorldPosition );
		if ( isInPark )
		{
			GuestManager.Instance.RegisterGuest( this, false );
		}

		SetupSkin();
		GameObject.Name = $"Guest ({FullName})";
	}

	protected override void OnDestroy()
	{
		if ( GuestManager.Instance.IsValid() )
		{
			GuestManager.Instance.UnregisterGuest( this );
		}
	}

	[Property] public LineRenderer Line { get; private set; }

	Color green = "#2FFF3D";
	Color red => green.WithAlpha( 0f );

	void UpdateSelected()
	{
		if ( Controller.IsNavigating )
		{
			Line.Enabled = true;
			Line.VectorPoints = Controller.GetNetworkedPath().Select( x => x.WithZ( x.z + 8f ) ).ToList();

			var progress = Controller.GetPathProgress();

			Line.Color = new Gradient(
			[
				new Gradient.ColorFrame( 0f, red ),
				new Gradient.ColorFrame( progress + 0.0025f, red ),
				new Gradient.ColorFrame( progress + 0.02f, green ),
				new Gradient.ColorFrame( 1f, green )
			] );
		}
	}

	Window IInspectable.Select()
	{
		var inspector = GuestInspector.Show();
		inspector.Guest = this;

		return inspector;
	}

	void IParkEvents.OnAgentExit( Agent agent )
	{
		if ( agent != this || !Networking.IsHost )
			return;

		DestroyGameObject();
	}
}