# `BP_DoorActor` — Door Actor System

**Parent Class:** `Actor`
**Category:** Interaction
**Implements:** `I_Interactable`
**Target UE Version:** 5.5–5.7
**Build Phase:** 2 — Interaction

---

## 1. Overview

`BP_DoorActor` powers all door-like actors in the game world — standard hinged doors, sliding doors, double doors, and barricaded passages. It manages a discrete 6-state machine (`Closed → Opening → Open → Closing → Locked → Barricaded`), supports key/lock mechanics, item-required unlocking, one-way passage, partial-open positions, and networked replication.

The door state is exposed via Event Dispatchers so other systems (AudioManager, CameraStateLayer, AI, Narrative) can react.

---

## 2. Mermaid — Door State Machine & Interaction Flow

```mermaid
flowchart TD
    A[Idle Closed] --> B{Interact?}
    B -->|Player presses Interact| C[TryOpen]
    C --> D{Is Locked?}
    D -->|Yes: Has Required Item?| E{Remove Item?}
    D -->|Yes: No Item| F[Play Locked Feedback]
    E -->|Yes| G[Unlock & Open]
    E -->|No| F
    D -->|No| H[Play Open Anim]
    H --> I[State = Opening]
    I --> J[State = Open]
    J --> K{Close Conditions Met?}
    K -->|Auto-Close Timer| L[Play Close Anim]
    K -->|Player Interact| L
    K -->|Manual Call| L
    L --> M[State = Closing]
    M --> A

    N[Locked Entry] --> O[State = Locked]
    P[Barricaded Entry] --> Q[State = Barricaded]
    Q --> R{Barricade Broken?}
    R -->|Yes| A
    R -->|No| Q
```

---

## 3. Enums

### `E_DoorState`
Defined in `E_DoorState` enum asset.

| Value | Description |
|-------|-------------|
| `Closed` | Door fully closed, no movement. Can be interacted with. |
| `Opening` | Door playing open animation. Input blocked. |
| `Open` | Door fully open. Can be interacted with to close, or auto-closes. |
| `Closing` | Door playing close animation. Input blocked. |
| `Locked` | Door locked. Cannot be opened unless unlocked via key/item or external trigger. |
| `Barricaded` | Door physically blocked. Must be destroyed/breached. |

### `E_DoorType`

| Value | Description |
|-------|-------------|
| `Hinged` | Standard door that swings open/closed. |
| `Sliding` | Door slides horizontally into a wall pocket. |
| `Double` | Two doors that open outward/inward. |
| `RollUp` | Garage-style door that rolls upward. |
| `TrapDoor` | Floor/ceiling door that opens vertically. |

### `E_LockState`
Optional sub-state for locked doors.

| Value | Description |
|-------|-------------|
| `Unlocked` | Door can be opened normally. |
| `KeyRequired` | Requires a specific key item in inventory. |
| `ItemRequired` | Requires a specific non-key item (crowbar, code). |
| `PuzzleLinked` | Lock is controlled by an external puzzle actor. |
| `Breachable` | Lock can be broken with force (weapon/explosive). |

---

## 4. Structs

### `S_DoorConfig`

| Field | Type | Description |
|-------|------|-------------|
| `DoorType` | `E_DoorType` | Visual/mechanical type of door. |
| `DefaultState` | `E_DoorState` | State the door starts in at BeginPlay. |
| `LockState` | `E_LockState` | Lock type if DefaultState is Locked. |
| `RequiredItemTag` | `FGameplayTag` | Tag of item required to unlock (if KeyRequired/ItemRequired). |
| `RemoveItemOnUse` | `bool` | If true, the key/item is consumed on unlock. |
| `AutoCloseDelay` | `float` | Seconds before door auto-closes. 0 = never auto-close. |
| `OpenAngle` | `float` | Degrees the door opens (default 90). |
| `OpenSpeed` | `float` | Animation play rate / interpolation speed. |
| `CloseSpeed` | `float` | Animation play rate for closing. |
| `IsOneWay` | `bool` | If true, door only opens from one side. |
| `CanBeBarricaded` | `bool` | If true, door can transition to Barricaded state. |
| `BarricadeHealth` | `float` | Damage required to break barricade. |
| `bReplicates` | `bool` | Whether door state is replicated. |

### `S_DoorAudioConfig`

