# Item Example — Keycard (Key Item)

**Item Type:** `KeyItem`
**Complexity:** Low
**Systems Used:** `DA_ItemData`, `BP_ItemPickup`, `BPC_InventorySystem`, `BPC_KeyItemSystem`, `I_Lockable`, `BP_DoorActor`
**What You Learn:** Key item Data Asset, auto-protection from drop/clear, used-once pattern, door unlocking via `I_Lockable`

---

## 1. Create the DA_ItemData

### 1.1 — Create the Data Asset

```
Content Browser → Game/Items/
  Right-click → Miscellaneous → Data Asset
  Class: DA_ItemData
  Name: DA_Item_Keycard_Omega
```

### 1.2 — Fill Properties

| Property | Value | Notes |
|----------|-------|-------|
| `Item Tag` | `Framework.Item.KeyItem.KeycardOmega` | Unique — registered in `DA_GameTagRegistry` |
| `Display Name` | "Omega Keycard" | Player sees this |
| `Description` | "A high-security keycard labeled 'Omega Wing.'" | Shown in journal/inventory |
| `Icon` | `T_Keycard_Icon` | Card-shaped texture |
| `World Mesh` | `SM_Keycard` | Flat card mesh |
| `Weight` | `0.1` | Very light |
| `Stack Limit` | `1` | One per slot — cannot stack keycards |
| `Item Type` | `KeyItem` | Key items are auto-protected |
| `b Is Key Item` | ✓ (checked) | This property also appears — it's a boolean flag |
| `b Can Be Dropped` | ✗ (unchecked) | Key items should NOT be droppable (auto-forced by `bIsKeyItem`) |

### 1.3 — Save

No sub-data needed. Key items don't have Equipment or Consumable data.

---

## 2. Create the BP_Pickup_KeycardOmega

Same pattern as other pickups:

### 2.1 — Create Blueprint

```
Content Browser → Game/Pickups/
  Right-click → Blueprint Class → Actor
  Name: BP_Pickup_KeycardOmega
```

### 2.2 — Components

| # | Component | Name | Purpose |
|---|-----------|------|---------|
| 1 | `StaticMeshComponent` | `Mesh` | Card model |
| 2 | `SphereComponent` | `PickupTrigger` | Radius 150, `OverlapOnlyPawn` |

### 2.3 — Variable

`ItemData` → Type: `DA_ItemData → Object Reference` → Instance Editable ✓

### 2.4 — Construction Script (same pattern)

```
ItemData → Get World Mesh → Load Synchronous → Set Static Mesh (Mesh)
ItemData → Get Display Name → Set Actor Label
```

### 2.5 — I_Interactable Wiring (same pattern)

```
Interactor → Get BPC_InventorySystem → CanAddItem(ItemData, 1)
  True → AddItem → Destroy Actor → Return True
  False → Print "Inventory Full" → Return False
```

---

## 3. Create the Lockable Door

### 3.1 — Create Door Blueprint

```
Content Browser → Game/Actors/
  Right-click → Blueprint Class → Actor (or BP_DoorActor from framework)
  Name: BP_Door_OmegaWing
```

### 3.2 — Add Components

| # | Component | Name | Purpose |
|---|-----------|------|---------|
| 1 | `StaticMeshComponent` | `DoorFrame` | The door frame (static) |
| 2 | `StaticMeshComponent` | `DoorPanel` | The moving door part |
| 3 | `BoxComponent` | `InteractionTrigger` | Door interaction range |

### 3.3 — Add Interfaces

Class Settings → Interfaces → Add:
- `UInteractable`
- `ULockable`

### 3.4 — Variables

| Variable | Type | Default | Purpose |
|----------|------|---------|---------|
| `bIsLocked` | Boolean | `true` | Door starts locked |
| `bIsOpen` | Boolean | `false` | Door starts closed |
| `RequiredKeyTag` | GameplayTag | `Framework.Item.KeyItem.KeycardOmega` | Which key unlocks this |

### 3.5 — Wire I_Lockable

```
Event Try Unlock (Interface -> ULockable)
  │ Unlocker: AActor*, KeyTag: FGameplayTag
  │ Return Boolean
  │
  ├─ bIsLocked? → Branch
  │    ├─ True:
  │    │    ├─ KeyTag == RequiredKeyTag? → Branch
  │    │    │    ├─ True:
  │    │    │    │    ├─ Set bIsLocked = false
  │    │    │    │    ├─ Unlocker → Get BPC_KeyItemSystem
  │    │    │    │    │    └─ Consume Key (KeyTag) ← removes key from inventory
  │    │    │    │    ├─ Print "Door unlocked with Omega Keycard"
  │    │    │    │    └─ Return True
  │    │    │    │
  │    │    │    └─ False:
  │    │    │         ├─ Print "Wrong key — requires Omega Keycard"
  │    │    │         └─ Return False
  │    │    │
  │    │    └─ False: (already unlocked)
  │    │         └─ Return True

Event Is Locked
  │ Return Boolean
  └─ Return bIsLocked

Event Get Required Key Tag
  │ Return FGameplayTag
  └─ Return RequiredKeyTag

Event Try Lock
  │ Locker: AActor*
  │ Return Boolean
  └─ Set bIsLocked = true → Return True  (re-lockable for puzzle purposes)
```

