Files
UE5-Modular-Game-Framework/docs/developer/02-player-systems.md
Lefteris Notas b2b6e1e7c7 Add developer documentation for systems 11-16, including architecture overview and implementation patterns
- Created detailed documentation for systems 102-135 covering achievements, settings, polish, data assets, input management, and state management.
- Added INDEX.md for easy navigation of developer reference materials.
- Introduced architecture-overview.md to provide a high-level understanding of the framework's structure and communication methods.
- Compiled implementation-patterns.md to outline common UE5 Blueprint patterns for consistent development practices.
2026-05-19 14:13:51 +03:00

26 KiB

02 — Player State & Embodiment Systems (Systems 08-15)

Category Purpose: These 8 systems form the player character's core simulation layer — health, stamina, stress, movement, hiding, first-person body, camera, and metrics tracking. They cascade: health affects stress, stress affects movement, movement affects camera. All feed into the animation system (ABP_GASP) via event dispatchers.


System Index

# System Asset Type Role
08 BPC_HealthSystem Component Health pool, damage resistance, death trigger, healing
09 BPC_StaminaSystem Component Stamina pool, sprint/action drain, exhaustion states
10 BPC_StressSystem Component Psychological stress, tiers (Calm→Catatonic), hallucinations
11 BPC_MovementStateSystem Component Movement mode + posture tracking; GASP liaison; footsteps
12 BPC_HidingSystem Component Hide/peek/breath-hold; LOS checks; stress decay while hidden
13 BPC_EmbodimentSystem Component First-person body mesh, arm IK, visibility modes, overlays
14 BPC_CameraStateLayer Component Camera FOV/offset/rotation layers for all states; shake system
15 BPC_PlayerMetricsTracker Component Player metrics: accuracy, deaths, playstyle ratios

Category Data Flow — The Cascade

┌──────────────────────────────────────────────────────────────────────┐
│                      PLAYER SIMULATION CASCADE                       │
│                                                                      │
│  Combat Damage                                                       │
│      ↓                                                               │
│  BPC_HealthSystem                                                    │
│      ↓ dispatchers: OnDamageTaken →                                  │
│  BPC_StressSystem  ←── also fed by: enemy proximity, environment,    │
│      ↓ dispatchers: OnStressTierChanged →         narrative events   │
│  BPC_CameraStateLayer  (FOV pulse, chromatic aberration)             │
│  BPC_MovementStateSystem  (movement penalties at high stress)        │
│      ↓ dispatchers: OnMovementModeChanged →                          │
│  BPC_StaminaSystem  (regen blocked while sprinting)                  │
│  ABP_GASP  (animation selection)                                     │
│      ↓ dispatchers: OnSprintStateChanged →                           │
│  BPC_StaminaSystem  (continuous drain during sprint)                 │
│                                                                      │
│  BPC_HidingSystem  ←── interacts with both:                          │
│      ↓ stress decay while hidden                                     │
│      ↓ camera constrained while hiding                              │
│      ↓ movement disabled while inside spot                           │
│                                                                      │
│  BPC_EmbodimentSystem  ←── visual overlays from damage/water         │
│  BPC_PlayerMetricsTracker  ←── records everything for analytics      │
└──────────────────────────────────────────────────────────────────────┘

08 — BPC_HealthSystem: Health, Damage & Death

What It Does: The central survivability component. Manages a health pool (MaxHealth → CurrentHealth), applies damage with type-based resistance calculation, handles healing, tracks death state (Alive → Dying → Dead → PermaDeath), and fires dispatchers that cascade to stress, UI, and death handling systems.

How It Works Internally:

Damage Application Flow:

  1. ApplyDamage(DamageEvent) called by weapon, trap, or environment
  2. Early-out checks: Is DeathState == Dead? Is bIsInvincible? → return 0
  3. Calculate resistance: look up S_DamageResistance for DamageType, multiply BaseAmount by Multiplier
  4. CurrentHealth -= EffectiveDamage
  5. Reset RegenDelay timer (regen starts after delay from last damage)
  6. Fire OnDamageTakenBPC_StressSystem reacts, HUD updates
  7. Check thresholds: if CurrentHealth <= 0HandleDeath(); if CurrentHealth <= CriticalHealthPercent * MaxHealth → fire OnHealthCritical
  8. If DamageType is Fear → stress multiplier on BPC_StressSystem

