AI/Staff/Staff.cs
using HC3.UI;

namespace HC3;

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

	[Property] public StaffDefinition Definition { get; set; }

	/// <summary>
	/// How alert this member of staff is. This value will act as a multiplier
	/// to the suspicion gain if they notice a crime being committed.
	/// </summary>
	[Property, Feature( "Crime" )]
	public float Alertness { get; set; } = 1f;

	[Sync( SyncFlags.FromHost )]
	public bool IsWorking { get; private set; }

	public void SetWorkingState( bool isWorking )
	{
		if ( !Networking.IsHost )
			return;

		GameObject.Root.Enabled = isWorking;
		IsWorking = isWorking;
		Network.Refresh();
	}

	public override void Tick()
	{
		UpdateAnimation();

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

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

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

		base.OnAwake();
	}

	protected override void OnStart()
	{
		if ( !Game.IsPlaying )
			return;

		SetupSkin();
		GameObject.Name = $"{Definition.DisplayName} ({FullName}) [Staff]";
	}

	protected override async void OnEnabled()
	{
		base.OnEnabled();

		SetupSkin();
		// Conna: HACK! This is because we want to reset the SceneModel attributes from
		// the model renderer but the SceneModel won't have been re-created yet, as
		// children's OnEnabled are called after us.
		await Task.FrameEnd();
		SetupSkin();
	}

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

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

	void UpdateSelected()
	{
		if ( !IsWorking || !Controller.IsNavigating )
			return;

		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 = new StaffInspector();
		inspector.Staff = this;

		return inspector;
	}

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

		SetWorkingState( false );
	}

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

		SetWorkingState( true );
	}
}