Skip to content

Damage system guide

Mass Forge Damage Definitions turn project-owned attributes into a reusable, deterministic combat calculation. They are intended for damage against actorless or represented Mass entities. Attribute names are never reserved: Health, Shield, Power, and Armor below are examples selected in the asset.

Ordinary Actor targets such as a non-Mass player continue to use the generic Effect Receiver adapter described in the combat integration guide. This keeps Mass Forge compatible with a project's existing GAS, health component, or other Actor-side state instead of creating a competing store.

One-time setup

  1. Add current Health to a Vital, Combat, or Support schema and give it a non-negative lower bound if zero means dead.
  2. Optionally add Shield, source Power, target mitigation, Critical Chance, and Critical Multiplier attributes.
  3. Assign the schemas under Project Settings > Mass Forge > Global Attribute Schemas.
  4. Add Mass Forge Attributes Trait to every participating Mass Entity Config.
  5. Add Mass Forge Gameplay Tag Trait when the definition uses required, blocked, or death tags.
  6. Create a Mass Forge Damage Definition Data Asset and select those attributes.

Direct Damage Definition targeting Vital.Health with no mitigation and no critical calculation

This minimal authored definition turns the request magnitude into final Health damage. Enable shield routing, source power, mitigation, or critical rules only when the game needs those stages.

The Damage Definition validates its ID, attribute references, finite scales, critical bounds, positive armor constant, distinct Health/Shield fields, and contradictory required/blocked tags. The selected attributes still resolve against the configured schemas at runtime, so a renamed or missing project attribute returns a structured failure instead of silently changing another slot.

Blueprint entry points

Blueprint close-up applying entity-to-entity damage between separate Mass Forge handles beside a direct attribute operation and a reusable Instant Effect

The middle node is the common entity-to-entity damage path. The surrounding nodes show why raw stat changes, damage formulas, and reusable healing/effects remain separate public operations.

  • Apply Mass Forge Damage accepts a complete request and is the most flexible node.
  • Apply Mass Forge Entity Damage To Entity fills source and target entity handles for common Mass combat.
  • Apply Mass Forge Actor Damage To Entity accepts an ordinary or represented source Actor. If the Actor represents a Mass entity, its handle is resolved automatically. Source-attribute formulas require that representation; an ordinary Actor can still deal definition-based damage when source attributes are disabled.
  • Queue Mass Forge Damage safely defers a complete request when the call may overlap Mass processing.

The three Apply nodes are immediate. If Mass is processing, direct application returns Mass Is Processing before invoking policy providers or reading entity state. Queue the request in callbacks that may overlap Mass work.

An accepted queued request returns a positive monotonic Request Id. Requests execute FIFO while Mass is idle, up to Max Queued Damage Requests Per Frame under Project Settings > Mass Forge > Global Attribute Schemas > Runtime. Max Pending Queued Damage Requests supplies hard back-pressure; overflow returns Damage Queue Full and consumes no ID. Each request is revalidated at execution, so a stale entity or changed/unloaded definition completes with a structured failure rather than touching state. Bind On Damage Request Completed on the Damage Subsystem and match its ID with the enqueue receipt. Successful damage/death events occur during application, followed by the request-completion event. Cross-type ordering follows the deferred command contract.

Calculation order

One request is evaluated in this order:

  1. Validate the world, definition, generation-checked entities, numeric inputs, and self-damage rule.
  2. Evaluate required target tags, blocked target tags, and optional dead-target rejection.
  3. Read the configured Health, optional Shield, source attributes, and mitigation attribute.
  4. Calculate Base Damage + Source Power × Source Power Scale, clamped to at least zero.
  5. Resolve critical chance and multiplier. A critical occurs only when the caller's Critical Roll is lower than the resolved chance.
  6. Apply the selected mitigation policy and caller-provided penetration.
  7. Apply Minimum Damage when pre-mitigation damage was positive.
  8. Send the requested bypass fraction directly toward Health; Shield absorbs the remaining shieldable amount up to its current value.
  9. Clamp projected Health and Shield through their schema entries.
  10. Atomically commit every changed attribute and the optional first-death tag.
  11. If this is a first-death transition, schedule the selected Death Handling Policy, then publish damage, kill, and optional project-deactivation events.