Resistance System:

  • Default resistances stored as array of S_DamageResistance (type → multiplier)
  • 7 damage types: Physical, Arcane, Fire, Poison, Fear, Environmental, True (bypasses all)
  • AddResistance() / RemoveResistance() at runtime for buffs/debuffs

Death States:

  • Alive → normal; Dying → downed, waiting for recovery/final death; Dead → no actions; PermaDeath → save-scrubbing locked
  • On death: clear all timers (regen, DoT, invincibility), fire OnDeath, notify GM_CoreGameMode.HandlePlayerDead()

Health Regeneration:

  • RegenDelay seconds after last damage before regen starts
  • Timer ticks RegenRate HP per second until CurrentHealth >= MaxHealth
  • Blocked by death state

Implementation Patterns:

  • GetHealthNormalised() returns 0.0-1.0 for UI bars — smooth interpolation, never raw polling
  • KillInstant() bypasses everything for scripted deaths
  • ApplyDamageOverTime() creates a looping timer with unique SourceName to prevent stacking
  • SetMaxHealth(NewMax, bMaintainRatio) scales CurrentHealth proportionally or clamps
  • All dispatchers fire on authority; UI binds and reacts

Integration Points:

  • Listens to: Nothing directly (called by damagers)
  • Broadcasts: OnHealthChanged, OnDamageTaken, OnHealthCritical, OnDeath, OnDeathStateChanged, OnInvincibilityChanged
  • Key consumers: BPC_StressSystem (damage → stress), WBP_HUD (health bar), GM_CoreGameMode (death), BPC_HitReactionSystem (stagger)

Edge Cases:

  • Invincibility blocks all damage for its duration (used after respawn/dodge)
  • DoT with same SourceName replaces existing (no stacking)
  • ApplyHealing on dead character returns 0, no dispatchers
  • Negative damage treated as 0

09 — BPC_StaminaSystem: Stamina Pool & Exhaustion

What It Does: Manages a stamina resource that drains during sprinting, jumping, climbing, dodging, and special attacks. Enforces minimum stamina thresholds per action, applies exhaustion penalties (Normal → Low → Exhausted), and coordinates with MovementState for regen blocking while moving.

How It Works Internally:

Drain System:

  • Each E_StaminaActionType (Sprint, Jump, Climb, SpecialAttack, Dodge, Environment) has a S_StaminaDrainRate config: DrainPerSecond (continuous), DrainFlat (one-shot), MinStamina (threshold to perform), CooldownAfterUse
  • DrainStamina(ActionType) checks: cooldown active? sufficient stamina? → deduct, update exhaustion, start regen delay
  • StartContinuousDrain(ActionType) for sprint/climb — timer runs at 0.1s intervals
  • StopContinuousDrain(ActionType) stops when action ends

Exhaustion States:

  • Normal (full operation) → Low (below LowThreshold, heavy breathing) → Exhausted (below ExhaustedThreshold, cannot sprint, slow regen)
  • UpdateExhaustionState() checks CurrentStamina / MaxStamina against configured thresholds
  • Transition downward is instant; recovery is gradual
  • OnExhausted dispatcher → player controller shows feedback, sprint blocked

Regeneration:

  • RegenSettings configures: RegenRate, RegenDelay, ExhaustedRegenRate, ExhaustedRegenDelay, RegenBlockedWhileMoving
  • If RegenBlockedWhileMoving: listens to BPC_MovementStateSystem.OnMovementModeChanged, pauses regen when speed > walk
  • BlockRegen(Duration) for external debuffs

Implementation Patterns:

  • CanAffordAction(ActionType) checks both stamina level and cooldown before allowing
  • Per-action cooldowns prevent dodge/jump spamming
  • RestoreStamina(Amount, Tags) for potions/resting
  • SetMaxStamina(NewMax, bMaintainRatio) scales current proportionally

Integration Points:

  • Called by: PC_PlayerController (sprint, jump, dodge input)
  • Broadcasts: OnStaminaChangedWBP_HUD, OnExhausted → movement/audio, OnExhaustionStateChangedABP_GASP (breathing anim)
  • Listens to: BPC_MovementStateSystem.OnMovementModeChanged (regen blocking)
  • Key consumers: BPC_MovementStateSystem (exhausted blocks sprint), BPC_CameraStateLayer (exhaustion effects)

Edge Cases:

  • Multiple continuous drains stack independently
  • DrainStamina during cooldown returns false without side effects
  • MaxStamina change with bMaintainRatio preserves current percentage
  • All timers cleaned on component destroy

