The Games DevProgramming and Game Development. Tips, Tricks and Tutorials.

Damage Types, Resistances, Gameplay Tags and Gameplay Effects.

· Updated Gameplay Ability System

Updated for UE 5.8: fixed the execution sample so it compiles, noted that Asset Tags and Granted Tags are now Gameplay Effect Components (the screenshots below still show the older layout), and that modifier tag requirements now also work on instant and periodic effects (fixed in 5.4).

In this post, I want to discuss ways to deal with Damage Types using Gameplay Tags and Gameplay Effects, and how to read resistances for a specific damage type from a single attribute. We will also cover things like resistances to certain damage types, whilst utilizing as few Attributes as possible.

One thing I see a lot, and get asked a lot, is how to do damage types, how to do resistances, etc. I see many people having 10-20 attributes for different resistances, damage buffs, etc. For example:

FireResistance
IceResistance

EnergyResistance
PhysicalResistance
MeleeResistance
WeaponDamageResistance
Etc.

As you can see above, we hit a bit of a problem: if we want to handle another damage type, we have to add more Attributes, and this can be quite a lot if you have a complex game.

Gameplay Tags

Using a Gameplay Tag to determine your damage type is a simple and clean way to handle multiple damage types, without needing multiple attributes. We can have one Attribute for Resistance and pull the values we need by utilizing the Asset Tags on the Gameplay Effect and the Owned Tags on the Source or Target (discussed further down). A simple tag hierarchy could be:

DamageType.Elemental.Fire
DamageType.Elemental.Ice
DamageType.Physical.Poison
DamageType.Physical.Energy

As you can see we have 4 different Damage Types here, represented just by a Gameplay Tag. (This is just an example hierarchy, use whatever split makes sense for your game.) Because tags are hierarchical, a requirement on DamageType.Elemental is also met by a container holding DamageType.Elemental.Fire, so you can write one resistance modifier that covers every elemental type if you want.

Gameplay Effects

Gameplay Effects, along with Gameplay Tags, are a very powerful combination. You can do a lot of things with Gameplay Effects: block things with specific tags, only apply things with specific tags. A few key things (we will be using for this example) are below. I will do a more thorough write up of Gameplay Effects in another post, but for now, we will focus on just what we need for this example.

Attribute Modifier Restrictions

You can make a Gameplay Effect only evaluate and use an Attribute modifier if Tag Requirements are met, take this example:

From the above, this is a Duration based Gameplay Effect that has an Attribute Modifier for the DamageResistance attribute, which adds a Damage Resistance value (based on the level). But this modifier has a special requirement: it requires the Source to have provided the DamageType.Elemental.Fire tag for this modification to happen. This is the important bit. If, say, we throw a fireball at the player, that fireball applies a Gameplay Effect that has the DamageType.Elemental.Fire tag. This would mean this modifier would be evaluated in the Damage Calculation, and the resistance would be 25 (if the Gameplay Effect was at level 3 as in the example above). If they had a snowball thrown at them, which has the DamageType.Elemental.Ice, then this resistance would not be in the calculation, and the resistance would be 0 (if no resistance of the ice type was applied from another Gameplay Effect).

For duration and infinite effects like this one, the requirement is checked when the modifier’s attribute is evaluated with a given set of source and target tags (which is exactly what we do in the calculation below). Since UE 5.4 the same Must Have / Must Not Have tag requirements on a modifier are also respected for instant and periodic effects (there is a fix controlled by the AbilitySystem.Fix.UseModTagReqsOnAllGE console variable, on by default).

Gameplay Effect Asset Tags

Effect Asset Tags are very powerful; we can use them to describe what this Gameplay Effect is, what it does, how things should react to it (Attributes), etc. Let’s show an example, and I will explain a bit more.

So here is a very simple Damage Gameplay Effect that is Instant and applies 26 Damage at Level 4. The crucial part here is the Gameplay Effect Asset Tags.
As you can see we have 2 tags, the Damage Type and the Effect Type. The latter can be used for further details about the Gameplay Effect, but our focus will be on the Damage Type for this example.

In UE 5.3 and later the Asset Tags (and the Granted Tags) are no longer fields directly on the Gameplay Effect, they are added as Gameplay Effect Components (the Asset Tags (on Gameplay Effect) component and the Target Tags (Granted to Actor) component). The screenshots here are from an older version, but it is the same data in a different place.

When a Gameplay Effect is applied, the tags from the source and target are read, aggregated, and passed into the evaluators. This includes tags from Granted Tags and Effect Asset Tags as well as any Tags applied to the Source/Target’s ASC.