The caller supplies Critical Roll in [0, 1]. This makes the calculation deterministic and replayable; the project can use its own seeded random stream, authoritative server roll, or fixed test value. Mass Forge does not hide an uncontrolled random-number source inside the subsystem.

Mitigation policies

PolicyFormula after criticalMeaning of penetration
No MitigationDamageIgnored
Flat Reductionmax(0, Damage - max(0, Mitigation × Scale - Penetration))Flat mitigation points ignored
Percentage ReductionDamage × (1 - clamp(Mitigation × Scale - Penetration, 0, 1))Fractional reduction ignored
Armor RatioDamage × K / (K + max(0, Armor × Scale - Penetration))Flat armor points ignored

K is Armor Ratio Constant. At effective Armor equal to K, damage is halved. Minimum Damage is evaluated after the selected mitigation formula.

Tags, immunity, and death

Required Target Tags are useful for eligibility such as State.Alive or Faction.Damageable. Blocked Target Tags are useful for invulnerability, damage-type immunity, protected phases, or project-specific faction policy. Queries are hierarchical, so a parent blocker can reject owned child tags.

When Reject Dead Targets is enabled, zero Health or an already-owned configured Death Tag returns Target Already Dead. When positive Health reaches zero, bKilled is true, the optional Death Tag is added in the same transaction, and On Entity Killed is broadcast once for that transition.

Each Damage Definition selects one explicit post-kill policy:

Death Handling PolicyBehavior
Keep EntityDefault. Publish the normal damage/kill events and leave lifecycle state unchanged. This supports corpses, resurrection, and project-owned state machines.
Request Project DeactivationAssign a positive correlation ID and publish On Entity Deactivation Requested after On Entity Killed. The entity remains valid; the project decides how to disable AI/movement, pool representation, reward, ragdoll, respawn, or remove it.
Destroy Mass Entity (Deferred)Queue generation-safe Mass-entity destruction. Kill listeners and queued-damage completion run first; the bounded Death Handling phase destroys the entity before the Ability phase and publishes On Death Destruction Completed.

The killing result exposes the policy, scheduling result, and request ID. Queue Full applies only to the optional destruction request: lethal damage and its atomic Health/death-tag transaction still succeed, the request ID remains zero, and the still-valid dead entity is available for recovery. Configure Max Death Destructions Per Frame and Max Pending Death Destructions under the Runtime settings.

Deferred destruction removes only the Mass entity. It never destroys or hides a represented Actor and never invents pooling, rewards, ragdoll, respawn, or replication behavior. Use Request Project Deactivation when any of those project-specific actions are required. A direct lethal call queues destruction for the next coordinator tick; a lethal request executed in the Damage phase is destroyed later in that same tick. If another system removes the entity first, completion reports Entity Already Invalid without touching a reused generation.

For exact same-tick precedence between Persistent Effects, Damage events, request completion, destruction, active Ability lifecycles, and new Ability requests, see the deterministic gameplay ordering contract.

For the complete destruction, generation reuse, Actor representation, pooling, and world-teardown rules, see the entity lifecycle safety contract.

Friendly fire, factions, ownership, and safe zones

These rules depend on project data, so Mass Forge exposes a policy contract instead of inventing a team model. The easiest Blueprint setup is:

  1. Create a Blueprint subclass of Mass Forge Damage Policy Component.
  2. Add one instance to a persistent world manager Actor or Game State. Auto Register is enabled by default.
  3. Override Evaluate Mass Forge Damage Policy.
  4. Read Source Entity, Target Entity, resolved source/target Actors, Damage Id, and the context payload from the query.
  5. Query the project's team, faction, owner, safe-zone, or diplomacy data.
  6. Return Deny with a stable Policy Id and machine-readable Reason when damage is forbidden. Return Abstain when this provider has no opinion, or Allow to record an affirmative decision while still letting other providers veto.

