Files
UE5-Modular-Game-Framework/Source/Framework/Private/Weapons/BPC_DamageReceptionSystem.cpp
Lefteris Notas f6c4f44827 feat: Add Enhanced Input Manager for context management and key rebinding
- Implemented USS_EnhancedInputManager to manage input contexts with priority.
- Added methods for pushing, popping, and querying input contexts.
- Integrated input mode switching and key rebinding functionality.

feat: Introduce Inventory System Component for item management

- Created UBPC_InventorySystem to handle inventory operations such as adding, removing, and sorting items.
- Implemented weight management and slot organization features.
- Added event dispatchers for inventory changes.

feat: Develop Item Data Asset for item definitions

- Established UDA_ItemData as a base class for all items, encapsulating properties like type, weight, and stack limits.
- Included conditional sub-data structures for equipment, consumables, and inspect data.

feat: Create State Manager Component for player state management

- Developed UBPC_StateManager to manage player action states and overlays.
- Implemented gating logic for action requests and vital sign tracking.

feat: Implement Save Manager for game state persistence

- Introduced USS_SaveManager for handling save/load operations and slot management.
- Utilized FArchive for efficient binary serialization.

feat: Implement Damage Reception System for combat mechanics

- Created UBPC_DamageReceptionSystem to process incoming damage and apply resistance calculations.
- Added event dispatchers for damage reception and hit reactions.
2026-05-20 15:04:17 +03:00

137 lines
3.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — BPC_DamageReceptionSystem Implementation
#include "Weapons/BPC_DamageReceptionSystem.h"
DEFINE_LOG_CATEGORY_STATIC(LogDamage, Log, All);
UBPC_DamageReceptionSystem::UBPC_DamageReceptionSystem()
{
PrimaryComponentTick.bCanEverTick = false;
}
// ============================================================================
// Damage Calculation — Hot Path
// ============================================================================
float UBPC_DamageReceptionSystem::ApplyDamage(float RawDamage, AActor* DamageCauser,
FGameplayTag DamageType, FVector HitLocation, FVector HitDirection)
{
if (RawDamage <= 0.0f || !DamageType.IsValid())
{
return 0.0f;
}
// Step 1: Calculate damage multiplier from modifiers.
float Multiplier = GetDamageMultiplier(DamageType);
// Step 2: Apply resistance.
float Resistance = CalculateResistance(DamageType);
float ResistedAmount = RawDamage * Resistance;
// Step 3: Calculate final damage.
float FinalDamage = (RawDamage * Multiplier) - ResistedAmount;
FinalDamage = FMath::Max(FinalDamage, 0.0f); // No negative damage.
// Check for flat reduction modifiers.
for (const FDamageModifier& Mod : DamageModifiers)
{
if (Mod.DamageType == DamageType && Mod.bFlatReduction)
{
FinalDamage = FMath::Max(FinalDamage - Mod.FlatReduction, 1.0f); // Minimum 1 damage.
}
}
// Step 4: Apply shield absorption if available.
if (CachedShieldSystem)
{
// Shield absorbs damage before health.
// FinalDamage = CachedShieldSystem->AbsorbDamage(FinalDamage);
}
// Step 5: Route to health system.
if (CachedHealthSystem)
{
// CachedHealthSystem->ApplyHealthDamage(FinalDamage);
}
// Step 6: Evaluate hit reaction.
EvaluateHitReaction(FinalDamage, DamageCauser, HitDirection);
// Step 7: Broadcast.
OnDamageReceived.Broadcast(RawDamage, FinalDamage, DamageCauser, DamageType, HitLocation);
if (ResistedAmount > 0.0f)
{
OnDamageResisted.Broadcast(ResistedAmount, DamageType,
FString::Printf(TEXT("Resistance: %.1f%%"), Resistance * 100.0f));
}
UE_LOG(LogDamage, Verbose, TEXT("ApplyDamage — Raw: %.1f → Final: %.1f (Type: %s, Resist: %.1f%%)"),
RawDamage, FinalDamage, *DamageType.GetTagName().ToString(), Resistance * 100.0f);
return FinalDamage;
}
float UBPC_DamageReceptionSystem::CalculateResistance(FGameplayTag DamageType) const
{
if (!DamageType.IsValid())
{
return 0.0f;
}
// Base resistance + equipment-specific bonuses.
float TotalResistance = BaseResistance;
if (EquipmentConfig)
{
// EquipmentConfig would provide per-damage-type resistance values.
// TotalResistance += EquipmentConfig->GetResistance(DamageType);
}
return FMath::Clamp(TotalResistance, 0.0f, 1.0f);
}
float UBPC_DamageReceptionSystem::GetDamageMultiplier(FGameplayTag DamageType) const
{
if (!DamageType.IsValid())
{
return 1.0f;
}
for (const FDamageModifier& Mod : DamageModifiers)
{
if (Mod.DamageType == DamageType && !Mod.bFlatReduction)
{
return Mod.Multiplier;
}
}
return 1.0f; // No modifier — normal damage.
}
// ============================================================================
// Hit Reaction
// ============================================================================
void UBPC_DamageReceptionSystem::EvaluateHitReaction(float FinalDamage, AActor* DamageCauser,
FVector HitDirection)
{
if (FinalDamage >= KnockdownThreshold)
{
UE_LOG(LogDamage, Log, TEXT("EvaluateHitReaction — Knockdown! (%.1f damage)"), FinalDamage);
OnKnockedDown.Broadcast(DamageCauser, FinalDamage);
}
else if (FinalDamage >= StaggerThreshold)
{
UE_LOG(LogDamage, Verbose, TEXT("EvaluateHitReaction — Stagger (%.1f damage)"), FinalDamage);
OnStaggered.Broadcast(DamageCauser, FinalDamage);
}
// Route to dedicated hit reaction system for animation selection.
if (CachedHitReactionSystem)
{
// CachedHitReactionSystem->PlayHitReaction(FinalDamage, HitDirection, DamageCauser);
}
}