AI/ActionSystem/Actions/Staff/CollectTrashAction.cs
using HC3.Inventory;
namespace HC3;
public sealed class CollectTrashAction : BehaviorTreeAction
{
private TrashPile Trash { get; set; }
public override float Score()
{
if ( !Agent.IsValid() ) return 0f;
if ( Trash.IsValid() ) return 300f;
if ( TrashPile.All.Count == 0 ) return 0f;
FindClosestTrash();
return Trash.IsValid() ? 300f : 0f;
}
protected override void OnTreeStart()
{
if ( !Trash.IsValid() )
FindClosestTrash();
Controller.ClearNavigation();
Agent.Body.SetBodyGroup( 0, 1 );
}
protected override void OnTreeStop()
{
Trash = null;
Agent.Body.SetBodyGroup( 0, 0 );
}
protected override Node BuildTree()
{
if ( !Trash.IsValid() )
return null;
return new SequenceNode( new()
{
new MoveToNode( Agent, Trash.WorldPosition, reason: "Heading to trash pile" ),
new AgentSequenceNode( Agent, "Action_Sweep", 5f, reason: "Cleaning trash" ),
new RemoveTrashNode( Agent, Trash )
} );
}
private void FindClosestTrash()
{
TrashPile closest = null;
float closestDist = float.MaxValue;
foreach ( var t in TrashPile.All )
{
float dist = t.WorldPosition.DistanceSquared( Agent.WorldPosition );
if ( dist < closestDist )
{
closestDist = dist;
closest = t;
}
}
Trash = closest;
}
}
file sealed class RemoveTrashNode : Node
{
private readonly TrashPile Trash;
private readonly Agent Agent;
private bool _done;
public RemoveTrashNode( Agent agent, TrashPile trash )
{
Agent = agent;
Trash = trash;
}
public override Status Tick()
{
if ( _done )
return Status.Success;
if ( Trash?.GameObject?.Root.IsValid() != true )
return Status.Failure;
if ( Agent is Staff staff )
staff.IncreaseStat( StaffStats.TrashCleanedUp );
Trash.GameObject.Root.Destroy();
Stats.Increment( "staff.trash_cleaned" );
_done = true;
return Status.Success;
}
public override ActionDisplayInfo? GetDisplay()
{
return new ActionDisplayInfo( "recycling", "Cleaning trash...", 0 );
}
}