# Death Saves (D&D 5e)

Concept and rule structure for the death-save state machine. Reference for how
combat tracking should behave at 0 HP. This is the 5e death-save loop, not a
code spec.

## Scope: tracker tracks, DM decides

This tracker is not a virtual tabletop. It does not roll dice or interpret the
table. The DM rolls at the table, decides what happened, and feeds the result
into the tracker through the UI. The tracker records the result and applies the
automatic pieces.

- DM does: rolls the d20, determines crits vs normal hits, declares damage
  amounts, decides when to stabilize or heal.
- Tracker does: increments success/failure counters on DM input, resolves the
  terminal states (3 successes → stable, 3 failures → dead), resets counters on
  heal or stabilize, records HP changes.

The transitions below describe the rules the tracker must honor once the DM
hands it a result. The DM is the source of truth for what happened; the tracker
is the source of truth for what state that produces.

## State

A character or NPC at 0 HP enters a death-save loop. Track per death-save participant:

```ts
deathSaveSuccesses: 0 | 1 | 2 | 3
deathSaveFailures:  0 | 1 | 2 | 3
status:             "conscious" | "dying" | "stable" | "dead"
hp:                 number
```

## Transitions

**Drop to 0 HP** (damage, character/NPC):
- If damage >= currentHp + maxHp → outright dead (massive damage). Equivalently: after reducing currentHp to 0, overflow damage >= maxHp.
- Otherwise → `status = "dying"`, counters reset to 0.

**Drop to 0 HP** (monster):
- Non-NPC monsters do not use death saves.
- `status = "dead"`, counters reset, `isActive = false`.

**Death save** (d20 roll on a dying character/NPC turn):

```ts
if roll === 1:          failures += 2      // natural 1 = two failures
else if roll === 20:    hp = 1; successes = 0; failures = 0; status = "conscious"  // nat 20 = 1 HP, conscious
else if roll >= 10:     successes += 1
else:                   failures += 1
```

Then resolve immediately on the click/action that reaches 3:

```ts
if failures >= 3:  status = "dead"; successes = 0; failures = 0
if successes >= 3: status = "stable"; successes = 0; failures = 0
```

The UI must transition immediately. A third failure shows Dead state, not three
active failure boxes. A third success shows Stable state, not three active
success boxes.

**Damage while dying** (at 0 HP):

```ts
failures += isCriticalHit ? 2 : 1
if failures >= 3: status = "dead"
```

Attacks from within 5 ft against an unconscious creature are auto-crits, so
melee vs a dying character/NPC adds 2 failures.

**Healing while dying or stable**:

Any +HP received while `dying` or `stable` makes the character/NPC conscious.
This usually comes from magic, or from the stable-state time-delayed recovery
(1 HP after 1d4 hours, if the DM chooses to track it here).

```ts
hp = max(1, hp + amount)
successes = 0
failures = 0
status = "conscious"
```

Any HP regained from `dying` or `stable` clears all counters and ends the
death-save loop. This does **not** apply to `dead`; dead requires revive flow,
revival magic, or DM state override, not normal healing.

**Stabilize** (manual action, not a save):

```ts
hp = 0
successes = 0
failures = 0
status = "stable"
```

## Stable state

- Stays at 0 HP, unconscious, no longer makes death saves.
- 3 successes = **stable (unconscious)**, NOT conscious. NOT 1 HP.
  1 HP only comes from a natural 20 or healing.
- Taking any damage ends stable → back to `dying` (counters reset, then damage
  applies its failure per "damage while dying").

## Tool-specific initiative behavior

Death is a combat state, not an automatic removal action.

When a character or NPC becomes `dead`:
- Do **not** remove them from initiative.
- Do **not** automatically deactivate them.
- Do **not** remove them from the encounter participants list.
- Leave them in turn order. Other table/tool events may still matter on that
  initiative count.
- DM may manually mark them inactive or remove them.

When a non-NPC monster becomes `dead`:
- Set `isActive = false` automatically.
- Keep it in the encounter participants list until DM removes it.
- Player display hides it because inactive participants are hidden.

## Invariants

- `status === "dying"` ⟺ hp === 0 AND no terminal flag.
- `status === "stable"` ⟹ hp === 0, unconscious, counters 0.
- `status === "dead"` ⟹ hp === 0, no further saves, counters 0.
- `status === "dead"` ⟹ participant remains in initiative and participants until DM removes them.
- `status === "dead"` does not itself mean inactive; monster death sets inactive as a separate rule.
- Normal +HP applies to `dying` or `stable`, not `dead`; dead requires revive, revival, or DM override.
- Successes and failures tracked **independently**. 2 fail + 3 success = stable.
  Counters do not need to be consecutive.
- A roll of 10+ is a success. 9 or lower is a failure.

## Sources

- [PHB 5e: Death Saving Throws](https://roll20.net/compendium/dnd5e/Rules%3ADamage%20and%20Healing)
- [Reddit: What happens on 3 successful death saves?](https://www.reddit.com/r/DnD/comments/io5js7/what_happens_if_you_succeed_in_3_death_saving/)
- [Roll20: Conditions (Unconscious)](https://roll20.net/compendium/dnd5e/Conditions)
