Skip to content
HELIX is in Closed Alpha. Some features and documentation may be non-functional or out of date.

Working With Character Health#

This guide explains how character health works in HELIX: what happens when a character runs out of health, how the downed, revive, and respawn flows behave, and how the optional per-limb damage system works. It then walks through the scripting API (Lua/BP) for reading health/death state, applying damage and healing, and reacting to changes. The downed and respawn behavior is configured with gameplay rules, and the relevant rules are listed in their respective sections below.


Overview#

Every character has a health component that tracks its health and armor, and owns the full death lifecycle. Characters in HELIX use HCharacterHealthComponent by default.

Note

There is also a more generic HActorHealthComponent used for non-character actors. It handles health, and death, but has no concept of a downed state. Everything in this guide that mentions downed/revive applies only to characters using HCharacterHealthComponent. The plain health/death API is shared by both.

At a high level:

  • Health is the character's life total. When it reaches 0, the character either dies instantly or enters a downed state first, depending on whether the downed rule is enabled (see Downed State).
  • Armor absorbs incoming damage before health is touched.
  • Death is final. Once a character has started dying, it cannot be brought back. A revive is only possible from the downed state, before death begins.

What Happens When Health Reaches 0#

When a character's health drops to 0, one of two things happens, depending on whether the downed state is enabled:

  • Downed disabled (default): the character dies immediately. The death sequence starts, the character goes into a ragdoll state, and then finishes. This is irreversible.
  • Downed enabled: the character enters the downed state instead of dying right away, giving teammates a window to revive them.

The downed state is controlled by a gameplay rule (see Downed State below). Death itself is covered in Death.


Death#

Death moves through three states: NotDead → DeathStarted → DeathFinished.

Death is irreversible

There is no transition back to NotDead. Healing a character that has already started dying does not bring them back. If you want characters to be recoverable, use the downed state, that is the only revivable phase.

When death begins, the character plays out its death sequence and is then cleaned up (by default, the actor is destroyed after a short delay, and the player respawns, see Respawn). Bind to OnDeathStarted / OnDeathFinished to hook your own logic into this (see Delegates).


Downed State#

When enabled, a player-controlled character that reaches 0 health enters the downed state instead of dying. While downed:

  • A bleed-out timer counts down. When it expires, the character dies from bleed-out.
  • Taking further damage while downed can shorten the remaining bleed-out time.
  • The character can be healed back up. Once healing brings them past the revive threshold, they are revived and return to normal play.
  • If the downed character takes a finishing/lethal hit, or chooses to give up (by default, pressing K), they go straight to death.

Warning

For now, the downed state is only available to player-controlled characters. NPCs always go straight to death when their health reaches 0, regardless of the downed rule.

Revive vs. Death#

The downed state always ends in one of two ways, and the reason is reported to anything listening (via OnDownedStateFinished):

  • Revived: the character was healed back above the revive threshold (or revived by script). They return to a normal, alive state.
  • Died: the bleed-out timer ran out, a lethal hit landed, or the player gave up. The character transitions into Death, and there is no coming back. A downed character is not yet dead, that's the window in which a revive can happen.

Tuning the downed state#

The downed behavior is configured through gameplay rules. They can be set as base values for an experience or overridden at runtime, see Gameplay Rules for how the rule system works. The available downed rules are:

Rule Tag Type Default Description
GameplayRule.Health.DownedState.Enable Toggle false Enables the downed state instead of instant death when health reaches 0.
GameplayRule.Health.DownedState.Duration Scalar 300 How long (seconds) the downed state lasts before the character dies from bleed-out.
GameplayRule.Health.DownedState.ReviveHealthRatio Scalar 0.5 Health ratio (0–1) a downed character must be healed up to in order to revive.
GameplayRule.Health.DownedState.DamageTimeReductionMult Scalar 1 Multiplier controlling how much taking damage while downed shortens the bleed-out timer.
GameplayRule.Health.DownedState.ShowDefaultUI Toggle true Shows the built-in bleed-out timer widget on the HUD when downed. Disable to drive your own custom UI.
GameplayRule.Health.DownedState.AllowGiveUp Toggle true Lets a downed player give up by pressing K to skip straight to death.

