Skip to content

Introduction to ShowdownActions

ShowdownActions is a Fabric mod for Cobblemon servers that lets you declare Showdown effects — stat boosts, status, weather, terrain, aspects, even raw Showdown JS handlers — in plain .conf files, gated by Molang predicates that fire at battle start.

The pitch is short: form changes that depend on time of day, ability buffs that depend on weather, species-specific quirks that should always trigger on switch-in, “this Pokémon is always Toxic on send-out” — all of it normally requires writing a custom Java/Kotlin mod for each case. ShowdownActions packages that plumbing once. You write the .conf, ShowdownActions wires up the Cobblemon battle event → Molang predicate → Showdown injection.

Every action is one declarative file under config/showdown_actions/actions/. When a battle is about to start:

  1. Each registered action is checked against every Pokémon on each player’s team.
  2. Property checks happen first (species, ability, level bands, etc.). Misses are dropped immediately.
  3. Anything dynamic — time of day, weather, biome, custom predicates — is evaluated as Molang against the live (player, pokemon, world, battle) context.
  4. Surviving matches go through final gates: optional permission node, probability roll, and mutex-group resolution (so only the highest-priority winner fires when several variants compete).
  5. Cobblemon-side effects (forced aspects, console commands) run immediately. Showdown-side effects (boosts, status, weather, terrain, custom hooks) are applied as a Showdown volatile when the matched Pokémon switches in.

The whole pipeline is fault-tolerant. Missing fields are treated as “don’t care”, failed Molang evaluations log a warning and count as no match, and a hot reload via /showdownactions reload never restarts Showdown.

ShowdownActions is designed so you only reach for power you actually need. The three tiers escalate in capability:

Tier 1 — Sugar (no scripting) : match { species, form, type, ability, heldItem, aspect, minLevel, maxLevel, ... } paired with apply { aspect, boosts { atk, def, ... }, status, weather, terrain, message, command }. Covers the majority of “this species in these conditions gets these stat changes” cases without touching a script.

Tier 2 — Raw Molang predicates : When sugar can’t express the gate, drop a whenMolang = "..." expression into the match clause. You get q.pokemon, q.player, q.world, and q.battle bindings — the same surface the rest of Cobblemon’s Molang ecosystem exposes — plus a few ShowdownActions-specific helpers under q.world.*. Compose these freely with the sugar fields; everything is ANDed.

Tier 3 — Raw Showdown JS : When the effect itself can’t be reduced to “boost some stats / set a status / change the weather”, drop a showdown { conditionId, hooks { onStart, onModifyAtk, onResidual, ... } } block. The hooks are passed verbatim to Cobblemon’s Showdown JS context as a real Dex.data.Conditions[…] entry. Anything Showdown supports is supported here — if it’s a function key Showdown calls during battle simulation, you can hook it.

Use the lowest tier that does the job. Most actions never need to leave sugar; a handful need a Molang gate; a few percent need raw JS.

A “Lycanroc gets +1 Spe/Atk and a dusk aspect at dusk” rule, in full:

id = "lycanroc_dusk"
displayName = "Lycanroc - Dusk Form"
target = "SELF"
match {
species = "lycanroc"
sugar {
time = "dusk"
}
}
apply {
aspect = "dusk"
boosts { spe = 1, atk = 1 }
message = "{name} resonates with the dusk light!"
}

A “Swift Swim mons gain +2 Speed in the rain, but only if they’re at least level 30”:

id = "rainy_swift_swim"
match {
ability = "swiftswim"
whenMolang = "q.world.is_raining && q.pokemon.level >= 30"
}
apply {
boosts { spe = 2 }
}

A “Gyarados gets a custom Intimidate handler that runs whatever Showdown code you want”:

id = "custom_intimidate"
match { species = "gyarados" }
showdown {
conditionId = "showdownactionsgyaradosintimidate"
conditionName = "Sigil Intimidate"
scope = "volatile"
hooks {
onStart = """function(pokemon) {
var foe = pokemon.side.foe.active[0];
if (foe && !foe.fainted) {
this.boost({atk: -2}, foe, pokemon);
this.add('-message', pokemon.name + ' glares menacingly at ' + foe.name + '!');
}
}"""
}
}

Required:

  • Minecraft 1.21.1 (Fabric)
  • Java 21+
  • Cobblemon (compatible build)
  • Ceremony 4.7+
  • Fabric API
  • Fabric Language Kotlin

Optional but recommended:

  • fabric-permissions-api / LuckPerms (for the permission field on actions)

If you’ve used Journey, the predicate model will feel familiar — ShowdownActions reuses Cobblemon’s Molang runtime the same way Journey’s filters do, with the same q.pokemon / q.player / q.world bindings. The big difference is when it runs: Journey predicates fire at task-event time; ShowdownActions predicates fire once at battle start, then the Showdown side takes over.

  1. Installation — drop the jar in, where the configs live, what to expect on first launch.
  2. Configurationconfig.conf settings, hot reload, debug logging.
  3. Action Files — the structure of a single .conf, the three tiers in detail.
  4. Match Clause and Apply Clause — the two halves of every action.
  5. Molang Predicates — bindings, helpers, what you can ask the world.
  6. Showdown Research — how the Showdown engine is structured and how to learn enough of it to write your own raw hooks.