Damage And Mitigation
Applying Damage
First, let's discuss how damage is applied in the system.
First and foremost, to apply damage, you simply need to apply a Gameplay Effect to a Target that adds (or overrides)
the value of the PendingDamage
attribute. Once this Gameplay Effect is received by the Attribute Set, the damage
processing (including the defense system), will be triggered.
Here's an example where the source's BaseDamage
attribute is being added to the target's PendingDamage
attribute.
Add or Override Pending Damage
Adding will append this damage to any other damage that is being already added in this tick. Overriding will ensure that the actual damage is exclusively handled, and other potential amounts of damage are discarded. You may choose one or the other depending on your design. If you are unsure, adding is the safest approach.
Also, if you want to categorize this damage, so it can be properly identified later on during the Hit Reaction or Death phases, or even consider the damage type while defending it, make sure to add a Gameplay Tag that properly identifies this damage type.
Damage Calculation
The Calculation can be more elaborate than just adding the value of BaseDamage
. The system also supports
attributes for Critical Damage: CriticalHitChance
and CriticalHitMultiplier
. You can use the provided
Calculation Class, UCombatExecution_Damage
, to account for these attributes. In which case, the calculation
would be:
if critical_damage_chance_test
then:
pending_damage += base_damage * critical_damage_multiplier
else:
pending_damage += base_damage
This calculation class also supports SetByCaller
magnitudes, using the following Data Tags:
Gameplay Tag | Description |
---|---|
Combat.Data.Damage |
Overrides the BaseDamage attribute. |
Combat.Data.CriticalHitChance |
Overrides the CriticalHitChance attribute. |
Combat.Data.CriticalHitMultiplier |
Overrides the CriticalHitMultiplier attribute. |
Furthermore, each step in this is broken down into proper functions, which can be extended in case you want to add more elements to the damage calculation.
This is how a Gameplay Effect using the Calculation Class looks like. Once again, note the presence of the Damage Tags, mentioned before, used to identify the damage. They might be useful in the Damage Calculation as well!
Breaking Defense and Breaking Stance
Damage effects can eventually break a target's defense/blocking stance. The most common reason for that is because they ran out of stamina to soak incoming damage. In which case, the damage will trigger a breaker hit.
Incoming damage can also reduce the target's poise. Once the target's poise reaches zero, it will be staggered, cancelling any ongoing action (attacks or evades).
If you want your attacks to affect poise, make sure to reduce the proper Poise
attribute and to also apply the
Tag_Combat_Effect_Cancel_Regeneration_Poise
for a certain duration, which will cancel the immediate poise regeneration.
Base Effect Classes
The system provides two base Gameplay Effect classes that can be used to configure your Damage Effects. They are optional, but if used, they'll be properly setup with the Tags component and Calculation.
Base Class | Description |
---|---|
UCombatEffect_MeleeHit |
Represents a hit resulting from a Melee Hit. |
UCombatEffect_RangedHit |
Represents a hit resulting from a Ranged Hit. |
Defending Damage
Once the PendingDamage
change is received by the Attribute Set, it will invoke the owner's Defense Manager
to defend against the incoming damage. This will consider the target's Block, Defense and Armor, plus the global
Damage Modifier that we will check next.
Damage Mitigation
A combatant has a few layers of possible damage mitigation:
Mitigation | Description |
---|---|
Invulnerability |
Completely ignores damage if the character is currently invulnerable. |
Block |
Usually related to the usage of shields. Has a chance, reduction percent, limit, angle and stamina cost. |
Defense |
Extra defense that can be applied from other sources. Has a chance, reduction percent, limit and stamina cost. |
Armor |
Flat damage reduction from armor. |
LastStand |
An "extra life" effect that can revert fatal damage. Has charges and a percent of max health returned. |
Poise |
Not necessarily related to direct mitigation, but hits can affect poise. If poise reaches zero, the character is staggered. |
Damage is defended in the following order:
if block_chance_test and block_stamina_test and block_angle_test
then:
incoming_damage -= Min(incoming_damage * block_reduction, block_cap)
mitigation_cost += block_cost * incoming_damage
if defense_chance_test and defense_stamina_test
then:
incoming_damage -= Min(incoming_damage * defense_reduction, defense_cap)
mitigation_cost += block_cost * incoming_damage
incoming_damage -= armor_mitigation
if is_fatal_damage then:
apply_last_stand
By properly adjusting your attributes you can accomplish things like:
- If the block or defense chances are
1
(meaning 100%), then the character always blocks. - If the block angle is
360
, then the character can block damage from behind. - If the block or defense costs are
0
, then no stamina is required to block or defend. - If the block or defense limits are
0
, then they can mitigate as much damage as possible.
Invincibility
To make your character invincible, you simply need to apply the UCombatEffect_Invulnerability
Effect.
If you want to create Invincibility Frames, commonly seen in abilities like rolling, then you can use the appropriate
Gameplay Effect, which will communicate back to the ability (UCombatAbility_Evade
) and apply the effect.
Global Damage Modifier
The system provides an interface, ICombatDamageModifierInterface
that can be implemented by your Game Mode or Game State.
If you do that, then every damage being applied can be modified by these classes, at the very first step of the damage mitigation.
Friendly Fire
This is useful if you want to remove something like "Friendly Fire". For example, let's say that you have the Ninja Factions plugin and can determine that two actors are members of the same faction. You can use this extension point to modify any damage between these actors, so it's always "zero".
The ICombatDamageModifierInterface
has one function to be implemented: Modify Damage
, with the following properties:
Property | Description |
---|---|
Damage | Final damage being tentativelly applied. |
Instigator | Instigator applying the damage. |
Target | Target receiving the damage. |
Source Tags | All gameplay tags collected from the incoming damage. |
Target Tags | All gameplay tags collected from the target. |
Handling Received Damage
Now let's discuss how damage is received and processed.
Damage Manager Component
This component receives incoming damage and orchestrates the handling of these events.
The default implementation, UNinjaCombatDamageManagerComponent
, is an implementation of the appropriate interface,
ICombatDamageManagerInterface
and added to the combatant via the Combat Manager (or reused if such component is already
present in the owner).
This component is integrated with the Combat Attribute Set, since it applies damage and sends the event to the component. It's also responsible for broadcasting incoming damage to the "Receive Hit" and "Death" abilities, based on the damage being fatal or not.
Finally, this component is also responsible for providing a Hit Reaction system, via Gameplay Cues, but using a replicated list of recent damage, thus allowing these cues to be added locally and yet being fully replicated, without relying on Multicast RPCs.
Hit Reactions
Hit Reactions are implemented by the CombatAbility_ReceiveHit
Gameplay Ability. This ability, by default, is activated
by a Gameplay Event trigger. The event itself is broadcast by the Damage Manager, whenever necessary.
Whenever damage is applied to the Damage Component, not only Hit Reactions will be triggered for non-fatal damage, but the
OnDamageReceived
Multicast Delegate will broadcast with the damage information.
Stagger
If the Poise attribute has been fully depleted from a hit, a different type of Hit Reaction will be triggered. Instead
of the default Hit Reaction, which may not interrupt actions, the CombatAbility_Stagger
Gameplay Ability is triggered.
This version of a Hit Reaction will interrupt actions.
Death
Hit Reactions are implemented by the CombatAbility_Death
Gameplay Ability. This ability, by default, is activated
by a Gameplay Event trigger. The event itself is broadcast by the Damage Manager, whenever necessary.
Death is also partially handled by the Damage Manager component, and if you decide to implement your own component, then make sure to account for this fact.
Whenever fatal damage is applied to the Damage Component, the Death Ability will be triggered and the OnOwnerDeath
Multicast Delegate will broadcast the damage information.
Damage Entry
This Struct is commonly used by the Damage System. It aggregates damage information, for damage events that have been accepted and processed by the Damage Manager Component. When the Damage Manager stores recent damage (based on the setting from the Ninja Combat plugin), this is the struct used to do so.
Hit and Death Gameplay Cues
Damage events, non-fatal and fatal, can have cosmetics presented via the Gameplay Cue system. The Damage Manager component
will use the GameplayCue.Combat.Hit
and GameplayCue.Combat.Death
cues for these events, respectivelly. In the GAS Integration
page, there's a dedicated section explaining how to configure the systems default Combat Cue Manager to handle these events.
Damage Handlers
When damage is applied and accepted, a chain of Damage Handlers is triggered. These are defined by a UNinjaCombatDamageHandlerData
asset assigned to your Damage Manager Component. This allows you to create a damage reaction via aggregation os small behaviors.
You can create Damage Handlers by extending the UNinjaCombatDamageHandler
. By default, the system provides the following handlers:
-
Cosmetics: Allows a damage causer to handle damage cosmetics, via the proper
ICombatMeleeInterface
andICombatProjectileInterface
interface functions:HandleMeleeDamageCosmetics
andHandleImpactCosmetics
, respectivelly. -
Damage Sense: Triggers the Damage AI sense to notify the AI Perception System about damage received. The actor who applied the damage (Instigator) is used in the Perception Event and the total amount of damage is used as the strength.
-
Physical Animation: Invokes the Physical Animation Component to play a physical animation.
-
Widget Component: Forwards the damage event to a widget component in the owner. This componnet must be the class provided by the Ninja Combat plugin,
UNinjaCombatWidgetComponent
, which is specialized to receive the Gameplay Cue and to properly set the Combat Actor as the component owner. More information is available in this page.