10 — BPC_StressSystem: Psychological Stress & Sanity

What It Does: Simulates the player's psychological state via an accumulating stress meter. Multiple stress sources contribute simultaneously (enemy proximity, environmental horror, health deficit, narrative events, supernatural, isolation). Stress tiers (Calm→Uneasy→Distressed→Panicked→Terrified→Catatonic) drive visual distortion, audio hallucinations, movement penalties, and narrative branching.

How It Works Internally:

Multi-Source Architecture:

  • ActiveSources map (FName identifier → S_StressSourceData) tracks all contributing sources
  • Each source has: CurrentIntensity, MaxIntensity, DecayRate, SourceTags
  • AddStressSource() adds or updates a source; RemoveStressSource() removes it
  • RecalculateFromSources() sums all source intensities and updates total

Stress Events:

  • AddStress(Event) can be instant (bIsInstant) or gradual (adds to source system)
  • HealthDeficitMultiplier amplifies incoming stress when health < 50% — creates death spiral feel
  • OnDamageTakenHandler converts damage amount to stress (Fear damage type gets 2x multiplier)
  • ForcePanic(Duration) temporarily forces Panicked tier for narrative use

Tier System:

  • 6 tiers with configurable thresholds: Uneasy (subtle audio), Distressed (visual noise, heartbeat), Panicked (heavy distortion, movement penalty), Terrified (hallucinations, input inversion), Catatonic (freeze/stumble)
  • UpdateTier() compares CurrentStress against threshold values
  • Tier transitions fire OnStressTierChanged — systems react to tier, not raw stress value
  • TierEntryTimes map records when each tier was entered for duration tracking

Hallucination System:

  • At Terrified tier: HandleHallucinationCheck() rolls random chance each tick
  • Triggers random hallucination events (visual, audio, dialogue)
  • Stops when tier drops below Distressed

Safe Zones & Recovery:

  • SetSafeZone(bSafe) toggles passive decay
  • PassiveDecayTick() slowly reduces stress when in safe area or below Distressed
  • OnSafeZoneChanged dispatcher → atmosphere system adjusts

Implementation Patterns:

  • Sources with identifiers enable precise tracking (e.g., "Enemy_Guard_12", "Area_Basement")
  • GetTierDuration(Tier) for narrative systems to query how long player has been panicked
  • At Catatonic, further stress accumulation is blocked (immune at max)
  • All effects driven by tier dispatchers, never by polling

Integration Points:

  • Called by: Enemies (proximity), environment triggers, BPC_HealthSystem (damage handler)
  • Broadcasts: OnStressTierChangedBPC_CameraStateLayer (post-process), ABP_GASP (anim), WBP_HUD (vignette), OnHallucinationTriggered → hallucination/audio managers, OnCatatonicStateEntered → input lockdown
  • Listens to: BPC_HealthSystem.OnDamageTaken

Edge Cases:

  • Catatonic blocks all non-instant stress additions
  • Stress clamping prevents overflow past MaxStress
  • Source with matching identifier updates existing entry (no duplicate sources)
  • ForcePanic temporarily locks tier and restores gradually after duration

11 — BPC_MovementStateSystem: Movement Mode & Posture

What It Does: The "movement oracle" — tracks the player's current state (movement mode + posture), reports changes via dispatchers, and applies movement settings to the CharacterMovementComponent. Other systems query here instead of polling the movement component directly. Bridges gameplay state to GASP animation.

How It Works Internally:

Dual State Tracking:

  • CurrentMovementMode (Idle, Walking, Jogging, Sprinting, CrouchWalk, Sneaking) — speed tier
  • CurrentPosture (Standing, Crouching, Prone, Sliding, Climbing, Vaulting) — body position
  • These are independent — you can be Sprinting while Standing, or CrouchWalk while Crouching
  • PreviousMovementMode and PreviousPosture stored for transition detection

Movement Settings Application:

  • MovementSettings map (Mode → S_MovementSettings) defines: MaxWalkSpeed, Acceleration, Deceleration, GroundFriction, bCanSprint, bCanCrouch, StaminaDrainMultiplier
  • SetMovementMode(NewMode) applies the corresponding settings to CharacterMovementComponent
  • SetPosture(NewPosture) adjusts CapsuleComponent half-height (Standing=96, Crouch=60, Prone=30)
  • Prone requires going through Crouching first (enforced)

