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; } }