# BP_PuzzleDeviceActor — Puzzle Device Actor **Parent Class:** `Actor` **Category:** Interaction **Target UE Version:** 5.5–5.7 **Build Phase:** 2 — Interaction --- ## 1. Overview `BP_PuzzleDeviceActor` is the base actor for all puzzle devices in the world — levers, pressure plates, valve wheels, keypads, combination locks, circuit boards, and custom logic puzzles. Each instance references a [`DA_PuzzleData`](../14-data-assets/DA_PuzzleData.md) that defines the puzzle rules, solution, and completion effects. --- ## 2. Enums ### `E_PuzzleType` | Value | Description | |-------|-------------| | `Lever` | Single or multi-lever sequence | | `PressurePlate` | Weight-activated plate | | `ValveWheel` | Rotate-to-open valve | | `Keypad` | Numeric code entry | | `CombinationLock` | Multi-dial combination | | `CircuitBoard` | Connect-the-pins puzzle | | `Custom` | Script-driven puzzle | ### `E_PuzzleState` | Value | Description | |-------|-------------| | `Unsolved` | Puzzle not yet completed | | `InProgress` | Player interacting with puzzle | | `Solved` | Puzzle completed successfully | | `Failed` | Puzzle failed (if retryable) | | `Locked` | Puzzle locked (requires item/flag) | --- ## 3. Variables | Variable | Type | Description | |----------|------|-------------| | `PuzzleData` | `DA_PuzzleData*` | Data asset defining this puzzle | | `CurrentState` | `E_PuzzleState` | Current puzzle state | | `bIsInteractable` | `bool` | Can player interact with this puzzle | | `InteractionPrompt` | `FText` | Prompt text for interaction | | `LinkedActor` | `AActor*` | Actor to notify on solve (door, gate, etc.) | | `bResetOnFail` | `bool` | Auto-reset after failure | | `MaxAttempts` | `int32` | Max attempts before lockout (-1 = unlimited) | | `CurrentAttempts` | `int32` | Attempts used so far | | `CooldownSeconds` | `float` | Time before re-interaction allowed | --- ## 4. Functions | Function | Description | |----------|-------------| | `BeginInteraction` | Player starts interacting with puzzle | | `EndInteraction` | Player exits puzzle UI | | `CheckSolution` | Validates player input against puzzle data | | `OnPuzzleSolved` | Processes completion — notifies LinkedActor | | `OnPuzzleFailed` | Processes failure — resets or locks | | `ResetPuzzle` | Resets puzzle to default state | | `GetPuzzleState` | Returns current `E_PuzzleState` | --- ## 5. Event Dispatchers | Dispatcher | Payload | Description | |------------|---------|-------------| | `OnPuzzleStateChanged` | `E_PuzzleState NewState` | State transition occurred | | `OnPuzzleSolved` | `AActor* Solver` | Puzzle completed | | `OnPuzzleFailed` | `int32 AttemptNumber` | Attempt failed | | `OnPuzzleLinkedActorTriggered` | `AActor* LinkedActor` | Linked actor notified | --- ## 6. Dependencies & Communication | System | Relationship | |--------|--------------| | `DA_PuzzleData` | Defines puzzle rules and solution | | `BPC_InteractionDetector` | Focus and interaction initiation | | `BP_DoorActor` | Common linked actor (unlock on solve) | | `BPC_NarrativeStateSystem` | Set narrative flags on solve | | `SS_SaveManager` | Persist puzzle state | --- ## 7. Reuse Notes - All puzzle logic is data-driven via `DA_PuzzleData` - LinkedActor pattern decouples puzzle from effect --- ## 8. Manual Implementation Guide ### 8.1 Class Setup 1. Create Blueprint Class: Parent = `Actor`, Name = `BP_PuzzleDeviceActor` 2. Add components: StaticMesh (visual), InteractionCollision (Sphere), WidgetComponent (for interaction prompt) 3. Implement Interfaces: `I_Interactable` 4. Save to: `Content/Framework/Interaction/` ### 8.2 Variable Initialization (BeginPlay / Construction Script) ``` Event BeginPlay ├─ Set CurrentState = Unsolved (or Locked if requires unlock first) ├─ Set CurrentAttempts = 0 ├─ Load PuzzleData → if valid: │ ├─ Set InteractionPrompt = PuzzleData.PromptText │ ├─ Set MaxAttempts = PuzzleData.MaxAttempts │ ├─ Set CooldownSeconds = PuzzleData.Cooldown │ └─ Apply initial visual state (dim if locked, glowing if interactable) └─ Register with SS_SaveManager if implements I_Persistable ``` ### 8.3 Function Implementations #### `I_Interactable: OnInteract(Instigator: Actor)` → `Boolean` ``` [Function: OnInteract] — called by BPC_InteractionDetector Step 1: Branch on CurrentState: Case Unsolved → Call BeginInteraction(Instigator) → Return true Case Solved → Play solved animation/sound → Return false (already solved) Case Locked → Check if Instigator has required key: If yes → unlock → BeginInteraction If no → Play locked feedback → Return false Case InProgress → Return false (already interacting) Case Failed → If bResetOnFail: ResetPuzzle → BeginInteraction ``` #### `BeginInteraction(Instigator: Actor)` → `void` ``` [Function: BeginInteraction] Step 1: Set CurrentState = InProgress Step 2: Set bIsInteractable = false (block re-interaction during solve) Step 3: Fire OnPuzzleStateChanged(InProgress) Step 4: Branch on PuzzleData.PuzzleType: Lever, PressurePlate, ValveWheel: - No UI overlay needed; player manipulates world objects - Enable input on the puzzle's interactive levers/buttons Keypad, CombinationLock, CircuitBoard: - Open puzzle UI widget (attached to WidgetComponent or fullscreen) - Set player input mode to UI Only - Route input to puzzle widget Step 5: Block player movement (optional, per puzzle config) Step 6: Set interaction camera view (zoom to puzzle if needed) ``` #### `CheckSolution(PlayerInput: varies by puzzle type)` → `Boolean` ``` [Function: CheckSolution] Step 1: Read correct solution from PuzzleData.Solution Step 2: Compare player input against solution: - Lever sequence: check order of pulled levers matches solution - Keypad: check entered code matches solution code - CombinationLock: check each dial position - CircuitBoard: check all connections match solution - PressurePlate: check weight/actor matches Step 3: If match: Call OnPuzzleSolved(Instigator) Return true Step 4: If no match: Increment CurrentAttempts Branch on MaxAttempts != -1 AND CurrentAttempts >= MaxAttempts: True → Call OnPuzzleFailed() False → Show hint/wrong feedback, allow retry Return false ``` **Node example for keypad puzzle:** ``` Get SolutionString from PuzzleData Branch: PlayerInputCode == SolutionString ``` #### `OnPuzzleSolved(Solver: Actor)` → `void` ``` [Function: OnPuzzleSolved] Step 1: Set CurrentState = Solved Step 2: Set bIsInteractable = false (permanently) Step 3: Play solved visual: change material to green/solved glow Step 4: Play solved sound via SS_AudioManager Step 5: Fire OnPuzzleSolved(Solver) Step 6: Fire OnPuzzleStateChanged(Solved) Step 7: Notify LinkedActor (if set): If LinkedActor valid: If LinkedActor implements I_Toggleable → Call Toggle(Solver) If LinkedActor implements I_Lockable → Call Unlock(Solver) Fire OnPuzzleLinkedActorTriggered(LinkedActor) Step 8: Grant rewards from PuzzleData: Get BPC_InventorySystem → If PuzzleData.RewardItem valid → Call AddItem Get BPC_NarrativeStateSystem → Set flag: PuzzleData.CompletionFlag Step 9: EndInteraction() ``` #### `OnPuzzleFailed()` → `void` ``` [Function: OnPuzzleFailed] Step 1: Set CurrentState = Failed Step 2: Play failure sound/visual Step 3: Fire OnPuzzleFailed(CurrentAttempts) Step 4: Fire OnPuzzleStateChanged(Failed) Step 5: Branch on bResetOnFail: True → Start timer for CooldownSeconds → Call ResetPuzzle False → If MaxAttempts reached: Set CurrentState = Locked permanently Step 6: EndInteraction() ``` #### `EndInteraction()` → `void` ``` [Function: EndInteraction] Step 1: Close puzzle UI widget (if open) Step 2: Restore player input mode to Game Only Step 3: Re-enable player movement Step 4: Restore camera to default Step 5: If CurrentState != InProgress → Set bIsInteractable = true ``` #### `ResetPuzzle()` → `void` ``` [Function: ResetPuzzle] Step 1: Set CurrentState = Unsolved Step 2: Set CurrentAttempts = 0 Step 3: Reset all puzzle levers/dials/inputs to default positions Step 4: Set bIsInteractable = true Step 5: Fire OnPuzzleStateChanged(Unsolved) ``` ### 8.4 Blueprint Build Checklist - [ ] Create BP_PuzzleDeviceActor actor with mesh + collision + widget components - [ ] Implement I_Interactable interface - [ ] Add all variables: PuzzleData, CurrentState, bIsInteractable, LinkedActor, MaxAttempts, etc. - [ ] Implement BeginInteraction with type-switch (lever vs UI vs custom) - [ ] Implement CheckSolution with type-specific validation - [ ] Implement OnPuzzleSolved (visual, sound, LinkedActor, rewards, narrative flag) - [ ] Implement OnPuzzleFailed (retry or lockout) - [ ] Implement EndInteraction (UI close, input restore, camera restore) - [ ] Implement ResetPuzzle for retryable puzzles - [ ] Bind to BPC_InteractionDetector via I_Interactable - [ ] Test: approach puzzle → interact → solve → door unlocks → save/load restores state