Skip to content

Commit

Permalink
[#9] [#53] Fire Off Gameplay Cue when Damage is Inflicted
Browse files Browse the repository at this point in the history
This might get reworked later, since I am not sure if a GE exec is
supposed to make changes outside the scope of executing a GE, but this
seems like the best place to do this logic since it has all the context
about the type and amount of each damage type.
  • Loading branch information
GuyPaddock committed Dec 18, 2023
1 parent d38c3ea commit 7b28fa6
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Config/Tags/PF2GameplayCues.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
; OpenPF2 for UE Game Logic, Copyright 2023, Guy Elsmore-Paddock. All Rights Reserved.
;
; This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
; distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

; Gameplay Cues that provide special FX and sound FX in response to effect activations.
[/Script/GameplayTags.GameplayTagsList]
GameplayTagList=(Tag="GameplayCue.Character.InflictDamage", DevComment="Gameplay cue fired whenever one character inflicts damage on another.")
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

#include "Libraries/PF2AbilitySystemLibrary.h"

#include "Utilities/PF2GameplayAbilityUtilities.h"

UPF2ApplyDamageFromSourceExecution::UPF2ApplyDamageFromSourceExecution()
{
const FPF2AttackAttributeStatics AttackCaptures = FPF2AttackAttributeStatics::GetInstance();
Expand All @@ -28,15 +30,22 @@ UPF2ApplyDamageFromSourceExecution::UPF2ApplyDamageFromSourceExecution()
{
this->RelevantAttributesToCapture.Add(*Capture);
}

// Cache the tag to avoid lookup overhead.
this->InflictDamageCueTag = PF2GameplayAbilityUtilities::GetTag(
FName("GameplayCue.Character.InflictDamage")
);
}

void UPF2ApplyDamageFromSourceExecution::Execute_Implementation(
const FGameplayEffectCustomExecutionParameters& ExecutionParams,
FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const
{
UAbilitySystemComponent* TargetAsc = ExecutionParams.GetTargetAbilitySystemComponent();
const FPF2AttackAttributeStatics AttackCaptures = FPF2AttackAttributeStatics::GetInstance();
const FPF2TargetCharacterAttributeStatics TargetCaptures = FPF2TargetCharacterAttributeStatics::GetInstance();
float AttackDegreeOfSuccess = 0.0f;
bool bHaveAnyDamage = false;

const FAggregatorEvaluateParameters EvaluationParameters =
UPF2AbilitySystemLibrary::BuildEvaluationParameters(ExecutionParams);
Expand Down Expand Up @@ -102,6 +111,8 @@ void UPF2ApplyDamageFromSourceExecution::Execute_Implementation(

if (EffectiveDamage > 0)
{
FGameplayCueParameters CueParams = PopulateGameplayCueParameters(ExecutionParams);

// Apply: Damage, less resistance.
OutExecutionOutput.AddOutputModifier(
FGameplayModifierEvaluatedData(
Expand All @@ -110,6 +121,38 @@ void UPF2ApplyDamageFromSourceExecution::Execute_Implementation(
EffectiveDamage
)
);

bHaveAnyDamage = true;

// For now, pass the damage type along as a source tag. These feels like a hack, but saves us from having to
// define a custom parameter object and/or context object to pass along inside the parameter object.
//
// An alternative would be to pass the damage type along in the OriginalTag field, but the intent of that
// field appears to be to capture what gameplay tag was emitted by a GE to locate the cue. The
// MatchedTagName field, meanwhile, appears to be for holding the name of the tag that the selected cue has.
CueParams.AggregatedSourceTags.AddTag(
AttackCaptures.GetDamageTypeForDamageAttribute(Capture->AttributeToCapture)
);

CueParams.RawMagnitude = EffectiveDamage;

TargetAsc->ExecuteGameplayCue(
this->InflictDamageCueTag,
CueParams
);
}
}

if (!bHaveAnyDamage)
{
// Fire off a cue for a miss (no damage), so that the player can see a zero.
FGameplayCueParameters CueParams = PopulateGameplayCueParameters(ExecutionParams);

CueParams.RawMagnitude = 0;

TargetAsc->ExecuteGameplayCue(
this->InflictDamageCueTag,
CueParams
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ class OPENPF2CORE_API UPF2ApplyDamageFromSourceExecution : public UGameplayEffec
{
GENERATED_BODY()

/**
* The gameplay tag for gameplay cues that activate upon damage being inflicted to the target.
*/
FGameplayTag InflictDamageCueTag;

public:
// =================================================================================================================
// Constructors
Expand All @@ -42,4 +47,32 @@ class OPENPF2CORE_API UPF2ApplyDamageFromSourceExecution : public UGameplayEffec
// =================================================================================================================
virtual void Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams,
OUT FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const override;

protected:
/**
* Gets the gameplay tag for gameplay cues that activate upon damage being inflicted to the target.
*
* @return
* The gameplay tag for the damage cue.
*/
FORCEINLINE const FGameplayTag& GetInflictDamageCueTag() const
{
return this->InflictDamageCueTag;
}

/**
* Populates parameters from a gameplay cue from the parameters of the current GE execution.
*
* @param [in] ExecutionParams
* The parameters passed to the current GE execution.
*
* @return
* The new Gameplay Cue parameters.
*/
FORCEINLINE FGameplayCueParameters PopulateGameplayCueParameters(
const FGameplayEffectCustomExecutionParameters& ExecutionParams) const
{
return FGameplayCueParameters(ExecutionParams.GetOwningSpec().GetEffectContext());
}

};

0 comments on commit 7b28fa6

Please sign in to comment.