Section 13 complete, Damage numbers, added Block chance and Critical Hit chance

This commit is contained in:
2025-11-09 16:27:22 -05:00
parent 2dbdfa5bf8
commit b51c555d9e
112 changed files with 11164 additions and 9455 deletions

View File

@@ -49,7 +49,7 @@ void UAuraAbilitySystemLibrary::InitializeDefaultAttributes(const UObject* World
const AActor* AvatarActor = ASC->GetAvatarActor();
UCharacterClassInfo* CharacterClassInfo = AuraGameMode->CharacterClassInfo;
UCharacterClassInfo* CharacterClassInfo = GetCharacterClassInfo((WorldContextObject));
const FCharacterClassDefaultInfo ClassDefaultInfo = CharacterClassInfo->GetClassDefaultInfo(CharacterClass);
FGameplayEffectContextHandle PrimaryAttributesContextHandle = ASC->MakeEffectContext();
@@ -70,11 +70,7 @@ void UAuraAbilitySystemLibrary::InitializeDefaultAttributes(const UObject* World
void UAuraAbilitySystemLibrary::GiveStartupAbilities(const UObject* WorldContextObject, UAbilitySystemComponent* ASC)
{
AAuraGameMode* AuraGameMode = Cast<AAuraGameMode>(UGameplayStatics::GetGameMode(WorldContextObject));
if (AuraGameMode == nullptr) return;
UCharacterClassInfo* CharacterClassInfo = AuraGameMode->CharacterClassInfo;
UCharacterClassInfo* CharacterClassInfo = GetCharacterClassInfo((WorldContextObject));
for (TSubclassOf<UGameplayAbility> AbilityClass : CharacterClassInfo->CommonAbilities)
{
FGameplayAbilitySpec AbilitySpec = FGameplayAbilitySpec(AbilityClass, 1);
@@ -83,3 +79,10 @@ void UAuraAbilitySystemLibrary::GiveStartupAbilities(const UObject* WorldContext
}
UCharacterClassInfo* UAuraAbilitySystemLibrary::GetCharacterClassInfo(const UObject* WorldContextObject)
{
AAuraGameMode* AuraGameMode = Cast<AAuraGameMode>(UGameplayStatics::GetGameMode(WorldContextObject));
if (AuraGameMode == nullptr) return nullptr;
return AuraGameMode->CharacterClassInfo;
}

View File

@@ -9,6 +9,9 @@
#include "GameFramework/Character.h"
#include "Net/UnrealNetwork.h"
#include "AuraGameplayTags.h"
#include "Interact/CombatInterface.h"
#include "Kismet/GameplayStatics.h"
#include "Player/AuraPlayerController.h"
UAuraAttributeSet::UAuraAttributeSet()
{
@@ -104,7 +107,7 @@ void UAuraAttributeSet::SetEffectProperties(const FGameplayEffectModCallbackData
}
if (Props.SourceController)
{
ACharacter* SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());
Props.SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());
}
}
@@ -120,6 +123,17 @@ void UAuraAttributeSet::SetEffectProperties(const FGameplayEffectModCallbackData
}
}
void UAuraAttributeSet::ShowFloatingText(const FEffectProperties& Props, float Damage, bool bCritical, bool bBlocked)
{
if (Props.SourceCharacter != Props.TargetCharacter)
{
if (AAuraPlayerController* APC = Cast<AAuraPlayerController>(UGameplayStatics::GetPlayerController(Props.SourceCharacter, 0)))
{
APC->ShowDamageNumber(Damage, Props.TargetCharacter, bCritical, bBlocked);
}
}
}
void UAuraAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
@@ -148,8 +162,20 @@ void UAuraAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallba
if (bFatal)
{
ICombatInterface* CombatInterface = Cast<ICombatInterface>(Props.TargetAvatarActor);
if (CombatInterface)
{
CombatInterface->Die();
}
}
else
{
FGameplayTagContainer TagContainer;
TagContainer.AddTag(FAuraGameplayTags::Get().Combat_HitReact);
Props.TargetASC->TryActivateAbilitiesByTag(TagContainer);
}
ShowFloatingText(Props, LocalIncomingDamage, 0, 0);
}
}
}

