# 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) │ ├─ AmmoPool (Map) │ ├─ EquipmentState (Map) │ ├─ NarrativeFlags (Map) │ ├─ Objectives (Array) │ ├─ DeathsThisChapter (Int32) │ └─ FearHistory (Array) │ └─ WorldState (BPC_PersistentWorldStateRecorder) ├─ DoorStates (Array) — position, locked, barricaded ├─ PickupStates (Array) — collected or not ├─ EnemyStates (Array) — alive/dead, position ├─ PuzzleStates (Array) — solved/unsolved, progress └─ GlobalFlags (Map) ``` ### 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) │ └─ { Location, Cause, Chapter, Timestamp } ├─ CheckpointsActivated (Array) ├─ TimePerChapter (Map) ├─ 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.*