| Field | Type | Description |
|-------|------|-------------|
| `OpenSound` | `USoundBase*` | Sound played when door begins opening. |
| `CloseSound` | `USoundBase*` | Sound played when door begins closing. |
| `LockedSound` | `USoundBase*` | Sound played when player tries to open a locked door. |
| `UnlockSound` | `USoundBase*` | Sound played when door is unlocked. |
| `BarricadeBreakSound` | `USoundBase*` | Sound played when barricade is destroyed. |
| `SqueakInterval` | `float` | Seconds between squeak sounds during movement (0 = no squeak). |

---

## 5. Variables

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

| Variable | Type | Description |
|----------|------|-------------|
| `DoorConfig` | `S_DoorConfig` | Primary configuration struct. |
| `AudioConfig` | `S_DoorAudioConfig` | Audio configuration struct. |
| `LinkedActors` | `TArray<AActor*>` | Actors to notify on door open/close (lights, alarms, traps). |
| `RequiredItemTag` | `FGameplayTag` | Shortcut to DoorConfig.RequiredItemTag (for BP pin). |

### State (Blueprint Read Only, Replicated)

| Variable | Type | Description |
|----------|------|-------------|
| `CurrentState` | `E_DoorState` | Current door state. Replicated using `OnRep_DoorState`. |
| `CurrentLockState` | `E_LockState` | Current lock state. Replicated. |
| `CurrentBarricadeHealth` | `float` | Remaining barricade health. Replicated. |
| `bIsOpenFromFront` | `bool` | Tracks which side the door was opened from (for one-way logic). |

### Internal (Blueprint Read Only, Not Replicated)

| Variable | Type | Description |
|----------|------|-------------|
| `OwningDoorActor` | `AActor*` | Cached reference to owning actor (BP_DoorBase). |
| `DoorMeshComponent` | `UStaticMeshComponent*` | Cached reference to the door's static mesh (if hinged/sliding). |
| `DoorAudioComponent` | `UAudioComponent*` | Cached audio component for spatialized sounds. |
| `AutoCloseTimerHandle` | `FTimerHandle` | Handle for auto-close timer. |
| `AnimationTimeline` | `float` | Internal 0-1 progress of open/close animation. |

---

## 6. Functions & Events

### Public Functions

| Function | Description |
|----------|-------------|
| `Interact_Implementation` | Implements `I_Interactable.ExecuteInteraction`. Routes to `TryOpen` if Closed/Locked/Barricaded, or `TryClose` if Open. |
| `TryOpen` | Checks state: if Locked, attempts unlock (check inventory or puzzle); if Barricaded, plays blocked feedback; if Closed, begins open animation. Returns `E_DoorOperationResult`. |
| `TryClose` | If Open, begins close animation. If Opening/Closing, ignores. Returns bool. |
| `LockDoor` | Transitions to Locked state. Optionally sets lock type and required item. |
| `UnlockDoor` | Removes lock, plays unlock effects. If `bAutoOpenOnUnlock`, begins opening. |
| `BarricadeDoor` | Transitions to Barricaded state, sets health. |
| `DamageBarricade` | Reduces barricade health by damage amount. If health reaches 0, removes barricade and transitions to Closed. |
| `ForceSetState` | Bypasses animation; immediately sets door to any valid state. Used for save/load. |
| `IsDoorUsable` | Returns true if door can be interacted with (not Opening/Closing/Barricaded with health). |
| `GetDoorState` | Returns current `E_DoorState`. |
| `GetDoorType` | Returns `E_DoorType` from config. |

### Protected Functions

| Function | Description |
|----------|-------------|
| `BeginPlay` | Caches references, applies default state, initialises audio component. |
| `PlayOpenAnimation` | Starts timeline/interp for door rotation/slide. Plays open sound. Calls `OnOpenComplete` when finished. |
| `PlayCloseAnimation` | Starts timeline/interp for reverse. Plays close sound. Calls `OnCloseComplete` when finished. |
| `OnOpenComplete` | Sets state to Open, clears auto-close timer if `AutoCloseDelay > 0`, notifies `LinkedActors`. |
| `OnCloseComplete` | Sets state to Closed. |
| `TryUnlockWithItem` | Checks player inventory for `RequiredItemTag`. If found and `RemoveItemOnUse`, consumes the item. Returns bool. |
| `CheckPuzzleUnlockCondition` | Returns true if linked puzzle is solved. |
| `PlayLockedFeedback` | Plays locked sound + optional UI prompt notifying player of required item. |
| `OnRep_DoorState` | RepNotify: when `CurrentState` changes, plays appropriate animation on remote clients. |

### Event Dispatchers

