> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eucaengine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Abilities & status effects

> Apply a poison DoT and a slow to any unit over HTTP, step the tick loop to watch them count down, and cleanse them off — plus how the active-ability routes work (and why they're dormant over HTTP today). Built end to end on a local server.

Euca splits "active skills" from "things happening to you." A **status effect** is a tagged, timed bundle
of stat modifiers plus an optional damage/heal-over-time tick — you apply it to **any** entity over HTTP.
An **ability** lives in an `AbilitySet` slot (`Q`/`W`/`E`/`R`) with a cooldown, a mana cost, and a
composable `effect`; the `/ability/*` routes drive whatever ability set an entity already carries.
Attaching an `AbilitySet` is done only in Rust (by the [MOBA example game](/systems/moba)'s `spawn_hero`),
which the shipped world does not currently call — so the ability routes are **dormant over HTTP** today
(see [Active abilities](#active-abilities)). Both advance only when the simulation ticks — you queue or
apply them over HTTP, then `/step`. This page applies a poison and a slow to a freshly spawned unit and
watches them tick; every command is real and runnable against a [local server](/quickstart), and the
outputs below are captured from one.

## Apply a poison and a slow, then cleanse

**1. Spawn a unit.** A generic [unit](/systems/heroes) is enough — status effects work on any entity.

```bash theme={null}
curl -s -X POST http://localhost:3917/spawn -H 'Content-Type: application/json' \
  -d '{"health":600,"team":1}'
# {"entity_id":1,"entity_generation":0}
```

**2. Apply a poison DoT and a slow.** A status effect is a `tag`, a `duration`, a list of
`"stat:op:value"` modifiers, an optional `tick_effect` (`dps:N` / `hps:N` / `custom:name`), and a
`stack_policy` (`replace` or `stack:N`). Apply two — one that ticks damage, one that only modifies a stat.

```bash theme={null}
curl -s -X POST http://localhost:3917/effect/apply -H 'Content-Type: application/json' -d '{
  "entity_id":1,"tag":"poison","duration":4.0,
  "modifiers":["move_speed:multiply:0.5"],"tick_effect":"dps:10","stack_policy":"stack:3"}'
# {"ok":true,"message":"Applied effect 'poison' to entity 1 for 4s"}

curl -s -X POST http://localhost:3917/effect/apply -H 'Content-Type: application/json' \
  -d '{"entity_id":1,"tag":"slow","duration":3.0,"modifiers":["move_speed:multiply:0.6"]}'
# {"ok":true,"message":"Applied effect 'slow' to entity 1 for 3s"}

curl -s http://localhost:3917/effect/list/1
# Before stepping, remaining == duration on both:
# {"count":2,"effects":[
#   {"tag":"poison","duration":4.0,"remaining":4.0,"modifiers":["move_speed:multiply:0.5"],
#    "tick_effect":"dps:10","source":null},
#   {"tag":"slow","duration":3.0,"remaining":3.0,"modifiers":["move_speed:multiply:0.6"],
#    "tick_effect":null,"source":null}],"entity_id":1}
```

**3. Step one second and watch them tick.** `remaining` counts down by the elapsed time; the poison's
`dps` drains health.

```bash theme={null}
curl -s -X POST http://localhost:3917/step -H 'Content-Type: application/json' -d '{"ticks":60}'

curl -s http://localhost:3917/effect/list/1
# poison remaining 4.0 → ~3.0, slow 3.0 → ~2.0:
# {"count":2,"effects":[{"tag":"poison",...,"remaining":3.0000010,...},
#                       {"tag":"slow",...,"remaining":2.0000010,...}],"entity_id":1}

curl -s http://localhost:3917/entities/1
# health dropped from [600,600] to about [580.16, 600.0]
```

**4. Cleanse.** `/effect/cleanse` removes effects whose tag matches `filter`; an empty `filter` clears
everything.

```bash theme={null}
curl -s -X POST http://localhost:3917/effect/cleanse \
  -H 'Content-Type: application/json' -d '{"entity_id":1,"filter":"poison"}'
# {"ok":true,"message":"Removed 1 effects matching 'poison' from entity 1"}

curl -s http://localhost:3917/effect/list/1
# only the slow is left:
# {"count":1,"effects":[{"tag":"slow",...,"remaining":2.0000010,...}],"entity_id":1}

curl -s -X POST http://localhost:3917/effect/cleanse \
  -H 'Content-Type: application/json' -d '{"entity_id":1,"filter":""}'
# {"ok":true,"message":"Removed 1 effects matching '' from entity 1"}
```

## Active abilities

The `/ability/*` routes operate on any entity that carries an `AbilitySet` (with the `Mana` and
base/growth stats that go with it). **There is no generic HTTP route to attach one** — an `AbilitySet`
is inserted only in Rust, by the MOBA example game's `spawn_hero`. And the shipped MOBA world does **not**
currently invoke `spawn_hero` (its level data carries no ability sets), so on every entity you can reach
over HTTP today, `/ability/list` returns an empty set. The routes are wired and correct; the ability data
to drive them is, for now, dormant.

`/ability/list/{id}` always answers — it reports each slot's cooldown, mana cost, and `ready` flag for an
ability-carrying unit, or an empty set otherwise:

```bash theme={null}
# any reachable entity (no AbilitySet attached) — empty set, null mana:
curl -s http://localhost:3917/ability/list/1
# {"abilities":[],"entity_id":1,"gold":600,"level":{"level":1,"xp":0,"xp_to_next":180},"mana":null}
```

`/ability/use` queues a use-ability event for the next tick. On a unit with no ability in that slot it
returns `ok:true` but does nothing (the event is queued, then dropped); on a unit that *does* carry the
slot, the cooldown starts and the mana is spent when the ability system runs on the next `/step`:

```bash theme={null}
curl -s -X POST http://localhost:3917/ability/use \
  -H 'Content-Type: application/json' -d '{"entity_id":1,"slot":"Q"}'
# {"ok":true,"message":"Used ability Q on entity 1"}
```

## Behavior and gotchas

The things you only learn by running it:

* **Status effects work on any entity; abilities need an `AbilitySet` that nothing currently attaches over
  HTTP.** `/effect/*` applies to a bare `/spawn` unit. `/ability/use` and `/ability/list` answer for any
  entity, but every reachable entity lists `"abilities":[]` and `"mana":null`, and `/ability/use` is a
  no-op on them — the use event is queued, then dropped because there's no ability to fire.
* **The deleted hero routes are gone.** `/hero/define` and `/hero/select` (the old way to stamp an
  `AbilitySet`) 404. The only path that attaches abilities is the MOBA game's Rust `spawn_hero`, which the
  shipped world does not call — so the ability routes are dormant over HTTP until a game wires it.
* **Cooldown and mana resolve on a tick, not on the call.** `/ability/use` queues a `UseAbilityEvent`;
  read `/ability/list` immediately and it's still `ready:true` at full mana. `/step` once, then read.
* **The poison's DoT double-drains like direct damage.** One second of `dps:10` took health from `600` to
  about `580.16`, not `590` — the same event-buffer double-drain documented on
  [Gameplay & combat](/systems/gameplay-and-combat#behavior-and-gotchas). The countdown of `remaining` is
  exact; treat the DoT *magnitude* from a manual apply as approximate.
* **`modifiers` are recorded on the effect; this page verifies the bookkeeping, not movement.** The
  `move_speed:multiply:0.5` string is stored and returned verbatim by `/effect/list`. Whether the unit
  actually moves slower is the movement system's job.
* **Cleansing leaves an empty effect set, not a missing one.** After clearing everything,
  `/effect/list/{id}` returns `{"count":0,"effects":[]}` — the `StatusEffects` component still exists. The
  `"Entity not found or has no status effects"` error is for an entity that never had one.

## Endpoints

| Method | Path                 | Description                                                                                 |
| ------ | -------------------- | ------------------------------------------------------------------------------------------- |
| `POST` | `/effect/apply`      | Apply a timed status effect (`tag`, `duration`, `modifiers`, `tick_effect`, `stack_policy`) |
| `GET`  | `/effect/list/{id}`  | Active effects with `remaining`/`duration`, modifiers, and tick effect                      |
| `POST` | `/effect/cleanse`    | Remove effects by tag `filter` (empty `filter` clears all)                                  |
| `POST` | `/ability/use`       | Queue a use-ability event for a slot (`Q`/`W`/`E`/`R`); resolves on the next tick           |
| `GET`  | `/ability/list/{id}` | Abilities (cooldown, mana cost, `ready`), plus mana, gold, and level                        |

An `AbilitySet` reaches a unit only through the [MOBA game](/systems/moba)'s Rust `spawn_hero` (not yet
called by the shipped world); the health and damage abilities move live on
[Gameplay & combat](/systems/gameplay-and-combat).

## Status

* **Shipped, all headless** — status-effect durations, set/add/multiply modifiers, DoT/HoT ticks,
  stacking, and cleanse (on any entity); ability cooldowns, mana cost and regen, per-level scaling, and
  channel state (on entities that carry an `AbilitySet`).
* **Game-side** — attaching an `AbilitySet` is done in-engine by the MOBA example game's `spawn_hero`;
  there is no generic HTTP route for it.
* **Known issue** — a DoT (like direct damage) resolves on two consecutive ticks, so a manual apply
  removes roughly twice the per-second amount; see the [combat double-drain note](/systems/gameplay-and-combat#behavior-and-gotchas).

<Card title="Ability & effect endpoints" icon="wand-magic-sparkles" href="/api-reference/introduction" horizontal>
  Every ability and status-effect endpoint, with request and response schemas.
</Card>