Movement Penalties:

  • ApplyMovementPenalty(Multiplier, Duration, PenaltyTag) temporarily multiplies MaxWalkSpeed
  • Timer restores original value after Duration
  • Used by stress system (movement penalty at high stress), injury system, debuffs
  • Each penalty tagged for tracking — multiple penalties stack multiplicatively?

Footstep System:

  • CalculateFootstep(): line trace downward from foot → get surface physical material → look up S_FootstepProfile matching surface and mode
  • DefaultFootstepProfile as fallback
  • Fires OnFootstep dispatcher with mode and surface type for audio system
  • Velocity threshold determines soft vs hard footstep sound

GASP Integration:

  • On every mode/posture change: notify ABP_GASP via direct reference or interface
  • Sets GASP-specific animation variables (bStrafing, bSprinting, gait, stance)
  • This is the ONLY component that talks directly to ABP_GASP for movement state

Implementation Patterns:

  • Does NOT handle input — input remains in PC_PlayerController
  • CanTransitionToPosture(TargetPosture) traces for ceiling clearance
  • SetSprinting(bSprinting) wraps SetMovementMode with stamina awareness
  • OnMovementUpdated(Tick) checks velocity, detects start/stop, tracks ground state
  • GetCurrentSpeedNormalised() for smooth animation blend values

Integration Points:

  • Called by: PC_PlayerController (input → mode changes)
  • Broadcasts: OnMovementModeChanged, OnPostureChanged, OnMovementStart/Stop, OnSprintStateChanged, OnJumped/Landed, OnFootstep
  • Key consumers: ABP_GASP (animation), BPC_StaminaSystem (drain/regen), BPC_CameraStateLayer (FOV), BP_AudioManager (footsteps), BPC_InteractionDetector (range scaling)

Edge Cases:

  • Forced transitions (knockdown) apply impulse regardless of current state
  • Cannot transition to upright if ceiling is too low (traced by CanTransitionToPosture)
  • Rapid mode switching is protected by TransitionBlendTime
  • Sprinting auto-stops when stamina hits 0 (external listener)

12 — BPC_HidingSystem: Stealth & Concealment

What It Does: Manages the player entering, occupying, peeking from, and exiting environmental hiding spots. Handles line-of-sight checks against enemies, breath-holding mechanics, and stress reduction while concealed. The central hub for all stealth gameplay.

How It Works Internally:

Hide State Machine:

Exposed → Entering → Hidden ⇄ Peeking → Exiting → Exposed
  • Entering/Exiting: transient animation states
  • Hidden: fully concealed, LOS blocked, stress decaying
  • Peeking: partial exposure, camera offset, timed max duration
  • Each transition broadcasts OnHideStateChanged

Hide Spot Types:

  • Locker: fully enclosed (wardrobe, locker) — complete concealment
  • BehindCover: behind low wall/crate — peeking possible
  • Under: under bed/table — prone entry
  • InShadow: standing in shadow volume — dynamic, proximity-based
  • TallGrass: crouch-moving through vegetation — partial concealment
  • Each type stored in S_HideSpotInfo from the hiding spot actor

Entry Protocol:

  1. Player presses interact near a hide spot
  2. EnterHideSpot(HideSpotActor) → validate I_HidingSpot interface, check slot availability
  3. Set CurrentHideState = Entering, disable movement input
  4. Play entering animation → animation notify triggers OnAnimationHideEnterComplete
  5. Set CurrentHideState = Hidden, start stress decay timer, start periodic LOS check

Line of Sight (LOS) System:

  • IsPlayerDetectable(EnemyLocation, DetectionRange) called by AI perception
  • If not hidden: always detectable
  • If hidden: line trace from enemy to player → if trace hits hide spot actor before player: concealed
  • Peeking state increases detection radius
  • PerformLOSCheck() runs on timer: iterates all enemies in range, checks each
  • If any enemy has LOS: fire OnHideSpotCompromised → stress spike, forced exit warning

Peek System:

  • StartPeek(Direction) — Left/Right/Over from behind cover
  • Camera moves to peek socket location on hide spot actor
  • MaxPeekDuration timer forces return to Hidden
  • PeekCooldown prevents rapid toggling

Stress Interaction:

  • StressDecayWhileHidden applied per second while in Hidden state
  • bBlocksStress on hide spot prevents new stress sources from affecting player
  • Hide spots double as psychological safe rooms

