# BPC_HitReactionSystem — Hit Reaction System

> **⚡ C++ Status: Stub** — `Source/PG_Framework/Public/Weapons/BPC_HitReactionSystem.h` provides the UCLASS shell, `PlayHitReaction()` stub, `FlinchThreshold`, and `RagdollThreshold`. **The C++ stub has NO gameplay logic.** **Create a BP child** and build ALL logic: hit reaction animation selection, stagger/knockdown/ragdoll trigger, directional response, camera trauma. Attach to player/enemy pawns. See `docs/developer/cpp-integration-guide.md`.
>
> ---

## Blueprint Spec — UE 5.5–5.7

---

### Parent Class
`ActorComponent`

### Dependencies
- **Requires:** [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md) — Receives damage events
- **Requires:** [`BPC_CameraStateLayer`](../02-player/14_BPC_CameraStateLayer.md) — Camera trauma effects
- **Requires:** [`S_DamageEvent`](../02-player/08_BPC_HealthSystem.md) — Damage event struct (E_DamageType, Amount, HitLocation, HitNormal)
- **Requires:** [`E_DamageType`](../01-core/03_I_InterfaceLibrary.md) — Damage type enum for montage selection
- **Required By:** [`BPC_AdaptiveEnvironmentDirector`](../10-adaptive/BPC_AdaptiveEnvironmentDirector.md) — Reads trauma intensity for atmosphere
- **Engine/Plugin Requirements:** Animation Blueprint (ABP_PlayerBody), GASP animation hooks

### Purpose
Drives physical hit reaction behaviour: flinch animations, ragdoll blends, and camera trauma. Processes incoming damage events and triggers appropriate reaction animations based on damage magnitude, direction, and type.

---

## 1. Enums

*Uses `E_DamageType` from [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md) — Physical, Fire, Psychic, Environmental, InstantKill, Scripted.*

---

## 2. Structs

*No new structs defined. Uses `S_DamageEvent` from [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md).*

---

## 3. Variables

### Configuration (Instance Editable, Expose On Spawn)

| Variable | Type | Default | Category | Description |
|----------|------|---------|----------|-------------|
| `FlinchThreshold` | Float | 5.0 | HitReaction | Minimum damage to trigger flinch animation |
| `RagdollThreshold` | Float | 50.0 | HitReaction | Damage amount that triggers ragdoll blend |
| `TraumaDecayRate` | Float | 2.0 | HitReaction | Camera trauma points recovered per second |
| `HitReactionMontages` | Map (E_DamageType → AnimMontage) | Empty | HitReaction | Per-damage-type hit reaction animations |

### Internal (Private / Protected, No Expose)

| Variable | Type | Default | Category | Description |
|----------|------|---------|----------|-------------|
| `CurrentTrauma` | Float | 0.0 | Internal | Accumulated camera trauma level |
| `bIsReacting` | Bool | False | Internal | Reaction animation currently playing |
| `LastDamageDirection` | Vector | (0,0,0) | Internal | Direction of most recent damage for animation blend |
| `NextReactionIndex` | Integer | 0 | Internal | Cycles through available montages per type for variety |

---

## 4. Functions

### Public Functions

#### `ProcessHitReaction` → `void`
- **Description:** Main entry point. Called when player receives damage. Determines reaction type based on damage amount vs thresholds.
- **Parameters:**
  | Param | Type | Description |
  |-------|------|-------------|
  | `DamageEvent` | S_DamageEvent | Full damage context from HealthSystem |
- **Blueprint Authority:** Any
- **Flow:** Checks thresholds → selects montage → plays animation → applies trauma → broadcasts dispatchers

#### `ApplyTrauma` → `void`
- **Description:** Adds camera trauma based on damage amount.
- **Parameters:**
  | Param | Type | Description |
  |-------|------|-------------|
  | `Amount` | Float | Trauma points to add |
- **Blueprint Authority:** Any

#### `GetCurrentTrauma` → `Float`
- **Description:** Returns current accumulated trauma level (0–100).
- **Parameters:** None
- **Blueprint Authority:** Any