Note

Death and downed are each driven by their own gameplay ability, running on the server and the owning client. You don't interact with these abilities directly, they react to the health component's state for you. The downed ability handles the visible side of being downed (animations, the bleed-out timer, the K give-up action, and the default downed UI when those rules are enabled). The death ability is intentionally minimal, it cleans the actor up after a short delay.


Health State on Server vs. Client#

The health component is server-authoritative. All real decisions (taking damage, dying, entering downed, reviving) happen on the server, and the resulting state is replicated to clients.

This matters for the delegates below: they fire on both server and clients so your UI and cosmetic logic work everywhere, but on clients some context may be missing. In particular, on a client the instigator (who caused the change) and similar fields may be null, because that information isn't always replicated. Treat client-side delegate calls as "this happened" notifications for presentation, and keep authoritative gameplay logic on the server.


Delegates (Events)#

You can bind to the following events to react to health and death changes. All are available to script and Blueprint.

On HActorHealthComponent (and inherited by characters)#

Delegate When it fires Notes
OnHealthChanged Health value changed (damage or healing) Fires on server and client. Instigator may be null on clients.
OnMaxHealthChanged Max health changed Fires on server and client.
OnArmorChanged Armor value changed Fires on server and client.
OnMaxArmorChanged Max armor changed Fires on server and client.
OnDeathStarted The death sequence has begun Fires on server and client. Good place to start death animations/ragdoll, disable input, etc.
OnDeathFinished The death sequence has completed Fires on server and client. Good place for final cleanup, respawn handoff, etc.

On HCharacterHealthComponent (downed-capable characters)#

Delegate When it fires Notes
OnDownedStateStarted The character entered the downed state Fires on server and client. Provides the downed state info (instigator, hit result, tags).
OnDownedStateFinished The character left the downed state Fires on server and client. Reports the reason: Revived or Died.

A typical flow for a player going down and being revived looks like:

OnDownedStateStarted        -> show downed UI, play down animation
(... healing or bleed-out ...)
OnDownedStateFinished(Revived) -> hide downed UI, return to normal

And for a player who bleeds out:

OnDownedStateStarted          -> show downed UI
(... timer expires ...)
OnDownedStateFinished(Died)   -> hide downed UI
OnDeathStarted                -> play death sequence
OnDeathFinished               -> cleanup

Reading Health & State (API)#

These functions are available on the character health component for reading current state. They're safe to call from anywhere (client or server) for display purposes.

Health & armor#

Function Returns
GetHealth() Current health value
GetMaxHealth() Current maximum health
GetHealthNormalized() Health in the 0.0 – 1.0 range
GetArmor() Current armor value
GetMaxArmor() Current maximum armor
GetArmorNormalized() Armor in the 0.0 – 1.0 range

Death state#

Function Returns
GetDeathState() Current death state (NotDead, DeathStarted, DeathFinished)
IsDeadOrDying() true if the character has started dying (or is already dead)

Downed state (characters only)#

Function Returns
GetDownedState() Current downed state (NotDowned, Downed)
IsDowned() true if the character is currently downed
ReviveFromDownedState() Server only. Ends the downed state as a revive. No effect if the character isn't downed.

Finding the component#

You can look up the component on an actor:

  • HCharacterHealthComponent.FindCharacterHealthComponent(Actor): returns the character health component if the actor has one.
  • HActorHealthComponent.FindHealthComponent(Actor): returns the more generic base component (also matches character health components).

Damaging & Healing#

Rather than poking at health values directly, you apply damage and healing through helper functions in the gameplay system library, UHGameplaySystemGlobals. These route through the proper gameplay systems, so they correctly trigger death, downed, limb damage, armor absorption, and all the delegates above. In Lua, call them as static functions on the class, e.g. UHGameplaySystemGlobals.HealTarget(...).