Implementation Patterns:

  • ForceKickFromHide() for enemy discovery — bForceExit skips animation
  • TryBreathHold() reduces noise for 8 seconds near enemies
  • OnDamageWhileHiding handler: penetrating damage forces exit; non-penetrating converts to stress
  • Destroying a hide spot while player is inside force-exits them

Integration Points:

  • Called by: PC_PlayerController (interact input), AI (IsPlayerDetectable queries)
  • Broadcasts: OnHideStateChanged, OnEntered/ExitedHidingSpot, OnPeekStarted/Ended, OnHideSpotCompromised, OnForcedExitWarning, OnBreathHoldChanged
  • Key consumers: BPC_CameraStateLayer (peek/hide offsets), BPC_StressSystem (decay), ABP_GASP (hide anims), AI_EnemyController (awareness), WBP_HUD (hide indicators)

Edge Cases:

  • EnterHideSpot while already hiding returns false
  • ExitHideSpot while Exposed does nothing
  • Multiple players can't occupy limited-slot spots
  • Peek max duration and cooldown enforced
  • Shutting down the hide spot actor force-exits the player

13 — BPC_EmbodimentSystem: First-Person Body

What It Does: Creates first-person body awareness — the player sees their arms, shadow, and optionally legs/torso in context-appropriate situations. Manages mesh visibility modes, environmental body overlays (blood, water, mud), wall proximity detection for arm IK, and shadow casting.

How It Works Internally:

Visibility Modes:

  • FullBody (third-person, mirrors, death) → ArmsOnly (default first-person) → ArmsAndShadowMinimal (only hands, high stress) → Hidden (cutscenes, UI)
  • SetVisibilityMode(NewMode, bInstant) toggles mesh components: ArmsMesh, BodyShadowComponent, optional TorsoMesh
  • S_BodyPartVisibility struct derived from mode controls individual part visibility

Overlay System:

  • E_BodyOverlayState: Clean, BloodSpatter, WaterDroplets, Mud, Toxic
  • ApplyOverlay(Overlay) with blend: sets MaterialParameter on ArmsMesh toward TargetValue at BlendSpeed
  • Auto-fades after Duration seconds
  • ClearOverlay(Type) removes single or all overlays
  • Multiple overlays stack: blood + water = combined effect on material
  • ApplyOverlayBlendTick() runs each frame for smooth transitions

Wall Proximity / Arm IK:

  • CheckWallProximity(): line trace from camera forward by BrushTraceDistance
  • If wall detected: apply IK offset to arms (avoids clipping), set bIsNearWall = true
  • Fires OnWallProximityChanged → ABP_Arms for IK adjustment

Damage/Environment Integration:

  • OnDamageTakenBloodHandler: blood overlay intensity scales with damage amount
  • OnEnterWaterHandler: water droplets overlay with fast blend, auto-dries
  • Bound to BPC_HealthSystem.OnDamageTaken and water volume triggers

Implementation Patterns:

  • Mesh references cached at BeginPlay from owner (first-person skeletal mesh)
  • Shadow uses separate component with shadow-only material — not full character mesh
  • All overlay blending uses Material Parameter Collections for real-time updates
  • Wall proximity is simple line trace; advanced IK requires arms animation blueprint

Integration Points:

  • Listens to: BPC_HealthSystem.OnDamageTaken (blood), water volume triggers
  • Broadcasts: OnVisibilityModeChangedBPC_CameraStateLayer (FOV adjust), OnOverlayChangedWBP_HUD (screen effects), OnWallProximityChanged → ABP_Arms

Edge Cases:

  • Rapid visibility changes don't cause rendering glitches due to fade transitions
  • Overlays stack: intensity values combined via material logic
  • Hidden mode overrides all — hides everything regardless of other settings

14 — BPC_CameraStateLayer: Dynamic Camera Controller

What It Does: Centralizes all camera-modifying logic: field-of-view changes per state, camera shake system with priority queuing, post-process overrides (vignette, chromatic aberration, color grading), head bob, and location/rotation offsets per game state. Other systems request camera changes here instead of directly manipulating the camera.

How It Works Internally:

Camera State System:

  • 10 states: Default, Aiming, Sprinting, Crouching, Peeking, Hiding, Stressed, Injured, Death, Cutscene
  • Each has S_CameraStateConfig: TargetFOV, BlendSpeed, HeadOffset, HeadRotation, pitch constraints, head bob settings
  • RequestCameraState(NewState, bImmediate) sets targets and starts blending
  • BlendToTargetFOV() runs per tick: smooth interpolation to target FOV
  • BlendCameraOffset() interpolates head position/rotation offsets

