- Created ui-overrides.md detailing game-specific Widget Blueprint overrides, including purpose, widget index, visual styling, and accessibility requirements. - Established weapons-index.md outlining all held weapon actors, including their components, logic, and comparisons for gameplay mechanics.
388 lines
15 KiB
Markdown
388 lines
15 KiB
Markdown
# Save System & Checkpoints — Persistence, Death, Void Space
|
||
|
||
**Game:** Project Void | **Build Phases:** 15
|
||
**Framework Systems:** 35_SS_SaveManager, 36_I_Persistable, 37_BP_Checkpoint, 38_BPC_AltDeathSpaceSystem, 39_BPC_DeathHandlingSystem, 40_BPC_PersistentCorpseSystem, 41_BPC_PersistentWorldStateRecorder, 42_BPC_PlayerRespawnSystem, 43_BPC_RunHistoryTracker
|
||
|
||
---
|
||
|
||
## Purpose
|
||
|
||
Defines the complete save/load, checkpoint, death handling, and void space systems. Every framework save system is demonstrated.
|
||
|
||
---
|
||
|
||
## Save Slots & Save Manager
|
||
|
||
### SS_SaveManager Configuration
|
||
|
||
```
|
||
SS_SaveManager (35) — initialized by GI_HorrorGame on boot
|
||
|
||
Save Slots:
|
||
├─ SaveSlot_1 → AutoSave (checkpoint-based)
|
||
├─ SaveSlot_2 → QuickSave (pause menu quick save)
|
||
├─ SaveSlot_3 → ManualSave (pause menu manual save)
|
||
└─ (Up to 10 slots configurable via DA_SaveSettings)
|
||
|
||
Save Structure (per slot):
|
||
├─ SaveHeader
|
||
│ ├─ SlotName (Text)
|
||
│ ├─ TimeStamp (DateTime)
|
||
│ ├─ PlaytimeSeconds (Float)
|
||
│ ├─ ChapterTag (GameplayTag)
|
||
│ ├─ PlayerTransform (Transform)
|
||
│ ├─ Thumbnail (Texture2D*) — screenshot at save time
|
||
│ └─ VersionNumber (Int32)
|
||
│
|
||
├─ PlayerState (PS_HorrorPlayerState)
|
||
│ ├─ Health (Float)
|
||
│ ├─ Stamina (Float)
|
||
│ ├─ Stress (Float)
|
||
│ ├─ InventorySlots (Array<FInventorySlot>)
|
||
│ ├─ AmmoPool (Map<GameplayTag, Int32>)
|
||
│ ├─ EquipmentState (Map<GameplayTag, DA_ItemData*>)
|
||
│ ├─ NarrativeFlags (Map<GameplayTag, Boolean>)
|
||
│ ├─ Objectives (Array<ObjectiveState>)
|
||
│ ├─ DeathsThisChapter (Int32)
|
||
│ └─ FearHistory (Array<GameplayTag>)
|
||
│
|
||
└─ WorldState (BPC_PersistentWorldStateRecorder)
|
||
├─ DoorStates (Array<FDoorState>) — position, locked, barricaded
|
||
├─ PickupStates (Array<FPickupState>) — collected or not
|
||
├─ EnemyStates (Array<FEnemyState>) — alive/dead, position
|
||
├─ PuzzleStates (Array<FPuzzleState>) — solved/unsolved, progress
|
||
└─ GlobalFlags (Map<GameplayTag, Boolean>)
|
||
```
|
||
|
||
### Save Trigger Points
|
||
|
||
| Trigger | Save Type | When |
|
||
|---------|----------|------|
|
||
| `BP_Checkpoint` overlap | AutoSave (Slot 1) | Player touches checkpoint |
|
||
| `PauseMenu → Save` | ManualSave (Slot 3) | Player manually saves |
|
||
| `GM_HorrorGameMode.HandlePlayerDead` | AutoSave (Slot 1) | Death → respawn |
|
||
| `TransitionToChapter` | AutoSave (Slot 1) | Level transition |
|
||
| `GI_HorrorGame.QuitToDesktop` | QuickSave (Slot 2) | Clean shutdown |
|
||
| `SS_SettingsSystem.OnSettingsChanged` | — | Settings saved separately (not slot-based) |
|
||
|
||
---
|
||
|
||
## Checkpoint System
|
||
|
||
### BP_Checkpoint Actors
|
||
|
||
| Checkpoint | Level | Location | Features |
|
||
|-----------|-------|----------|----------|
|
||
| `BP_Checkpoint_SafeRoom` | Entry, WardA, WardB, Basement | Safe rooms | Full restore, safe zone, stress decay |
|
||
| `BP_Checkpoint_Mirror` | WardA (Nurses Station) | Thematic | Also stores reflection (visual) |
|
||
| `BP_Checkpoint_BasementGate` | Basement | Before Shade zone | Warning: "Danger ahead" |
|
||
| `BP_Checkpoint_VoidThreshold` | Void Space | One-time save | Disappears after first use |
|
||
|
||
### Checkpoint Blueprint Flow
|
||
|
||
```
|
||
BP_Checkpoint — Event ActorBeginOverlap (Player)
|
||
│
|
||
├─ [Already Activated?]
|
||
│ └─ bActivated AND not bReusable? → Return
|
||
│
|
||
├─ [Activation]
|
||
│ ├─ Set bActivated = true
|
||
│ ├─ Play activation effect:
|
||
│ │ ├─ Light pulse (warm amber glow)
|
||
│ │ ├─ Sound: soft chime
|
||
│ │ └─ Particle: floating dust motes
|
||
│ │
|
||
│ ├─ [Save State]
|
||
│ │ ├─ SS_SaveManager.CreateAutoSave(SlotName = ChapterTag)
|
||
│ │ ├─ BPC_PersistentWorldStateRecorder.SaveWorldState()
|
||
│ │ └─ Store player transform + all state data
|
||
│ │
|
||
│ ├─ [Restore Player]
|
||
│ │ ├─ BPC_HealthSystem.RestoreFullHealth()
|
||
│ │ ├─ BPC_StaminaSystem.RestoreFullStamina()
|
||
│ │ └─ (Stress is NOT restored — checkpoint only saves, doesn't heal stress)
|
||
│ │
|
||
│ ├─ [Notify Player]
|
||
│ │ ├─ WBP_NotificationToast.Show("Checkpoint Reached")
|
||
│ │ ├─ WBP_ScreenEffectController.PulseVignette(0.3s)
|
||
│ │ └─ SS_AudioManager.PlaySFX("checkpoint")
|
||
│ │
|
||
│ └─ [Update Run History]
|
||
│ ├─ BPC_RunHistoryTracker.RecordCheckpoint(ChapterTag)
|
||
│ └─ Set GS_HorrorGameState → SaveGlobalFlag("Checkpoint_Entered", true)
|
||
│
|
||
└─ (Safe Room only) → BPC_StressSystem.StartRapidStressDecay()
|
||
└─ 5× normal decay rate while in safe room
|
||
```
|
||
|
||
---
|
||
|
||
## Death Handling System
|
||
|
||
### Death Flow (Complete)
|
||
|
||
```
|
||
BPC_HealthSystem.Health <= 0
|
||
│
|
||
├─ BPC_DeathHandlingSystem.TriggerDeath(DeathCause, Killer)
|
||
│
|
||
├─ [Immediate Effects]
|
||
│ ├─ BPC_StateManager.ForcePushState(Death)
|
||
│ ├─ Play death animation montage (GASP)
|
||
│ │ └─ Duration: 2.0 seconds
|
||
│ ├─ BPC_CameraStateLayer.SetDeathCamera()
|
||
│ │ └─ Camera falls to floor, tilts, fades to black
|
||
│ ├─ WBP_ScreenEffectController.PlayDeathFade()
|
||
│ │ └─ Red vignette fades in → black
|
||
│ └─ SS_AudioManager.TriggerDeathAudio(DeathCause)
|
||
│ ├─ SFX: heartbeat flatline
|
||
│ ├─ Music: fade out over 2s
|
||
│ └─ Ambience: dampen to near-silence
|
||
│
|
||
├─ [Death Classification]
|
||
│ │
|
||
│ ├─ Determine DeathCause from damage info:
|
||
│ │ ├─ "Physical" → Patient/Orderly melee
|
||
│ │ ├─ "Void" → Shade touch, void fall
|
||
│ │ ├─ "Environmental" → Falling debris, trap
|
||
│ │ └─ "Self" → (future: suicide? sanity loss?)
|
||
│ │
|
||
│ ├─ DeathCause == "Void" AND NOT GI_HorrorGame.GetSessionFlag("VoidSpaceVisited")?
|
||
│ │ ├─ True → [VOID DEATH] — redirect to void space (see below)
|
||
│ │ └─ False → [NORMAL DEATH] — respawn at checkpoint
|
||
│ │
|
||
│ └─ [Normal Death → Respawn]
|
||
│ │
|
||
│ ├─ Increment PS_HorrorPlayerState.DeathsThisChapter
|
||
│ ├─ Increment GI_HorrorGame.TotalDeaths
|
||
│ ├─ BPC_RunHistoryTracker.LogDeath(DeathCause, Location, Time)
|
||
│ │
|
||
│ ├─ BPC_PersistentCorpseSystem.LeaveCorpse(Location, DeathCause)
|
||
│ │ └─ Spawns ragdoll corpse at death location
|
||
│ │ └─ Persists until level transition or save clear
|
||
│ │
|
||
│ ├─ [Lose Items?]
|
||
│ │ ├─ Check DA_GameSettings.bLoseItemsOnDeath
|
||
│ │ └─ If true: remove random 1-3 non-key items from inventory
|
||
│ │
|
||
│ ├─ [Show Death Screen]
|
||
│ │ └─ WBP_DeathScreen.ShowDeathScreen(DeathCause, bVoidQualified=false)
|
||
│ │ └─ Player clicks "Continue" → respawn
|
||
│ │
|
||
│ ├─ [Respawn]
|
||
│ │ ├─ SS_SaveManager.LoadSaveSlot(SaveSlot_1) // auto-save
|
||
│ │ ├─ BPC_PlayerRespawnSystem.RespawnAtCheckpoint()
|
||
│ │ │ ├─ Load last checkpoint location
|
||
│ │ │ ├─ Restore health (checkpoint value, not full)
|
||
│ │ │ ├─ Restore inventory (minus death losses)
|
||
│ │ │ └─ Restore world state (doors, items, enemies)
|
||
│ │ │
|
||
│ │ ├─ WBP_DeathScreen.HideDeathScreen()
|
||
│ │ ├─ WBP_ScreenEffectController.PlayRespawnFadeIn()
|
||
│ │ └─ BPC_StateManager.RestorePreviousState()
|
||
│ │
|
||
│ └─ BPC_NarrativeStateSystem.SetFlag("PlayerDied")
|
||
```
|
||
|
||
---
|
||
|
||
## Void Space / Alt Death Space
|
||
|
||
### Entry Conditions
|
||
|
||
```
|
||
Player dies with DeathCause == "Void" (killed by Shade)
|
||
OR
|
||
Player interacts with void portal in Basement
|
||
AND
|
||
GI_HorrorGame.GetSessionFlag("VoidSpaceVisited") == false (first time only)
|
||
|
||
→ BPC_AltDeathSpaceSystem.EnterVoidSpace()
|
||
```
|
||
|
||
### Void Space Flow
|
||
|
||
```
|
||
EnterVoidSpace()
|
||
│
|
||
├─ BPC_StateManager.ForcePushState(AltDeathSpace)
|
||
├─ GM_HorrorGameMode → Set bVoidSpaceActive = true
|
||
├─ GS_HorrorGameState → SetVoidActive(true)
|
||
│
|
||
├─ [Transition]
|
||
│ ├─ SS_SaveManager.QuickSave("PreVoid") // save real-world state
|
||
│ ├─ GM_HorrorGameMode.TransitionToChapter(Chapter.VoidSpace)
|
||
│ └─ Level loads: L_Asylum_VoidSpace
|
||
│
|
||
├─ [Void Space Gameplay]
|
||
│ ├─ Environment: inverted lighting, non-Euclidean geometry
|
||
│ ├─ No map/HUD compass
|
||
│ ├─ Objective: "Find the light. Escape the void."
|
||
│ │
|
||
│ ├─ Puzzle: Activate 3 Memory Shrines
|
||
│ │ ├─ Shrine 1: Reflection shows death moment
|
||
│ │ ├─ Shrine 2: Voice whispers memory fragment
|
||
│ │ └─ Shrine 3: Touch the light
|
||
│ │
|
||
│ ├─ Threat: Shade pursues (same entity, void-empowered)
|
||
│ │ └─ Contact = restart at Shrine 1
|
||
│ │
|
||
│ └─ Timer: 5 minutes (Trial Scenario System)
|
||
│ └─ If time expires: Shade becomes unavoidable → restart
|
||
│
|
||
└─ [Exit Void Space]
|
||
│
|
||
├─ Player reaches exit portal (all 3 shrines activated)
|
||
│
|
||
├─ BPC_AltDeathSpaceSystem.ExitVoidSpace()
|
||
│
|
||
├─ [Return to Real World]
|
||
│ ├─ SS_SaveManager.LoadSaveSlot("PreVoid") // restore pre-void state
|
||
│ ├─ TransitionToChapter(OriginalChapter)
|
||
│ ├─ Spawn player at original death location (or nearest safe spot)
|
||
│ │
|
||
│ ├─ [Void-Touched Benefits]
|
||
│ │ ├─ GI_HorrorGame.SetSessionFlag("VoidSpaceVisited", true)
|
||
│ │ ├─ Player gains passive: +10% damage vs enemies
|
||
│ │ ├─ Player can see hidden void objects in real world
|
||
│ │ └─ New dialogue option: "I've touched the void"
|
||
│ │
|
||
│ ├─ Health/Inventory restored to pre-death state
|
||
│ └─ WBP_NotificationToast.Show("You are now Void-Touched")
|
||
│
|
||
└─ Achievement: "Touched the Void" unlocked
|
||
```
|
||
|
||
---
|
||
|
||
## I_Persistable Implementation
|
||
|
||
Every actor that needs to save/restore its state implements `I_Persistable`:
|
||
|
||
### Persistent Actor Types
|
||
|
||
| Actor | Saved Data | Restored On |
|
||
|-------|-----------|------------|
|
||
| `BP_Door_*` | bIsOpen, bIsLocked, bIsBarricaded, DoorRotation | Level load, death respawn |
|
||
| `BP_Pickup_*` | bIsCollected (if true → destroy on load) | Level load, death respawn |
|
||
| `BP_Enemy_*` | bIsDead, CorpseLocation, CorpseRotation | Level load, death respawn |
|
||
| `BP_Checkpoint_*` | bActivated, ActivationCount | Level load |
|
||
| `BP_PuzzleDeviceActor_*` | bIsSolved, CurrentStep, PuzzleStateData | Level load, death respawn |
|
||
| `BP_ContainerInventory` (chests/desks) | IsOpen, LootedItems, ContainerState | Level load, death respawn |
|
||
| `BP_NPC_Survivor` | Location, bIsFollowing, bIsAlive | Level load |
|
||
|
||
### I_Persistable Interface Functions
|
||
|
||
```
|
||
SaveState() → FPersistentData
|
||
├─ Actor serializes its current state into a struct
|
||
└─ Returns FPersistentData (includes ActorClass, ActorName, StatePayload)
|
||
|
||
LoadState(FPersistentData)
|
||
├─ Actor restores its state from saved data
|
||
└─ Returns Boolean (success/fail)
|
||
|
||
GetPersistenceID() → FName
|
||
└─ Returns unique ID for this actor instance (level name + actor name)
|
||
```
|
||
|
||
---
|
||
|
||
## Run History Tracker
|
||
|
||
### BPC_RunHistoryTracker Data
|
||
|
||
```
|
||
Current Run Stats:
|
||
├─ TotalDeaths (Int32)
|
||
├─ DeathLocations (Array<FDeathRecord>)
|
||
│ └─ { Location, Cause, Chapter, Timestamp }
|
||
├─ CheckpointsActivated (Array<GameplayTag>)
|
||
├─ TimePerChapter (Map<GameplayTag, Float>)
|
||
├─ ItemsFound (Int32 / TotalItems)
|
||
├─ EnemiesKilled (Int32)
|
||
├─ ScaresExperienced (Int32)
|
||
└─ PlaystyleTag (GameplayTag)
|
||
|
||
Displayed on:
|
||
├─ WBP_DeathScreen → Deaths + Chapter + Time
|
||
├─ WBP_GamePauseMenu → Chapter + Deaths + Time
|
||
└─ WBP_DeathScreen (post-credits) → Full summary
|
||
```
|
||
|
||
---
|
||
|
||
## Save/Load UI Flow
|
||
|
||
### Save Game Menu
|
||
|
||
```
|
||
SS_UIManager.PushMenu(SaveLoadMenu)
|
||
│
|
||
├─ [Display Save Slots]
|
||
│ └─ For each slot in SS_SaveManager.GetAllSlots():
|
||
│ ├─ Show slot thumbnail, chapter, playtime, timestamp
|
||
│ ├─ Empty slot → "Empty — [Create New Save]"
|
||
│ └─ Occupied slot → [Load] [Delete (hold to confirm)]
|
||
│
|
||
├─ [Load Game]
|
||
│ ├─ Selected slot → SS_SaveManager.LoadSaveSlot(SlotIndex)
|
||
│ ├─ Get SaveHeader.ChapterTag
|
||
│ ├─ TransitionToChapter(ChapterTag)
|
||
│ └─ On level loaded: BPC_PlayerRespawnSystem.RestoreState()
|
||
│
|
||
├─ [Delete Save]
|
||
│ ├─ Hold button for 1.5s to confirm (prevents accidental deletion)
|
||
│ ├─ SS_SaveManager.DeleteSaveSlot(SlotIndex)
|
||
│ └─ Refresh slot list
|
||
│
|
||
└─ [New Save — Manual]
|
||
└─ SS_SaveManager.CreateManualSave(SlotIndex, "Manual")
|
||
```
|
||
|
||
---
|
||
|
||
## Blueprint Wiring Checklist
|
||
|
||
### Save System
|
||
- [ ] Configure `SS_SaveManager` with 3 default save slots
|
||
- [ ] Implement `I_Persistable` on all 7 persistent actor types
|
||
- [ ] Wire `BPC_PersistentWorldStateRecorder` to capture world state at checkpoints/death
|
||
- [ ] Wire save/load UI through `WBP_GamePauseMenu` and `WBP_GameMainMenu`
|
||
|
||
### Checkpoints
|
||
- [ ] Create `BP_Checkpoint_SafeRoom`, `BP_Checkpoint_Mirror`, `BP_Checkpoint_BasementGate`, `BP_Checkpoint_VoidThreshold`
|
||
- [ ] Wire overlap → auto-save + health/stamina restore + notification
|
||
|
||
### Death
|
||
- [ ] Wire `BPC_DeathHandlingSystem` → death animation → death screen → respawn
|
||
- [ ] Wire `BPC_PersistentCorpseSystem` → leave corpse at death location
|
||
- [ ] Wire `BPC_PlayerRespawnSystem` → load checkpoint + restore state
|
||
- [ ] Wire `WBP_DeathScreen` with Continue/MainMenu/Void options
|
||
|
||
### Void Space
|
||
- [ ] Wire `BPC_AltDeathSpaceSystem` → enter void on Shade death
|
||
- [ ] Create void puzzle (3 memory shrines) in `L_Asylum_VoidSpace`
|
||
- [ ] Wire exit → restore pre-void state + void-touched benefits
|
||
|
||
### Run History
|
||
- [ ] Wire `BPC_RunHistoryTracker` to log deaths, checkpoints, chapter times
|
||
- [ ] Display stats on death screen + post-credits summary
|
||
|
||
---
|
||
|
||
## Notes for Expansion
|
||
|
||
- Add **cloud saves** (platform-specific: Steam Cloud, PSN, Xbox Live)
|
||
- Add **save file encryption** to prevent tampering (anti-cheat)
|
||
- Add **ironman/permadeath mode**: disable all saves except checkpoint auto-save, one life only
|
||
- Add **save transfer**: export/import saves for cross-platform
|
||
- Add **death replay**: camera pans to show how you died (like a replay of last 5 seconds)
|
||
- Void Space could have **multiple exits** that lead to different real-world locations
|
||
- Multiplayer: save states must be server-authoritative, replicated to joining clients
|
||
|
||
---
|
||
|
||
*Save System & Checkpoints for Project Void. See [GAMEINDEX.md](GAMEINDEX.md) for full game structure. See [35_SS_SaveManager.md](../blueprints/05-saveload/35_SS_SaveManager.md) for save subsystem spec.*
|