Apply Clause
Apply Clause
Section titled “Apply Clause”The apply { } block declares what happens when the match clause passes. Effects are split into two halves — ones that run Cobblemon-side (synchronous, server thread) and ones that compile to Showdown JS and fire when the matched Pokémon switches in.
A populated apply block is enough for an action to be useful at tier 1. You don’t need a showdown {} block; ShowdownActions synthesizes a Showdown condition for you, with an onStart hook that performs every effect you listed.
apply { aspect = "dusk" boosts { spe = 1, atk = 1 } status = "tox" weather = "raindance" heal = "25%" removeStatus = false message = "{name} resonates with the dusk light!" command = "playsound minecraft:entity.lightning_bolt.thunder ambient {player}"}Every populated field becomes part of the Pokémon’s switch-in effect. Multiple fields compose into a single hook — the auto-applied switch-in hook runs them in a deterministic order.
Cobblemon-Side Effects
Section titled “Cobblemon-Side Effects”These run once at battle start, on the server thread, when the action matches. They don’t go through Showdown.
| Field | Type | Effect |
|---|---|---|
aspect | String? | Adds an aspect to the matched Pokémon’s aspect set. The aspect persists until something else removes it. Use this for form swaps — pair with apply.boosts for stat changes. |
command | String? | Server console command, run as the server. {player} is replaced with the matched trainer’s username. Use vanilla syntax. |
aspect
Section titled “aspect”Cobblemon aspects drive how a Pokémon is rendered, what form it’s treated as, and which animations play. Adding "dusk" to a Lycanroc is the standard way to convert it to Lycanroc-Dusk for the duration of the battle. Adding "shiny" would force the shiny model on (though the legality of that depends on your server’s policy).
Forced aspects added by apply.aspect are additive — they’re appended to whatever aspects the Pokémon already has. ShowdownActions doesn’t strip them when the battle ends; if you want a temporary aspect, you’ll need to remove it via a separate hook or command.
command
Section titled “command”The command runs synchronously as the server console at battle start, before the Showdown side has registered any volatiles. It’s the right place for things that aren’t Pokémon mechanics — giving the player an item, playing a sound, broadcasting to a Discord webhook via your messaging mod, etc.
apply { command = "give {player} cobblemon:rare_candy 1"}Anything you’d type at the console works. Errors are caught and logged; a malformed command never breaks the battle.
Showdown-Side Effects (sugar)
Section titled “Showdown-Side Effects (sugar)”These compile into a auto-applied switch-in hook hook. The hook is registered as a Showdown condition, propagated to every cached ModdedDex, and applied as a volatile on the matched Pokémon’s slot when it switches in.
| Field | Type | Effect |
|---|---|---|
boosts | Block | Stat-stage boosts (atk, def, spa, spd, spe, accuracy, evasion), each in -6..+6. Plays Cobblemon’s stat-up/down animation and standard battle text. |
status | String? | Apply a major status. Showdown ids: brn, psn, tox, par, slp, frz. |
removeStatus | Boolean | Cure any active major status on switch-in. Default false. |
heal | String? | Heal HP. Accepts a percentage ("25%", of max HP) or a flat integer ("50"). Anything else is silently dropped with a log. |
volatile | String? | Add an arbitrary Showdown volatile by id (anything in Dex.data.Conditions). Examples: confusion, taunt, encore. |
weather | String? | Set field weather. Showdown ids: sunnyday, raindance, snow, sandstorm. Pair with target = "FIELD" so the effect lives at the field-owner slot. |
terrain | String? | Set field terrain. Showdown ids: electricterrain, grassyterrain, psychicterrain, mistyterrain. |
message | String? | Yellow battle-chat broadcast. {name} is replaced with the host’s species name at fire time. MiniMessage tags are stripped. |
Order of operations inside the auto-applied switch-in hook
Section titled “Order of operations inside the auto-applied switch-in hook”ShowdownActions composes the effects in this fixed order:
- Match guard (auto-generated for
SELF/ALLIES/EVERYONEtargets) — early-return if the switching-in Pokémon doesn’t match the species/form/type/ability/heldItem/teraType/level constraints. This is what stops a Pikachu-targeted effect from leaking onto a Bulbasaur on switch. oncePerBattlecheck — early-return if the action has already fired in this battle.removeStatus—pokemon.cureStatus()if a status is set.boosts—this.boost({...}, pokemon).status—pokemon.trySetStatus('<id>', pokemon).heal— percentage of max or flat amount.weather—this.field.setWeather('<id>', pokemon).terrain—this.field.setTerrain('<id>', pokemon).volatile—pokemon.addVolatile('<id>').message—this.add('-message', '<text>').
The whole hook is auto-wrapped so fires and errors land in the Showdown log as [ShowdownActions][<conditionId>] onStart fired/ERROR: …. With debug = true you can confirm the hook fired and see exactly what threw.
boosts
Section titled “boosts”The full block:
boosts { atk = 0 def = 0 spa = 0 spd = 0 spe = 0 accuracy = 0 evasion = 0}Each value is a stage delta in -6..+6. Zero is a no-op (omitted from the compiled call). Multiple non-zero stats are sent to this.boost as a single object, which means the Showdown engine treats them as one boost event — you get one set of stat-up/down particles and one chunk of battle text, not seven.
If boosts is the only effect and every value is zero, ShowdownActions skips synthesizing a Showdown condition entirely. The action still runs Cobblemon-side effects (aspect, command) but doesn’t touch the Showdown side.
status vs volatile
Section titled “status vs volatile”status is for the six major statuses Showdown supports as a single status slot per Pokémon (burn, poison, badly poisoned, paralysis, sleep, freeze). Setting one overwrites whatever status the Pokémon already had via trySetStatus, which respects type immunities (e.g. fire-types can’t be burned).
volatile is for the dozens of secondary effects Showdown tracks separately — confusion, taunt, encore, leech seed, perish song, you name it. Anything that’s a key in Dex.data.Conditions is fair game. ShowdownActions doesn’t validate the id; if you typo confusoin, Showdown will log “Unknown volatile” and the call is a no-op.
Two formats:
"25%"— 25% ofpokemon.maxhp, rounded down. Clamped to[0, 100]%."50"— a flat 50 HP, regardless of max.
Anything else (mistyped percentages, decimals, etc.) is silently dropped and logged as // invalid heal: ... inside the compiled hook. The rest of the effects still run.
weather and terrain
Section titled “weather and terrain”These set field state. They work regardless of target, but the conventional pairing is target = "FIELD":
target = "FIELD"match { species = "kyogre" }apply { weather = "raindance" message = "{name} commands the storm - Rain Dance is now active!"}Why pair with FIELD? Because field state is global — it doesn’t matter which side’s slot the volatile is registered against, the weather affects everyone. FIELD makes the intent clear and routes the volatile to the field-owner slot, which is the conventional place to register field-touching effects.
message
Section titled “message”The text is broadcast as battle chat in yellow, after the action effect plays. MiniMessage tags are stripped before broadcast (so <gold>...</gold> becomes ...). The {name} placeholder is replaced with the host’s species name at fire time.
If the action also has stat boosts, the Cobblemon stat-up animation plays first, then the message broadcasts. The order is enforced by Cobblemon’s action-effect playback, not by the auto-applied hook itself.
Composability
Section titled “Composability”You can populate as many fields as you want — they compose. The auto-applied hook orders them as listed above, runs each in turn, and broadcasts the message at the end.
A “rage” pattern that uses every category at once:
id = "berserker_mode"target = "SELF"oncePerBattle = true
match { species = "primeape" whenMolang = "q.pokemon.hp_ratio < 0.5"}
apply { aspect = "berserk" boosts { atk = 2, spe = 1, def = -1 } status = "brn" removeStatus = false message = "{name} flies into a rage!" command = "playsound minecraft:entity.ravager.roar hostile {player}"}Cobblemon-side: berserk aspect added, ravager roar plays. Showdown-side: a auto-applied condition with an onStart that, on Primeape’s switch-in, applies the boosts, sets burn, and broadcasts the message.
When apply Becomes Insufficient
Section titled “When apply Becomes Insufficient”The sugar fields cover every effect that fits the “trigger once on switch-in, change some state, broadcast a message” mould. They don’t cover:
- Multi-turn effects — e.g. “this Pokémon’s Atk goes up by 1 every turn it stays in”.
- Reactive handlers — e.g. “when this Pokémon takes damage, heal 10%”.
- Stat-modifier hooks — e.g. “permanently multiply this Pokémon’s Atk by 1.25”.
- Custom move semantics — e.g. “this Pokémon’s first attack each battle is a critical hit”.
For any of those, drop a showdown { hooks { ... } } block instead of (or alongside) apply. See Raw Showdown Hooks for the catalogue and Showdown Research for guidance on writing them.
apply and showdown can coexist. Sugar effects compile into the auto-applied condition; raw hooks live in their own condition that you registered. Both fire at switch-in.
Next Steps
Section titled “Next Steps”- Targeting — where the volatile gets registered.
- Raw Showdown Hooks — the tier-3 escape hatch.
- Recipes — working examples of every sugar field in context.