View File

@@ -0,0 +1,127 @@
// Copyright Echo Devgroup
#include "AbilitySystem/MMC/ExecCalc_Damage.h"
#include "AbilitySystemComponent.h"
#include "AuraGameplayTags.h"
#include "AbilitySystem/AuraAbilitySystemLibrary.h"
#include "AbilitySystem/AuraAttributeSet.h"
#include "AbilitySystem/Data/CharacterClassInfo.h"
#include "Interact/CombatInterface.h"
struct AuraDamageStatics
{
DECLARE_ATTRIBUTE_CAPTUREDEF(Armor);
DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetration);
DECLARE_ATTRIBUTE_CAPTUREDEF(BlockChance);
DECLARE_ATTRIBUTE_CAPTUREDEF(CriticalChance);
DECLARE_ATTRIBUTE_CAPTUREDEF(CriticalResistance);
DECLARE_ATTRIBUTE_CAPTUREDEF(CriticalDamage);
AuraDamageStatics()
{
DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, Armor, Target, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, ArmorPenetration, Source, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, BlockChance, Target, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, CriticalChance, Source, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, CriticalResistance, Target, false);
DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, CriticalDamage, Source, false);
}
};
static const AuraDamageStatics DamageStatics()
{
static AuraDamageStatics DStatics;
return DStatics;
}
UExecCalc_Damage::UExecCalc_Damage()
{
RelevantAttributesToCapture.Add(DamageStatics().ArmorDef);
RelevantAttributesToCapture.Add(DamageStatics().BlockChanceDef);
RelevantAttributesToCapture.Add(DamageStatics().ArmorPenetrationDef);
RelevantAttributesToCapture.Add(DamageStatics().CriticalChanceDef);
RelevantAttributesToCapture.Add(DamageStatics().CriticalResistanceDef);
RelevantAttributesToCapture.Add(DamageStatics().CriticalDamageDef);
}
void UExecCalc_Damage::Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams,
FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const
{
//Set Gameplay Effect variables
const FGameplayEffectSpec& Spec = ExecutionParams.GetOwningSpec();
//Get Source info
const UAbilitySystemComponent* SourceASC = ExecutionParams.GetSourceAbilitySystemComponent();
AActor* SourceAvatar = SourceASC ? SourceASC->GetAvatarActor() : nullptr;
ICombatInterface* SourceCombatInterface = Cast<ICombatInterface>(SourceAvatar);
const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
//Get Target info
const UAbilitySystemComponent* TargetASC = ExecutionParams.GetTargetAbilitySystemComponent();
AActor* TargetAvatar = TargetASC ? TargetASC->GetAvatarActor() : nullptr;
ICombatInterface* TargetCombatInterface = Cast<ICombatInterface>(TargetAvatar);
const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();
FAggregatorEvaluateParameters EvaluateParams;
EvaluateParams.SourceTags = SourceTags;
EvaluateParams.TargetTags = TargetTags;
//Get Damage set by caller magnitude
float Damage = Spec.GetSetByCallerMagnitude(FAuraGameplayTags::Get().Damage);
//Capture BlockChance on Target, and determine if there was a successful block
//If blocked, reduce damage to 50% damage
float TargetBlockChance = 0.f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().BlockChanceDef, EvaluateParams, TargetBlockChance);
TargetBlockChance = FMath::Max<float>(TargetBlockChance, 0.f);
const bool bBlocked = FMath::RandRange(1, 100) < TargetBlockChance;
Damage = bBlocked ? Damage / 2.f : Damage;
//TODO: Elemental weaknesses
//TODO: Add Resistances
const UCharacterClassInfo* CharacterClassInfo = UAuraAbilitySystemLibrary::GetCharacterClassInfo(SourceAvatar);
const FRealCurve* ArmorPenetrationCurve = CharacterClassInfo->DamageCalculationCoefficients->FindCurve(FName("ArmorPenetration"), FString());
const float ArmorPenetrationCoefficient = ArmorPenetrationCurve->Eval(SourceCombatInterface->GetPlayerLevel());
const FRealCurve* EffectiveArmorCurve = CharacterClassInfo->DamageCalculationCoefficients->FindCurve(FName("EffectiveArmor"), FString());
const float EffectiveArmorCoefficient = ArmorPenetrationCurve->Eval(TargetCombatInterface->GetPlayerLevel());
//Armor calculations
//Get the Target's armor
float TargetArmor = 0.f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorDef, EvaluateParams, TargetArmor);
TargetArmor = FMath::Max<float>(TargetArmor, 0.f);
//Source Armor Penetration, ignores a percentage of the Target's Armor.
float SourceArmorPenetration = 0.f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorPenetrationDef, EvaluateParams, SourceArmorPenetration);
SourceArmorPenetration = FMath::Max<float>(SourceArmorPenetration, 0.f);
//4 points Armor penetration is 1% armor ignored
const float EffectiveArmor = TargetArmor *= (100 - SourceArmorPenetration * ArmorPenetrationCoefficient) / 100.f;
//Damage reduced by Armor % where 5 armor = 1%
Damage *= (100 - EffectiveArmor * EffectiveArmorCoefficient) / 100.f;
//Critical Hit Chance
float SourceCriticalChance = 0.f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().CriticalChanceDef, EvaluateParams, SourceCriticalChance);
SourceCriticalChance = FMath::Max<float>(SourceCriticalChance, 0.f);
float TargetCriticalResistance = 0.f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().CriticalResistanceDef, EvaluateParams, TargetCriticalResistance);
TargetCriticalResistance = FMath::Max<float>(TargetCriticalResistance, 0.f);
float SourceCriticalDamage = 0.f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().CriticalDamageDef, EvaluateParams, SourceCriticalDamage);
SourceCriticalDamage = FMath::Max<float>(SourceCriticalDamage, 0.f);
const bool bCritical = FMath::RandRange(1, 100) < (SourceCriticalChance - TargetCriticalResistance);
Damage = bCritical ? Damage * 1+SourceCriticalDamage : Damage;
const FGameplayModifierEvaluatedData EvaluatedData(UAuraAttributeSet::GetIncomingDamageAttribute(), EGameplayModOp::Additive, Damage);
OutExecutionOutput.AddOutputModifier(EvaluatedData);
}

