Skip to content

🧩 Health — Rules Abstractions

This folder contains the core rule-level abstractions used by the Health system.

These interfaces define how external systems contribute to damage and healing without coupling themselves to concrete rule implementations.

They are: - Runtime-safe - Netcode-friendly - Deterministic by design - Stable extension seams

If you want to influence combat math without touching HealthSystem or rule code, this is where you plug in.


📦 What These Abstractions Are (and Aren’t)

They are - Narrow, single-purpose interfaces - Implemented by gameplay, abilities, buffs, AI, or netcode layers - Consumed by concrete rules inside the Health pipeline

They are not - Rules themselves - State owners - Opinionated gameplay logic

These abstractions exist to keep the rule system open for extension and closed for modification.


⚔️ Attacker-Side Interfaces

IAttackerDamageModifier

Contributes an attacker-side damage multiplier to the damage pipeline.

Used by: - AttackerDamageMultiplierRule

public interface IAttackerDamageModifier
{
    float GetDamageDealtMultiplier(in DamageContext ctx);
}

Semantics

  • Implement this on the attacker
  • Your value is multiplied into the outgoing damage chain
  • Return values:
  • 0 → cancel outgoing damage entirely
  • 1 → no change
  • > 1 → amplify damage
  • Multiple modifiers stack multiplicatively

Typical uses: - Berserk / rage buffs - Temporary power-ups - Weapon enchantments - Ability-driven damage bonuses - AI difficulty scaling

This interface never mutates health directly — it only influences math.


🎲 Deterministic Randomness

IRng

Minimal RNG abstraction for probabilistic rules.

Used by: - CritRule - Any custom rule that requires random rolls

public interface IRng
{
    float Next01(); // returns [0,1)
}

This abstraction allows rules to remain: - deterministic when required - replay-safe - multiplayer-authoritative


Built-in RNG Implementations

SystemRng

  • Deterministic and seedable
  • Backed by System.Random
  • Ideal for:
  • authoritative multiplayer
  • replays
  • lockstep simulations
  • automated testing

UnityRng

  • Uses UnityEngine.Random.value
  • Non-deterministic unless Unity’s RNG is manually seeded
  • Suitable for:
  • single-player games
  • cosmetic randomness
  • non-critical effects

Example Usage

IRng rng = new SystemRng(seed: 1234);

if (rng.Next01() < 0.25f)
{
    // 25% chance
}

Because rules depend on IRng rather than UnityEngine.Random, you can swap randomness sources without changing rule logic.


🧠 Design Notes

  • These abstractions keep attacker logic separate from victim logic
  • They allow abilities, buffs, and AI to influence combat without becoming Health dependencies
  • Deterministic RNG is critical for:
  • rollback-safe combat
  • authoritative servers
  • consistent AI simulation
  • Safe to implement in any runtime assembly:
  • Gameplay
  • Abilities
  • AI
  • Netcode
  • Tools

❌ What Not To Do

  • Do not mutate health inside these interfaces
  • Do not embed stateful logic here
  • Do not assume execution order beyond the consuming rule
  • Do not use these as a replacement for rules

These are contribution points, not behaviour owners.


🔗 See Also