# BPC_AIPerceptionSystem — AI Perception System

## Blueprint Spec — UE 5.5–5.7

---

### Parent Class
`ActorComponent`

### Dependencies
- [`AI_BaseAgentController`](AI_BaseAgentController.md) — Owner controller
- [`BPC_AlertSystem`](60_BPC_AlertSystem.md) — Alert level processing
- `DA_AIProfile` — Perception config
- `Engine.AIPerception` — UE5's `UAIPerceptionComponent` (or custom)

### Purpose
Encapsulates all sensory perception for AI: sight, hearing, smell, and damage detection. Processes stimulus data, performs line-of-sight checks, applies detection modifiers (lighting, noise, movement speed), and reports findings to the owner [`AI_BaseAgentController`](AI_BaseAgentController.md). Supports configurable sensor ranges, cone angles, and stimulus decay rates.

### Variables

| Name | Type | Description |
|------|------|-------------|
| `SightRange` | Float | Maximum sight distance (cm) |
| `SightHalfAngle` | Float | Cone half-angle (degrees) |
| `SightLossHalfAngle` | Float | Peripheral angle before losing target |
| `HearingRange` | Float | Maximum hearing distance (cm) |
| `bUseSight` | Bool | Enable sight perception |
| `bUseHearing` | Bool | Enable hearing perception |
| `bUseDamageSense` | Bool | React to being damaged |
| `DetectionMultiplier_Lighting` | Float | 0.5–2.0 based on ambient light |
| `DetectionMultiplier_Movement` | Float | 1.0 standing, 0.3 crouched, 0.1 still |
| `DetectionMultiplier_Noise` | Float | Noise volume factor |
| `MaxAge` | Float | Seconds before stimulus decays |
| `SightDelay` | Float | Time before initial detection |
| `bTargetInSight` | Bool | Current LOS status |
| `LastSightTime` | Float | Last successful sight check |
| `RegisteredStimuli` | Array<FStimulusInfo> | Current active stimuli |

### Structs

| Struct | Fields | Description |
|--------|--------|-------------|
| `FStimulusInfo` | Type: EStimulusType, Source: AActor, Location: FVector, Strength: Float, Age: Float, bCurrentlyValid: Bool | A perceived event |

### Enums

| Enum | Values | Description |
|------|--------|-------------|
| `EStimulusType` | Sight, Hearing, Damage, Smell, Vibration | Sensory channel |

### Functions

| Name | Inputs | Outputs | Description |
|------|--------|---------|-------------|
| `InitializePerception` | Config: FPerceptionConfig | — | Set ranges, angles from profile |
| `OnSightStimulus` | Target: AActor | Bool | LOS check with modifiers |
| `OnHearingStimulus` | Location: FVector, NoiseTag: FGameplayTag, Loudness: Float | — | Sound detection |
| `OnDamageStimulus` | Instigator: AActor | — | Direct damage detection |
| `PerformLineOfSightCheck` | Target: AActor | Bool | Raycast with channel |
| `ApplyDetectionModifiers` | BaseChance: Float | Float | Apply darkness, movement, cover |
| `RegisterStimulus` | Info: FStimulusInfo | — | Add to active list |
| `ForgetStimulus` | Target: AActor | — | Clear specific source |
| `GetDominantStimulus` | — | FStimulusInfo | Highest priority active |
| `HasLineOfSightTo` | Target: AActor | Bool | Public wrapper |
| `GetSightStrength` | Target: AActor | Float | 0.0–1.0 detection confidence |
| `DecayStimuli` | DeltaTime: Float | — | Age all stimuli |

### Event Dispatchers

| Name | Parameters | Fired When |
|------|-----------|-----------|
| `OnTargetDetected` | Target: AActor, Strength: Float, Type: EStimulusType | New target detected |
| `OnTargetLost` | Target: AActor | Target out of perception |
| `OnLineOfSightChanged` | Target: AActor, bHasLOS: Bool | LOS state change |
| `OnSoundHeard` | Location: FVector, Loudness: Float | Sound detected |

### Blueprint Flow

```
[OnSightStimulus]
  └─► If !bUseSight → return false
  └─► If Distance > SightRange → return false
  └─► If Angle > SightHalfAngle → return false (outside cone)
  └─► // Modifier layer
         ModChance = ApplyDetectionModifiers(1.0)
         If Random < ModChance → return false (failed detection check)
  └─► // LOS check
         bHasLOS = PerformLineOfSightCheck(Target)
         If !bHasLOS → return false
  └─► // Confirmed
         Strength = CalculateStrength(Distance, Angle, Modifiers)
         FStimulusInfo = { Sight, Target, Location, Strength, 0, true }
         RegisterStimulus(Info)
         Broadcast OnTargetDetected(Target, Strength, Sight)
         Return true

[ApplyDetectionModifiers]
  └─► BaseChance *= DetectionMultiplier_Lighting (based on light channel)
  └─► BaseChance *= DetectionMultiplier_Movement (based on target velocity)
  └─► If target in cover → BaseChance *= 0.3 (partial cover) or 0.0 (full)
  └─► Return FMath::Clamp(BaseChance, 0.0, 1.0)

[PerformLineOfSightCheck]
  └─► Start = Owner Pawn EyeLocation
  └─► End = Target.GetActorLocation + Target BaseEyeHeight
  └─► Hit = LineTraceSingleByChannel(Channel = Visibility)
  └─► Return Hit.Actor == Target || Hit.Actor == nullptr
```

### Stimulus Priority Table

| Stimulus Type | Base Priority | Decay Rate | Triggers |
|---------------|--------------|-----------|----------|
| Damage | 100 | Instant forget on lost | Combat state |
| Sight (Combat) | 90 | 3 sec | Combat state |
| Sight (Suspicious) | 60 | 8 sec | Suspicious state |
| Hearing (Loud) | 50 | 5 sec | Investigate |
| Hearing (Quiet) | 20 | 10 sec | Brief suspicion |
| Vibration | 30 | 2 sec | Alert nearby |

### Communications With

| Target | Method | Why |
|--------|--------|-----|
| [`AI_BaseAgentController`](AI_BaseAgentController.md) | Owner | Send stimulus results |
| [`BPC_AlertSystem`](60_BPC_AlertSystem.md) | Get from Owner | Raise alerts based on perception |
| [`BP_EnemyBase`](58_BP_EnemyBase.md) | Owner Pawn | Check eye location, movement speed |
| World | Direct | Line trace queries |
| Audio Manager | Event | Query noise levels |

### Reuse Notes
- Entirely data-driven via DA_AIProfile.PerceptionConfig
- Detection modifiers allow stealth mechanics (darkness, crouch, cover)
- Sight checks use UE5 AIPerception for stimulus system, but LOS logic is custom for accuracy
- Hearing range accepts any gameplay-tagged noise source (footsteps, doors, gunshots)
- Stimulus decay prevents infinite chase after target disappears
- Renamed from `BPC_PerceptionComponent` to `BPC_AIPerceptionSystem` per Master naming convention.
- Cross-references updated: `BPC_AIControllerBase` → `AI_BaseAgentController`.