Files
UE5-Modular-Game-Framework/Source/PG_Framework/Private/Weapons/BPC_DamageReceptionSystem.cpp
Lefteris Notas f986343325 Add core gameplay systems and data assets for player mechanics
- Implemented DA_EquipmentConfig for managing equipment resistances, durability, and weight.
- Created DA_ItemData to serve as a base item data asset with various item types and properties.
- Introduced BPC_HealthSystem for managing player health and death events.
- Added BPC_MovementStateSystem to handle player movement modes with event delegation.
- Developed BPC_StaminaSystem to track player stamina and exhaustion states.
- Established BPC_StateManager as a central authority for managing player action states and gating.
- Created BPC_StressSystem to monitor and respond to player stress levels.
- Implemented PC_CoreController and PS_CorePlayerState for player controller and state management.
- Developed SS_SaveManager for save/load functionality with slot management and serialization.
- Introduced DA_StateGatingTable for defining action gating rules based on gameplay tags.
- Added BPC_DamageReceptionSystem to process incoming damage and apply resistance calculations.
- Implemented BPC_HitReactionSystem for managing hit reactions based on damage received.
- Created BPC_ShieldDefenseSystem to manage shield health and blocking mechanics.
- Added PG_FrameworkEditor.Target.cs for editor build configuration.
2026-05-21 14:38:30 +03:00

140 lines
4.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — BPC_DamageReceptionSystem Implementation
#include "Weapons/BPC_DamageReceptionSystem.h"
#include "Player/BPC_HealthSystem.h"
#include "Weapons/BPC_ShieldDefenseSystem.h"
#include "Weapons/BPC_HitReactionSystem.h"
DEFINE_LOG_CATEGORY_STATIC(LogFrameworkDamage, 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(LogFrameworkDamage, 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(LogFrameworkDamage, Log, TEXT("EvaluateHitReaction — Knockdown! (%.1f damage)"), FinalDamage);
OnKnockedDown.Broadcast(DamageCauser, FinalDamage);
}
else if (FinalDamage >= StaggerThreshold)
{
UE_LOG(LogFrameworkDamage, 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);
}
}