| Dispatcher | Payload | Description |
|------------|---------|-------------|
| `OnDoorStateChanged` | `E_DoorState NewState`, `AActor* Instigator` | Fired on any state transition. |
| `OnDoorOpened` | `AActor* Instigator`, `bool bFromFront` | Fired when door reaches Open state. |
| `OnDoorClosed` | `AActor* Instigator` | Fired when door reaches Closed state. |
| `OnDoorLocked` | `AActor* Instigator` | Fired when door transitions to Locked. |
| `OnDoorUnlocked` | `AActor* Instigator` | Fired when door is unlocked. |
| `OnBarricadeBroken` | `AActor* Instigator` | Fired when barricade health reaches 0. |
| `OnInteractionFailed` | `E_DoorState CurrentState`, `FText FailReason` | Fired when player cannot interact. |

---

## 7. Blueprint Graph Flow

### Event Graph Flow

```
Event BeginPlay
    → GetOwner → Cast to BP_DoorBase → Cache OwningDoorActor
    → FindComponentByClass UStaticMeshComponent → Cache DoorMeshComponent
    → Create Audio Component → Cache
    → Apply Default State from DoorConfig.DefaultState
    → If Locked → Set CurrentLockState → LockDoor

On Interact_Implementation
    → Branch: CurrentState
        — Closed → Call TryOpen
        — Locked → Call TryUnlockWithItem → Branch Result
            — Success → Play Unlock Effects → Call TryOpen
            — Fail → Play LockedFeedback → Broadcast OnInteractionFailed
        — Barricaded → Play Blocked Feedback → Broadcast OnInteractionFailed
        — Open → Call TryClose
        — Opening/Closing → Ignore (return)

TryOpen
    → IsDoorUsable? → If not, return false
    → Set CurrentState = Opening
    → Broadcast OnDoorStateChanged
    → Set bIsOpenFromFront = (player side check)
    → PlayOpenAnimation

TryClose
    → IsDoorUsable? → If not, return false
    → Set CurrentState = Closing
    → Broadcast OnDoorStateChanged
    → Clear AutoCloseTimerHandle
    → PlayCloseAnimation

PlayOpenAnimation
    → Timeline: 0→1 over 1/OpenSpeed seconds
    → Interp: DoorMeshComponent RelativeRotation.Yaw from 0 → OpenAngle (or DoorConfig sign for direction)
    → PlaySound: AudioConfig.OpenSound
    → On Finished → OnOpenComplete

PlayCloseAnimation
    → Timeline: 1→0 over 1/CloseSpeed seconds
    → Interp: DoorMeshComponent RelativeRotation.Yaw from current → 0
    → PlaySound: AudioConfig.CloseSound
    → On Finished → OnCloseComplete

OnOpenComplete
    → Set CurrentState = Open
    → Broadcast OnDoorOpened
    → If AutoCloseDelay > 0 → Set Timer by Event (AutoCloseDelay, Call TryClose)
    → Notify LinkedActors (Open event)

OnCloseComplete
    → Set CurrentState = Closed
    → Broadcast OnDoorClosed
    → Notify LinkedActors (Close event)

LockDoor
    → Set CurrentState = Locked
    → Set CurrentLockState = Input LockState
    → Broadcast OnDoorLocked

UnlockDoor
    → Set CurrentLockState = Unlocked
    → If bAutoOpenOnUnlock → Call TryOpen
    → Broadcast OnDoorUnlocked

DamageBarricade
    → CurrentBarricadeHealth -= Damage
    → If CurrentBarricadeHealth <= 0
        → Set CurrentState = Closed
        → Broadcast OnBarricadeBroken
        → Broadcast OnDoorStateChanged
```

---

## 8. Replication

| Variable | Replication | Callback |
|----------|-------------|----------|
| `CurrentState` | `RepNotify` | `OnRep_DoorState` — plays matching animation on remote |
| `CurrentLockState` | `Replicated` | — |
| `CurrentBarricadeHealth` | `Replicated` | — |
| `bIsOpenFromFront` | `Replicated` | — |

**Server authority:** All state transitions are executed on the server. Clients predict input via `Interact_Implementation`, but the server validates and broadcasts the authoritative state.

---

## 9. Dependencies & Communication