Warning

All of these are server-only. They do nothing if called on a client. Run them from server-side script/Blueprint (or guard with an authority check).

Function Purpose
UHGameplaySystemGlobals.HealTarget(TargetActor, HealAmount) Heals the target by the given amount (clamped to max health).
UHGameplaySystemGlobals.GiveArmorToTarget(TargetActor, ArmorAmount) Adds armor to the target (clamped to max armor).
UHGameplaySystemGlobals.HealTargetLimb(TargetActor, LimbTag, HealAmount) Heals a specific limb. LimbTag is a GameplayEffect.DamageArea tag.
UHGameplaySystemGlobals.DamageTarget(TargetActor, DamageInstigator, Params) Applies damage to the target. DamageInstigator can be null, in which case the target is treated as its own instigator. Params carries the damage amount and options.
UHGameplaySystemGlobals.GetTargetActorLimbHealthState(TargetActor, LimbTag, OutLimbState) Reads the current state of a single limb.
UHGameplaySystemGlobals.GetTargetActorAllLimbHealthStates(TargetActor, OutLimbStates) Reads the state of all limbs.

Each returns true if the action was successfully triggered.

Note

Healing is the intended way to bring a downed character back up. If you heal a downed character past the ReviveHealthRatio threshold, the downed system revives them automatically, you don't need to call any revive function yourself. ReviveFromDownedState() exists for the case where you want to force a revive immediately regardless of current health.


Limb Damage System#

Characters can optionally track per-limb health on top of their overall health, via a separate limb health component. This lets you react to specific body parts being damaged or disabled, for example, slowing a character whose leg has been crippled, or lowering accuracy when an arm is hurt.

There are six limbs, each tracked independently with its own health (0–100). Each maps to a damage-area gameplay tag:

Limb Tag
Head GameplayEffect.DamageArea.Head
Torso GameplayEffect.DamageArea.Torso
Left Arm GameplayEffect.DamageArea.Arm.Left
Right Arm GameplayEffect.DamageArea.Arm.Right
Left Leg GameplayEffect.DamageArea.Leg.Left
Right Leg GameplayEffect.DamageArea.Leg.Right

These tags are how damage and healing target a specific limb. They all live under the GameplayEffect.DamageArea parent tag.

How limb health changes#

Limb health is server-authoritative and replicated to clients. You don't usually drive it directly, it follows the character's overall health:

  • When the character takes damage and the incoming damage carries a limb tag (GameplayEffect.DamageArea.*), the corresponding limb is damaged. Limb damage is amplified relative to the character damage, so a limb degrades faster than the overall health bar.
  • When the character is healed without a specific limb tag, healing is spread proportionally across all injured limbs, so every limb reaches full at the same time the character's health does.
  • When a specific limb is healed (see HealTargetLimb above), only that limb is restored.

A limb is considered crippled when its health reaches 0. This is the moment to apply whatever gameplay consequence you want for that body part.

Note

Limb damage is tied to the tags on the incoming damage effect. Damage with no limb tag only affects overall health and leaves limbs untouched. Whether a given weapon/effect tags a limb is decided by how that damage is set up, not by this component.

Reading limb state#

Use the UHGameplaySystemGlobals helpers to query limb state from anywhere:

Function Purpose
UHGameplaySystemGlobals.GetTargetActorLimbHealthState(TargetActor, LimbTag, OutLimbState) Reads a single limb's state.
UHGameplaySystemGlobals.GetTargetActorAllLimbHealthStates(TargetActor, OutLimbStates) Reads all limb states at once.

Each limb state exposes its LimbTag, CurrentHealth, MaxHealth, and the RecentDamageTypes it has been hit with.

If you have the component directly (UHLimbHealthComponent), you can also call:

