- 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.
15 KiB
15 KiB
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_SaveManagerwith 3 default save slots - Implement
I_Persistableon all 7 persistent actor types - Wire
BPC_PersistentWorldStateRecorderto capture world state at checkpoints/death - Wire save/load UI through
WBP_GamePauseMenuandWBP_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_DeathScreenwith 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_RunHistoryTrackerto 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 for full game structure. See 35_SS_SaveManager.md for save subsystem spec.