# 61 — BPC_AIStateMachine ## Blueprint Spec — UE 5.5–5.7 --- ### Parent Class `ActorComponent` ### Dependencies - [`BPC_AIControllerBase`](55_BPC_AIControllerBase.md) — Owner controller, blackboard access - [`BPC_AlertSystem`](60_BPC_AlertSystem.md) — Alert level triggers state transitions - [`BPC_PerceptionComponent`](56_BPC_PerceptionComponent.md) — Stimulus input - [`BPC_BehaviorTreeManager`](57_BPC_BehaviorTreeManager.md) — Tree lifecycle requests - [`BP_EnemyBase`](58_BP_EnemyBase.md) — Pawn animation state requests - [`DA_AIProfile`](../12-content/63_DA_AIProfileDataAsset.md) — State timings, cooldowns, transition rules ### Purpose High-level finite state machine for AI behavior. Manages valid state transitions, cooldowns, priority overrides, and lifecycle events for each AI state (Patrol, Investigate, Search, Combat, Flee, Idle, Stunned). Interprets alert level changes from the alert system and resolves transitions with rule checking before delegating to the behavior tree manager. ### Enums | Enum | Values | Description | |------|--------|-------------| | `EAIState` | Idle, Patrol, Investigate, Search, Combat, Flee, Stunned, Dead | All possible AI states | | `EStateTransitionRule` | Allow, Block (Cooldown), Block (Priority), Block (Health), Block (Narrative) | Transition permission results | | `EStatePriority` | None, Low, Medium, High, Critical | State override priority | ### Structs | Struct | Fields | Description | |--------|--------|-------------| | `FStateConfig` | State: EAIState, bCanTransitionFrom: Array, MinTimeInState: Float, MaxTimeInState: Float, CooldownAfterExit: Float, Priority: EStatePriority, bAllowInterrupt: Bool, AssociatedTree: EBehaviorTreeType | Configuration per state | | `FStateInstance` | State: EAIState, EnterTime: Float, LastExitTime: Float, bIsActive: Bool, CustomData: FName (tag), bCanInterrupt: Bool | Runtime state tracking | | `FTransitionRequest` | RequestedState: EAIState, Priority: EStatePriority, Reason: FName, Instigator: AActor | Queued transition | ### Variables | Name | Type | Description | |------|------|-------------| | `CurrentState` | EAIState | Active state | | `PreviousState` | EAIState | State before last transition | | `StateMap` | Map | All state configs from profile | | `StateInstances` | Map | Runtime state trackers | | `PendingTransitions` | Array | Queue of requested transitions | | `bIsTransitioning` | Bool | Lock during transition processing | | `MaxTransitionsPerTick` | Int | Safety limit (default 3) | | `bLockedByNarrative` | Bool | Story script lock | | `NarrativeLockReason` | FName | Why narrative locked AI | | `StunnedDuration` | Float | Current stun timer remaining | | `FleeThreshold` | Float | Health % below which AI flees | | `bCanFlee` | Bool | Permission to flee | ### Functions — Core | Name | Inputs | Outputs | Description | |------|--------|---------|-------------| | `RequestTransition` | NewState: EAIState, Priority: EStatePriority, Reason: FName, Instigator: AActor | Bool | Queue or execute state change | | `ProcessPendingTransitions` | — | — | Evaluate queue on tick | | `EvaluateTransitionRules` | FromState: EAIState, ToState: EAIState | EStateTransitionRule | Check if transition is allowed | | `ForceTransition` | NewState: EAIState | — | Bypass rules (narrative/debug) | | `GetCurrentState` | — | EAIState | BB getter | | `GetTimeInCurrentState` | — | Float | Duration in current state | | `CanTransitionTo` | NewState: EAIState | Bool | Public permission check | | `IsStateActive` | State: EAIState | Bool | Check any state | ### Functions — State Lifecycle | Name | Inputs | Outputs | Description | |------|--------|---------|-------------| | `EnterState` | NewState: EAIState, Instigator: AActor | — | State entry logic | | `ExitState` | CurrentState: EAIState | — | State exit cleanup | | `UpdateState` | DeltaTime: Float | — | Per-tick state behavior | | `OnStateEnter_Patrol` | — | — | Setup patrol BB keys | | `OnStateEnter_Investigate` | Location: FVector | — | Setup investigation | | `OnStateEnter_Search` | LastKnownLocation: FVector | — | Setup search area | | `OnStateEnter_Combat` | Target: AActor | — | Combat initialization | | `OnStateEnter_Flee` | ThreatLocation: FVector | — | Flee setup | | `OnStateEnter_Stunned` | Duration: Float | — | Stun timer | | `OnStateEnter_Idle` | — | — | Idle setup | | `OnStateEnter_Dead` | — | — | Death state | | `OnStateExit_All` | — | — | Common exit behavior | ### Functions — Transition Rules | Name | Inputs | Outputs | Description | |------|--------|---------|-------------| | `CheckCooldown` | State: EAIState | Bool | Has cooldown expired | | `CheckHealthThreshold` | ToState: EAIState | Bool | Health gate check for flee/stun | | `CheckNarrativeLock` | — | Bool | Is AI locked by script | | `CheckPriorityOverride` | Request: FTransitionRequest | Bool | Higher priority can interrupt | | `CheckMinStateTime` | — | Bool | Minimum time in current state met | ### Blueprint Flow — Transition Resolution ``` [RequestTransition] └─► If bLockedByNarrative AND not ForceTransition: deny (return false) └─► If bIsTransitioning: queue to PendingTransitions, return false └─► EvaluateTransitionRules: Call CheckNarrativeLock --> if blocked, deny Call CheckCooldown(FromState) --> if active, deny Call CheckMinStateTime --> if not met, queue or deny Call CheckPriorityOverride --> if request priority >= current, allow Else: deny or queue └─► If Allowed: bIsTransitioning = true ExitState(CurrentState) EnterState(NewState) Update blackboard Request BehaviorTree switch from BT Manager bIsTransitioning = false Return true [ProcessPendingTransitions] └─► Sort PendingTransitions by Priority (high first) └─► For each (up to MaxTransitionsPerTick): Try RequestTransition again If success: remove from queue If fails again: increment failure counter, remove if > 3 attempts [Event Tick] └─► UpdateState(DeltaTime): Switch CurrentState: Patrol: Check patrol timer, check patrol completion Investigate: Update investigation timer, check timeout Search: Update search timer, check coverage Combat: Update combat timer, check health for flee Flee: Update flee timer, check distance from threat Stunned: StunnedDuration -= DeltaTime; if <= 0, transition Idle: Update idle timer Check external triggers: If bCanFlee && Health < FleeThreshold: RequestTransition(Flee) If AlertSystem.IsInCombat && CurrentState != Combat: RequestTransition(Combat) ``` ### State Transition Map (Allowed) | From \ To | Idle | Patrol | Investigate | Search | Combat | Flee | Stunned | Dead | |-----------|------|--------|------------|--------|--------|------|---------|------| | Idle | — | Yes | Yes | No | Yes | No | Yes | Yes | | Patrol | Yes | — | Yes | No | Yes | No | Yes | Yes | | Investigate | Yes | Yes | — | Yes | Yes | No | Yes | Yes | | Search | Yes | Yes | No | — | Yes | Yes | Yes | Yes | | Combat | No | No | No | No | — | Yes | Yes | Yes | | Flee | Yes | Yes | No | No | No | — | Yes | Yes | | Stunned | Yes | Yes | Yes | No | Yes | Yes | — | Yes | | Dead | No | No | No | No | No | No | No | — | ### Event Dispatchers | Name | Delegate Signature | Purpose | |------|-------------------|---------| | `OnAIStateChanged` | EAIState NewState, EAIState PreviousState, AActor Instigator | For all listeners | | `OnStateTransitionBlocked` | EAIState Requested, FStateTransitionRule Reason | Debug logging | | `OnAIDefeated` | AActor Killer | Death sequence | | `OnAIFled` | — | Flee started | | `OnAIStunned` | Float Duration | Stun entered | | `OnAIStateTimerWarning` | EAIState, Float RemainingTime | State expiry warning | ### Communications With | Target | Method | Why | |--------|--------|-----| | [`BPC_AlertSystem`](60_BPC_AlertSystem.md) | Event listener | Alert level changes trigger transitions | | [`BPC_BehaviorTreeManager`](57_BPC_BehaviorTreeManager.md) | Direct call | Request tree switch on state enter | | [`BPC_AIControllerBase`](55_BPC_AIControllerBase.md) | Owner reference | Update BB keys | | [`BP_EnemyBase`](58_BP_EnemyBase.md) | Event dispatcher | Trigger state animations | | [`DA_AIProfile`](../12-content/63_DA_AIProfileDataAsset.md) | Data lookup | Load state configs | | [`BPC_PerceptionComponent`](56_BPC_PerceptionComponent.md) | Direct call | Get stimulus for investigate | | Narrative system | Event dispatcher | Narrative lock/unlock | | [`BPC_HealthComponent`](../01-player/01_BPC_HealthComponent.md) | Event listener | Health threshold checks | ### Reuse Notes - One per AIController; state configs defined per AI type in DA_AIProfile - Priority queue prevents infinite loops during rapid state changes - Narrative lock allows scripted moments where AI cannot react - Stun state can be triggered by weapons, environment, or narrative events - Flee uses the same path system as patrol (inverted direction) - Dead state is terminal — no transitions out (death is hard finality by design for this horror framework)