Function Returns
GetLimbHealth(LimbTag) Current health of a limb.
GetLimbHealthNormalized(LimbTag) Limb health in the 0.0 – 1.0 range.
GetTotalLimbDeficit() Total missing health summed across all limbs.
FindLimbHealthComponent(Actor) Looks up the limb component on an actor (returns null if it has none).

Limb delegates#

Bind to these on the limb component to react to changes:

Delegate When it fires Notes
OnLimbHealthChanged A limb's health changed Fires on server and client. Provides the limb tag, old value, and new value.
OnLimbCrippled A limb dropped to 0 health Fires on server and client. Provides the limb tag and the damage that crippled it.

Warning

Not every character has a limb health component, it's optional. Always check that FindLimbHealthComponent (or the query functions returning true) succeeded before relying on limb data.


Respawn#

When a character dies, what happens next depends on the auto-respawn rule. Like the downed rules, it can be set per-experience or overridden at runtime, see Gameplay Rules.

Rule Tag Type Default Description
GameplayRule.Health.AutoRespawn.Enable Toggle true Automatically respawns the player after death. The closest player start point in the world is selected by default.

Auto-respawn enabled (default): the player is respawned automatically after death. You don't need to do anything.

Auto-respawn disabled: the player stays dead until you respawn them from script. This is how you implement custom respawn behavior, for example, respawning at a hospital entrance after bleeding out, or at a checkpoint. Disable the rule, listen for death, and call one of the respawn functions yourself.

The respawn functions also live in UHGameplaySystemGlobals and are all server-only:

Function Purpose
UHGameplaySystemGlobals.RespawnPlayerByCharacter(TargetCharacter) Respawns the player owning this character, at a default player start.
UHGameplaySystemGlobals.RespawnPlayerByController(TargetController) Respawns the player for this controller, at a default player start.
UHGameplaySystemGlobals.RespawnPlayerByCharacterAtTransform(TargetCharacter, SpawnTransform) Respawns at a specific transform.
UHGameplaySystemGlobals.RespawnPlayerByControllerAtTransform(TargetController, SpawnTransform) Respawns at a specific transform.

Each returns true if the respawn was successfully triggered. These also work on a character that's still alive (they'll just restart the pawn).


Sample Scripts#

The examples below assume the standard Lua bindings (HCharacterHealthComponent, HGameplayRulesetComponent). Adapt the lookups to however your project resolves the local character / GameState.

Getting gameplay tags in Lua

Functions that take a gameplay tag (rule tags, limb/damage-area tags) expect an FGameplayTag, which you resolve from its string name through the tag manager:

local TagManager = UGameplayTagsManager.Get()
local LeftLegTag = TagManager:RequestGameplayTag("GameplayEffect.DamageArea.Leg.Left")

The samples below resolve tags this way. To keep things short, they assume a small helper:

local function Tag(name)
    return UGameplayTagsManager.Get():RequestGameplayTag(name)
end

1. React to a character going down and being revived#

local HealthComp = HCharacterHealthComponent.FindCharacterHealthComponent(Character)
if HealthComp then
    HealthComp.OnDownedStateStarted:Add(self, function(self, OwningActor, DownedState)
        -- Show your downed UI, spawn a particle etc.
        print("Character is downed!")
    end)

    HealthComp.OnDownedStateFinished:Add(self, function(self, OwningActor, Reason)
        if Reason == EHDownedEndReason.Revived then
            print("Character was revived!")
        else -- EHDownedEndReason.Died
            print("Character bled out / died while downed.")
        end
    end)
end

2. Update a health bar#

local HealthComp = HActorHealthComponent.FindHealthComponent(Character)
if HealthComp then
    HealthComp.OnHealthChanged:Add(self, function(self, Comp, OldValue, NewValue, Instigator, HitResult, SourceTags)
        local ratio = Comp:GetHealthNormalized()
        UpdateHealthBar(ratio)
    end)
end

3. Handle death cleanup#