Damage Execution Calculation

We need to touch on the Damage Execution Calculation and how we can utilize what we did above to produce a final damage value. This is a very crude calculation and should be taken as an example. (If you haven’t seen Execution Calculations before, have a look at my post on understanding them first.)

The first thing we need to do in our Damage Calculation is grab the tags from the source and the target, and put them in a special struct to pass to the evaluators.

const FGameplayEffectSpec& Spec = ExecutionParams.GetOwningSpec();

// Grab the tags from source and target
const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();

// Setup our evaluate params
FAggregatorEvaluateParameters EvaluateParameters;
EvaluateParameters.SourceTags = SourceTags;
EvaluateParameters.TargetTags = TargetTags;

This struct EvaluateParameters will be passed into the evaluators for the attributes we need, and they return the value. Example below:

// Grab any damage resistances from the target.
float DamageResistance = 0.0f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(AresDamageStatics().DamageResistanceDef, EvaluateParameters, DamageResistance);

// Calculate the Outgoing Ability Damage.
float AbilityDamage = 0.0f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(AresDamageStatics().OutgoingAbilityDamageDef, EvaluateParameters, AbilityDamage);

As you can see above, we are getting the Damage Resistance from the target and passing in our evaluate struct, which has our Source and Target Tags, and this returns our Damage Resistance. We are also grabbing the Ability Damage (which we set in the Gameplay Effect).

For this to work, DamageResistanceDef has to be a capture definition for the Resistance attribute on the Target, and it has to be added to RelevantAttributesToCapture in the calculation’s constructor. I would not snapshot it, so you read the target’s resistances as they are at the moment of the hit:

DamageResistanceDef = FGameplayEffectAttributeCaptureDefinition(UAresHealthSet::GetDamageResistanceAttribute(), EGameplayEffectAttributeCaptureSource::Target, false);

Then use the value however your game wants. A crude example, treating resistance as a percentage:

const float DamageDone = FMath::Max(AbilityDamage * (1.f - FMath::Clamp(DamageResistance, 0.f, 100.f) * 0.01f), 0.f);
if (DamageDone > 0.f)
{
	OutExecutionOutput.AddOutputModifier(FGameplayModifierEvaluatedData(UAresHealthSet::GetDamageAttribute(), EGameplayModOp::Additive, DamageDone));
}

Reading the Damage Resistance for a Specific Damage Type

One thing you may be asking is, how can I read the Damage Resistance for a specific type if it’s a single attribute? Well fear not, the Gameplay Ability System has you covered.

This node (Evaluate Attribute Value With Tags, from the Ability System Blueprint Library, there is also a version that takes a base value) will allow you to evaluate an attribute and return the float value, based on the tags provided, for example:

This will show the Damage Resistance to Fire Elemental Damage. Useful for things like UI, etc.

Putting it all together

We will now put it all together and do a test, and I’ll show you some debugger outputs for different test scenarios, showing the power of Gameplay Tags for your Damage Type.

In this example, I will apply two Gameplay Effects at level 1, one with Ice Resistance and one with Fire Resistance:

As you can see, they both have different values at level 1, Fire is 5 resistance, Ice is 3 resistance.

The damage GE will apply Fire Damage.

As seen in the Ability System Debugger

We have our two resistances applied, but as you can also see they require a source tag. You can also see our DamageResistance is 0 because nothing is telling those modifiers to apply.

Now when we apply our Damage Gameplay Effect, our execution will fire, and will grab the tags relevant for that GE execution:

As you can see, our Source Tags do indeed contain our Elemental.Fire Damage Type. This is because it was in the Gameplay Effect’s Asset Tags.

Now we get on to the Damage Resistance Calculation

As you can see, when we ran the evaluator, we got the correct Damage Resistance of 5, not 8 and not 0. This is because it matched the tags, and only returned the relevant attribute value.

Wrapping up

A few things to keep in mind:

  • The tags on the damage effect decide which resistance modifiers count, so make sure every damage effect carries a damage type tag, otherwise none of the typed resistances will apply.
  • Modifiers are matched against the aggregated tags, so they can also key off tags on the source or target actors themselves (for example a “Burning” state), not just the effect’s asset tags.
  • If your damage should also drive Gameplay Cues by type, note that the cue parameters carry AggregatedSourceTags and AggregatedTargetTags, so a cue can look at the same damage type tags.

I really hope this helps with understanding how to do this, and hopefully you can see the power in it, and how powerful Gameplay Tags are with Gameplay Effects.

If you need more help, have questions, or would like me to focus on other topics, you can see my contact details in the About Me page.