Camera Shake System:

  • S_CameraShakeRequest: ShakeClass, Scale, Priority (Low/Medium/High/Cinematic), Duration, bIsLooping, Tag
  • Priority system: higher priority shakes override lower; same tag replaces existing
  • PlayCameraShake(ShakeRequest) adds to ActiveShakeRequests map and starts playback
  • If Duration > 0: timer auto-stops shake
  • StopCameraShake(ShakeTag) removes specific shake

Post-Process Overrides:

  • S_PostProcessOverride: vignette, chromatic aberration, color grading LUT
  • ApplyPostProcessOverride(Override, bInstant) blends Material Parameter Collection values
  • ClearPostProcessOverride(BlendTime) returns to defaults
  • Used by stress system (CA at high stress), injury (vignette), death (fade to black)

Dynamic Effects:

  • Sprint: FOV widens by SprintFOVMultiplier
  • Stress: UpdateStressPulse() applies sine-wave FOV oscillation for "unease" feel
  • Crouch: slight downward offset
  • Peek: camera moves to hide spot peek socket
  • Hiding: constricted FOV, darkness effect

Reactivity:

  • Binds to BPC_MovementStateSystem.OnMovementModeChanged → Sprint/Crouch/Default FOV
  • Binds to BPC_StressSystem.OnStressTierChanged → stress effects at Panicked+
  • Binds to BPC_HealthSystem.OnDamageTaken → injury shake, vignette
  • Called directly by BPC_HidingSystem for peek/hide camera states

Implementation Patterns:

  • Uses Material Parameter Collection (MPC_CameraEffects) for post-process parameters
  • Camera shakes authored as Blueprint Camera Shake classes
  • Pitch constraints enforced during hiding/peeking states
  • All blending is frame-rate independent via DeltaTime

Integration Points:

  • Broadcasts: OnCameraStateChanged, OnFOVChanged, OnShakeStarted/Ended, OnPostProcessChanged
  • Called by: Any system needing camera change
  • Key consumers: PlayerCameraManager (direct application), WBP_HUD (post-process materials)

Edge Cases:

  • Shake with same tag and lower priority is ignored (not stacked)
  • Rapid FOV switching blends smoothly — no snap transitions
  • Stress pulse uses sine wave to prevent jitter
  • All active shakes stopped on component destroy or pawn unpossess

15 — BPC_PlayerMetricsTracker: Analytics & Playstyle

What It Does: Records player behavior metrics throughout a session: accuracy (shots fired vs hit), deaths count, damage dealt/received, items used, hiding time, sprint time, objectives completed. Used by BPC_PlaystyleClassifier to categorize player as Aggressive/Stealthy/Explorer/Balanced, and by BPC_DifficultyManager for adaptive tuning.

How It Works Internally:

  • Listens to relevant dispatchers from HealthSystem (deaths), WeaponBase (shots/hits), InventorySystem (items used), HidingSystem (hide time), MovementState (sprint time)
  • Accumulates counters and ratios internally
  • Provides query functions for other adaptive systems
  • Persists across sessions via I_Persistable for long-term playstyle tracking

Implementation Patterns:

  • Pure listener — never calls into other systems, only receives events
  • All metrics are gameplay-tag keyed for extensibility
  • Ratios computed on demand, not continuously

Common Implementation Patterns in This Category

  1. Cascade Architecture: Systems don't poll each other — they bind to dispatchers. Health change → stress reaction → camera effect → movement penalty. Each system reacts independently.
  2. Normalized Values for UI: GetHealthNormalised(), GetStaminaNormalised(), GetStressNormalised() all return 0.0-1.0 — UI widgets interpolate smoothly.
  3. Timer-Based Ticks: Regen, drain, stress decay all use 0.1s interval timers — not event tick. Better performance.
  4. State Not Polling: Camera doesn't ask "am I sprinting?" — it binds to OnMovementModeChanged and reacts.
  5. Threshold Not Continuous: Stress/hiding systems use tier/state thresholds — other systems react to tier changes, not raw values.
  6. Data Config Everything: Damage resistances, movement speeds, stamina drain rates, stress thresholds — all in exposed variables or Data Assets, never hardcoded.

Developer Reference v1.0 — 02 Player Systems. Companion to docs/blueprints/02-player/ specs.