# BPC_JournalSystem — Journal System

**Parent Class:** `ActorComponent`
**Category:** Inventory
**Target UE Version:** 5.5–5.7
**Build Phase:** 3 — Inventory

## 1. Overview

`BPC_JournalSystem` manages the player journal — tracking discovered entries, quest notes, character bios, and lore entries. Provides query functions for UI display and narrative progression tracking.

## 2. Variables

| Variable | Type | Description |
|----------|------|-------------|
| `JournalEntries` | `TArray<S_JournalEntry>` | All journal entries |
| `EntryCategories` | `TArray<E_JournalCategory>` | Quest, Character, Lore, Notes, Tips |
| `UnreadCount` | `int32` | Total unread entries |
| `bAutoAddOnDiscovery` | `bool` | Auto-add entries on narrative flag |

## 3. Functions

| Function | Description |
|----------|-------------|
| `AddJournalEntry` | Adds new entry |
| `MarkAsRead` | Marks entry read |
| `GetEntriesByCategory` | Returns filtered entries |
| `HasEntry` | Checks if entry exists |
| `GetUnreadCount` | Returns unread count |

## 4. Event Dispatchers

| Dispatcher | Payload | Description |
|------------|---------|-------------|
| `OnJournalEntryAdded` | `S_JournalEntry Entry` | New entry discovered |
| `OnJournalEntryRead` | `FGuid EntryID` | Entry marked read |

## 5. Dependencies

| System | Relationship |
|--------|--------------|
| `BPC_NarrativeStateSystem` | Narrative-driven journal entries |
| `WBP_JournalDocumentViewer` | UI display |

## 6. Reuse Notes
- Journal entries are narrative-gated via gameplay tags

---

## 7. Manual Implementation Guide

### 7.1 Class Setup
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_JournalSystem`
2. Add to Player Character
3. Define enum `E_JournalCategory`: Quest, Character, Lore, Notes, Tips
4. Define struct `S_JournalEntry`: `EntryID` (Guid), `EntryTag` (GameplayTag), `Title` (Text), `Body` (Text), `Category` (E_JournalCategory), `bIsRead` (Boolean), `Timestamp` (Float), `RequiredFlag` (GameplayTag), `SourceObjective` (GameplayTag)

### 7.2 Variable Initialization (BeginPlay)
```
Event BeginPlay
  ├─ Set JournalEntries = empty Array<S_JournalEntry>
  ├─ Set UnreadCount = 0
  ├─ Set bAutoAddOnDiscovery = true
  ├─ Get Owner → Find Component by Class (BPC_NarrativeStateSystem) → Cache
  │    └─ Bind to OnNarrativeFlagSet → OnFlagSetHandler
  └─ Get Owner → Find Component by Class (BPC_ObjectiveSystem) → Cache
       └─ Bind to OnObjectiveCompleted → OnObjectiveCompleteHandler
```

### 7.3 Function Implementations

#### `AddJournalEntry(EntryTag: GameplayTag, Title: Text, Body: Text, Category: E_JournalCategory)` → `S_JournalEntry`

```
[Function: AddJournalEntry]
  Step 1: Check duplicate — ForEach JournalEntries:
    If Entry.EntryTag == EntryTag → return existing entry (no dupes)
  Step 2: Create S_JournalEntry:
    - EntryID = New Guid
    - EntryTag = input
    - Title = input
    - Body = input
    - Category = input
    - bIsRead = false
    - Timestamp = Get Game Time in Seconds
  Step 3: Add to JournalEntries array
  Step 4: Increment UnreadCount
  Step 5: Fire OnJournalEntryAdded(newEntry)
  Step 6: Return newEntry
```

**Nodes:** `New Guid`, `Make S_JournalEntry`, `Add to Array`, `Increment Int`

#### `AddEntryFromDataAsset(JournalData: DA_JournalData)` → `S_JournalEntry`

```
[Function: AddEntryFromDataAsset]
  Step 1: Read fields from DA_JournalData
  Step 2: Call AddJournalEntry(Data.EntryTag, Data.Title, Data.Body, Data.Category)
  Step 3: If Data.RequiredFlag is valid AND bAutoAddOnDiscovery:
    Register listener on NarrativeStateSystem for that flag
  Step 4: Return entry
```

#### `MarkAsRead(EntryID: Guid)` → `void`

```
[Function: MarkAsRead]
  Step 1: ForEach JournalEntries (with Break):
    If Entry.EntryID == EntryID:
      If NOT Entry.bIsRead:
        Set bIsRead = true
        Decrement UnreadCount
        Fire OnJournalEntryRead(EntryID)
      Return
```

#### `GetEntriesByCategory(Category: E_JournalCategory)` → `Array<S_JournalEntry>`

```
[Function: GetEntriesByCategory] (Pure)
  Step 1: Results = empty Array
  Step 2: ForEach JournalEntries:
    If Entry.Category == Category → Add to Results
  Step 3: Return Results
```

#### `GetUnreadEntries()` → `Array<S_JournalEntry>`

```
[Function: GetUnreadEntries] (Pure)
  ForEach JournalEntries:
    If NOT Entry.bIsRead → Add to Results
  Return Results
```

#### `HasEntry(EntryTag: GameplayTag)` → `Boolean`

```
[Function: HasEntry] (Pure)
  ForEach JournalEntries:
    If Entry.EntryTag == EntryTag → Return true
  Return false
```

### 7.4 Event Dispatcher Bindings
| Bind to Dispatcher | Custom Event | Logic |
|-------------------|-------------|-------|
| `BPC_NarrativeStateSystem.OnNarrativeFlagSet(Flag)` | `OnFlagSetHandler` | Check if any journal entry has RequiredFlag == Flag → AddJournalEntry for that entry |
| `BPC_ObjectiveSystem.OnObjectiveCompleted(ObjectiveTag)` | `OnObjectiveCompleteHandler` | Add journal entry summarizing completed objective |

### 7.5 Blueprint Build Checklist
- [ ] Define enum `E_JournalCategory` and struct `S_JournalEntry`
- [ ] Create BPC_JournalSystem, add to Player Character
- [ ] Add variables: JournalEntries, EntryCategories, UnreadCount, bAutoAddOnDiscovery
- [ ] Implement AddJournalEntry with duplicate check
- [ ] Implement AddEntryFromDataAsset with DA_JournalData reading
- [ ] Implement MarkAsRead with unread counter
- [ ] Implement filtered query functions
- [ ] Bind to NarrativeStateSystem and ObjectiveSystem for auto-adding
- [ ] Test: progress story → journal entries appear → UI shows unread badge