Npcs/Scientist/ScientistWanderSchedule.cs
using Sandbox.Npcs.Layers;
using Sandbox.Npcs.Tasks;

namespace Sandbox.Npcs.Schedules;

/// <summary>
/// Wander to a random nearby point, avoiding player directions.
/// </summary>
public sealed class ScientistWanderSchedule : ScheduleBase
{
	private static readonly string[] WanderLines =
	[
		"Let me check over here...",
		"Hmm, what's over there?",
		"I should stretch my legs.",
		"*whistles*",
	];

	protected override void OnStart()
	{
		var randomDir = Vector3.Random.WithZ( 0 ).Normal;

		// Don't wander toward nearby players
		var nearest = Npc.Senses.Nearest;
		if ( nearest.IsValid() )
		{
			var toPlayer = (nearest.WorldPosition - GameObject.WorldPosition).WithZ( 0 ).Normal;
			if ( randomDir.Dot( toPlayer ) > 0.3f )
			{
				// Flip away from the player with some randomness
				randomDir = (-toPlayer + Vector3.Random.WithZ( 0 ).Normal * 0.5f).WithZ( 0 ).Normal;
			}
		}

		var wanderTarget = GameObject.WorldPosition + randomDir * Game.Random.Float( 150f, 350f );

		AddTask( new MoveTo( wanderTarget, 15f ) );

		// Occasionally say something while walking
		var speech = Npc.Speech;
		if ( speech is not null && speech.CanSpeak && Game.Random.Float() < 0.2f )
		{
			var line = WanderLines[Game.Random.Int( 0, WanderLines.Length - 1 )];
			AddTask( new Say( line, 2.5f ) );
		}

		AddTask( new Wait( Game.Random.Float( 1f, 2f ) ) );
	}
}