Skip to main content

Loot and Advancement Criteria

Besides the datapack registries, MiXianTu registers a small set of vanilla types so that content packs can read and change a player's cultivation state from ordinary loot tables, loot modifiers and advancements. They are written as "type": "mxt:..." inside normal vanilla JSON — there is no special file layout.

File Locations​

KindWhere it is used
Advancement criteriaThe criteria section of data/<namespace>/advancement/<path>.json
Loot functions and loot conditionsdata/<namespace>/loot_table/<path>.json, or any JSON that accepts vanilla loot functions and conditions, such as block or entity loot tables and loot modifiers

Advancement Criteria​

All four criteria share one shape: an optional definition filter plus the standard vanilla player predicate. A criterion goes in the trigger of a criteria entry, and conditions is the two fields below.

CriterionFires whenWhat definition holds
mxt:breakthroughA breakthrough succeedsThe realm stage that was reached
saturn:abilityA cast is committedThat ability
mxt:alchemyAn alchemy batch completesThat recipe
mxt:tribulationA tribulation completes successfullyThat tribulation
FieldTypeDefaultDescription
playerVanilla player predicatenoneApplies to the player who earns the advancement
definitionIdentifiernoneOnly this definition fires it; when omitted, any definition fires the criterion

saturn:ability only knows casts: pressing a toggle ability pays through its own path and does not fire it, and a channelled ability fires it once when it starts, not on the pulses that follow.

{
"criteria": {
"foundation": {
"trigger": "mxt:breakthrough",
"conditions": {
"definition": "example:foundation"
}
}
},
"requirements": [["foundation"]]
}

Loot Conditions​

A loot condition uses the vanilla "condition" dispatch key: {"condition": "mxt:has_ability", ...}.

ConditionTrue whenRequired field
mxt:has_abilityThe entity has been granted this abilityability
mxt:has_curseThe entity carries a curse the query accepts—
mxt:realmThe entity has reached that realm, in any resource chainrealm
mxt:has_spirit_rootThe entity has that spirit rootspirit_root
mxt:has_elementOne of the elements named by the entity's enabled spirit roots is listed in elementselements
mxt:has_physiqueThe entity has that physiquephysique
mxt:techniqueThe entity has learned the listed techniques—
mxt:jsA server script callback returns trueid

The one field every condition has:

FieldTypeDefaultDescription
entityEntity selectionthisWhich entity of the loot context is checked: this, attacker, direct_attacker, attacking_player, target_entity or interacting_entity

When the selected entity is not present in the loot context, the condition is false.

All four filter fields of mxt:has_curse are optional, and whatever is written has to hold for the same curse instance; writing none of them only asks "is a curse held at all". Several tags in tags mean "carries all of these", and for "any of these" wrap the condition in mxt:or. stacks and remaining_ticks are range objects with min / max (either end may be omitted, closed interval), and remaining_ticks treats a curse that never expires as infinite — it can answer a lower bound and never an upper one.

FieldTypeDefaultDescription
curseCurse entrynoneOnly this one curse counts
tagsTag array[]Every tag the curse has to carry
stacksRangenoneStack range
remaining_ticksRangenoneRemaining duration range, in ticks

The spirit_root field of mxt:has_spirit_root takes an entry, a # tag or an array of them, so "any fire spirit root" is one tag. mxt:has_element asks the coarser question — "is this a fire cultivator": elements is a list of element references, each one an element or a # tag, so a spirit root of the same kind added later needs no edit to the loot table, and elements needs at least one entry (an empty array is refused at load).

The two fields of mxt:technique have the same shape as the entity condition of the same name:

FieldTypeDefaultDescription
techniquesEntry or tag array[]The techniques to ask about; an empty list asks "has learned any at all"
matchany / allanyall requires every entry in the list to be learned; all with an empty list is refused at load

It reads the grant ledger the body carries, not the definitions in the current pack; a technique has no enable/disable switch, so learned is learned.

{
"conditions": [
{"condition": "mxt:has_spirit_root", "spirit_root": "example:fire_root"},
{"condition": "mxt:realm", "realm": "example:foundation"}
]
}

mxt:js takes an id registered with MxtLoot.condition(...) and an optional params object. Unlike the built-in conditions it has no entity field: the callback receives the whole vanilla loot context and decides for itself which entity to read. A callback that is missing makes the condition false, and so does one that throws; both log a line.

{"condition": "saturn:js", "id": "example:first_clear", "params": {"dungeon": "example:fire_temple"}}

Loot Functions​

A loot function uses the vanilla "function" dispatch key: {"function": "mxt:grant_ability", ...}. Every function also accepts the vanilla conditions field.

FunctionEffect
mxt:grant_abilityGrants an entity a persistent ability source and refreshes its trigger-rule subscriptions
mxt:set_artifact_ownerAssigns the dropped artifact to an entity, then runs the artifact's claim_action
mxt:apply_curseApplies a curse to an entity, with mxt:loot as the application source
mxt:jsReplaces the generated item stack with whatever a server script returns

mxt:grant_ability​

FieldTypeDefaultDescription
abilityIdentifierrequiredThe ability to grant
entityEntity selectionthisThe entity that receives the ability
sourceIdentifiermxt:lootSource id recorded with the grant, so the ability can be revoked by source
{
"function": "mxt:grant_ability",
"ability": "example:fire_manual",
"source": "example:fire_temple"
}

mxt:set_artifact_owner​

FieldTypeDefaultDescription
entityEntity selectionthisThe entity that becomes the artifact's owner

If the item stack already belongs to another owner, nothing happens: the drop is left as it is and claim_action does not run.

When the ownership is written, claim_action runs once — it pays the same price and runs the same effects as claiming by long press (what claiming costs is that action's own default), because both paths go through the same claiming settlement. This path does not judge claim_condition, though: that condition is the long press gesture's own gate, and the loot table has already named an owner by its own judgement.

{
"function": "mxt:set_artifact_owner"
}

mxt:apply_curse​

FieldTypeDefaultDescription
curseIdentifierrequiredThe curse to apply
stacksInteger 1..2561How many stacks of that curse to apply
entityEntity selectionthisThe entity that receives the curse
{
"function": "mxt:apply_curse",
"curse": "example:blood_oath",
"stacks": 2
}

mxt:js​

FieldTypeDefaultDescription
idStringrequiredCallback ID registered with MxtLoot.function(...)
paramsObject{}Arbitrary JSON passed to the callback
{
"function": "saturn:js",
"id": "example:bless",
"params": {"multiplier": 3}
}

The callback receives the generated item stack and the loot context, and returns the item stack to keep: returning the argument as it came in leaves the drop alone, returning a new item stack replaces it, and returning null keeps the original item. When the callback is missing or fails, the item stack stays as it is and a line is logged.

Putting It Together​

A chest that drops a manual only for a player who already has the matching spirit root:

{
"type": "minecraft:chest",
"pools": [
{
"rolls": 1,
"entries": [
{"type": "minecraft:item", "name": "minecraft:book"}
],
"conditions": [
{"condition": "mxt:has_spirit_root", "spirit_root": "example:fire_root"}
],
"functions": [
{"function": "mxt:grant_ability", "ability": "example:fire_manual"}
]
}
]
}