Damage and life

Attribute sets

Health, shield and stamina are the attribute sets of PulseAttributes (UPulseHealthAttributeSet, UPulseStaminaAttributeSet, see Attributes); combat adds damage types, modifiers, death and teams on top. The damage execution hands its FPulseDamageResult to the health set as payload; the set reports what it did (FPulseHealthChange) and the combat component turns both into the final result (Pulse::Combat::MakeDamageResult).

The damage pipeline

Pulse::Combat::ApplyDamage(Target, Spec) (Blueprint: Apply Damage, Apply Simple Damage) runs on the authority:

  1. Friendly fire: damage from an instigator to a friend is dropped unless bAllowFriendlyFire is set.
  2. Target with ability system and health set: the damage effect (UPulseDamageEffect, or the class in the settings or in the spec) is applied. Amount and crit permission travel as set-by-caller values, the damage type and the spec tags as dynamic asset tags, location and direction as hit result of the effect context.
  3. UPulseDamageExecution runs the damage modifiers and writes the result to IncomingDamage. Dead targets take no damage.
  4. The health set applies it, fills the result (shield absorbed, health damage, killed) and reports it.
  5. Targets without ability system implementing IPulseDamageable get ReceivePulseDamage(Spec) instead. Evaluate Damage runs the same modifiers for them. When IsHitByAnyAttacker returns true, attacks that only hit enemies (bOnlyHostile) hit them too, as resource nodes and breakable objects want; they decide themselves in ReceivePulseDamage what a hit does.

FPulseDamageSpec: Amount, DamageType (Pulse.Combat.DamageType.*, empty = default type), Tags (for example Melee, Heavy, Pulse.Combat.Damage.Unblockable), Instigator, Causer, HitLocation, HitDirection, bCanCrit, EffectClass.

FPulseDamageResult: bApplied, BaseAmount, Amount, ShieldAbsorbed, HealthDamage, StaminaDamage, DamageType, Tags, bCritical, bBlocked, bImmune, bShieldBroken, bKilled, Instigator, Causer, Target, HitLocation, HitDirection, Direction (front, back, left, right of the target).

Other functions: Apply Healing (returns the health actually restored; the dead are not healed), Kill (ignores modifiers and blocking), Revive, Set Max Health, Is Hostile, Is Alive, Classify Hit Direction.

Damage types

Native types: Pulse.Combat.DamageType.Physical (default), .Fire, .Frost, .Lightning, .Poison, .Magic. Add your own below Pulse.Combat.DamageType in the tag settings.

Damage modifiers

Modifiers are instanced structs derived from FPulseDamageModifier. They come from three lists and run sorted by Priority (lowest first):

  • UPulseCombatSettings::GlobalDamageModifiers (every damage; default: immunity while invulnerable),
  • OutgoingDamageModifiers of the attacker’s combat component,
  • IncomingDamageModifiers of the target’s combat component.
Modifier Default priority Does
Immunity -100 No damage while the target’s tags match TargetQuery (default Pulse.Combat.State.Invulnerable), optional DamageQuery. Stops the chain.
Adjust 0 (Amount + Add) * Multiplier when Condition (on damage type and tags) matches.
Type Resistance 10 Multiplier per damage type; parent types match children.
Critical 20 With Chance the damage is multiplied (bCanCrit of the spec must allow it).
Block 30 While the target has BlockTag (Pulse.Combat.State.Blocking) and the attacker is within MaxAngle in front: Amount * Multiplier; the blocked part can cost stamina (StaminaPerBlockedDamage). Unblockable damage ignores it.

Damage with Pulse.Combat.Damage.IgnoreModifiers skips all modifiers. Write own modifiers in C++ by overriding Modify(Context, InOutResult); Pulse::Combat::CalculateDamage is a pure function and easy to test.

The combat component

UPulseCombatComponent (Pulse Combat) turns an actor with health set into a combatant:

  • Life: Alive / Dead with the last killer as one replicated value, FPulseLifeState (GetLifeState). On death it adds Pulse.Combat.State.Dead (replicated loose tag), cancels abilities (CancelAbilitiesWithTagsOnDeath, empty = all) and remembers the killer twice: as reference (GetKiller, null on machines where the killer is not relevant or once it is gone) and as values every machine can read, FPulseKillerIds (GetKillerIds, GetKillerPlayerId):
    • PlayerId: the player id of a player killer; empty for NPCs and for bots, even when they have a player state.
    • ActorKey: the name-based save key of a killer placed in a level (with its streamed level) or with a Save Identity, the same on every machine and in later sessions; none for players and for actors spawned while playing.
    • Team and ActorClass: what kind of killer it was. Kill and Revive on the authority. Reviving clears killer and ids. The rules are pure functions in Pulse::Combat::Life (PulseLifeState.h: MakeDead, MakeAlive, MakeKillerIds, DiffLifeStates; specs PulseCombat.Life).
  • Hostility: IsHostileTo. The teams come from Pulse Foundation (Pulse::Team::GetTeam: a Pulse Team component or the team interface on the actor or its player, see the Teams page of the Pulse Foundation docs). The rule is UPulseCombatSettings::HostilityRule (default Teams: same or allied teams are friends, actors without team are enemies of everyone unless bNoTeamIsHostile is off, Pulse.Team.Neutral is no one’s enemy). Teams of Pulse Foundation: Pulse.Team.Player, Pulse.Team.Enemy, Pulse.Team.Neutral; games add their own below Pulse.Team.
  • Attribute sets: Default Attribute Sets (default: the health set) are added to the ability system on the authority when it has none of their class, with their default values, so a Blueprint actor with an Ability System Component and Pulse Combat is a combatant without C++ or a data table. Clients get the sets with the ability system.
  • Startup effects: applied once the ability system is found (default UPulseHealthRegenEffect).
  • Regeneration: HealthRegenRate per second, paused for RegenDelayAfterDamage seconds after damage (Pulse.Combat.State.RegenBlocked). Stamina regenerates with UPulseStaminaRegenEffect unless Pulse.Combat.State.StaminaRegenBlocked is present.
  • Events: On Damaged (FPulseDamageEvent), On Healed, On Death, On Revived (dynamic and native), gameplay events Pulse.Combat.Event.Damaged, .Died, .Revived on the authority for ability triggers.
  • Ability system later: it retries for 10 seconds after BeginPlay; call Refresh Ability System when you give the ability system or the health set later.