local HealthComp = HActorHealthComponent.FindHealthComponent(Character)
if HealthComp then
    HealthComp.OnDeathStarted:Add(self, function(self, OwningActor)
        -- Death is irreversible from here.
        DoStuff(OwningActor)
    end)

    HealthComp.OnDeathFinished:Add(self, function(self, OwningActor)
        -- Final cleanup / hand off to respawn happens during this callback.
    end)
end

4. Enable and tune the downed state at runtime (server)#

-- Run on the server (authority).
-- (See the Gameplay Rules doc for how rule overrides work.)
local Ruleset = HGameplayRulesetComponent.GetGameplayRulesetComponent(WorldContextObject)
if Ruleset then
    -- Turn the downed state on for this match.
    Ruleset:OverrideToggleRule(Tag("GameplayRule.Health.DownedState.Enable"), true)

    -- Make bleed-out faster (60 seconds instead of the default 300).
    Ruleset:OverrideScalarRule(Tag("GameplayRule.Health.DownedState.Duration"), 60.0)

    -- Require healing to 75% to revive.
    Ruleset:OverrideScalarRule(Tag("GameplayRule.Health.DownedState.ReviveHealthRatio"), 0.75)
end

5. Drive a custom downed UI#

-- Disable the built-in downed widget so you can show your own.
local Ruleset = HGameplayRulesetComponent.GetGameplayRulesetComponent(WorldContextObject)
if Ruleset then
    Ruleset:OverrideToggleRule(Tag("GameplayRule.Health.DownedState.ShowDefaultUI"), false)
end

-- Then build your UI off the downed delegates from Sample 1.

6. Revive a downed teammate by healing them (server)#

-- Server-side: heal a downed character back up.
-- Once healing crosses the ReviveHealthRatio threshold, the downed system
-- revives them automatically, no explicit revive call needed.
if UHGameplaySystemGlobals.HealTarget(TargetCharacter, 50.0) then
    print("Healed downed teammate.")
end

7. Custom respawn at a fixed location (server)#

-- Disable auto-respawn so we control where players come back.
-- (See the Gameplay Rules doc for how rule overrides work.)
local Ruleset = HGameplayRulesetComponent.GetGameplayRulesetComponent(WorldContextObject)
if Ruleset then
    Ruleset:OverrideToggleRule(Tag("GameplayRule.Health.AutoRespawn.Enable"), false)
end

-- Then, when a character dies, respawn them at the hospital entrance.
local HealthComp = HActorHealthComponent.FindHealthComponent(Character)
if HealthComp then
    HealthComp.OnDeathFinished:Add(self, function(self, OwningActor)
        UHGameplaySystemGlobals.RespawnPlayerByCharacterAtTransform(OwningActor, HospitalEntranceTransform)
    end)
end

8. Apply damage / healing from script (server)#

-- Heal a target by 25.
UHGameplaySystemGlobals.HealTarget(TargetActor, 25.0)

-- Give 50 armor.
UHGameplaySystemGlobals.GiveArmorToTarget(TargetActor, 50.0)

-- Heal a specific limb.
UHGameplaySystemGlobals.HealTargetLimb(TargetActor, Tag("GameplayEffect.DamageArea.Leg.Left"), 40.0)

9. React to a crippled limb#

local LimbComp = UHLimbHealthComponent.FindLimbHealthComponent(Character)
if LimbComp then
    local LeftLeg = Tag("GameplayEffect.DamageArea.Leg.Left")
    local RightLeg = Tag("GameplayEffect.DamageArea.Leg.Right")

    LimbComp.OnLimbCrippled:Add(self, function(self, Comp, LimbTag, CausingDamage)
        if LimbTag == LeftLeg or LimbTag == RightLeg then
            -- e.g. slow the character down while a leg is crippled.
            ApplyLegInjuryEffect(Character)
        end
    end)

    LimbComp.OnLimbHealthChanged:Add(self, function(self, Comp, LimbTag, OldValue, NewValue)
        UpdateLimbWidget(LimbTag, Comp:GetLimbHealthNormalized(LimbTag))
    end)
end