View File

@@ -30,6 +30,30 @@ UAnimMontage* AAuraCharacterBase::GetHitReactMontage_Implementation()
return HitReactMontage;
}
void AAuraCharacterBase::Die()
{
Weapon->DetachFromComponent(FDetachmentTransformRules(EDetachmentRule::KeepWorld, true));
MulticastHandleDeath();
}
void AAuraCharacterBase::MulticastHandleDeath_Implementation()
{
Weapon->SetSimulatePhysics(true);
Weapon->SetCollisionEnabled(ECollisionEnabled::PhysicsOnly);
Weapon->SetEnableGravity(true);
GetMesh()->SetSimulatePhysics(true);
GetMesh()->SetEnableGravity(true);
GetMesh()->SetCollisionEnabled(ECollisionEnabled::PhysicsOnly);
GetMesh()->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Block);
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
Dissolve();
}
void AAuraCharacterBase::BeginPlay()
{
Super::BeginPlay();
@@ -73,4 +97,20 @@ void AAuraCharacterBase::AddCharacterAbilities()
}
void AAuraCharacterBase::Dissolve()
{
if (IsValid(DissolveMaterialInstance))
{
UMaterialInstanceDynamic* DynamicMatInst = UMaterialInstanceDynamic::Create(DissolveMaterialInstance, this);
GetMesh()->SetMaterial(0, DynamicMatInst);
StartDissolveTimeline(DynamicMatInst);
}
if (IsValid(WeaponDissolveMaterialInstance))
{
UMaterialInstanceDynamic* DynamicMatInst = UMaterialInstanceDynamic::Create(WeaponDissolveMaterialInstance, this);
Weapon->SetMaterial(0, DynamicMatInst);
StartWeaponDissolveTimeline(DynamicMatInst);
}
}

