I will leave this info here, since it is never old to necropost something regading UE solutions.
TLDR. Any numeric data related to effects can be managed with SetByCaller magnitudes. You can store cooldown turns remaining directly inside SBC Data of said effect, and decrease/increase it, and then remove said effect with your own logic , i.e at turn end event.
You will need to do few things:
- Tags or Names to store data on effect (avoid overlap with any attribute calculation related data)
- Functions to Read Write SetByCaller Data from ActiveEffect
- Way to handle turn start / end , any other means to tick duration and remove effect if said effect SetByCaller value dropped below 0.
I will give a brief steps creating a cooldown effect and using it with ability.
Create a BlueprintLibrary in C++:
Active Effect SetByCaller Accessors
I found easiest way to create Static Library . Note ASC has function to set SetByCallerData on active effect (which is stored in spec anyaway), read can be done directly from Spec.
float UPJCAbilitySystemBlueprintLibrary::GetActiveEffectSetByCallerMagnitude(FActiveGameplayEffectHandle SpecHandle, FGameplayTag Tag)
{
float Result = -1;
UAbilitySystemComponent* ASC = SpecHandle.GetOwningAbilitySystemComponent();
if (ASC)
{
auto Effect = ASC->GetActiveGameplayEffect(SpecHandle);
if(Effect)
{
Result = Effect->Spec.GetSetByCallerMagnitude(Tag,false,-1);
}
}
return Result;
}
void UPJCAbilitySystemBlueprintLibrary::SetActiveEffectSetByCallerMagnitude(FActiveGameplayEffectHandle SpecHandle, FGameplayTag Tag, float Magnitude)
{
float Result = -1;
UAbilitySystemComponent* ASC = SpecHandle.GetOwningAbilitySystemComponent();
if (ASC)
{
ASC->UpdateActiveGameplayEffectSetByCallerMagnitude(SpecHandle,Tag,Magnitude);
}
}
Cooldown Effect
Setup Effect Components with :
- Asset Tags to filter it later in manager ability.
- Granted Tag for Ability to know it is on cooldown.
Ability With Cooldown
Add properties to control cooldown, and duration on your TurnBasedAbilityBase class ,as well as i use base class cooldown effect class property field.
UPROPERTY(EditDefaultsOnly, Category = Cooldowns)
int32 CooldownInTurns = 1;
UPROPERTY(EditDefaultsOnly, Category = Cooldowns)
FGameplayTag SetByCallerTurnBasedCooldownTag;
// Override ApplyCooldown function to create spec,inject SetByCaller data andapply to self.
void UTurnBasedAbilityBase::ApplyCooldown(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) const
{
UGameplayEffect* CooldownGE = GetCooldownGameplayEffect();
if (CooldownGE)
{
FGameplayEffectSpecHandle SpecHandle = MakeOutgoingGameplayEffectSpec(Handle, ActorInfo, ActivationInfo, CooldownGE->GetClass(), 1);
if(FGameplayEffectSpec* Spec = SpecHandle.Data.Get())
{
Spec->SetSetByCallerMagnitude(SetByCallerTurnBasedCooldownTag, CooldownInTurns);
ApplyGameplayEffectSpecToOwner(Handle,ActorInfo,ActivationInfo,SpecHandle);
}
}
}
Manager Ability
- Create regular ability.
- Add a Trigger Data , i use events to control all combat events.
- Override Activate From Event Function and do :
- Grant this ability to your ASC owner Actor on BeginPlay
- Send Turn Related evens from your Combat Manager to all relevant Actors.
Additionaly:
You might want to subscribe to FAbilitySpecDirtied AbilitySpecDirtiedCallbacks
delegate inside ASC to watch over any Spec changes, it should include our SetByCaller magnitudes too, i.e for UI display.
You might want to pay attention to client/server things in case you networking this.
You might want to use different route for ability to indentify it is on cooldown, different from effect granted tags, then look into ASC functions like : GetCooldownTags(), CheckCooldown() and there is also FName SetByCaller version, probably for times when you want to generate data dynamicaly.