| System | Relationship |
|--------|--------------|
| `BPC_InteractionDetector` | Calls `Interact_Implementation` when player looks at door and presses Interact. |
| `BPC_InventorySystem` | Queried via `TryUnlockWithItem` for item possession and consumption. |
| `BPC_HealthSystem` | Listens to `OnBarricadeBroken` for environmental damage credit. |
| `BPC_CameraStateLayer` | May request FOV push when door opens into a large space. |
| `AudioManager` | Consumes `AudioConfig` and may play ambient/occlusion changes on door state. |
| `AI Perception` | AI listens to `OnDoorOpened`/`OnDoorClosed` to update pathfinding and awareness. |
| `Save/Load System` | Calls `ForceSetState` and `LockDoor`/`UnlockDoor` during restore. |
| `Narrative Subsystem` | May bind to `OnDoorUnlocked` to trigger dialogue when a story-key door is opened. |
| `BP_PuzzleDeviceActor` | `PuzzleLinked` lock type — puzzle completion calls `UnlockDoor`. |
| `BPC_DifficultyManager` | May adjust `AutoCloseDelay` and `BarricadeHealth` based on player performance metrics. |

---

## 10. Success Criteria

1. Player can open/close a hinged door with standard interaction.
2. Locked door plays feedback sound and shows item-required prompt.
3. Player with correct key/item unlocks door; item is consumed if configured.
4. Door auto-closes after configurable delay; auto-close timer resets on re-open.
5. Barricaded door blocks passage until its health reaches 0 via damage.
6. `PuzzleLinked` door unlocks when linked `BP_PuzzleDeviceActor` reports completion.
7. One-way doors only open from the configured side.
8. Double doors open/close in sync as a paired animation.
9. Multiplayer: server-authoritative state syncs to all clients via `OnRep_DoorState`.
10. Save/load correctly restores door state, lock state, and barricade health.

---

## 11. Data Flow Summary

```
Player Presses Interact
    → BPC_InteractionDetector.ScanForInteractables
    → Closest valid target = BP_DoorActor
    → Call I_Interactable.ExecuteInteraction
    → BP_DoorActor.Interact_Implementation
    → State check / lock check / inventory check
    → Play animation / sound
    → Broadcast Event Dispatchers
    → Downstream systems react (AI, Audio, Narrative, Save)
```

## 12. Reuse Notes

- This renamed file (formerly `BPC_InteractableDoorComponent`) is now an Actor-based system (`BP_DoorActor`) as per Master Section 3.5.
- The door actor encapsulates all door logic directly rather than as an ActorComponent.
- Cross-references updated: `BPC_InventoryComponent` → `BPC_InventorySystem`, `BPC_LeverPuzzleComponent` → `BP_PuzzleDeviceActor`.

---

## 13. Multiplayer Networking (Expanded)

### Server RPCs

| RPC | Direction | Description |
|-----|-----------|-------------|
| `Server_Interact` | Client→Server | Client requests door interaction. Server validates range, state, lock, then executes TryOpen/TryClose. |
| `Server_DamageBarricade` | Client→Server | Client deals damage to barricade. Server validates damage source, applies to barricade health. |
| `Server_TryUnlock` | Client→Server | Client attempts unlock with key item. Server validates inventory, consumes item if configured. |

### Authority Gates

```
Interact_Implementation
  If NOT HasAuthority:
    → Call Server_Interact(DoorActor)
    → Return (client prediction: show prompt, wait for OnRep)
  // Server executes authoritative logic
  → TryOpen / TryClose / TryUnlock
  → OnRep broadcasts to all clients
```

### Client Prediction
- **Interaction:** Client calls `Server_Interact` RPC; server validates and changes state.
- **Animation:** `OnRep_DoorState` triggers animation on all clients identically.
- **Locked feedback:** Played locally by client when server rejects interaction.

### Anti-Cheat
- Server validates player is within interaction range before opening door.
- Server validates key item is in player inventory before unlocking.
- Server validates barricade damage source.

---

## 14. Manual Implementation Guide

### 14.1 Class Setup
1. Create Blueprint Class: Parent = `Actor`, Name = `BP_DoorActor`
2. Add components: `DoorRoot` (SceneComponent), `DoorFrame` (StaticMesh — static), `DoorMesh` (StaticMesh — rotates/slides), `InteractionCollision` (Box or Sphere)
3. Implement Interfaces: `I_Interactable`, `I_Persistable`
4. Set `Replicates` = true in Class Defaults

### 14.2 Variable Defaults
| Variable | Default |
|----------|---------|
| `CurrentState` | `Closed` |
| `CurrentLockState` | `Unlocked` |
| `CurrentBarricadeHealth` | `100.0` |
| `AutoCloseDelay` | `3.0` (0 = never) |
| `OpenAngle` | `90.0` |
| `OpenSpeed` | `2.0` |
| `CloseSpeed` | `1.5` |

### 14.3 Function Node-by-Node

