Npcs/Diner/DinerFleeSchedule.cs
using Sandbox.Npcs.Layers;
using Sandbox.Npcs.Tasks;
namespace Sandbox.Npcs.Schedules;
/// <summary>
/// Sprint away from whatever just drove through the breakfast.
/// Lines are specific to the diner context — these people are UPSET about their food.
/// </summary>
public class DinerFleeSchedule : ScheduleBase
{
public GameObject Source { get; set; }
public float PanicLevel { get; set; } = 0.5f;
private static readonly string[] PanicLines =
[
"MY EGGS!",
"MY COFFEE!!!",
"What is WRONG with you?!",
"That was a FULL ENGLISH!",
"I hadn't even finished!",
"THERE'S A CAR IN THE RESTAURANT!",
"Call the police!",
"My croissant!!",
"I was EATING that!",
"YOU MANIAC!",
"Every single time...",
"Not again!!",
"My mimosa!!!",
"I'm going to TripAdvisor about this!",
];
protected override void OnStart()
{
if ( !Source.IsValid() ) return;
// Run faster the more scared they are (180–380)
Npc.Navigation.WishSpeed = 180f + 200f * PanicLevel;
Npc.Animation.ClearLookTarget();
// Scream immediately
if ( Npc.Speech.CanSpeak )
{
var line = PanicLines[Game.Random.Int( 0, PanicLines.Length - 1 )];
Npc.Speech.Say( line, 2.5f );
}
// Flee away from the vehicle with some spread
var awayDir = (Npc.GameObject.WorldPosition - Source.WorldPosition).WithZ( 0 ).Normal;
var spread = Game.Random.Float( -50f, 50f );
awayDir = Rotation.FromAxis( Vector3.Up, spread ) * awayDir;
var fleeDist = 400f + 800f * PanicLevel;
var fleeTarget = Npc.GameObject.WorldPosition + awayDir * fleeDist;
if ( Npc.Scene.NavMesh.GetClosestPoint( fleeTarget ) is { } navPoint )
AddTask( new MoveTo( navPoint, 15f ) );
else
AddTask( new MoveTo( fleeTarget, 15f ) );
// After reaching safety, catch breath and mutter something
AddTask( new Wait( Game.Random.Float( 0.5f, 1.5f ) ) );
if ( Npc.Speech.CanSpeak )
{
var afterLine = AfterFleeLines[Game.Random.Int( 0, AfterFleeLines.Length - 1 )];
AddTask( new Say( afterLine, 3f ) );
}
}
protected override void OnEnd()
{
Npc.Navigation.WishSpeed = 100f;
}
protected override bool ShouldCancel() => !Source.IsValid();
private static readonly string[] AfterFleeLines =
[
"Is it safe?",
"*heavy breathing*",
"I can't believe this.",
"Every Sunday!",
"I'm switching to brunch.",
"Where's my coffee gone?",
"This neighbourhood is going downhill.",
];
}