Hit reactions

UPulseHitReactComponent (Pulse Hit React) picks one of its Reactions for every hit: side of the hit (Directions, none = all), minimum damage in percent of MaxHealth (the highest that is reached wins) and damage types. It plays the montage on every machine (character mesh, or the skeletal mesh with MeshComponentTag) and, on the authority, staggers for StaggerDuration (Pulse.Combat.State.Staggered, cancels CancelAbilitiesWithTagsOnStagger). Kills, immune and (unless bReactWhenBlocked) blocked hits do not react. Event On Hit React.

Targeting

UPulseTargetingComponent (Pulse Targeting) finds combatants in front of the view (the controller’s view point, else the actor’s eyes):

  • Find Soft Target / Find Targets: in SearchDistance and SearchAngle, ranked by angle and distance (DistanceWeight), only enemies (bOnlyHostile) and visible ones (bRequireLineOfSight).
  • Lock-on: Toggle Lock On, Set Lock On Target, Switch Lock On Target (left/right), Get Lock On Target, On Lock On Changed. The lock breaks when the target dies or is farther than LockOnBreakDistance.
  • The camera stays with the game; Get Rotation To Target helps to turn towards the target.

View models

View model For Values
UMVVMPulseCombatant Health bars of the own player (create with the Pulse Player View Model Resolver) or of any actor (Set Combatant) Health, MaxHealth, Shield, MaxShield, Stamina, MaxStamina, bIsDead, GetHealthPercent, GetShieldPercent, GetStaminaPercent, HasShield, HasStamina; events On Damaged, On Death, On Revived
UMVVMPulseAttribute Any attribute (mana, armor) Value, MaxValue, GetPercent; set Attribute / MaxAttribute

Both update from the ability system’s attribute change delegates (no polling) and follow the player’s pawn after respawns.

Messages

Channel When Payload
Pulse.Message.Combat.Damaged On Damaged FPulseCombatMessage (Target, Instigator, Amount, DamageType, bCritical, bKilled, Team of the target)
Pulse.Message.Combat.Healed On Healed FPulseCombatMessage
Pulse.Message.Combat.Died On Death FPulseCombatMessage (Instigator = killer)
Pulse.Message.Combat.Revived On Revived FPulseCombatMessage

The context of the messages (Pulse::Combat::MakeMessageContext) has the combatant as Target, the attacker, healer or killer as Instigator, the damage type in Tags and the damage or healing in Amount (1 for Died and Revived). Player is the player the message is about: the instigator when it belongs to a player (a kill of the player), else the target when it does (the player took damage). Quests and achievements can count kills with them (for example “defeat the boss”) without a bridge.

Settings

Project Settings > Pulse > Core > Combat (UPulseCombatSettings): DamageEffectClass, HealEffectClass, DefaultDamageType, GlobalDamageModifiers, bAllowFriendlyFire, HostilityRule.

Debugging and cheats

The combat component is a snapshot provider: health, shield, stamina, state tags, modifiers and the last damage show in the Pulse Debugger and the gameplay debugger category Pulse. Damage, deaths and revives are written to the timeline.

Cheat Does
PulseCombatGrant [max health] [stamina 1/0] Ability system (if missing), health set, optional stamina set and combat component (team Player) for the pawn
PulseCombatSpawnDummy [max health] [shield] [team] Training dummy in front of the player; tips over when it dies and stands up after 3 s
PulseCombatHit <amount> [type] The player hits the combatant in front (or the nearest one)
PulseCombatDamage <amount> [type] [target], PulseCombatHeal <amount> [target] Damage or heal the player or the target
PulseCombatKill [target], PulseCombatRevive [target or all] Kill or revive
PulseCombatGod, PulseCombatTag <state> [target] Toggle invulnerability or any state tag (Blocking, Staggered, …)
PulseCombatInfo [target] Prints the snapshot
PulseCombatLockOn Toggles the lock-on of the local player

In PIE, clients need EnableCheats first; damage cheats run on the server.


PulseCore plugin documentation.

This site uses Just the Docs, a documentation theme for Jekyll.