Define an Ability
An ability defines one generic skill: an active, passive, triggered, targeted, channelled or interval skill of a player or an artifact, an aura effect, a storage cell, a flight toggle and so on. What it does is written in the action fields; what it costs and when it may run are written in the declaration fields.
This tutorial adds two abilities to the example pack:
- an active bolt cast from the wheel;
- a triggered recovery that answers damage.
What You Are Building
| File | Purpose |
|---|---|
data/example/saturn/ability/qi_bolt.json | The active bolt: costs, cooldown and condition, running its own four action fields on the press. |
data/example/saturn/ability/qi_recovery.json | The triggered recovery: it reacts to being hurt and runs its own action fields once the trigger fires. |
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/technique/azure_breath.json | (edited) grants both once learned. |
Step 1 — An Active Ability
// data/example/saturn/ability/qi_bolt.json
{
"type": "mxt:active",
"icon": "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", "aura": "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"}
}
}
The fields this ability reads (cooldown and the four action fields below it are not fields shared by every ability - the first is read only by a type that pays, the others are declared only by a type that runs actions):
| Field | What it does |
|---|---|
type | Selects the lifecycle from the built-in ability_type registry; every type is on Ability Types. |
icon | Optional. A bare string is a 16x16 GUI texture; an object is an item stack template ({"id": ...}, optionally count and components). Without it the entry is drawn with its name. |
costs | A list of Cost objects, paid before the behaviour runs, all or nothing as one array. The four entries and the {"id": ..., "amount": ...} shorthand are on Cost Types. |
cast_time | Cast duration in ticks. |
cooldown | Cooldown in ticks, reported back to the client so the wheel can lay the cooldown sheet over that sector's icon and say "On cooldown 4.3s" - the seconds left, always one decimal. |
condition | An entity condition that must pass before the ability can be used. Its only job here is to keep Mortals from throwing bolts. For a passive mxt:modifier or mxt:aura ability the same field keeps working after the cast: it is re-checked every tick and the passive effect is withdrawn while it fails. |
mxt:active also declares these four action fields itself - they are not fields shared by every ability; only the types that run actions declare them:
| Field | What it does |
|---|---|
target_selector | Which entities the bi-entity behaviour applies to; mxt:self (the default) selects only the caster. The shape of every selector and their limit and order are on Ability Target Selectors. The example uses mxt:area - a box, not a sphere - and include_actor decides whether the caster counts as part of the set. |
bi_entity_action | Run for each selected target, and a failing one never stops the rest. 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. |
target_condition | The bi-entity condition every target has to pass; mxt:always by default. |
The four action fields always run in this order: entity_action first, then target_selector picks targets, then each target is tested by target_condition, and only then does bi_entity_action run. The full per-type timing table is on Ability Types · The Four Action Fields.
A few more fields are worth knowing about:
chargesis the only state parameter left on the definition: writing{"maximum": ..., "recharge_ticks": ...}(both required) makes the ability pay per use — one charge per payment, refused at zero (failure reasonNO_CHARGES) — and the remaining count is state rather than a declaration. Only a payment on the cast pipeline spends one; a key going through the shared gate (mxt:flight_control/mxt:storage) spends no charge. Which state kinds can be held is declared by thetypein code, so there is nocomponentsto write any more (writing one is silently ignored like any unknown key); see Ability Casting for the kinds and the conditions that read them.- Element affinity is not written on the ability: it is its own data pack registry, see ability_affinity. Once an ability is named there it is both a cast gate and part of the formula variable
damage_multiplier, so you neither write nor multiply an affinity factor by hand. hiddenis skipped only in an artifact's tooltip and is still granted and still works; it takes no part in the wheel's filter (the pool only offers pressable types), so a pressable ability with it still takes a wheel cell.
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. Its own part is "which signal, how likely", and what runs is written in its own action fields:
// data/example/saturn/ability/qi_recovery.json
{
"type": "mxt:triggered",
"triggers": [{"type": "mxt:hurt"}],
"chance": 1,
"cooldown": 100,
"condition": {"type": "mxt:has_realm", "aura": "example:qi"},
"costs": [
{"type": "mxt:resource", "resource": "example:qi", "amount": 5}
],
"entity_action": {"type": "mxt:heal", "amount": "2 + damage * 0.5"}
}
triggersis the list of built-in matchers; each entry names a type id and carries no fields of its own. Every entry is on Triggers.chanceis a number provider,1by default, and it is rolled once per matching trigger: a formula that throws or does not evaluate to a finite number means not allowed,<= 0is not allowed,>= 1always is, and anything in between rolls the entity's random once. Do not confuse it with thechanceof the same name in thesaturn/triggerrule table — there a value that cannot be computed counts as1.- The
hurttrigger addsdamage— the damage actually inflicted — which is why the heal can scale with the hit; variables injected by other triggers are just as readable to this ability's own action fields, and the table is on Formula Variables.
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. Write the action into the item_binding definition that claims the item:
// data/example/mxt/item_binding/root_pellet.json
{
"items": "kubejs:root_pellet",
"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/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 — Putting the Ability on the Wheel
Active abilities can be put on the twelve-sector wheel that abilities and spirit power share (a main wheel plus pages read from what you carry):
- Type
/wheelin chat (the client command, the same as the "Open Wheel Configuration" key, unbound by default) to open the wheel editor: six columns of spirit power on the left, six columns of the skills you have learned and of the skills the artifacts in your Curios slots declare on the right (a skill only a main-hand or off-hand item declares is not there - it only appears on the pages read from your gear), and one row of twelve shared cells underneath which are the main wheel's twelve cells (1is straight up, counting clockwise). Left-click the bolt in the right pool to pick it up, then click a cell to put it there, and pressEscapeto save and close. A cell you deliberately leave empty stays empty, and a saved cell whose definition no longer exists shows a red?and is never replaced by something else. - Hold "Wheel Menu" (
Rby default) and point at that cell - pointing is what changes the selection, which is never empty: the wheel opens with the first cell that holds anything already selected (that is where the gold frame sits before you move the pointer), and pointing at an empty cell leaves the selection where it was. Letting go ofRonly closes the wheel and casts nothing. Press "Use Wheel Selection" (Vby default) to cast it, and the wheel stays open so you can move to another cell and press it again; with the wheel closedVspends the cell the number you chose stands for right now (a number addressing a page that is gone falls back to the last cell holding anything, and is never rewritten), and a left click is the same asV. The "Wheel Grid" on the left of the screen is a four-column view of the whole wheel, one row per three cells of a page, and the cell outlined in gold is whatVwould spend. - Everything is server-authoritative: the client only sends which kind and which id was used, and the server decides the grant, the conditions, the costs, the cooldown, the duration and the effects.
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
/saturn ability cast example:qi_bolt → forces the cast (gamemaster permission)
- Before entering the chain,
/saturn 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. - Cast it from the wheel (hold
R, point at the sector you put it in, then pressV).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 in the wheel's pool | The pool lists the skills that need a key; triggered and passive abilities have no wheel entry of their own. |
| Costs are never paid | An entry needs a type together with its own fields, such as {"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. |
| The actions never happen and nothing errors | The four action fields were written on a type that does not run actions (mxt:modifier / mxt:mount / mxt:storage and the like). Only the five types that run actions read them, so on any other type they are keys nobody reads (no error, no effect) — switch this ability to a type that runs actions, or move the keys to the ability that really runs them. The table of types and fields is on Ability Types · The Four Action Fields. |
An "effect": "..." line does nothing | The ability-reference effect field is a key nobody reads: write the four action fields on the firing type itself and leave the effect line out; the effect of mxt:word is a different thing (its own effect enum) and is unaffected. |
| A targeted skill only says "no target matches" when pressed | The target_selector of the mxt:targeted ability picked no entity at all, or every pick was filtered out by the payload ability's target_condition: check the selector's distance (mxt:area's radius, mxt:ray / mxt:cone's length). Landing on nobody is decided before anything is paid, so it costs nothing; an ability that cannot act on a target reports the other reason, "the ability it names cannot act on a target". |
Next
- Ability — the full field list, including
chargesand channelled upkeep. - Define a Technique and Its Levels — hang these abilities on a progression chain that climbs, so mastery decides when each one unlocks.
- 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.
- Write a Cost — what each of the four entry types takes, and when several payments in one action are rolled back whole.
- Launch a Sword Aura — use
mxt:spawn_sword_aurato make an ability throw a flying blade.