View File

@@ -41,6 +41,12 @@ int32 AAuraEnemy::GetPlayerLevel()
return Level;
}
void AAuraEnemy::Die()
{
SetLifeSpan(LifeSpan);
Super::Die();
}
void AAuraEnemy::BeginPlay()
{
Super::BeginPlay();

View File

@@ -4,6 +4,7 @@
#include "AbilitySystemBlueprintLibrary.h"
#include "AuraGameplayTags.h"
#include "EnhancedInputSubsystems.h"
#include "MovieSceneTracksComponentTypes.h"
#include "NavigationPath.h"
#include "NavigationSystem.h"
#include "AbilitySystem/AuraAbilitySystemComponent.h"
@@ -11,6 +12,9 @@
#include "Components/SplineComponent.h"
#include "Input/AuraInputComponent.h"
#include "Interact/EnemyInterface.h"
#include "GameFramework/Character.h"
#include "UI/Widget/DamageTextComponent.h"
AAuraPlayerController::AAuraPlayerController()
{
@@ -27,6 +31,18 @@ void AAuraPlayerController::PlayerTick(float DeltaTime)
}
void AAuraPlayerController::ShowDamageNumber_Implementation(float DamageAmount, ACharacter* TargetCharacter, bool bCritical, bool bBlocked)
{
if (IsValid(TargetCharacter) && DamageTextComponentClass)
{
UDamageTextComponent* DamageText = NewObject<UDamageTextComponent>(TargetCharacter, DamageTextComponentClass);
DamageText->RegisterComponent();
DamageText->AttachToComponent(TargetCharacter->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
DamageText->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
DamageText->SetDamageText(DamageAmount, bCritical, bBlocked);
}
}
void AAuraPlayerController::AutoRun()
{
if (!bAutoRunning) return;
@@ -91,8 +107,8 @@ void AAuraPlayerController::AbilityInputTagReleased(FGameplayTag InputTag)
{
APawn* ControlledPawn = GetPawn();
//Why no Splines?
const FString msg = FString::Printf(TEXT("NavPoints: ActorLoc: %s - CachedLoc: %s"), *ControlledPawn->GetActorLocation().ToString(), *CachedDestination.ToString());
GEngine->AddOnScreenDebugMessage(5,8.f, FColor::Blue,msg);
//const FString msg = FString::Printf(TEXT("NavPoints: ActorLoc: %s - CachedLoc: %s"), *ControlledPawn->GetActorLocation().ToString(), *CachedDestination.ToString());
//GEngine->AddOnScreenDebugMessage(5,8.f, FColor::Blue,msg);
if (FollowTime <= ShortPressThreshold && ControlledPawn)
{
@@ -104,7 +120,7 @@ void AAuraPlayerController::AbilityInputTagReleased(FGameplayTag InputTag)
for (const FVector& PointLoc : NavPath->PathPoints)
{
Spline->AddSplinePoint(PointLoc, ESplineCoordinateSpace::World);
DrawDebugSphere(GetWorld(), PointLoc, 8.f, 8, FColor::Green, false, 5.f);
//DrawDebugSphere(GetWorld(), PointLoc, 8.f, 8, FColor::Green, false, 5.f);
CachedDestination = NavPath->PathPoints.Last();
}
bAutoRunning = true;

View File

@@ -0,0 +1,5 @@
// Copyright Echo Devgroup
#include "UI/Widget/DamageTextComponent.h"