⚔️ Health — Damage Rules¶
This folder contains all damage-side rule components that plug into
DamageRuleHub.
Damage rules define how incoming damage is shaped before it reaches
HealthSystem, and how systems react after damage has been applied.
All damage rules are:
- Modular
- Order-driven via Priority
- Authority-agnostic
- Composable per prefab
📦 What Damage Rules Are (and Aren’t)¶
Damage rules are - Deterministic pipeline steps - Context mutators (PRE) or observers (POST) - The primary extension surface for combat math
Damage rules are not - Health state owners - Networking or replication logic - UI or presentation systems
They sit between input and mutation — never replacing HealthSystem.
🧩 Basic Usage¶
- Add a
DamageRuleHubto the GameObject withHealthSystem - Add any rule components from this folder
- Rules implementing:
IDamageRulerun in PREIPostDamageRulerun in POST- Lower
Priorityruns first - POST rules always run after shields and final damage resolution
No damage rules are required by default.
🧮 Common Priority Bands¶
| Priority | Purpose | Example Rules |
|---|---|---|
| 40 | Team gating | TeamRule |
| 50–99 | RNG / crit | CritRule |
| 90–120 | Execute / armor / affinity | ExecuteThresholdRule, ArmorRule, AffinityRule |
| 140–199 | Multipliers | AttackerDamageMultiplierRule, DamageTakenMultiplierRule |
| 900+ | Safety & post | DamageClampRule, ReflectStacksRule, LifestealRule |
See DamageRulePriority.cs for canonical constants.
⚙️ PRE Damage Rules¶
PRE rules mutate DamageContext before shields and health mutation.
They may:
- modify RawAmount, Multiplier, or FlatDelta
- set ctx.Cancelled = true
- return false to short-circuit the chain
TeamRule (priority 40)¶
- Cancels same-team damage unless
allowFriendlyFireis enabled - Applies
friendlyFireScaleorenemyScale - Uses
DamageContext.TeamIdand victimITeamProvider
CritRule (priority 50)¶
- Performs a critical hit roll
- Adds
DamageTag.Criton success - Multiplies damage via
critMultiplier - Supports:
- deterministic seeds
- Unity RNG
- external RNG providers
- forced crits for testing
ExecuteThresholdRule (priority 90)¶
When victim HP% ≤ threshold:
ctx.BypassShields = truectx.BypassRules |= RuleBypass.Armorctx.Tags |= DamageTag.True
Ensures true-damage behaviour before armor and affinity.
ArmorRule (priority 100)¶
- Flat and percent mitigation
- Applied only to selected
DamageTagmasks - Mutates
ctx.RawAmount - Skipped when
RuleBypass.Armoris set
AffinityRule (priority 120)¶
- Queries all victim-side
IDamageAffinityproviders - Multiplies all returned opinions:
0→ immunity (cancel)<1→ resist>1→ weak- Skipped when
RuleBypass.Affinityis set
AttackerDamageMultiplierRule (priority 140)¶
- Queries attacker for all
IAttackerDamageModifiercomponents - Multiplies results into
ctx.Multiplier - If final product =
0, the hit is cancelled
DamageTakenMultiplierRule (priority 150)¶
- Victim-side, stackable multiplier rule
- Runtime API:
Push(multiplier)Pop(multiplier)Clear()- Product of all stacks is applied
- Safety-clamped via
minFactor/maxFactor 0cancels the hit
DamageClampRule (priority 900)¶
Final guardrail before shields.
- Clamps post-rule damage into
[minAfterAll, maxAfterAll] - Adjusts via
FlatDeltato preserve rule ordering - Prevents runaway math or negative damage
💥 POST Damage Rules¶
POST rules never mutate damage. They react to finalized results only.
ctx.FinalApplied is guaranteed to be valid.
ReflectStacksRule (priority 980)¶
- Stack-based reflect collector
- Used with
ReflectBuff - Sums reflect contributions, clamped by
maxTotal - Reflects % of final applied damage
- Skips reflected hits to avoid loops
- Optional skip for true damage
DamageReflectRule (priority 990)¶
- Simple one-off reflect rule
- Reflects % of final applied damage
- Optional
reflectOnTrueDamage - Tags reflected hits with
DamageTag.Reflect
LifestealRule (priority 999)¶
- Heals attacker for % of final applied damage
- Uses attacker’s
IHealthWriter - Skips when:
FinalApplied <= 0- (optionally) hit was tagged
True
🧠 Design Guarantees¶
- PRE rules mutate context; POST rules observe results
- Rule order is explicit and deterministic
- Rules never mutate health directly
- Different prefabs may have entirely different rule stacks
- Adding/removing rules is safe at runtime
❌ What Damage Rules Should Not Do¶
- Do not modify health directly
- Do not assume a specific rule order beyond
Priority - Do not embed authority or networking logic
- Do not mix UI or presentation logic into rules
Damage rules exist to stay small, predictable, and composable.