Npcs/Scientist/ScientistInspectPropSchedule.cs

A schedule for a Scientist NPC that inspects a prop. It sets the NPC to look at a target prop, walks to it, then either picks it up and carries it to a random nearby navmesh point before dropping it if the prop is small, or just observes it for a short time if the prop is large.

using Sandbox.Npcs.Layers;
using Sandbox.Npcs.Tasks;

namespace Sandbox.Npcs.Schedules;

/// <summary>
/// Walk to a nearby prop, look at it, and maybe comment on it.
/// If the prop is small enough, pick it up, carry it around, then drop it.
/// </summary>
public sealed class ScientistInspectPropSchedule : ScheduleBase
{
	public GameObject PropTarget { get; set; }

	protected override void OnStart()
	{
		if ( !PropTarget.IsValid() ) return;

		// Persistently track the prop — the NPC will keep looking at it
		// throughout the entire schedule without needing repeated LookAt tasks.
		Npc.Animation.SetLookTarget( PropTarget );

		// Walk toward the prop — tracks it if it moves
		AddTask( new MoveTo( PropTarget, 40f ) );

		AddTask( new Wait( 1 ) );

		var bounds = PropTarget.GetBounds();
		var isSmall = bounds.Size.Length < 256;

		if ( isSmall )
		{
			// Pick it up, carry it around, then drop it.
			AddTask( new PickUpProp( PropTarget ) );

			// Try to find a reachable wander point on the navmesh
			var randomDir = Vector3.Random.WithZ( 0 ).Normal;
			var wanderTarget = PropTarget.WorldPosition + randomDir * Game.Random.Float( 150f, 300f );

			if ( Npc.Scene.NavMesh.GetClosestPoint( wanderTarget ) is Vector3 navPoint )
			{
				AddTask( new MoveTo( navPoint, 15f ) );
			}

			// Always added — even if MoveTo was skipped or would have failed,
			// the NPC still holds the prop for a bit, then drops it properly.
			AddTask( new Wait( Game.Random.Float( 3f, 6f ) ) );

			AddTask( new DropProp( PropTarget ) );
		}
		else
		{
			// Just observe the big prop.
			AddTask( new Wait( Game.Random.Float( 2f, 4f ) ) );
		}
	}

	protected override void OnEnd()
	{
		Npc.Animation.ClearLookTarget();
		Npc.Animation.ClearHeldProp();
	}
}