Gameplay Ability System - dynamic cooldowns

Hello,

We’ve implemented the GAS in our game with basic cooldowns; each GA has a GE_cooldown with a fixed cooldown value.

How could we make it so the cooldowns are dynamic ?
IE: the cooldown for a fireball ability is 10 seconds, if the player activates a “boost” the next fireball would have a 20% cooldown reduction, so would be 8 seconds.

One way we could do this would be with ability level table but I don’t think this would be flexible enough for us.

Thanks

1 Like

*bump

This logic requires four sources of information: a gameplay TAG associated with Boosting ability, a node inside your Gameplay Ability ‘Assign set by caller magnitude’, a ‘Data Tag’ (for instance, SetbyCaller.Cooldown), and a gameplay effect (your ability cooldown) with a calculation modifier set to use Caller Magnitude (the Lyra Demo has a blueprint GE_Damage_Basic_SetByCaller already setup for this logic.)

From your GA, check if owning actor (player or even an AI) has a matching tag ‘is Boosting’. If true (player has tag), use a select node and modify the magnitude value of the node Assign set by caller magnitude. Finally set your cooldown GE to calculate magnitude using information from caller.

Take a look at this github page, at chapter 4.5.9.1 SetByCallers:

tranek/GASDocumentation: My understanding of Unreal Engine 4’s GameplayAbilitySystem plugin with a simple multiplayer sample project. (github.com)

Here is the quote:

4.5.9.1 SetByCallers

SetByCallers allow the GameplayEffectSpec to carry float values associated with a GameplayTag or FName around. They are stored in their respective TMaps: TMap<FGameplayTag, float> and TMap<FName, float> on the GameplayEffectSpec. These can be used to as Modifiers on the GameplayEffect or as generic means of ferrying floats around. It is common to pass numerical data generated inside of an ability to GameplayEffectExecutionCalculations or ModifierMagnitudeCalculations via SetByCallers.

SetByCaller Use Notes
Modifiers Must be defined ahead of time in the GameplayEffect class. Can only use the GameplayTag version. If one is defined on the GameplayEffect class but the GameplayEffectSpec does not have the corresponding tag and float value pair, the game will have a runtime error on application of the GameplayEffectSpec and return 0. This is a potential problem for a Divide operation. See Modifiers.
Elsewhere Does not need to be defined ahead of time anywhere. Reading a SetByCaller that does not exist on a GameplayEffectSpec can return a developer defined default value with optional warnings.

To assign SetByCaller values in Blueprint, use the Blueprint node for the version that you need (GameplayTag or FName):

Assigning SetByCaller

To read a SetByCaller value in Blueprint, you will need to make custom nodes in your Blueprint Library.

To assign SetByCaller values in C++, use the version of the function that you need (GameplayTag or FName):

void FGameplayEffectSpec::SetSetByCallerMagnitude(FName DataName, float Magnitude);

void FGameplayEffectSpec::SetSetByCallerMagnitude(FGameplayTag DataTag, float Magnitude);

To read a SetByCaller value in C++, use the version of the function that you need (GameplayTag or FName):

float GetSetByCallerMagnitude(FName DataName, bool WarnIfNotFound = true, float DefaultIfNotFound = 0.f) const;

float GetSetByCallerMagnitude(FGameplayTag DataTag, bool WarnIfNotFound = true, float DefaultIfNotFound = 0.f) const;

I recommend using the GameplayTag version over the FName version. This can prevent spelling errors in Blueprint and GameplayTags are more efficient to send over the network when the GameplayEffectSpec replicates than FNames since the TMaps replicate too.

1 Like

Something like this then ?


(in GA_Fireball)

How could I get the value from the GA boost, the one that gives the actor the tag and the 20% CD reduction, and plug that in to the switch ?

Is this sufficient for the GE ? In the Lyra Demo there’s an ExecCalculation, but that seems to be only for attributes, but the data I would use would only be the magnitude and the base CD from the GA


(GE_Fireball_Cooldown)

Thanks

1 Like

In your picture, has matching gameplay tag should be booster effect, not cooldown. You want to give the 20% reduction if booster is still active, correct? Not during booster cooldown.

You are almost there. The booster tag can be assigned to the actor right after executing the booster ability inside Booster GA. To achieve that, you need to use the nodes Add Granted Tag or Add Granted Tags. Make sure the booster tag is removed after finishing the booster effect. For this one, you can use ‘remove gameplay tag’ inside GA or ‘add granted tag’ inside the GE Booster settings (the Action RPG game template has examples of adding granted tags inside GE. These tags will be removed after the effect finishes.)

image

1 Like

My bad, the name I was wasn’t explicit enough, it is indeed the cooldownReduction effect.

Like this ? Or is this too much ?


(ga_cooldownReduction)

Does my GE make sense ?


Is this where I would declare the % of reduction I wanted ?

Also regardless of the magnitude I set to my SetByCallerMagnitude, the CD is always 1 second

1 Like

Good progress, but keep in mind if you add the node ‘add granted tag’ inside GA, there is no need to do it again inside GE. You should pick one or another. The percent reduction is going to be calculated inside the GA Fireball that checks if player has matching tag and also contains the set by caller. The select node shown in GA Fireball contains 1 and 0.8, try something more noticeable, like 10 and 5 sec, after testing you can set back to 1 and 0.8. You may want to add print string nodes to check if the tags are being added/removed timely.

To wrap-up, it is a good practice to create a workflow, or a flowchart with all steps you are envisioning. For instance:

  1. Player activates booster
  2. GA Booster adds tag booster.cooldownreduction to the player during the booster effect duration.
    2.1. If any other ability reads that tag, perform condition checks and move to true/ false branches.
    2.2 If player executes Fireball, GA Fireball checks if player has matching tag and selects fireball cooldown duration depending on true/false. This info is fed into Fireball GE via set by caller.
  3. After 20sec, booster effect ceases and the tag booster.cooldownreduction is removed from player.

I’m sorry I haven’t been clear enough, I say 20% as an example, but the amount of cooldown reduction would depend on the level of the GA_boost, for example :10%, 20%, 40%, 50% (would be 0% if the tag branch is false). Could this be determined by a table in GE_cooldown_reduction ?


(ga_fireball)

I put here 30 for testing the magnitude regardless of if it’s actor has the tag or not, however the cooldown is still one second, I feel like I’m missing something in the GE_fireball_cooldown


(ge_fireball_cooldown)

I believe these are my last issues, I think I understand the big picture
Thank you for you help so far

You can use a curve table, similarly to player level in the Action RPG template. There are two nodes: get ability level, set ability level. Try to update values manually and see what happens. It seems to me these nodes are disabled by default in UE4; thus, you need to modify the source code in C++. I haven’t tested these nodes in UE5, perhaps Epic fixed the code.

It seems that the ability level, by default, is set to follow the player level. So, if you create a logic to level up your player, all abilities will level up accordingly, unless you modify the code in C++. I cannot help you on that. There is a channel that teaches GAS with C++ and also provides source code at git hub.

UE4 Gameplay Ability System Practical Example – Part 0 Introduction - YouTube

UE4 Gameplay Ability System for Blueprint Programmers - Pt 0 - Introduction - YouTube

1 Like