Table of Contents
- 02 — Player State & Embodiment Systems (Systems 08-15)
- System Index
- Category Data Flow — The Cascade
- 08 — BPC_HealthSystem: Health, Damage & Death
- 09 — BPC_StaminaSystem: Stamina Pool & Exhaustion
- 10 — BPC_StressSystem: Psychological Stress & Sanity
- 11 — BPC_MovementStateSystem: Movement Mode & Posture
- 12 — BPC_HidingSystem: Stealth & Concealment
- 13 — BPC_EmbodimentSystem: First-Person Body
- 14 — BPC_CameraStateLayer: Dynamic Camera Controller
- 15 — BPC_PlayerMetricsTracker: Analytics & Playstyle
- Common Implementation Patterns in This Category
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:
ApplyDamage(DamageEvent)called by weapon, trap, or environment- Early-out checks: Is DeathState == Dead? Is bIsInvincible? → return 0
- Calculate resistance: look up
S_DamageResistanceforDamageType, multiplyBaseAmountbyMultiplier CurrentHealth -= EffectiveDamage- Reset
RegenDelaytimer (regen starts after delay from last damage) - Fire
OnDamageTaken→BPC_StressSystemreacts, HUD updates - Check thresholds: if
CurrentHealth <= 0→HandleDeath(); ifCurrentHealth <= CriticalHealthPercent * MaxHealth→ fireOnHealthCritical - If DamageType is
Fear→ stress multiplier onBPC_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, notifyGM_CoreGameMode.HandlePlayerDead()
Health Regeneration:
RegenDelayseconds after last damage before regen starts- Timer ticks
RegenRateHP per second untilCurrentHealth >= MaxHealth - Blocked by death state
Implementation Patterns:
GetHealthNormalised()returns 0.0-1.0 for UI bars — smooth interpolation, never raw pollingKillInstant()bypasses everything for scripted deathsApplyDamageOverTime()creates a looping timer with unique SourceName to prevent stackingSetMaxHealth(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 aS_StaminaDrainRateconfig:DrainPerSecond(continuous),DrainFlat(one-shot),MinStamina(threshold to perform),CooldownAfterUse DrainStamina(ActionType)checks: cooldown active? sufficient stamina? → deduct, update exhaustion, start regen delayStartContinuousDrain(ActionType)for sprint/climb — timer runs at 0.1s intervalsStopContinuousDrain(ActionType)stops when action ends
Exhaustion States:
Normal(full operation) →Low(below LowThreshold, heavy breathing) →Exhausted(below ExhaustedThreshold, cannot sprint, slow regen)UpdateExhaustionState()checksCurrentStamina / MaxStaminaagainst configured thresholds- Transition downward is instant; recovery is gradual
OnExhausteddispatcher → player controller shows feedback, sprint blocked
Regeneration:
RegenSettingsconfigures:RegenRate,RegenDelay,ExhaustedRegenRate,ExhaustedRegenDelay,RegenBlockedWhileMoving- If
RegenBlockedWhileMoving: listens toBPC_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/restingSetMaxStamina(NewMax, bMaintainRatio)scales current proportionally
Integration Points:
- Called by:
PC_PlayerController(sprint, jump, dodge input) - Broadcasts:
OnStaminaChanged→WBP_HUD,OnExhausted→ movement/audio,OnExhaustionStateChanged→ABP_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:
ActiveSourcesmap (FName identifier →S_StressSourceData) tracks all contributing sources- Each source has:
CurrentIntensity,MaxIntensity,DecayRate,SourceTags AddStressSource()adds or updates a source;RemoveStressSource()removes itRecalculateFromSources()sums all source intensities and updates total
Stress Events:
AddStress(Event)can be instant (bIsInstant) or gradual (adds to source system)HealthDeficitMultiplieramplifies incoming stress when health < 50% — creates death spiral feelOnDamageTakenHandlerconverts 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()comparesCurrentStressagainst threshold values- Tier transitions fire
OnStressTierChanged— systems react to tier, not raw stress value TierEntryTimesmap records when each tier was entered for duration tracking
Hallucination System:
- At
Terrifiedtier: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 decayPassiveDecayTick()slowly reduces stress when in safe area or below DistressedOnSafeZoneChangeddispatcher → 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:
OnStressTierChanged→BPC_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 tierCurrentPosture(Standing, Crouching, Prone, Sliding, Climbing, Vaulting) — body position- These are independent — you can be Sprinting while Standing, or CrouchWalk while Crouching
PreviousMovementModeandPreviousPosturestored for transition detection
Movement Settings Application:
MovementSettingsmap (Mode →S_MovementSettings) defines:MaxWalkSpeed,Acceleration,Deceleration,GroundFriction,bCanSprint,bCanCrouch,StaminaDrainMultiplierSetMovementMode(NewMode)applies the corresponding settings toCharacterMovementComponentSetPosture(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 upS_FootstepProfilematching surface and modeDefaultFootstepProfileas fallback- Fires
OnFootstepdispatcher 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 clearanceSetSprinting(bSprinting)wraps SetMovementMode with stamina awarenessOnMovementUpdated(Tick)checks velocity, detects start/stop, tracks ground stateGetCurrentSpeedNormalised()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 statesHidden: fully concealed, LOS blocked, stress decayingPeeking: partial exposure, camera offset, timed max duration- Each transition broadcasts
OnHideStateChanged
Hide Spot Types:
Locker: fully enclosed (wardrobe, locker) — complete concealmentBehindCover: behind low wall/crate — peeking possibleUnder: under bed/table — prone entryInShadow: standing in shadow volume — dynamic, proximity-basedTallGrass: crouch-moving through vegetation — partial concealment- Each type stored in
S_HideSpotInfofrom the hiding spot actor
Entry Protocol:
- Player presses interact near a hide spot
EnterHideSpot(HideSpotActor)→ validate I_HidingSpot interface, check slot availability- Set
CurrentHideState = Entering, disable movement input - Play entering animation → animation notify triggers
OnAnimationHideEnterComplete - 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
MaxPeekDurationtimer forces return to HiddenPeekCooldownprevents rapid toggling
Stress Interaction:
StressDecayWhileHiddenapplied per second while in Hidden statebBlocksStresson hide spot prevents new stress sources from affecting player- Hide spots double as psychological safe rooms
Implementation Patterns:
ForceKickFromHide()for enemy discovery — bForceExit skips animationTryBreathHold()reduces noise for 8 seconds near enemiesOnDamageWhileHidinghandler: 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) →ArmsAndShadow→Minimal(only hands, high stress) →Hidden(cutscenes, UI)SetVisibilityMode(NewMode, bInstant)toggles mesh components: ArmsMesh, BodyShadowComponent, optional TorsoMeshS_BodyPartVisibilitystruct derived from mode controls individual part visibility
Overlay System:
E_BodyOverlayState: Clean, BloodSpatter, WaterDroplets, Mud, ToxicApplyOverlay(Overlay)with blend: sets MaterialParameter on ArmsMesh towardTargetValueatBlendSpeed- Auto-fades after
Durationseconds 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 byBrushTraceDistance- 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 amountOnEnterWaterHandler: water droplets overlay with fast blend, auto-dries- Bound to
BPC_HealthSystem.OnDamageTakenand 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:
OnVisibilityModeChanged→BPC_CameraStateLayer(FOV adjust),OnOverlayChanged→WBP_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 blendingBlendToTargetFOV()runs per tick: smooth interpolation to target FOVBlendCameraOffset()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 LUTApplyPostProcessOverride(Override, bInstant)blends Material Parameter Collection valuesClearPostProcessOverride(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_HidingSystemfor 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_Persistablefor 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
- Cascade Architecture: Systems don't poll each other — they bind to dispatchers. Health change → stress reaction → camera effect → movement penalty. Each system reacts independently.
- Normalized Values for UI:
GetHealthNormalised(),GetStaminaNormalised(),GetStressNormalised()all return 0.0-1.0 — UI widgets interpolate smoothly. - Timer-Based Ticks: Regen, drain, stress decay all use 0.1s interval timers — not event tick. Better performance.
- State Not Polling: Camera doesn't ask "am I sprinting?" — it binds to
OnMovementModeChangedand reacts. - Threshold Not Continuous: Stress/hiding systems use tier/state thresholds — other systems react to tier changes, not raw values.
- 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.