### 3.6 — Wire I_Interactable (on door)

```
Event Interact (Interface -> UInteractable)
  │ Interactor: AActor*
  │ Return Boolean
  │
  ├─ bIsLocked? → Branch
  │    ├─ True:
  │    │    ├─ Interactor → Get BPC_KeyItemSystem
  │    │    │    └─ Has Key(RequiredKeyTag)?
  │    │    │         ├─ True:
  │    │    │         │    ├─ Call Try Unlock (self, Interactor, RequiredKeyTag)
  │    │    │         │    └─ (If unlocked) → Open Door (see below)
  │    │    │         │
  │    │    │         └─ False:
  │    │    │              ├─ Print "Door is locked. Find Omega Keycard."
  │    │    │              └─ Return False
  │    │    │
  │    │    └─ Return False
  │    │
  │    └─ False: (door is unlocked)
  │         ├─ bIsOpen? → Branch
  │         │    ├─ True → Close Door → Return True
  │         │    └─ False → Open Door → Return True

Function: Open Door
  │
  ├─ Timeline (Rotation track, 0 → OpenAngle over OpenDuration)
  │    └─ Update: DoorPanel → Set Relative Rotation
  ├─ Set bIsOpen = true
  └─ (Optional) Play door creak sound

Function: Close Door
  │
  ├─ Timeline (Rotation track, OpenAngle → 0 over CloseDuration)
  │    └─ Update: DoorPanel → Set Relative Rotation
  ├─ Set bIsOpen = false
  └─ (Optional) Play door close sound
```

---

## 4. Wire BPC_KeyItemSystem (On Player Pawn)

The `BPC_KeyItemSystem` tracks which key items the player holds. It automates:
- Protecting key items from being dropped/cleared
- Validating key item requirements on door/lock interactions
- Removing consumed key items after use

In your BP child of `BPC_KeyItemSystem`:

```
Function: Has Key (KeyTag: GameplayTag) → Boolean
  │
  ├─ Get Owner → Get BPC_InventorySystem
  ├─ Get All Items → For Each Loop
  │    ├─ Item → Get bIsKeyItem → Branch
  │    │    ├─ True: Item → Get ItemTag == KeyTag? → Return True
  │    │    └─ False: Continue
  │    │
  │    └─ Loop end → Return False

Function: Consume Key (KeyTag: GameplayTag)
  │
  ├─ Get Owner → Get BPC_InventorySystem
  ├─ Has Key(KeyTag)? → Branch
  │    ├─ True: Inventory → Remove Item (by KeyTag, Quantity=1)
  │    └─ False: Print "No such key in inventory"
```

> In the full framework, `BPC_KeyItemSystem` also prevents `Clear Inventory` and `Drop` operations from affecting key items by checking `bIsKeyItem` on the Data Asset.

---

## 5. Verification Checklist

**Step 1 — Pickup:**
- [ ] `BP_Pickup_KeycardOmega` placed in level, mesh visible
- [ ] Walk up → prompt "Pick up Omega Keycard" → press Interact → card goes to inventory

**Step 2 — Inventory Protection:**
- [ ] Keycard appears in inventory with "KEY" badge/indicator
- [ ] Try to drop keycard → blocked (cannot drop key items)
- [ ] Try "Clear Inventory" → keycard remains (protected)

**Step 3 — Door Interaction:**
- [ ] Walk up to `BP_Door_OmegaWing` while locked → prompt "Door is locked"
- [ ] Interact → door stays closed, shows "Requires Omega Keycard"
- [ ] Pick up keycard → walk to door → interact → door unlocks, keycard consumed from inventory
- [ ] Interact again → door opens

**Step 4 — Wrong Key:**
- [ ] Create a `DA_Item_Keycard_Beta` with a different tag
- [ ] Pick it up, try on Omega door → "Wrong key — requires Omega Keycard"
- [ ] Keycard_Beta stays in inventory (not consumed on wrong door)

---

## 6. KeyItem vs Regular Item — What's Different

| Behavior | Regular Item | Key Item (`bIsKeyItem = true`) |
|----------|-------------|-------------------------------|
| Can be dropped? | Yes (if `bCanBeDropped`) | No (auto-protected) |
| Can be cleared (death/new game)? | Yes | No (preserved across death) |
| Stacks | Yes (up to StackLimit) | Usually StackLimit=1 |
| Appears in inventory? | Yes | Yes, with KEY indicator |
| Consumed on use? | Depends on type | Yes (used once, then removed) |
| Sells to vendor? | Yes | No (protected from sale) |

Key items exist specifically to **gate progression**. They're a player's permanent proof of having solved a puzzle, explored an area, or defeated a boss. The framework ensures they can't be accidentally lost.