#### `ResetTrauma` → `void`
- **Description:** Clears all accumulated camera trauma to zero.
- **Parameters:** None
- **Blueprint Authority:** Any

### Protected / Private Functions

#### `SelectHitReactionMontage` → `AnimMontage`
- **Description:** Picks a hit reaction montage based on damage type and cycles through available options for variety.
- **Parameters:**
  | Param | Type | Description |
  |-------|------|-------------|
  | `DamageType` | E_DamageType | Type of damage received |
  | `DamageAmount` | Float | Magnitude of damage |
- **Flow:** Look up HitReactionMontages map by damage type → cycle through entries → return selected montage

#### `TickTraumaDecay` → `void`
- **Description:** Called on tick to decay camera trauma toward zero at TraumaDecayRate.
- **Parameters:**
  | Param | Type | Description |
  |-------|------|-------------|
  | `DeltaTime` | Float | Frame delta time |
- **Flow:** `CurrentTrauma = FMath::FInterpTo(CurrentTrauma, 0.0, DeltaTime, TraumaDecayRate)`

---

## 5. Event Dispatchers

| Dispatcher | Parameters | Bind Access | Description |
|------------|-----------|-------------|-------------|
| `OnFlinchTriggered` | DamageType: E_DamageType, Amount: Float | Public | Flinch animation fired (damage below ragdoll threshold) |
| `OnRagdollBlend` | Amount: Float, Direction: Vector | Public | Ragdoll blend triggered (damage exceeded ragdoll threshold) |
| `OnTraumaChanged` | CurrentTrauma: Float | Public | Trauma level changed (for camera/screen effects) |
| `OnHitReactionComplete` | DamageType: E_DamageType | Public | Reaction animation finished playing |

---

## 6. Overridden Events / Custom Events

### Event: `ReceiveDamage`
- **Description:** Called by [`BPC_DamageReceptionSystem`](BPC_DamageReceptionSystem.md) when player takes damage. Routes to `ProcessHitReaction`.
- **Flow:**
  1. Extract damage amount and type from DamageEvent
  2. If DamageAmount >= FlinchThreshold → ProcessHitReaction
  3. If DamageAmount >= RagdollThreshold → trigger ragdoll blend instead
  4. Calculate LastDamageDirection from HitLocation relative to player
  5. ApplyTrauma proportional to damage amount

---

## 7. Blueprint Graph Logic Flow

```mermaid
flowchart TD
    A[ReceiveDamage called] --> B{Damage >= RagdollThreshold?}
    B -->|Yes| C[Disable input temporarily]
    B -->|No| D{Damage >= FlinchThreshold?}
    C --> E[Play ragdoll physics blend]
    D -->|Yes| F[SelectHitReactionMontage by DamageType]
    D -->|No| G[Skip reaction, only apply trauma]
    F --> H[Play montage with directional blend]
    H --> I[Broadcast OnFlinchTriggered]
    I --> J[Wait for montage end]
    J --> K[Broadcast OnHitReactionComplete]
    E --> L[Set bIsReacting = true]
    L --> M[Wait for ragdoll timer]
    M --> N[Recover from ragdoll]
    N --> K
    G --> O[ApplyTrauma proportional to damage]
    K --> O
    O --> P[Broadcast OnTraumaChanged]
    P --> Q[Camera system reads trauma]
```

---

## 8. Communication Matrix

| Who Talks | How | What Is Sent |
|-----------|-----|-------------|
| [`BPC_DamageReceptionSystem`](BPC_DamageReceptionSystem.md) | Direct call | `S_DamageEvent` |
| [`BPC_CameraStateLayer`](../02-player/14_BPC_CameraStateLayer.md) | Dispatcher (`OnTraumaChanged`) | `CurrentTrauma: Float` |
| [`WBP_ScreenEffectController`](../06-ui/WBP_ScreenEffectController.md) | Dispatcher (`OnTraumaChanged`) | `CurrentTrauma: Float` |
| [`ABP_PlayerBody`](../02-player/13_BPC_EmbodimentSystem.md) | Direct (anim var write) | `LastDamageDirection`, reaction montage reference |
| [`BPC_AdaptiveEnvironmentDirector`](../10-adaptive/BPC_AdaptiveEnvironmentDirector.md) | Direct read | `CurrentTrauma` via getter |

