using UnityEngine;
///
/// AIAction — Abstract base class for all AI actions.
/// Each action knows how to score itself (utility) and execute.
/// Stateless scoring — all context comes from AIBlackboard.
///
/// Subclasses: CollectBagAction, DepositBagAction, AttackEnemyAction,
/// DefendVaultAction, PatrolAction, RetreatAction,
/// EscortCarrierAction, InterceptCarrierAction
///
public abstract class AIAction
{
/// Display name for debug.
public abstract string Name { get; }
///
/// Evaluate how desirable this action is (0-1 range, higher = more desirable).
/// Called every AI decision tick. Must be allocation-free.
///
/// Per-AI knowledge store
/// Shared team knowledge
/// Utility score 0-1
public abstract float Score(AIBlackboard blackboard, TeamBlackboard teamBoard);
///
/// Execute this action for one tick.
/// Called every AI tick while this is the active action.
///
/// The AI brain executing this action
/// Per-AI knowledge
/// Team knowledge
public abstract void Execute(AIBrain brain, AIBlackboard blackboard, TeamBlackboard teamBoard);
/// Called when this action becomes active (optional setup).
public virtual void OnEnter(AIBrain brain, AIBlackboard blackboard, TeamBlackboard teamBoard) { }
/// Called when this action is replaced by another (optional cleanup).
public virtual void OnExit(AIBrain brain, AIBlackboard blackboard, TeamBlackboard teamBoard) { }
///
/// Whether this action can interrupt the current action.
/// High-priority actions (defend vault, retreat) return true.
///
public virtual bool CanInterrupt => false;
// ─── Utility Helpers ─────────────────────────────────────
/// Smooth curve: high when value is low, low when value is high.
protected float InverseCurve(float value, float max)
{
return Mathf.Clamp01(1f - (value / max));
}
/// Smooth curve: high when value is high.
protected float LinearCurve(float value, float max)
{
return Mathf.Clamp01(value / max);
}
/// Step function: 1 if above threshold, 0 otherwise.
protected float StepAbove(float value, float threshold)
{
return value >= threshold ? 1f : 0f;
}
/// Step function: 1 if below threshold, 0 otherwise.
protected float StepBelow(float value, float threshold)
{
return value < threshold ? 1f : 0f;
}
}