533 lines
17 KiB
C++
533 lines
17 KiB
C++
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||
|
|
||
|
#include "LyraGameplayAbility.h"
|
||
|
#include "LyraLogChannels.h"
|
||
|
#include "AbilitySystem/LyraAbilitySystemComponent.h"
|
||
|
#include "Player/LyraPlayerController.h"
|
||
|
#include "Character/LyraCharacter.h"
|
||
|
#include "LyraGameplayTags.h"
|
||
|
#include "LyraAbilityCost.h"
|
||
|
#include "Character/LyraHeroComponent.h"
|
||
|
#include "AbilitySystemBlueprintLibrary.h"
|
||
|
#include "AbilitySystemGlobals.h"
|
||
|
#include "LyraAbilitySimpleFailureMessage.h"
|
||
|
#include "GameFramework/GameplayMessageSubsystem.h"
|
||
|
#include "AbilitySystem/LyraAbilitySourceInterface.h"
|
||
|
#include "AbilitySystem/LyraGameplayEffectContext.h"
|
||
|
#include "Physics/PhysicalMaterialWithTags.h"
|
||
|
|
||
|
UE_DEFINE_GAMEPLAY_TAG(TAG_ABILITY_SIMPLE_FAILURE_MESSAGE, "Ability.UserFacingSimpleActivateFail.Message");
|
||
|
UE_DEFINE_GAMEPLAY_TAG(TAG_ABILITY_PLAY_MONTAGE_FAILURE_MESSAGE, "Ability.PlayMontageOnActivateFail.Message");
|
||
|
|
||
|
ULyraGameplayAbility::ULyraGameplayAbility(const FObjectInitializer& ObjectInitializer)
|
||
|
: Super(ObjectInitializer)
|
||
|
{
|
||
|
ReplicationPolicy = EGameplayAbilityReplicationPolicy::ReplicateNo;
|
||
|
InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;
|
||
|
NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::LocalPredicted;
|
||
|
NetSecurityPolicy = EGameplayAbilityNetSecurityPolicy::ClientOrServer;
|
||
|
|
||
|
ActivationPolicy = ELyraAbilityActivationPolicy::OnInputTriggered;
|
||
|
ActivationGroup = ELyraAbilityActivationGroup::Independent;
|
||
|
|
||
|
ActiveCameraMode = nullptr;
|
||
|
}
|
||
|
|
||
|
ULyraAbilitySystemComponent* ULyraGameplayAbility::GetLyraAbilitySystemComponentFromActorInfo() const
|
||
|
{
|
||
|
return (CurrentActorInfo ? Cast<ULyraAbilitySystemComponent>(CurrentActorInfo->AbilitySystemComponent.Get()) : nullptr);
|
||
|
}
|
||
|
|
||
|
ALyraPlayerController* ULyraGameplayAbility::GetLyraPlayerControllerFromActorInfo() const
|
||
|
{
|
||
|
return (CurrentActorInfo ? Cast<ALyraPlayerController>(CurrentActorInfo->PlayerController.Get()) : nullptr);
|
||
|
}
|
||
|
|
||
|
AController* ULyraGameplayAbility::GetControllerFromActorInfo() const
|
||
|
{
|
||
|
if (CurrentActorInfo)
|
||
|
{
|
||
|
if (AController* PC = CurrentActorInfo->PlayerController.Get())
|
||
|
{
|
||
|
return PC;
|
||
|
}
|
||
|
|
||
|
// Look for a player controller or pawn in the owner chain.
|
||
|
AActor* TestActor = CurrentActorInfo->OwnerActor.Get();
|
||
|
while (TestActor)
|
||
|
{
|
||
|
if (AController* C = Cast<AController>(TestActor))
|
||
|
{
|
||
|
return C;
|
||
|
}
|
||
|
|
||
|
if (APawn* Pawn = Cast<APawn>(TestActor))
|
||
|
{
|
||
|
return Pawn->GetController();
|
||
|
}
|
||
|
|
||
|
TestActor = TestActor->GetOwner();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
ALyraCharacter* ULyraGameplayAbility::GetLyraCharacterFromActorInfo() const
|
||
|
{
|
||
|
return (CurrentActorInfo ? Cast<ALyraCharacter>(CurrentActorInfo->AvatarActor.Get()) : nullptr);
|
||
|
}
|
||
|
|
||
|
ULyraHeroComponent* ULyraGameplayAbility::GetHeroComponentFromActorInfo() const
|
||
|
{
|
||
|
return (CurrentActorInfo ? ULyraHeroComponent::FindHeroComponent(CurrentActorInfo->AvatarActor.Get()) : nullptr);
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::NativeOnAbilityFailedToActivate(const FGameplayTagContainer& FailedReason) const
|
||
|
{
|
||
|
bool bSimpleFailureFound = false;
|
||
|
for (FGameplayTag Reason : FailedReason)
|
||
|
{
|
||
|
if (!bSimpleFailureFound)
|
||
|
{
|
||
|
if (const FText* pUserFacingMessage = FailureTagToUserFacingMessages.Find(Reason))
|
||
|
{
|
||
|
FLyraAbilitySimpleFailureMessage Message;
|
||
|
Message.PlayerController = GetActorInfo().PlayerController.Get();
|
||
|
Message.FailureTags = FailedReason;
|
||
|
Message.UserFacingReason = *pUserFacingMessage;
|
||
|
|
||
|
UGameplayMessageSubsystem& MessageSystem = UGameplayMessageSubsystem::Get(GetWorld());
|
||
|
MessageSystem.BroadcastMessage(TAG_ABILITY_SIMPLE_FAILURE_MESSAGE, Message);
|
||
|
bSimpleFailureFound = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (UAnimMontage* pMontage = FailureTagToAnimMontage.FindRef(Reason))
|
||
|
{
|
||
|
FLyraAbilityMontageFailureMessage Message;
|
||
|
Message.PlayerController = GetActorInfo().PlayerController.Get();
|
||
|
Message.FailureTags = FailedReason;
|
||
|
Message.FailureMontage = pMontage;
|
||
|
|
||
|
UGameplayMessageSubsystem& MessageSystem = UGameplayMessageSubsystem::Get(GetWorld());
|
||
|
MessageSystem.BroadcastMessage(TAG_ABILITY_PLAY_MONTAGE_FAILURE_MESSAGE, Message);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ULyraGameplayAbility::CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, FGameplayTagContainer* OptionalRelevantTags) const
|
||
|
{
|
||
|
if (!ActorInfo || !ActorInfo->AbilitySystemComponent.IsValid())
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
ULyraAbilitySystemComponent* LyraASC = CastChecked<ULyraAbilitySystemComponent>(ActorInfo->AbilitySystemComponent.Get());
|
||
|
const FLyraGameplayTags& GameplayTags = FLyraGameplayTags::Get();
|
||
|
|
||
|
if (!Super::CanActivateAbility(Handle, ActorInfo, SourceTags, TargetTags, OptionalRelevantTags))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//@TODO Possibly remove after setting up tag relationships
|
||
|
if (LyraASC->IsActivationGroupBlocked(ActivationGroup))
|
||
|
{
|
||
|
if (OptionalRelevantTags)
|
||
|
{
|
||
|
OptionalRelevantTags->AddTag(GameplayTags.Ability_ActivateFail_ActivationGroup);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::SetCanBeCanceled(bool bCanBeCanceled)
|
||
|
{
|
||
|
// The ability can not block canceling if it's replaceable.
|
||
|
if (!bCanBeCanceled && (ActivationGroup == ELyraAbilityActivationGroup::Exclusive_Replaceable))
|
||
|
{
|
||
|
UE_LOG(LogLyraAbilitySystem, Error, TEXT("SetCanBeCanceled: Ability [%s] can not block canceling because its activation group is replaceable."), *GetName());
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Super::SetCanBeCanceled(bCanBeCanceled);
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec)
|
||
|
{
|
||
|
Super::OnGiveAbility(ActorInfo, Spec);
|
||
|
|
||
|
K2_OnAbilityAdded();
|
||
|
|
||
|
TryActivateAbilityOnSpawn(ActorInfo, Spec);
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::OnRemoveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec)
|
||
|
{
|
||
|
K2_OnAbilityRemoved();
|
||
|
|
||
|
Super::OnRemoveAbility(ActorInfo, Spec);
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
|
||
|
{
|
||
|
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled)
|
||
|
{
|
||
|
ClearCameraMode();
|
||
|
|
||
|
Super::EndAbility(Handle, ActorInfo, ActivationInfo, bReplicateEndAbility, bWasCancelled);
|
||
|
}
|
||
|
|
||
|
bool ULyraGameplayAbility::CheckCost(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, OUT FGameplayTagContainer* OptionalRelevantTags) const
|
||
|
{
|
||
|
if (!Super::CheckCost(Handle, ActorInfo, OptionalRelevantTags) || !ActorInfo)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Verify we can afford any additional costs
|
||
|
for (TObjectPtr<ULyraAbilityCost> AdditionalCost : AdditionalCosts)
|
||
|
{
|
||
|
if (AdditionalCost != nullptr)
|
||
|
{
|
||
|
if (!AdditionalCost->CheckCost(this, Handle, ActorInfo, /*inout*/ OptionalRelevantTags))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::ApplyCost(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) const
|
||
|
{
|
||
|
Super::ApplyCost(Handle, ActorInfo, ActivationInfo);
|
||
|
|
||
|
check(ActorInfo);
|
||
|
|
||
|
// Used to determine if the ability actually hit a target (as some costs are only spent on successful attempts)
|
||
|
auto DetermineIfAbilityHitTarget = [&]()
|
||
|
{
|
||
|
if (ActorInfo->IsNetAuthority())
|
||
|
{
|
||
|
if (ULyraAbilitySystemComponent* ASC = Cast<ULyraAbilitySystemComponent>(ActorInfo->AbilitySystemComponent.Get()))
|
||
|
{
|
||
|
FGameplayAbilityTargetDataHandle TargetData;
|
||
|
ASC->GetAbilityTargetData(Handle, ActivationInfo, TargetData);
|
||
|
for (int32 TargetDataIdx = 0; TargetDataIdx < TargetData.Data.Num(); ++TargetDataIdx)
|
||
|
{
|
||
|
if (UAbilitySystemBlueprintLibrary::TargetDataHasHitResult(TargetData, TargetDataIdx))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
// Pay any additional costs
|
||
|
bool bAbilityHitTarget = false;
|
||
|
bool bHasDeterminedIfAbilityHitTarget = false;
|
||
|
for (TObjectPtr<ULyraAbilityCost> AdditionalCost : AdditionalCosts)
|
||
|
{
|
||
|
if (AdditionalCost != nullptr)
|
||
|
{
|
||
|
if (AdditionalCost->ShouldOnlyApplyCostOnHit())
|
||
|
{
|
||
|
if (!bHasDeterminedIfAbilityHitTarget)
|
||
|
{
|
||
|
bAbilityHitTarget = DetermineIfAbilityHitTarget();
|
||
|
bHasDeterminedIfAbilityHitTarget = true;
|
||
|
}
|
||
|
|
||
|
if (!bAbilityHitTarget)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
AdditionalCost->ApplyCost(this, Handle, ActorInfo, ActivationInfo);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FGameplayEffectContextHandle ULyraGameplayAbility::MakeEffectContext(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo) const
|
||
|
{
|
||
|
FGameplayEffectContextHandle ContextHandle = Super::MakeEffectContext(Handle, ActorInfo);
|
||
|
|
||
|
FLyraGameplayEffectContext* EffectContext = FLyraGameplayEffectContext::ExtractEffectContext(ContextHandle);
|
||
|
check(EffectContext);
|
||
|
|
||
|
check(ActorInfo);
|
||
|
|
||
|
AActor* EffectCauser = nullptr;
|
||
|
const ILyraAbilitySourceInterface* AbilitySource = nullptr;
|
||
|
float SourceLevel = 0.0f;
|
||
|
GetAbilitySource(Handle, ActorInfo, /*out*/ SourceLevel, /*out*/ AbilitySource, /*out*/ EffectCauser);
|
||
|
|
||
|
UObject* SourceObject = GetSourceObject(Handle, ActorInfo);
|
||
|
|
||
|
AActor* Instigator = ActorInfo ? ActorInfo->OwnerActor.Get() : nullptr;
|
||
|
|
||
|
EffectContext->SetAbilitySource(AbilitySource, SourceLevel);
|
||
|
EffectContext->AddInstigator(Instigator, EffectCauser);
|
||
|
EffectContext->AddSourceObject(SourceObject);
|
||
|
|
||
|
return ContextHandle;
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::ApplyAbilityTagsToGameplayEffectSpec(FGameplayEffectSpec& Spec, FGameplayAbilitySpec* AbilitySpec) const
|
||
|
{
|
||
|
Super::ApplyAbilityTagsToGameplayEffectSpec(Spec, AbilitySpec);
|
||
|
|
||
|
if (const FHitResult* HitResult = Spec.GetContext().GetHitResult())
|
||
|
{
|
||
|
if (const UPhysicalMaterialWithTags* PhysMatWithTags = Cast<const UPhysicalMaterialWithTags>(HitResult->PhysMaterial.Get()))
|
||
|
{
|
||
|
Spec.CapturedTargetTags.GetSpecTags().AppendTags(PhysMatWithTags->Tags);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ULyraGameplayAbility::DoesAbilitySatisfyTagRequirements(const UAbilitySystemComponent& AbilitySystemComponent, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, OUT FGameplayTagContainer* OptionalRelevantTags) const
|
||
|
{
|
||
|
// Specialized version to handle death exclusion and AbilityTags expansion via ASC
|
||
|
|
||
|
bool bBlocked = false;
|
||
|
bool bMissing = false;
|
||
|
|
||
|
UAbilitySystemGlobals& AbilitySystemGlobals = UAbilitySystemGlobals::Get();
|
||
|
const FGameplayTag& BlockedTag = AbilitySystemGlobals.ActivateFailTagsBlockedTag;
|
||
|
const FGameplayTag& MissingTag = AbilitySystemGlobals.ActivateFailTagsMissingTag;
|
||
|
|
||
|
// Check if any of this ability's tags are currently blocked
|
||
|
if (AbilitySystemComponent.AreAbilityTagsBlocked(AbilityTags))
|
||
|
{
|
||
|
bBlocked = true;
|
||
|
}
|
||
|
|
||
|
const ULyraAbilitySystemComponent* LyraASC = Cast<ULyraAbilitySystemComponent>(&AbilitySystemComponent);
|
||
|
static FGameplayTagContainer AllRequiredTags;
|
||
|
static FGameplayTagContainer AllBlockedTags;
|
||
|
|
||
|
AllRequiredTags = ActivationRequiredTags;
|
||
|
AllBlockedTags = ActivationBlockedTags;
|
||
|
|
||
|
// Expand our ability tags to add additional required/blocked tags
|
||
|
if (LyraASC)
|
||
|
{
|
||
|
LyraASC->GetAdditionalActivationTagRequirements(AbilityTags, AllRequiredTags, AllBlockedTags);
|
||
|
}
|
||
|
|
||
|
// Check to see the required/blocked tags for this ability
|
||
|
if (AllBlockedTags.Num() || AllRequiredTags.Num())
|
||
|
{
|
||
|
static FGameplayTagContainer AbilitySystemComponentTags;
|
||
|
|
||
|
AbilitySystemComponentTags.Reset();
|
||
|
AbilitySystemComponent.GetOwnedGameplayTags(AbilitySystemComponentTags);
|
||
|
|
||
|
if (AbilitySystemComponentTags.HasAny(AllBlockedTags))
|
||
|
{
|
||
|
const FLyraGameplayTags& GameplayTags = FLyraGameplayTags::Get();
|
||
|
if (OptionalRelevantTags && AbilitySystemComponentTags.HasTag(GameplayTags.Status_Death))
|
||
|
{
|
||
|
// If player is dead and was rejected due to blocking tags, give that feedback
|
||
|
OptionalRelevantTags->AddTag(GameplayTags.Ability_ActivateFail_IsDead);
|
||
|
}
|
||
|
|
||
|
bBlocked = true;
|
||
|
}
|
||
|
|
||
|
if (!AbilitySystemComponentTags.HasAll(AllRequiredTags))
|
||
|
{
|
||
|
bMissing = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SourceTags != nullptr)
|
||
|
{
|
||
|
if (SourceBlockedTags.Num() || SourceRequiredTags.Num())
|
||
|
{
|
||
|
if (SourceTags->HasAny(SourceBlockedTags))
|
||
|
{
|
||
|
bBlocked = true;
|
||
|
}
|
||
|
|
||
|
if (!SourceTags->HasAll(SourceRequiredTags))
|
||
|
{
|
||
|
bMissing = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (TargetTags != nullptr)
|
||
|
{
|
||
|
if (TargetBlockedTags.Num() || TargetRequiredTags.Num())
|
||
|
{
|
||
|
if (TargetTags->HasAny(TargetBlockedTags))
|
||
|
{
|
||
|
bBlocked = true;
|
||
|
}
|
||
|
|
||
|
if (!TargetTags->HasAll(TargetRequiredTags))
|
||
|
{
|
||
|
bMissing = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (bBlocked)
|
||
|
{
|
||
|
if (OptionalRelevantTags && BlockedTag.IsValid())
|
||
|
{
|
||
|
OptionalRelevantTags->AddTag(BlockedTag);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
if (bMissing)
|
||
|
{
|
||
|
if (OptionalRelevantTags && MissingTag.IsValid())
|
||
|
{
|
||
|
OptionalRelevantTags->AddTag(MissingTag);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::OnPawnAvatarSet()
|
||
|
{
|
||
|
K2_OnPawnAvatarSet();
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::GetAbilitySource(FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, float& OutSourceLevel, const ILyraAbilitySourceInterface*& OutAbilitySource, AActor*& OutEffectCauser) const
|
||
|
{
|
||
|
OutSourceLevel = 0.0f;
|
||
|
OutAbilitySource = nullptr;
|
||
|
OutEffectCauser = nullptr;
|
||
|
|
||
|
OutEffectCauser = ActorInfo->AvatarActor.Get();
|
||
|
|
||
|
// If we were added by something that's an ability info source, use it
|
||
|
UObject* SourceObject = GetSourceObject(Handle, ActorInfo);
|
||
|
|
||
|
OutAbilitySource = Cast<ILyraAbilitySourceInterface>(SourceObject);
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::TryActivateAbilityOnSpawn(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) const
|
||
|
{
|
||
|
const bool bIsPredicting = (Spec.ActivationInfo.ActivationMode == EGameplayAbilityActivationMode::Predicting);
|
||
|
|
||
|
// Try to activate if activation policy is on spawn.
|
||
|
if (ActorInfo && !Spec.IsActive() && !bIsPredicting && (ActivationPolicy == ELyraAbilityActivationPolicy::OnSpawn))
|
||
|
{
|
||
|
UAbilitySystemComponent* ASC = ActorInfo->AbilitySystemComponent.Get();
|
||
|
const AActor* AvatarActor = ActorInfo->AvatarActor.Get();
|
||
|
|
||
|
// If avatar actor is torn off or about to die, don't try to activate until we get the new one.
|
||
|
if (ASC && AvatarActor && !AvatarActor->GetTearOff() && (AvatarActor->GetLifeSpan() <= 0.0f))
|
||
|
{
|
||
|
const bool bIsLocalExecution = (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::LocalPredicted) || (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::LocalOnly);
|
||
|
const bool bIsServerExecution = (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::ServerOnly) || (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::ServerInitiated);
|
||
|
|
||
|
const bool bClientShouldActivate = ActorInfo->IsLocallyControlled() && bIsLocalExecution;
|
||
|
const bool bServerShouldActivate = ActorInfo->IsNetAuthority() && bIsServerExecution;
|
||
|
|
||
|
if (bClientShouldActivate || bServerShouldActivate)
|
||
|
{
|
||
|
ASC->TryActivateAbility(Spec.Handle);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ULyraGameplayAbility::CanChangeActivationGroup(ELyraAbilityActivationGroup NewGroup) const
|
||
|
{
|
||
|
if (!IsInstantiated() || !IsActive())
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (ActivationGroup == NewGroup)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponentFromActorInfo();
|
||
|
check(LyraASC);
|
||
|
|
||
|
if ((ActivationGroup != ELyraAbilityActivationGroup::Exclusive_Blocking) && LyraASC->IsActivationGroupBlocked(NewGroup))
|
||
|
{
|
||
|
// This ability can't change groups if it's blocked (unless it is the one doing the blocking).
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ((NewGroup == ELyraAbilityActivationGroup::Exclusive_Replaceable) && !CanBeCanceled())
|
||
|
{
|
||
|
// This ability can't become replaceable if it can't be canceled.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool ULyraGameplayAbility::ChangeActivationGroup(ELyraAbilityActivationGroup NewGroup)
|
||
|
{
|
||
|
ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN(ChangeActivationGroup, false);
|
||
|
|
||
|
if (!CanChangeActivationGroup(NewGroup))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (ActivationGroup != NewGroup)
|
||
|
{
|
||
|
ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponentFromActorInfo();
|
||
|
check(LyraASC);
|
||
|
|
||
|
LyraASC->RemoveAbilityFromActivationGroup(ActivationGroup, this);
|
||
|
LyraASC->AddAbilityToActivationGroup(NewGroup, this);
|
||
|
|
||
|
ActivationGroup = NewGroup;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::SetCameraMode(TSubclassOf<ULyraCameraMode> CameraMode)
|
||
|
{
|
||
|
ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN(SetCameraMode, );
|
||
|
|
||
|
if (ULyraHeroComponent* HeroComponent = GetHeroComponentFromActorInfo())
|
||
|
{
|
||
|
HeroComponent->SetAbilityCameraMode(CameraMode, CurrentSpecHandle);
|
||
|
ActiveCameraMode = CameraMode;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ULyraGameplayAbility::ClearCameraMode()
|
||
|
{
|
||
|
ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN(ClearCameraMode, );
|
||
|
|
||
|
if (ActiveCameraMode)
|
||
|
{
|
||
|
if (ULyraHeroComponent* HeroComponent = GetHeroComponentFromActorInfo())
|
||
|
{
|
||
|
HeroComponent->ClearAbilityCameraMode(CurrentSpecHandle);
|
||
|
}
|
||
|
|
||
|
ActiveCameraMode = nullptr;
|
||
|
}
|
||
|
}
|