# 62 — BPC_DifficultyManager ## Blueprint Spec — UE 5.5–5.7 --- ### Parent Class `ActorComponent` ### Dependencies - [`GI_GameFramework`](../01-core/04_GI_GameFramework.md) — Central game instance access - [`BPC_PlayerMetricsTracker`](../02-player/15_BPC_PlayerMetricsTracker.md) — Input for difficulty tuning - [`BPC_AtmosphereController`](64_BPC_AtmosphereController.md) — Output to atmosphere/scare systems - [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md) — Health/revive tuning - [`BPC_InventoryComponent`](../04-inventory/22_BPC_InventoryComponent.md) — Resource scarcity input ### Purpose Central difficulty orchestrator. Dynamically adjusts game challenge based on player performance metrics and explicit difficulty profile settings. Operates as a non-intrusive governor that tunes encounter intensity, resource availability, AI aggression, puzzle complexity, and survival pressure without direct player awareness (unless overridden by explicit difficulty mode selection). ### Variables | Name | Type | Description | |------|------|-------------| | `CurrentDifficulty` | EGameDifficulty | Active difficulty preset | | `bIsAdaptive` | Bool | Auto-adjust based on performance | | `AdaptiveBias` | Float (0.0–1.0) | Current adaptive tuning bias | | `PlayerEfficiencyScore` | Float (0.0–1.0) | Rolling efficiency metric | | `PlayerSurvivalScore` | Float (0.0–1.0) | Rolling survival metric | | `ExplorationThoroughness` | Float (0.0–1.0) | How much player explores | | `ResourceConsumptionRate` | Float | Scarcity/frequency of resources | | `bIsPaused` | Bool | Pause all difficulty adjustments | | `AdjustmentCooldown` | Float | Seconds between recalibrations | | `LastAdjustmentTime` | Float | Timestamp of last adjustment | | `PerformanceWindow` | TArray\ | Sliding window of recent metric samples | | `MaxWindowSize` | Int | Max samples before averaging | ### Enums | Enum | Values | Description | |------|--------|-------------| | `EGameDifficulty` | Story, Easy, Normal, Hard, Survival, Adaptive | Difficulty presets | ### Structs | Struct | Fields | Description | |--------|--------|-------------| | `FDifficultyParams` | HealthMultiplier, DamageMultiplier, AmmoScarcity, EnemyAggression, PuzzleComplexity, FearIntensity, ReviveCount, CheckpointFrequency, TimedPressure | Tuning package | ### Functions | Name | Inputs | Outputs | Description | |------|--------|---------|-------------| | `Initialize` | Difficulty: EGameDifficulty | — | Set initial difficulty state | | `SetDifficulty` | Difficulty: EGameDifficulty | — | Apply explicit difficulty preset | | `SetAdaptiveMode` | bEnabled: Bool | — | Toggle adaptive adjustment | | `RecalculateDifficulty` | — | — | Analyze metrics and adjust | | `GetCurrentParams` | — | FDifficultyParams | Return current tuning | | `ApplyHealthMultiplier` | BaseValue: Float | Float | Scaled health | | `ApplyDamageMultiplier` | BaseValue: Float | Float | Scaled damage | | `GetAmmoScarcity` | — | Float | 0.0 = abundant, 1.0 = scarce | | `GetEnemyAggressionModifier` | — | Float | Multiplier for AI aggression | | `GetFearIntensityModifier` | — | Float | Scare system intensity | | `GetReviveLimit` | — | Int | Max revives allowed | | `GetCheckpointFrequency` | — | Float | Time between auto-saves | | `IsTimedPressureActive` | — | Bool | Survival timer enabled | | `PauseAdjustments` | bPaused: Bool | — | Freeze recalibration | ### Event Dispatchers | Name | Parameters | Fired When | |------|-----------|-----------| | `OnDifficultyChanged` | NewDifficulty: EGameDifficulty | Difficulty preset changes | | `OnAdaptiveShift` | ShiftAmount: Float | Adaptive tuning adjusts | | `OnPerformanceWarning` | Metric: EPerformanceMetric, Value: Float | Player struggling/excelling | ### Blueprint Flow ``` [Initialize] └─► Set default difficulty based on game mode / save data └─► SetDifficulty(DefaultDifficulty) └─► If bIsAdaptive: Start recalibration timer (AdjustmentCooldown) Bind to BPC_PlayerMetricsTracker dispatchers [RecalculateDifficulty — called by timer or metric threshold] └─► Gather metrics from BPC_PlayerMetricsTracker: DeathCount, HealingUsed, AmmoUsed, EnemiesKilled, TimeInCombat, TimeHidden, PuzzlesSolved └─► Compute PlayerEfficiencyScore = (EnemiesKilled / TimeInCombat) * ExplorationThoroughness └─► Compute PlayerSurvivalScore = 1.0 - (DeathCount / MaxDeathsBeforeAdjust) └─► If PlayerSurvivalScore < LowThreshold: Reduce enemy aggression by 0.1 Increase ammo drops by 15% Extend checkpoint frequency Fire OnPerformanceWarning(Struggling) └─► If PlayerEfficiencyScore > HighThreshold AND DeathCount == 0: Increase enemy aggression by 0.1 Reduce ammo drops by 10% Shorten checkpoint frequency Fire OnPerformanceWarning(Excelling) └─► If bIsAdaptive: Lerp AdaptiveBias toward target BPC_AtmosphereController.SetTuningBias(AdaptiveBias) └─► Update LastAdjustmentTime └─► Broadcast OnAdaptiveShift [SetDifficulty — explicit override] └─► Set CurrentDifficulty = input └─► bIsAdaptive = false if explicit non-Adaptive difficulty └─► Broadcast OnDifficultyChanged └─► Apply to dependent systems: BPC_HealthSystem.MaxRevives = GetReviveLimit() SS_SaveManager.AutoSaveInterval = GetCheckpointFrequency() BPC_AtmosphereController.FearIntensityBias = GetFearIntensityModifier() ``` ### Communications With | Target | Method | Why | |--------|--------|-----| | [`BPC_PlayerMetricsTracker`](../02-player/15_BPC_PlayerMetricsTracker.md) | Get Owner Component | Feed performance data | | [`BPC_AtmosphereController`](65_BPC_AtmosphereController.md) | Direct call | Apply fear/intensity tuning | | [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md) | Get Owner Component | Revive limits | | [`SS_SaveManager`](../05-saveload/28_SS_SaveManager.md) | Game Instance | Checkpoint frequency | | [`BPC_InventoryComponent`](../04-inventory/22_BPC_InventoryComponent.md) | Get Owner Component | Resource scarcity input | | [`BPC_FearSystem`](90_BPC_FearSystem.md) | Direct call | Fear intensity modifier | | [`BPC_AlertSystem`](../09-ai/60_BPC_AlertSystem.md) | Get on AI Controller | Enemy aggression modifier | ### Reuse Notes - Single instance per game (attach to GameMode or persistent GameState) - Designed to be optional; game works without it using static defaults - Adaptive mode is additive; explicit difficulty modes override everything - Performance window smooths out spikes before adjustment triggers - All tuning values are configurable at runtime via console or debug menu