Add an Ability
An ability is the unit of gameplay a player spends aura on. It carries its own costs, cooldown, condition, target selection and behaviour, which means a single JSON file can describe a bolt, a buff, a passive bonus or a reaction to being hit.
This tutorial adds two abilities to the example pack: an active bolt cast from the hotbar, and a triggered recovery that answers damage.
What You Are Building
| File | Purpose |
|---|---|
data/example/mxt/ability/qi_bolt.json | An active ability with a cost, a cooldown and an area target. |
data/example/mxt/ability/qi_recovery.json | A triggered ability that reacts to being hurt. |
data/example/mxt/realm_stage/foundation.json | (edited) grants the bolt on breakthrough. |
data/example/mxt/item_binding/root_pellet.json | (edited) also grants the recovery ability. |
data/example/mxt/cultivation_technique/azure_breath.json | (edited) grants both once learned. |
Step 1 — An Active Ability
// data/example/mxt/ability/qi_bolt.json
{
"ability": {"type": "mxt:active", "slot": "primary"},
"icon": {"texture": "example:textures/gui/ability/qi_bolt.png"},
"costs": [
{"type": "mxt:resource", "resource": "example:qi", "amount": 10}
],
"cast_time": 10,
"cooldown": 40,
"condition": {"type": "mxt:has_realm", "resource": "example:qi"},
"target_selector": {"type": "mxt:area", "radius": 6, "include_actor": false},
"bi_entity_action": {
"type": "mxt:target_action",
"action": {"type": "mxt:damage", "amount": "6 + caster_level * 0.5"}
}
}
| Field | What it does |
|---|---|
ability.type | Selects the lifecycle from the built-in ability_type registry: empty, active, triggered, modifier, aura, channelled, composite, word. mxt:active is the type that appears on the ability hotbar. |
ability.slot | The hotbar slot group, primary by default, and it must not be blank. |
icon | Optional; it must define exactly one of texture (a 16x16 GUI texture) or item. Without it the entry is drawn with its name. |
costs | A list of Cost objects, paid before the behaviour runs. mxt:resource consumes a resource, mxt:item consumes items, and the {"id": ..., "amount": ...} shorthand means mxt:resource. |
cast_time | Cast duration in ticks; the hotbar draws a casting progress bar while it runs. |
cooldown | Cooldown in ticks, reported back to the client so the hotbar can grey the slot. |
condition | An entity condition that must pass before the ability can be used. Its only job here is to keep Mortals from throwing bolts. |
target_selector | Which entities the bi-entity behaviour applies to. mxt:self (the default) selects only the caster; mxt:area selects everything within radius (capped at 128), and include_actor decides whether the caster is part of that set. |
bi_entity_action | Run once for the caster and for each selected target. mxt:target_action forwards an entity action to the target — here 6 damage plus half the caster's experience level. |
entity_action | Runs on the caster. It defaults to mxt:no_op; use it for a self-buff, a particle burst or an aura change. |
Two extra fields are worth knowing about:
componentsadds state instead of a plain number:mxt:charges(limited uses that recharge),mxt:toggle,mxt:timer,mxt:resourceandmxt:target_lock.element_affinitylists elements (or element tags) the ability belongs to. When it is not empty, the formula variableelement_modifierbecomes available and can scale damage or costs by how well the caster's spirit root matches.
An ability formula runs in an entity context. It provides caster_health, caster_max_health, caster_level (the vanilla experience level), caster_<resource> and caster_<attribute> — but not realm_rank, which only exists in formulas evaluated for one resource. Use caster_example_qi when an ability should scale with the caster's aura.
Step 2 — A Triggered Ability
A triggered ability fires when the world does something to its owner. The trigger also injects a few variables that describe what happened.
// data/example/mxt/ability/qi_recovery.json
{
"ability": {
"type": "mxt:triggered",
"triggers": [{"type": "mxt:hurt"}],
"chance": 1
},
"cooldown": 100,
"condition": {"type": "mxt:has_realm", "resource": "example:qi"},
"costs": [
{"type": "mxt:resource", "resource": "example:qi", "amount": 5}
],
"entity_action": {"type": "mxt:heal", "amount": "2 + damage * 0.5"}
}
triggersis a list of built-in matchers:tick,attack,hurt,kill,block_break,block_use,item_use,equip,deathandbreakthrough. None of them takes a field of its own.chanceis a number provider,1by default, and it is rolled per matching trigger.- The
hurttrigger addsdamage— the damage actually inflicted — which is why the heal can scale with the hit. The other triggers add their own names:target_healthandtarget_is_livingforattack,block_x/y/zfor block events,use_durationforitem_use, and so on.
The full variable table is in Formula Variables.
Step 3 — Granting the Abilities
Defining an ability does nothing on its own: an entity has to hold it. The mxt:grant_ability entity action does that, and its source field records who granted it.
From a realm. Edit the realm the player reaches:
// data/example/mxt/realm_stage/foundation.json
"success_action": {
"type": "mxt:grant_ability",
"ability": "example:qi_bolt",
"source": "example:foundation"
}
success_action runs on the stage the player just entered, so reaching Foundation Establishment teaches the bolt. ability_requirements on a stage is the mirror image: it lists abilities that must already be held before the breakthrough is allowed.
From an item. Add the action to any binding table:
// data/example/mxt/item_binding/root_pellet.json
"actions": [
{"type": "mxt:grant_spirit_root", "spirit_root": "example:fire_root"},
{"type": "mxt:grant_ability", "ability": "example:qi_recovery", "source": "example:root_pellet"}
]
From a spirit root, physique or technique. Those definitions have a granted_abilities list that is applied while they are held:
// data/example/mxt/cultivation_technique/azure_breath.json
"granted_abilities": ["example:qi_bolt", "example:qi_recovery"]
Keep source stable and meaningful — the definition ID that granted the ability is a good choice. Abilities from different sources are tracked separately, and a source is what makes a later removal traceable, so two items can grant the same ability without one of them silently revoking the other.
Step 4 — Using the Ability Hotbar
Active abilities appear on the shared client hotbar:
/mxt abilityopens the Configure Hotbar screen for the ability entries. A slot you deliberately leave empty stays empty, and a saved entry whose ability no longer exists is refilled from the current runtime list.- Hold the ability keybind (
LAltby default, "Show Ability Hotbar") and press a number key1–9to cast the entry in that slot. Several keys can be held at once, and the client setting "Hotbar activation mode" switches between hold-to-show and press-to-toggle. - Everything is server-authoritative: the client only sends a use or cancel request, and the server decides costs, cooldowns, durations and effects. Cancelling a channelled ability works the same way.
Step 5 — Verify
Abilities are a data pack registry, so load the world again rather than running /reload:
(load the world again)
/mxt registries validate → no codec errors
/mxt attachment status → lists the abilities the entity holds
/mxt ability cast example:qi_bolt → forces the cast (gamemaster permission)
- Before entering the chain,
/mxt ability cast example:qi_boltfails: theconditionrejects it. - Break through to Foundation Establishment and check
/mxt attachment status. The bolt is now held, andsourceshows it came from the realm. - Open the hotbar with
LAltand cast it.10qi is deducted, the cooldown starts, and nearby entities take damage. Compare the value shown by/mxt resource example:qibefore and after. - Set the pool too low with
/mxt resource example:qi set 5and cast again: the cast is refused because the costs cannot be paid, and nothing is deducted. - Take a hit with
qi_recoverygranted: the heal amount scales with the damage taken,5qi is spent, and the 100-tick cooldown prevents it from firing again immediately.
Common Mistakes
| Symptom | Cause |
|---|---|
| The ability never appears on the hotbar | Only mxt:active abilities are listed; a triggered, modifier or channelled ability has no hotbar entry of its own. |
| A channelled ability cannot be released from the hotbar | mxt:active and mxt:channelled are mutually exclusive types. Wrap the channelled ability as the child of an mxt:composite ability and make the composite the top-level definition. |
| Costs are never paid | ResourceCost uses resource, but an ability's costs is a list of Cost. Write {"type": "mxt:resource", "resource": ..., "amount": ...} or the {"id": ..., "amount": ...} shorthand — not {"resource": ...} without a type. |
An ability formula is always 0 | It used a variable its context does not provide, such as realm_rank in an entity formula. The name is reported at evaluation time: a development environment logs the whole error, production logs one warning line per distinct message, and both continue with 0. |
mxt:word does nothing | It is a terminal, code-whitelisted effect (self_heal, purge_self_curses) and requires an operator by default. It is not a way to run commands. |
| Everyone has the ability immediately | It was granted by a granted_abilities list on a spirit root, physique or technique that everybody satisfies — those lists apply while the definition is held. |
Next
- Ability — the full field list, including components and channelled upkeep.
- Action Types and Condition Types — everything an ability can do and check.
- Loot and Advancement Criteria — rewards and advancements that react to breakthroughs and ability use.