Skip to content

Molang Predicates

The whenMolang field on a match clause is the escape hatch for predicates the sugar fields can’t express. It accepts any expression Cobblemon’s Molang runtime can evaluate, with a small set of bindings into the live battle context. A non-zero result is “match”; zero or a runtime error is “miss”.

match {
whenMolang = "q.world.is_raining && q.pokemon.level >= 30 && q.pokemon.shiny"
}

If you’ve written Molang for Journey task filters or NPC dialogue, this is the same surface and the same operators. The only differences are the bindings ShowdownActions chooses to expose and a handful of helpers it registers under q.world.*.


Inside a whenMolang expression, the following queries resolve to the live battle context at the moment of evaluation (battle start):

QuerySource
q.pokemonThe Pokémon being evaluated for this (action, pokemon) candidate.
q.playerThe matched trainer.
q.worldThe world the player is standing in.
q.battleThe active battle.

Each binding exposes the full set of Cobblemon query functions for its type — the same surface Journey filters and Cobblemon NPC dialogues use. A q.player.has_flag('foo') call works inside ShowdownActions because Cobblemon’s player surface is what’s bound to q.player.

A fresh Molang context is built for each evaluation, so there’s no carry-over state between actions or between battles. t.* (temp) variables are scoped to the single expression; v.* (variable) writes likewise don’t leak.


A non-exhaustive set of fields you’ll reach for most often. The full list is whatever Cobblemon exposes for its Pokémon objects in your version — run /ceremony dump molang (provided by Ceremony) to dump the live surface.

ExpressionReturns
q.pokemon.shiny1.0 if shiny, else 0.0
q.pokemon.levelCurrent level (1..100)
q.pokemon.hp_ratio0.0..1.0 — current HP / max HP
q.pokemon.is_fainted1.0 if HP is zero
q.pokemon.has_aspect('dusk')1.0 if the aspect is currently applied
q.pokemon.gender0 male, 1 female, 2 genderless
q.pokemon.friendship0..255
q.pokemon.species.nameSpecies id as a string

ShowdownActions evaluates property fields first and then runs the Molang only on Pokémon that already passed the property check. So q.pokemon.level in a whenMolang is redundant if you also set minLevel in the same match clause — the property check would have rejected mismatches before Molang ever ran. It’s still legal; it just costs a few cycles.


Native Cobblemon world queries plus the ShowdownActions extras.

ExpressionReturnsSource
q.world.is_raining1.0 / 0.0Cobblemon
q.world.is_thundering1.0 / 0.0Cobblemon
q.world.biomeBiome id as a stringCobblemon
q.world.dimensionDimension id as a stringCobblemon
q.world.day_timeMod-24000 time of dayCobblemon
q.world.is_time('night')1.0 if inside the named bucketShowdownActions
q.world.dimension_stringDimension id as a stringShowdownActions

Two things worth flagging on the ShowdownActions extras:

  • is_time('<bucket>') accepts morning, day, noon, evening, dusk, night, midnight. The bucket boundaries are documented on the Match Clause page. This is what sugar.time compiles down to.
  • biome_in_tag('<tag>') is currently a stub that always returns 0.0. World-bound Molang functions don’t have a player position to query against, and a position-aware implementation lives in a different code path. Use q.world.biome == 'minecraft:forest' for direct biome checks today; tag-based gates work via the sugar.biome = "#<tag>" field, which lifts position from the matcher context before evaluating.

The wrapper exposes Cobblemon’s full player query surface, which overlaps heavily with what Journey docs cover under Player Functions. Highlights for predicates:

ExpressionReturns
q.player.has_permission('foo.bar')1.0 / 0.0
q.player.is_creative1.0 if creative or spectator
q.player.is_sneaking1.0 while crouched
q.player.x, q.player.y, q.player.zWorld coordinates as numbers
q.player.has_flag('vip')1.0 / 0.0 (Journey-style flag check, when Journey is installed)
q.player.party_count()Number of Pokémon in party

