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:
- Friendly fire: damage from an instigator to a friend is dropped unless
bAllowFriendlyFireis set. - 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. UPulseDamageExecutionruns the damage modifiers and writes the result toIncomingDamage. Dead targets take no damage.- The health set applies it, fills the result (shield absorbed, health damage, killed) and reports it.
- Targets without ability system implementing
IPulseDamageablegetReceivePulseDamage(Spec)instead.Evaluate Damageruns the same modifiers for them. WhenIsHitByAnyAttackerreturns true, attacks that only hit enemies (bOnlyHostile) hit them too, as resource nodes and breakable objects want; they decide themselves inReceivePulseDamagewhat 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),OutgoingDamageModifiersof the attacker’s combat component,IncomingDamageModifiersof 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/Deadwith the last killer as one replicated value,FPulseLifeState(GetLifeState). On death it addsPulse.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.TeamandActorClass: what kind of killer it was.KillandReviveon the authority. Reviving clears killer and ids. The rules are pure functions inPulse::Combat::Life(PulseLifeState.h:MakeDead,MakeAlive,MakeKillerIds,DiffLifeStates; specsPulseCombat.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 isUPulseCombatSettings::HostilityRule(default Teams: same or allied teams are friends, actors without team are enemies of everyone unlessbNoTeamIsHostileis off,Pulse.Team.Neutralis no one’s enemy). Teams of Pulse Foundation:Pulse.Team.Player,Pulse.Team.Enemy,Pulse.Team.Neutral; games add their own belowPulse.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:
HealthRegenRateper second, paused forRegenDelayAfterDamageseconds after damage (Pulse.Combat.State.RegenBlocked). Stamina regenerates withUPulseStaminaRegenEffectunlessPulse.Combat.State.StaminaRegenBlockedis present. - Events:
On Damaged(FPulseDamageEvent),On Healed,On Death,On Revived(dynamic and native), gameplay eventsPulse.Combat.Event.Damaged,.Died,.Revivedon the authority for ability triggers. - Ability system later: it retries for 10 seconds after
BeginPlay; callRefresh Ability Systemwhen 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: inSearchDistanceandSearchAngle, 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 thanLockOnBreakDistance. - The camera stays with the game;
Get Rotation To Targethelps 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.