# 140 — Portal Surface Actor (`BP_Portal`)

## Purpose
Portal surface with linked target. Renders the view from another location in the world through a planar surface. Supports one-way vs two-way rendering, teleport on overlap, and clip plane for flush geometry placement.

## Dependencies
- **Requires:** `BP_PlanarCaptureActor` (137), `BPC_PlanarCapture` (136), `BPC_StateManager` (130) for teleport gating
- **Required By:** Narrative sequences, level transitions, horror portal variants
- **Engine/Plugin Requirements:** Oblique clip plane requires Renderer module (C++)

## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `BP_PlanarCaptureActor` (C++ `ABP_PlanarCaptureActor`) |
| **Class Type** | Blueprint Actor |
| **Asset Path** | `Content/Framework/Capture/BP_Portal.uasset` |
| **C++ Status** | 🔵 BP Spec Only |
| **BP Asset** | Create in editor: `BP_Portal` |

## 1. Configuration (Class Defaults)

| Variable | Value | Description |
|----------|-------|-------------|
| `CaptureComponent.CaptureMode` | `Portal` | Fixed to Portal mode |
| `CaptureComponent.LinkedTargetSurface` | (Set per instance) | Destination portal actor |
| `bStartEnabled` | `true` | Active by default |
| `SurfaceMPC` | `MPC_CaptureSurface` | Global MPC |

### Portal-Specific Properties (Custom Variables — add to BP)
| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| `bTeleportOnOverlap` | bool | true | Teleport player when they enter the portal volume |
| `bOneWay` | bool | true | True = only source→target; false = bidirectional |
| `TeleportTrigger` | BoxComponent | — | Overlap volume for teleport (separate from ProximityTrigger) |

## 2. Material Setup
| Slot | Material | Description |
|------|----------|-------------|
| SurfaceMesh[0] | `MI_Portal_Standard` | Portal surface with edge fade |
| Frame (optional) | Designer mesh + material | Portal frame decoration |

## 3. Event Graph

### Event BeginPlay
```
Event BeginPlay
  ├─ Parent: BeginPlay (registers with manager)
  ├─ Set CaptureComponent.CaptureMode = Portal
  ├─ Validate CaptureComponent.LinkedTargetSurface != nullptr
  │    └─ If null → Log Warning: "BP_Portal missing LinkedTargetSurface!"
  ├─ Bind TeleportTrigger.OnComponentBeginOverlap → OnPortalOverlap
  └─ EnableSurface()
```

### Event: OnPortalOverlap(OtherActor, OtherComp, ...)
```
OnPortalOverlap(OtherActor)
  ├─ Cast OtherActor to Player Pawn
  ├─ [If bTeleportOnOverlap and HasAuthority]
  │    ├─ Query BPC_StateManager.IsActionPermitted(Framework.Action.Teleport)
  │    │    └─ If denied → return (play denied feedback)
  │    ├─ Get LinkedTargetSurface actor transform
  │    ├─ Compute exit location: TargetTransform + offset
  │    ├─ Teleport player: SetActorLocation + SetActorRotation
  │    └─ Play portal travel SFX via SS_AudioManager
  └─ [If client] Call Server_TeleportThroughPortal RPC
```

### Server RPC: Server_TeleportThroughPortal
```
Server_TeleportThroughPortal (Server, Reliable)
  ├─ Validate HasAuthority
  ├─ Validate portal still active
  ├─ Validate LinkedTargetSurface still valid
  ├─ Teleport player (same as OnPortalOverlap logic)
  └─ Multicast_OnPlayerTeleported to notify all clients
```

## 4. Communication Matrix
| Target | Method | What |
|--------|--------|------|
| `BPC_StateManager` (130) | `IsActionPermitted()` | Teleport gating |
| `SS_AudioManager` (132) | Direct | Portal whoosh/disappear SFX |
| `SS_EnhancedInputManager` (128) | Direct (optional) | Context switch during portal transition |
| `BPC_CameraStateLayer` (14) | Direct (optional) | Camera FOV transition during teleport |

## 5. Manual Implementation Guide

### 5.1 Create BP_Portal
1. Create Blueprint Class: Parent = `BP_PlanarCaptureActor`, Name = `BP_Portal`
2. In Components: add `BoxComponent` named `TeleportTrigger`
3. Size `TeleportTrigger` slightly larger than surface mesh (50-100 units deep)
4. Set `TeleportTrigger.CollisionEnabled = QueryOnly`, response to Pawn = Overlap
5. Set `CaptureComponent.CaptureMode = Portal` in Class Defaults
6. Assign `MI_Portal_Standard` to SurfaceMesh

### 5.2 Portal Link Setup
1. Place `BP_Portal_Source` and `BP_Portal_Target` in level
2. On Source: set `CaptureComponent.LinkedTargetSurface` → Target actor
3. On Target: set `CaptureComponent.LinkedTargetSurface` → Source actor (if two-way)
4. Position surfaces facing each other's expected viewing directions

### 5.3 Teleport Implementation
```
Create custom event OnPortalOverlap (bind to TeleportTrigger)
  → Switch HasAuthority
    Authority:
      → Get LinkedTargetSurface → Get Actor Transform
      → Teleport: Set Actor Location (target location + forward * 200)
      → Set Actor Rotation (target rotation)
      → Play Sound 2D (portal whoosh cue via SS_AudioManager)
    Remote:
      → Call Server_TeleportThroughPortal (RPC)
```

## 6. Build Checklist
- [ ] Create BP_Portal with TeleportTrigger component
- [ ] Set CaptureMode=Portal
- [ ] Assign MI_Portal_Standard material
- [ ] Implement overlap teleport logic with HasAuthority gate
- [ ] Add Server_TeleportThroughPortal RPC
- [ ] Test one-way portal: source renders target view
- [ ] Test teleport: player overlaps and appears at target
- [ ] Test with BPC_StateManager gating (block teleport during certain states)
