> For the complete documentation index, see [llms.txt](https://malbersanimations.gitbook.io/animal-controller/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://malbersanimations.gitbook.io/animal-controller/global-components/stats.md).

# Stats

Last updated AC v1.5.3

## Overview

Stats are float values with logic attached. They describe an attribute of a character or an object (Health, Stamina, Mana, Attack, Durability...) and react when that value changes. They are managed by the **Stats** component, which holds a list of **Stat** entries.

Each Stat has a Value, a Min and Max range, a Multiplier, optional Regeneration and Degeneration over time, an Immune window, and a set of events (Full, Empty, Below, Above, Value Changed...).

{% hint style="success" %}
E.g. if the **Health** stat gets to **zero** we can Activate the [**Death**](/animal-controller/main-components/manimal-controller/states/death.md) State on the animal.
{% endhint %}

## Requirements

* Each Stat needs a **Stat ID** asset (`StatID`). Create one with **Create → Malbers Animations → ID → Stat ID**. The name of the asset is also the name of the Stat.
* The Stats component can live on any GameObject: a character, a weapon, a door, a destructible crate. It does not depend on the Animal Controller.

## How it Works

The Stats component builds a runtime dictionary from its list on `Awake`, keyed by the Stat ID. Every public method (`Stat_Get`, `Stat_ModifyValue`, `Stat_Pin`...) looks the Stat up in that dictionary.

On enable each Stat:

1. Stores its **Default** values (Value, Min, Max, Multiplier, Regen Rate, Degen Rate). The `Restore` options and `Restore All` go back to these.
2. Applies **Reset On Enable** if it is set.
3. Starts the Regeneration or Degeneration coroutine if enabled.
4. Two frames later invokes its value events, so UI bars can initialize.

When a Stat is modified (`Modify`, damage from a weapon, a Stat Modifier...):

* The change is multiplied by the **Multiplier**.
* The Value is clamped between **Min** and **Max**, then rounded if **Round** is set.
* **On Value Change**, **On Value Change Normalized** fire. **Full**, **Empty**, **Below** and **Above** fire when their condition is met.
* If **Immune Time** is greater than zero the Stat becomes immune for that time. Further modifications are ignored.
* Regeneration waits **Regen Wait** seconds and then restarts.

{% hint style="info" %}
A Stat with **Min** and **Max** both at **0** has no range. Its Value is never clamped and it is never Full or Empty. Use it for plain numbers, like a weapon `[Attack]` value, instead of a bar.
{% endhint %}

Regenerate and Degenerate are exclusive. Turning one on turns the other off. When it is turned off again, the other one comes back if it was enabled before.

**Pin Stat:** most `Stat_Pin_...` methods work on the last Stat found with `Stat_Pin` or `Stat_Get`. This is useful for UnityEvents, where you can call `Stat_Pin(Health)` first and then `Stat_Pin_ModifyValue(-10)`. In Play Mode the inspector shows which Stat is pinned. Since v1.5.3 the pinned Stat is a pure runtime cache and is no longer serialized (it used to make inspector edits on that Stat revert).

## Parameters

![](https://963537199-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lzhr1XSMzMqNXjRnNlb%2F-M5DxQE9r4CkogL8Iu5-%2F-M5E3N7x0jiXWfde4tNr%2Fimage.png?alt=media\&token=4174a5e4-f9c1-4684-8c97-9c1538d9f29b)

### Stat List

Each row of the list shows the Stat toggle, its ID, the numeric ID value and the current Value. Select a row to edit the Stat below the list. The selected Stat has two tabs: **General** and **Events**.

#### Active

Enable/Disable the Stat. A disabled Stat cannot be modified. Modifications already running (regeneration, ticks) are not stopped.

#### ID

The `StatID` asset that identifies the Stat. The name of the asset is also the name of the Stat, so `Stat_Get("Health")` works too. The number next to it is the ID value.

#### Value

Current Value of the Stat. Editing Value, Min or Max in the inspector re-clamps the Value into the range.

### General

#### Value

Current Value of the Stat.

#### Mult

Multiplier applied every time the Value is modified. Use it to halve the damage taken while wearing armor, or to double it when the character is vulnerable. `Multiply` calls do `Value += amount * Multiplier`.

#### Min

Minimum Value of the Stat. The Value cannot go below it.

#### Max

Maximum Value of the Stat. The Value cannot go above it.

### Regeneration

#### Can Regenerate

Enables or disables the whole Regeneration logic. When it is off, `Regenerate` is forced to false and cannot be turned on.

#### Regenerate

Regenerate the Value over time until it reaches Max. Turning it on stops Degeneration.

#### Rate

Regeneration Rate, in units per second. Zero disables the regeneration.

#### Wait

After the Stat is modified, seconds to wait before the regeneration starts again.

### Degeneration

#### Can Degenerate

Enables or disables the whole Degeneration logic. When it is off, `Degenerate` is forced to false and cannot be turned on.

#### Degenerate

Degenerate the Value over time until it reaches Min. Turning it on stops Regeneration.

#### Rate

Degeneration Rate, in units per second. Zero disables the degeneration.

#### Wait

After the Stat is modified, seconds to wait before the degeneration starts again.

### Options

#### Disable On Empty

If the Stat reaches its Min Value it is disabled, so it cannot be modified anymore. Common on Health.

#### Round

Rounds the Value to this number of decimals. `0` rounds to an integer. `-1` (default) skips the rounding.

#### Reset On Enable

What the Stat does when it is enabled.

* **None:** keep the serialized Value.
* **Reset To Min / Reset To Max:** set the Value to that end on enable.

This is also the target used by `Restart()`, `Restore All` and the `Value/Reset` Stat Option. With **None** those reset to the Max Value.

{% hint style="info" %}
Previous versions had a `Reset To` enum and a `Reset On Enable` toggle. They are now a single field. Existing prefabs default to **None**, so nothing resets unless you opt in.
{% endhint %}

#### Immune Time

If greater than zero, the Stat cannot be modified again until this time has passed since the last modification.

#### Immune

Set the Stat immune. While true its Value cannot be changed.

#### Parent Link

Three dropdowns (**Value**, **Max Value**, **Multiplier**) that make this Stat follow the same Stat on the closest Stats component above it in the hierarchy. See [Parent Link](#parent-link) below.

## Parent Link

\[Insert Image - Parent Link dropdowns inside the Options foldout]

A Stat can follow the **same Stat** (same ID) on the closest **Stats** component **above** it in the hierarchy. This is how a weapon adds the damage of the character holding it, or a shield takes the defense of its owner.

Each number of the Stat picks its own mode:

| Field          | None           | Additive     | Override            | Multiply     |
| -------------- | -------------- | ------------ | ------------------- | ------------ |
| **Value**      | Own Value      | Own + Parent | Parent replaces Own | Own x Parent |
| **Max Value**  | Own Max        | Own + Parent | Parent replaces Own | Own x Parent |
| **Multiplier** | Own Multiplier | Own + Parent | Parent replaces Own | Own x Parent |

**Example:** a sword has a local `[Attack 20]` with Value set to **Additive**. A character with `[Attack 30]` equips it. While the sword is in the character's hands or holster its Attack reads **50**. When the sword is dropped it goes back to **20**.

How the link behaves:

* **Live link.** While linked, the child follows the parent Stat. If the character gets an Attack buff, the sword's Attack updates too.
* **Resolved on enable and on every parent change.** The link is refreshed when the Stats component is enabled and whenever the object is re-parented (equipped, holstered, dropped). Re-parenting a disabled object is picked up on the next enable.
* **Only the parent contribution is tracked.** Modifications made while linked survive the unlink. A linked Attack that lost 5 points of durability wear keeps that loss after being dropped.
* **Apply order** is Multiplier, then Max, then Value, so an Additive Value is not clamped by a Max that has not grown yet. Removal is the reverse.
* The parent search never returns the component itself. A Stats component with no Stat opting in never links.

{% hint style="info" %}
The Stat must exist on the parent with the **same Stat ID**. If the parent Stats component has no Stat with that ID, nothing is linked and the own values are used.
{% endhint %}

{% hint style="info" %}
`Restart()` (the `IRestart` interface) unlinks first, resets the own values and then links again, so the parent contribution is applied only once.
{% endhint %}

## Events

Each Stat has its own set of events, on the **Events** tab.

![](https://963537199-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lzhr1XSMzMqNXjRnNlb%2F-M5DxQE9r4CkogL8Iu5-%2F-M5E4jX3rXd5kc-BnGr_%2Fimage.png?alt=media\&token=21e7ab09-45fb-41a5-929b-2c29cfc09d91)

### On \[Stat] change

Is invoked when the **stat** value is changed. Sends the new Value.

### On \[Stat] change Normalized

Is invoked when the **stat** value changes, but with a normalized value (Value / Max Value). Use it to drive UI bars. It also fires when the Max Value changes.

### On \[Stat] Max Value Change

Is invoked when the **Stat's Max Value** is changed. Sends the new Max Value.

### On \[Stat] Active

Is invoked when the **stat** becomes active or inactive. Sends `true` or `false`.

### On \[Stat] Full

Is invoked when the **Stat** value is equal to the Max Stat value.

### On \[Stat] Empty

Is invoked when the **Stat** value is equal to the Min Stat value.

### On \[Stat] Regenerate

Invoked when the **Stat** starts (`true`) or stops (`false`) regenerating.

### On \[Stat] Degenerate

Invoked when the **stat** starts (`true`) or stops (`false`) degenerating.

### Below / Above / %

Thresholds used by the two events below. With the **%** button enabled they are compared as a percent of the Max Value. Otherwise they are compared as plain values.

### On \[Stat] Below \[X]

Invoked once when the **stat** value drops to or below **Below**. It fires again only after the Stat went above the **Above** threshold.

### On \[Stat] Above \[Y]

Invoked once when the **stat** value rises to or above **Above**. It fires again only after the Stat went below the **Below** threshold.

{% hint style="info" %}
On enable, the value events (change, normalized, full, empty, above, below) are invoked once after a two frame delay, so UI elements get their starting value.
{% endhint %}

## API

The full method list is on the Public Methods sub-page. These are the entry points added or changed in v1.5.3.

```csharp
var stats = GetComponent<Stats>();

// Stats hands out IMStat (interface). Stat is the authored implementation.
IMStat health = stats.Stat_Get(HealthID);      // StatID, int or string overloads
stats.TryGetValue(HealthID.ID, out IMStat h);  // Same lookup without touching the Pinned Stat

// Accessors (Member Get reactions and conditions use these too)
float value      = stats.Stat_GetValue(HealthID);
float max        = stats.Stat_GetMax(HealthID);
float min        = stats.Stat_GetMin(HealthID);
float normalized = stats.Stat_GetNormalized(HealthID);
float multiplier = stats.Stat_GetMultiplier(HealthID);

// Regeneration / Degeneration switches
stats.Stat_Regenerate_On(StaminaID);
stats.Stat_Regenerate_Off(StaminaID);
stats.Stat_Degenerate_On(StaminaID);   // replaces the removed DegenerateOn(StatID)
stats.Stat_Degenerate_Off(StaminaID);  // replaces the removed DegenerateOff(StatID)

// Parent Link
stats.RefreshParentLink();             // Re-search the closest Stats above and link again
stats.SetParentStats(otherStats);      // Link to a specific Stats component. null unlinks
Stats parent   = stats.ParentStats;    // Current parent Stats. null when unlinked
IMStat parentStat = health.ParentStat; // Same Stat on the parent. null when unlinked
bool linked    = health.IsLinkedToParent;
bool optsIn    = health.UsesParentLink;
```

{% hint style="info" %}
`DegenerateOn(StatID)` and `DegenerateOff(StatID)` were marked obsolete and are now removed. Use `Stat_Degenerate_On` and `Stat_Degenerate_Off`. UnityEvents pointing at the old names show as **Missing** and need to be rewired.
{% endhint %}

### Extending Stats (IMStat)

`Stats` never exposes the `Stat` class directly at runtime. Every lookup returns `IMStat`, the contract a Stat fulfils (values, events, modify calls, parent link).

To intercept reads and writes, for example to sync a Stat over the network, subclass `Stats` and override `WrapStat`. It is called once per authored Stat when the dictionary is built. The authored list, the inspector and the prefab data stay untouched.

```csharp
public class NetworkStats : Stats
{
    protected override IMStat WrapStat(Stat stat) => new NetworkStat(stat);
}
```

`NetworkStat` implements `IMStat` and forwards to the wrapped `Stat`, adding whatever you need on top.