---

## 9. Validation / Testing Checklist

- [ ] FlinchThreshold: damage at 5.0+ triggers flinch animation
- [ ] RagdollThreshold: damage at 50.0+ triggers ragdoll blend
- [ ] TraumaDecayRate: trauma reduces to zero over time when no damage received
- [ ] HitReactionMontages map: correct montage plays per E_DamageType
- [ ] Edge case: zero damage events do not trigger any reaction
- [ ] Edge case: rapid succession hits cycle through montage variations
- [ ] Edge case: death event (HealthSystem OnDeath) skips flinch, goes directly to ragdoll

---

## 10. Reuse Notes

- FlinchThreshold and RagdollThreshold can be tuned per project for desired combat feel
- HitReactionMontages map uses E_DamageType as key — add new damage types without modifying core logic
- Trauma system is separate from camera shake — trauma drives persistent wobble, shake is transient
- For non-combat projects, set FlinchThreshold very high (e.g., 9999) to disable reactions entirely

---

*Specification based on Master Section 5.7, line 1821.*

---

## Manual Implementation Guide

### Class Setup
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_HitReactionSystem`
2. Add to Player Character (or EnemyBase)
3. Create HitReactionMontages per damage type: Physical, Fire, Explosive, etc.

### Variable Init (BeginPlay)
```
Event BeginPlay
  ├─ Set CurrentTrauma = 0.0, bIsReacting = false
  ├─ Populate HitReactionMontages map (E_DamageType → AnimMontage)
  ├─ Cache: BPC_HealthSystem (bind OnDamageTaken), BPC_CameraStateLayer
  └─ Start TraumaDecay timer (0.1s loop)
```

### Function Node-by-Node

#### `ProcessHitReaction(DamageEvent: S_DamageEvent)` → `void`
```
Step 1: If bIsReacting → Return (already playing reaction)
Step 2: Set LastDamageDirection = DamageEvent.HitNormal * -1  ← direction damage came from
Step 3: If DamageEvent.Amount >= RagdollThreshold:
  Play ragdoll blend: ABP → Set bRagdoll=true, physics blend
  Set bIsReacting = true → timer to recover
  Return
Step 4: If DamageEvent.Amount >= FlinchThreshold:
  Select montage: HitReactionMontages[DamageEvent.DamageType]
  If multiple: pick NextReactionIndex, cycle it
  Play Montage with blend from LastDamageDirection
  Set bIsReacting = true
Step 5: Call ApplyTrauma(DamageEvent.Amount * 0.5)
Step 6: Fire OnHitReactionPlayed(DamageEvent)
Step 7: On montage complete → Set bIsReacting = false
```

#### `ApplyTrauma(Amount: Float)` → `void`
```
Step 1: CurrentTrauma = Min(100, CurrentTrauma + Amount)
Step 2: Push to camera: BPC_CameraStateLayer.ApplyPostProcessOverride(TraumaVignette, CurrentTrauma/100)
Step 3: Fire OnTraumaChanged(CurrentTrauma)
```

#### `TraumaDecay Tick` → `void` *(Timer 0.1s)*
```
CurrentTrauma = Max(0, CurrentTrauma - TraumaDecayRate * 0.1)
Update camera effect intensity
If zero: clear post-process override
```

### Build Checklist
- [ ] Create BPC_HitReactionSystem, add to Player Character
- [ ] Create hit reaction montages per damage type
- [ ] Implement ProcessHitReaction with threshold branching
- [ ] Implement ApplyTrauma with camera effect push
- [ ] Set up trauma decay timer
- [ ] Bind to BPC_HealthSystem.OnDamageTaken
- [ ] Test: take small hit → flinch; take big hit → ragdoll; trauma decays over time