A simple friendly-fire Blueprint compares the project team IDs for the resolved source and target. If both are valid and equal, return Deny, Policy Id = TeamPolicy, and Reason = FriendlyFire; otherwise return Abstain.

Projects can also implement Mass Forge Damage Policy Provider on another UObject and use Register Mass Forge Damage Policy Provider and Unregister Mass Forge Damage Policy Provider manually. Registration is weak, world-scoped, duplicate-aware, and bounded to sixteen providers. Invalid objects, cross-world objects, duplicate registration, overflow, missing removal, and evaluation-time mutation all return distinct result values.

Providers run in registration order after endpoints and numeric inputs are validated but before tags or attributes are read. Any Deny stops the request immediately; no Health/Shield/tag mutation or damage/death event occurs. An Allow never bypasses a later provider or the Damage Definition's built-in tag and dead-target rules. Provider evaluation is synchronous and must be side-effect free. Recursive damage and provider-list mutation attempted from inside evaluation are rejected rather than allowing an unstable policy chain.

Reading the result

Mass Forge Damage Application Result contains:

  • the exact result enum and failed attribute or tag diagnostics;
  • requested damage, source-power contribution, pre-mitigation damage, mitigation value, and final damage;
  • resolved critical chance/multiplier and whether the supplied roll was critical;
  • Shield/Health before, applied damage, after values, and overkill;
  • whether this application caused the first positive-to-zero transition;
  • selected death policy, its scheduling result, and the positive request ID when one was produced;
  • the fully resolved effect context and underlying atomic Instant Effect transaction.

Successful zero-damage requests are valid and publish a damage-applied result without inventing an attribute change. Failed requests publish neither damage nor death events.

Context and presentation

The applied context can carry source/target entity handles, represented Actors, a logical Source ID, Ability ID, Damage Definition ID as Effect ID, origin, optional FHitResult, and project scalar parameters. Bind On Damage Applied for floating numbers, hit reactions, threat, audio, analytics, or combat logs. Bind On Entity Killed for common death presentation, On Entity Deactivation Requested for project-owned retirement, and On Death Destruction Completed for deferred-destruction bookkeeping. These listeners are not required by the simulation and should not mutate the same target recursively.

Safety boundaries

  • Health, Shield, and a first-death tag commit through one prevalidated transaction. A late tag-capacity or missing-fragment failure leaves attributes unchanged.
  • Non-finite damage, penetration, roll, bypass, asset scales, or calculated results are rejected.
  • Entity handles include serial numbers; stale source and target handles fail explicitly.
  • Source and target Actors must belong to the same world.
  • Direct calls are rejected while Mass is processing; queued calls wait for a safe tick and apply bounded work per frame.
  • Queued definitions are expected to be immutable during play. Mass Forge stores a soft reference and original Damage ID, rejecting an unloaded/replaced asset or identity change at execution.
  • This release supplies the policy-provider contract for project-defined friendly fire, teams, ownership, and protected zones, but deliberately does not define the project's relationships. Multiplayer damage can use Mass Forge's owner-bound authority transport and replicated state, but project policies must still define who may damage whom. Presentation prediction is available only for Ability activation; damage prediction, resistance by damage type, and represented-Actor lifecycle remain project integration work.

Automated proof

MassForge.Damage.DeterministicPolicyAndAtomicCommit runs in an isolated world with real Mass entities and configured schemas. It verifies formula order, deterministic criticals, armor ratio, Shield absorption and bypass, required and blocked tags, self-damage rejection, source requirements, minimum damage, first-death behavior, context identity/hit payloads, non-finite rejection, generic healing, full rollback when a lethal death-tag mutation cannot be committed, ordinary Actor sources, policy-provider behavior, queued FIFO budgeting/back-pressure, project-deactivation events, non-immediate Mass destruction, destruction request IDs, per-frame and pending limits, queue-full recovery, stale destruction, and completion results.

Mass Forge documentation — generated from the shipping Markdown source.