#### `BeginPlay`
```
Event BeginPlay
  → Cache OwningActor (Self)
  → Get DoorMesh by tag/name → Cache DoorMeshComponent
  → Spawn Audio Component → Cache DoorAudioComponent
  → Apply DefaultState from DoorConfig:
    Switch on DoorConfig.DefaultState:
      Closed → (nothing, already closed)
      Locked → Call LockDoor
      Open → Call ForceSetState(Open) ← for save/load or pre-opened doors
```

#### `Interact_Implementation(Instigator: Actor)` — I_Interactable
```
Switch on CurrentState:
  Closed → Call TryOpen(Instigator)
  Open → Call TryClose(Instigator)
  Locked → Call TryUnlockWithItem(Instigator)
    Branch on result:
      True → Call UnlockDoor → Call TryOpen(Instigator)
      False → Call PlayLockedFeedback → Fire OnInteractionFailed
  Barricaded → Call DamageBarricade(Instigator)
    If attack breaks barricade → OnBarricadeBroken → SetState Closed
  Opening/Closing → Return (ignored during animation)
```

#### `TryOpen(Instigator)` — **Must check HasAuthority() for MP**
```
  Branch: CurrentState != Closed → Return false
  If DoorConfig.IsOneWay:
    Check player side (dot product of door forward vs player forward)
    If wrong side → Play locked feedback → Return false
  SetWeaponState(Opening)
  Fire OnDoorStateChanged
  PlayOpenAnimation()  ← uses Timeline, not Timer
```

#### `PlayOpenAnimation` — **Key node setup:**
```
  Create Timeline (float track, 0→1 over OpenSpeed seconds)
    Timeline Update pin:
      → Get DoorMesh → Set Relative Rotation:
        Lerp (Quat): startRotation to startRotation + Rotator(0, OpenAngle, 0) by Timeline Alpha
    Timeline Finished pin:
      → Call OnOpenComplete
  Play Sound: AudioConfig.OpenSound at DoorMesh location via SS_AudioManager
```

#### `OnOpenComplete`
```
  Set CurrentState = Open
  Fire OnDoorOpened(Instigator, bIsOpenFromFront)
  If AutoCloseDelay > 0:
    Set Timer by Event (AutoCloseDelay) → Call TryClose(Self)
      Use "Self" as instigator for auto-close
  Notify LinkedActors with "Open" event
```

#### `TryClose(Instigator)`
```
  Branch: CurrentState != Open → Return false
  Set CurrentState = Closing
  Clear AutoCloseTimer (if running — prevents auto-close during manual close)
  Fire OnDoorStateChanged
  PlayCloseAnimation()
```

#### `TryUnlockWithItem(Instigator)` → `Boolean`
```
  If CurrentLockState == KeyRequired:
    Get RequiredItemTag from DoorConfig
    Get Instigator → Get BPC_InventorySystem → Call HasItemQuantity(RequiredItemTag, 1)
    If found:
      If DoorConfig.RemoveItemOnUse:
        BPC_InventorySystem.RemoveItemByTag(RequiredItemTag, 1)
      Return true
    Return false
  If CurrentLockState == PuzzleLinked:
    Get LinkedPuzzle → Call IsPuzzleSolved
    Return result
```

#### `DamageBarricade(Instigator, DamageAmount)` 
```
  Branch: CurrentState != Barricaded → Return
  CurrentBarricadeHealth -= DamageAmount
  If CurrentBarricadeHealth <= 0:
    Set CurrentBarricadeHealth = 0
    Set CurrentState = Closed
    Fire OnBarricadeBroken(Instigator)
    Fire OnDoorStateChanged
  Mark variable dirty (replication)
```

### 14.4 Blueprint Build Checklist
- [ ] Create BP_DoorActor with DoorFrame + DoorMesh + InteractionCollision
- [ ] Add all config variables (S_DoorConfig, S_DoorAudioConfig, LinkedActors)
- [ ] Set DoorMesh mobility to Movable (for rotation during animation)
- [ ] Implement I_Interactable with Interact_Implementation
- [ ] Build TryOpen/TryClose with state validation
- [ ] Create Timeline for door open/close animation (NOT Timer — Timeline for smooth interpolation)
- [ ] Implement auto-close timer with reset on re-open
- [ ] Build TryUnlockWithItem querying player inventory
- [ ] Implement lock/barricade damage with health tracking
- [ ] Add DoorAudioComponent for spatialized sounds
- [ ] Set up LinkedActors — designer assigns in editor
- [ ] Add networking: replicated CurrentState, Server_Interact RPC
- [ ] Test: approach → interact → door opens → auto-closes → locked door → use key → unlocks