# @tiptap/actors@0.1.0

<!-- Generated by scripts/gen-package-reference.mts from the package source.
     Do not edit: §15.4 — package docs are generated, nobody writes them. -->

**Spec §7.1: `@tiptap/actors`** — health, damage, resources, respawn timers,
teams.

Extracted from `arena2d`'s `apply_damage` and `respawn`. What comes out is the
bookkeeping every genre repeats and nobody enjoys writing twice: a handful of
counters that must not underflow, a countdown that must not restart itself,
and a friendly-fire rule.

## Resources rather than a `health` field

§7.1 says "health, damage, resources" as one entry, and one type covers all
three. A slot is a `u16` a game names: health, ammo, shield, mana, charge,
lives. `arena2d` has four. Nothing here knows which is which — [`Resources`]
is arithmetic that saturates, and the meanings live in the game's config.

That is not generality for its own sake. A `health: u16` field forces the next
genre that wants shields to either add a second field to a shared type or
reimplement the same clamping, and both of those are how a package stops being
shared.

## Saturating everywhere, and why that is a correctness rule here

`u16` damage against `u16` health underflows to 65,000 on exactly one line of
arithmetic, and a player who takes a fatal hit becomes the healthiest thing in
the room. Every operation here saturates.

The subtler one is [`Respawn::tick`]. A countdown that is reset while already
running is a player who never comes back — the classic version is a damage
event arriving during the respawn window and restarting the timer, and under
rollback that can happen on one client and not another.

## Types

```rust
pub struct Resources
```

One actor's counters.

```rust
pub struct Respawn
```

A respawn countdown.

Zero means alive. Any other value is ticks remaining.

## Aliases

```rust
pub type Team = u8
```

Which side an actor is on.

`0` is the free-for-all team and **is not friendly with itself** — that is the
deathmatch default, and making it a distinct value rather than a special case
keeps [`friendly`] a two-line function with no mode flag threaded through it.

## Constants

```rust
pub const MAX_RESOURCES: usize = 4
```

How many resource slots one actor carries.

Four. `arena2d`'s number, kept because it is the one the wire format and the
existing config schema are built around, and because a slot nobody uses costs
two bytes per actor per snapshot.

```rust
pub const SLOT_HEALTH: usize = 0
```

The slot conventionally used for health.

A convention rather than a rule — nothing in this crate treats slot 0
specially. It exists so games agree by default, because a UI that reads slot 0
and a game that stores health in slot 2 is a bug nobody sees in review.

```rust
pub const TEAM_NONE: Team = 0
```

The free-for-all team: everybody is everybody's enemy.

## Functions

```rust
pub fn drain(&mut self, slot: usize, amount: u16) -> u16
```

Take from a slot. Returns how much was **actually** taken.

The return is the point: a game that credits a kill, awards score or
counts damage dealt needs the amount that landed, not the amount asked
for, or the last hit on a dying player is worth more than it should be.

```rust
pub fn refill(&mut self, slot: usize, amount: u16, ceiling: u16) -> u16
```

Add to a slot, saturating at `ceiling`.

Returns how much was actually added, for the same reason [`drain`] does:
a health pack that healed nothing should not be consumed.

[`drain`]: Resources::drain

```rust
pub fn empty(&self, slot: usize) -> bool
```

Whether a slot has run out — by convention, whether the actor is dead.

```rust
pub fn begin(&mut self, ticks: u8) -> bool
```

Start the countdown — **only if it is not already running**.

Returns whether this call started it. The guard is the whole reason this
is a type: a second death event arriving while the timer runs would
restart it, and a player who is repeatedly "killed" while already dead
never comes back. Under rollback that can happen on one client and not
another, which turns a nuisance into a desync.

```rust
pub fn tick(&mut self) -> bool
```

Count down one tick. Returns `true` on the tick the actor comes back.

```rust
pub fn friendly(a: Team, b: Team) -> bool
```

Whether `a` and `b` should be prevented from hurting each other.

```rust
pub fn damage(
```

Apply damage from `source` to `target`, honouring the friendly-fire rule.

Returns `(dealt, killed)`. `dealt` is what actually landed, so a caller can
credit exactly that much; `killed` is true only on the transition, so a corpse
shot twice is not two kills.