Anything you’d use as a Journey task filter, you can use here. ShowdownActions doesn’t add player-side helpers of its own; the surface is whatever Cobblemon (and any other mod that contributes player-side Molang functions) registers.


The battle binding exposes battle-level queries — which actors are present, which side is which, turn count, etc. The exact surface depends on your Cobblemon version. Two predicates worth knowing:

ExpressionReturns
q.battle.actorsNumber of actors in the battle
q.battle.battle_typeBattle type as a string (pvp, pve, etc.)

For most use cases the global config flags (applyInPvp, applyInPve) make q.battle.battle_type redundant. Reach for it when you need finer-grained control than the three top-level toggles allow — e.g. “only fire in NPC fights against gym leaders”.


Molang’s operator set is the Bedrock-flavored subset. Quick reference:

OperatorMeaning
+ - * /Arithmetic
== != < <= > >=Comparison; result is 1.0 / 0.0
&& || !Boolean logic on 0.0 / non-zero
cond ? a : bTernary
'string'String literal (single quotes)
q.foo.bar(arg)Query function call
// line and /* block */Comments (only with MoLang Extensions installed)

If you have the MoLang Extensions mod installed, you also get if/else, switch(), while(), fn(), import(), struct creation, and compound assignment. ShowdownActions doesn’t depend on that mod, but whenMolang uses the same Molang runtime, so anything the runtime can evaluate works here.

For multi-line predicates, use HOCON’s triple-quoted string form:

match {
whenMolang = """
q.world.is_time('night') &&
q.pokemon.level >= 50 &&
(q.pokemon.shiny || q.world.is_thundering)
"""
}

No escaping needed. The trailing newline doesn’t affect evaluation.


When match has both sugar predicates and whenMolang, ShowdownActions compiles them into a single combined expression at load time:

match {
sugar { time = "dusk", weather = "rain" }
whenMolang = "q.pokemon.level >= 30"
}

becomes (logically):

(q.world.is_time('dusk')) && (q.world.is_raining) && (q.pokemon.level >= 30)

The result is what gets evaluated against the runtime. The combined expression is printed at debug-trace level when debug = true — you can see exactly what’s being passed to the runtime.

The property checks (species, ability, etc.) run before the combined Molang. A property mismatch short-circuits and skips the Molang entirely.


There’s no single canonical document for “every Molang query Cobblemon exposes” — the surface is built up dynamically from contributions by Cobblemon and any other mods you’ve installed. The right way to learn what’s available in your install is to dump it at runtime:

/ceremony dump molang

(Provided by Ceremony.) The dump prints every registered query function with its argument signatures, organized by namespace (q.player.*, q.world.*, q.pokemon.*, etc.). What shows up depends on which mods are installed — ShowdownActions itself contributes q.world.is_time and q.world.dimension_string; Journey contributes its full player suite; other mods may add more.

The dump is the source of truth — it reflects exactly what’s registered on your running server, including contributions from every installed mod, and updates as Cobblemon evolves between versions.


whenMolang is wrapped in a try/catch — it never crashes a battle. Failure modes:

SymptomCause
Molang evaluation failed for '...': <message> warning in the logParse error or runtime error in the expression. The action treats the result as false (no match).
The action silently never matchesThe expression evaluates to 0.0. Run with debug = true and read the matcher trace; the compiled expression is printed alongside its result.
The expression refers to a query that doesn’t existUnknown queries return 0.0 (Molang’s default), which evaluates as false. There’s no error, just no match.

The third failure mode is the one that bites. If you write q.pokemon.is_legendary and the actual field is named q.pokemon.is_legendary_species (made-up example), Molang resolves the typo to zero and the action quietly never matches. The fix is /ceremony dump molang to confirm the real names.


  • Showdown Research — if you want to write hooks that run inside Showdown’s JS engine, this is the pre-reading.
  • Match Clause — the rest of the gate, including the sugar fields that Molang composes with.
  • Recipes — worked examples that combine sugar and whenMolang.
  • MoLang Extensions — functions, conditionals, loops, and more for the Cobblemon Molang runtime ShowdownActions evaluates against.