AI/ActionSystem/Actions/ReturnToGridActon.cs
using HC3;
public sealed class ReturnToGridAction : AgentAction
{
private bool _navigating;
public override float Score()
{
if ( Agent.Building.IsValid() || Agent.IsMoving ) return 0;
var cell = GridManager.Instance.GetCell( GridManager.WorldToGridPosition( WorldPosition ) );
int level = GridManager.FloorWorldHeightToGrid( WorldPosition.z );
return cell?.IsWalkable( level ) ?? false ? 0f : 1010f;
}
public override void StartAction()
{
base.StartAction();
_navigating = false;
if ( TryFindRecoveryTarget( out var recoveryPoint ) )
{
Controller.Navigate( new List<Vector3> { recoveryPoint } );
_navigating = true;
}
}
public override Status TickAction()
{
if ( !_navigating )
return Status.Failure;
if ( Controller.IsNavigating )
return Status.Running;
var grid3d = GridManager.WorldToGridPosition3D( WorldPosition );
var cell = GridManager.Instance.GetCell( GridManager.WorldToGridPosition( WorldPosition ) );
int level = GridManager.FloorWorldHeightToGrid( WorldPosition.z );
return cell?.IsWalkable( level ) ?? false ? Status.Success : Status.Failure;
}
public override ActionDisplayInfo? GetDisplay()
{
return new ActionDisplayInfo( "error", "Returning to grid...", Controller.GetPathProgress() );
}
private bool TryFindRecoveryTarget( out Vector3 point )
{
point = default;
// Find closest walkable path tile without LINQ allocation
float closestDist = float.MaxValue;
Vector3? closest = null;
foreach ( var x in Scene.GetAll<Path>() )
{
if ( x.RegionId != 0 || x.IsElevated )
continue;
if ( !GridNavigation.Instance.CanEnter( new Vector2Int( x.TilePosition ), NavFlags.Default ) )
continue;
float dist = x.WorldPosition.DistanceSquared( WorldPosition );
if ( dist < closestDist )
{
closestDist = dist;
closest = x.WorldPosition;
}
}
if ( closest is null )
return false;
point = closest.Value;
return true;
}
}