AI/ActionSystem/Actions/Guest/PickpocketAction.cs
using Sandbox.Utility;
namespace HC3;
public sealed class PickpocketAction : AgentAction
{
[Sync( SyncFlags.FromHost )]
private Guest Victim { get; set; }
private Guest Guest => Agent as Guest;
public override float Score()
{
if ( !Guest.IsValid() || Guest.Delinquency < 0.7f ) return 0f;
if ( Victim.IsValid() ) return 300f;
// Pick random victim without allocating a filtered array (reservoir sampling)
Guest candidate = null;
int count = 0;
foreach ( var g in GuestManager.Instance.GuestList )
{
if ( g == Guest ) continue;
count++;
if ( Game.Random.Next( count ) == 0 )
candidate = g;
}
if ( count == 0 ) return 0f;
Victim = candidate;
return Victim.IsValid() ? 300f : 0f;
}
public override void StartAction()
{
Controller.ClearNavigation();
}
public override Status TickAction()
{
if ( !Victim.IsValid() )
return Status.Failure;
var targetPos = Victim.WorldPosition;
if ( !GridManager.IsWalkable( Agent.WorldPosition, targetPos ) )
{
Victim = null;
return Status.Failure;
}
if ( !Controller.Navigate( targetPos ) )
return Status.Running;
var moneyToTake = (Victim.Money * Game.Random.Float( 0.2f, 0.5f )).CeilToInt();
Guest.CommitCrime( 0.2f, Victim );
Victim.TakeMoney( moneyToTake );
Victim = null;
Guest.GiveMoney( moneyToTake );
return Status.Success;
}
public override void StopAction()
{
Victim = null;
}
public override ActionDisplayInfo? GetDisplay()
{
if ( !Victim.IsValid() ) return null;
var dist = Agent.WorldPosition.Distance( Victim.WorldPosition );
var progress = 1f - (dist / 1500f).Clamp( 0f, 1f );
return new ActionDisplayInfo(
"visibility_off",
$"Pickpocket",
progress
);
}
}