Skip to content

MoLang Query Reference

All conditions in the Smart Trainers AI system are written in MoLang. Queries are accessed through q.<namespace>.<property>. This page documents every available query, organized by namespace.

Queries about the AI’s currently active Pokemon. Used as q.pokemon.<property>.

QueryReturnsDescription
q.pokemon.idstringUUID of the Pokemon
q.pokemon.speciesstringSpecies name (e.g., “Garchomp”)
q.pokemon.leveldoubleLevel (1—100)
q.pokemon.current_hpdoubleCurrent HP value
q.pokemon.max_hpdoubleMaximum HP value
q.pokemon.current_hp_percentdouble (0.0—1.0)Current HP as a percentage. 0.5 = 50% HP.
q.pokemon.typesarrayList of type names (e.g., [“dragon”, “ground”])
q.pokemon.has_type(name)0/1Whether this Pokemon has the specified type. q.pokemon.has_type('fire')
q.pokemon.abilitystringAbility name
q.pokemon.has_ability(name)0/1Whether ability matches. q.pokemon.has_ability('intimidate')
q.pokemon.speeddoubleSpeed base stat
q.pokemon.attackdoubleAttack base stat
q.pokemon.defencedoubleDefence base stat
q.pokemon.special_attackdoubleSpecial Attack base stat
q.pokemon.special_defencedoubleSpecial Defence base stat
q.pokemon.statusstringCurrent status condition name (e.g., “burn”, “paralysis”), or "" if none
q.pokemon.has_status0/1Whether the Pokemon has any status condition
q.pokemon.stat_boostsstructStat boost sub-struct. See Stat Boosts.
q.pokemon.volatilesarrayList of volatile conditions (confusion, leech seed, etc.)
q.pokemon.has_volatile(name)0/1Whether a specific volatile is active
q.pokemon.has_substitute0/1Has a Substitute up
q.pokemon.has_confusion0/1Is confused
q.pokemon.has_leech_seed0/1Is Leech Seeded
q.pokemon.has_encore0/1Is Encored
q.pokemon.has_taunt0/1Is Taunted
q.pokemon.has_disable0/1Has a move Disabled
q.pokemon.has_torment0/1Is Tormented
q.pokemon.is_first_turn0/1Whether this is the Pokemon’s first turn on the field (relevant for Fake Out)
q.pokemon.last_movestringThe last move this Pokemon used (from memory)
q.pokemon.itemstringHeld item name (normalized)
q.pokemon.has_item0/1Whether the Pokemon is holding an item
q.pokemon.item_boosts_type(type)0/1Whether held item boosts the given type
q.pokemon.item_type_boost_multiplier(type)doubleType boost multiplier from held item
q.pokemon.item_boosted_typestringThe type name boosted by the held item, or ""
q.pokemon.item_has_category(cat)0/1Whether held item has a specific effect category
q.pokemon.item_is_choice0/1Is holding a Choice item (Band/Specs/Scarf)
q.pokemon.item_is_berry0/1Is holding a berry
q.pokemon.item_is_consumable0/1Is holding a consumable item
q.pokemon.item_stat_multiplier(stat)doubleStat multiplier from held item
q.pokemon.item_restricts_move0/1Whether held item restricts move choice
q.pokemon.item_recoildoubleRecoil multiplier from held item (e.g., Life Orb)
q.pokemon.is_choice_locked0/1Whether locked into one move by a Choice item
q.pokemon.effective_speeddoubleSpeed after boosts, paralysis, Choice Scarf, Tailwind, weather abilities (Chlorophyll, Swift Swim, etc.), Unburden
q.pokemon.action_speeddoubleRaw base Speed stat (no modifiers applied)
q.pokemon.has_recovery_move0/1Has any healing move (Recover, Roost, etc.)
q.pokemon.has_priority_move0/1Has any priority move (Quick Attack, Mach Punch, etc.)
q.pokemon.has_pivot_move0/1Has any pivot move (U-turn, Volt Switch, etc.)
q.pokemon.has_setup_move0/1Has any setup/buff move (Swords Dance, Calm Mind, etc.)
q.pokemon.has_hazard_move0/1Has any entry hazard move (Stealth Rock, Spikes, etc.)
q.pokemon.has_move(name)0/1Has a specific move. q.pokemon.has_move('earthquake')
q.pokemon.is_trapped0/1Cannot switch out (trapped by ability or move)
q.pokemon.turns_on_fielddoubleHow many turns this Pokemon has been active
q.pokemon.protected_last_turn0/1Used Protect/Detect last turn
q.pokemon.is_grounded0/1Affected by ground-based effects (terrain, Spikes, etc.)
q.pokemon.is_win_condition0/1Heuristic: is this Pokemon a win condition? (High offensive stats + stat boosts)
q.pokemon.is_threatening0/1Has high offensive stats (Attack or SpAtk > 100)
q.pokemon.is_targeted0/1Opponent has super-effective STAB type against us
q.pokemon.is_terastallized0/1Currently Terastallized
q.pokemon.is_mega_evolved0/1Currently Mega Evolved
q.pokemon.is_dynamaxed0/1Currently Dynamaxed
q.pokemon.tera_typestringTera type, or ""
q.pokemon.can_tera0/1Can Terastallize this turn
q.pokemon.can_mega0/1Can Mega Evolve this turn
q.pokemon.can_dynamax0/1Can Dynamax this turn
q.pokemon.can_zmove0/1Can use a Z-Move this turn
q.pokemon.tera_type_advantageous0/1Would Terastallizing give a type advantage?
q.pokemon.tera_resists_incoming0/1Would Tera type resist the opponent’s STAB?
q.pokemon.will_be_koed0/1Estimates whether the opponent can KO us this turn
q.pokemon.should_protectdouble (0.0—1.0)Heuristic score for how beneficial Protect would be
q.pokemon.under_threatdouble (0.0—1.0)How threatened this Pokemon is. Considers opponent SE types, speed, boosts, and our HP. Higher = more danger.
q.pokemon.se_threat_countdoubleNumber of opponents with super-effective coverage against us
q.pokemon.should_switchdouble (0.0—1.0)Heuristic for whether switching would be beneficial
q.pokemon.opponents_likely_to_protectdouble (0.0—1.0)Likelihood opponent will use Protect this turn
q.pokemon.held_itemstringSame as q.pokemon.item
q.pokemon.used_ally_switch_recently0/1Whether this Pokemon used Ally Switch recently (currently always 0)

Accessed via q.pokemon.stat_boosts.<stat> or q.target.stat_boosts.<stat>.

QueryReturnsDescription
.stat_boosts.atkdouble (-6 to +6)Attack boost stage
.stat_boosts.defdouble (-6 to +6)Defence boost stage
.stat_boosts.spadouble (-6 to +6)Special Attack boost stage
.stat_boosts.spddouble (-6 to +6)Special Defence boost stage
.stat_boosts.spedouble (-6 to +6)Speed boost stage
.stat_boosts.accuracydouble (-6 to +6)Accuracy boost stage
.stat_boosts.evasiondouble (-6 to +6)Evasion boost stage

Queries about the primary opponent. q.target.* and q.opponent.* are identical aliases.

QueryReturnsDescription
q.target.idstringUUID
q.target.speciesstringSpecies name
q.target.leveldoubleLevel
q.target.current_hpdoubleCurrent HP
q.target.max_hpdoubleMax HP
q.target.current_hp_percentdouble (0.0—1.0)HP percentage
q.target.typesarrayType names
q.target.has_type(name)0/1Type check
q.target.revealed_abilitystringAbility revealed during battle (from memory)
q.target.has_revealed_ability(name)0/1Ability match against revealed ability
q.target.revealed_itemstringItem revealed during battle (from memory)
q.target.statusstringStatus condition name, or ""
q.target.has_status0/1Has any status condition
q.target.stat_boostsstructStat boost sub-struct
q.target.predicted_speeddoubleEstimated speed considering known boosts/items
q.target.speeddoubleBase Speed stat
q.target.attackdoubleBase Attack stat
q.target.special_attackdoubleBase Special Attack stat
q.target.defencedoubleBase Defence stat
q.target.special_defencedoubleBase Special Defence stat
q.target.is_physical_attacker0/1Attack > Special Attack
q.target.is_dynamaxed0/1Is Dynamaxed
q.target.is_terastallized0/1Is Terastallized
q.target.is_mega_evolved0/1Is Mega Evolved
q.target.tera_typestringTera type (if revealed)
q.target.item_consumed0/1Whether the target’s item has been consumed (from memory)
q.target.is_threatening0/1High offensive stats
q.target.is_biggest_threat0/1Highest offensive stat among all opponents
q.target.will_attack0/1Predicts whether opponent will use an attacking move (not status)
q.target.used_setup_move0/1Opponent used a setup move recently
q.target.is_support0/1Appears to be a support Pokemon (high defenses, status moves)
q.target.likely_to_protectdouble (0.0—1.0)Likelihood of using Protect this turn
q.target.likely_to_switchdouble (0.0—1.0)Likelihood of switching out
q.target.threat_to_activedouble (0.0—1.0)How threatening this target is to our active Pokemon
q.target.can_ko_active0/1Estimates whether the target can KO our active Pokemon
q.target.predicted_actionstringBest guess of what opponent will do: "attack", "protect", "switch", "setup", "support"
q.target.priority_scoredoubleCombined threat/priority score for target selection

Queries about the specific move being evaluated. Only available during move scoring. Used as q.move.<property>.

QueryReturnsDescription
q.move.namestringMove name (Showdown ID, e.g., “earthquake”)
q.move.typestringElemental type (e.g., “ground”)
q.move.powerdoubleBase power (0 for status moves)
q.move.accuracydoubleAccuracy (0—100, or -1 for never-miss)
q.move.ppdoubleRemaining PP
q.move.max_ppdoubleMaximum PP
q.move.prioritydoubleMove priority (e.g., +1 for Quick Attack)
q.move.damage_categorystring"physical", "special", or "status"
q.move.is_physical0/1Is a physical move
q.move.is_special0/1Is a special move
q.move.is_status0/1Is a status move
q.move.categoriesarrayAI categories (e.g., [“damage”, “priority”])
q.move.has_category(cat)0/1Has a specific AI category. q.move.has_category('heal')
q.move.is_stab0/1Same-Type Attack Bonus — move type matches one of the user’s types
q.move.type_effectivenessdoubleType effectiveness multiplier (0, 0.25, 0.5, 1, 2, 4)
q.move.effectivenessdoubleSame as type_effectiveness
q.move.predicted_damagedoubleEstimated raw damage amount
q.move.predicted_damage_percentdouble (0.0—1.0+)Estimated damage as a percentage of target’s current HP
q.move.min_damagedoubleMinimum possible damage (low roll)
q.move.max_damagedoubleMaximum possible damage (high roll)
q.move.is_ohko0/1Can this move one-hit KO the target?
q.move.is_2hko0/1Can two uses of this move KO?
q.move.hits_to_kodoubleEstimated number of hits needed to KO
q.move.is_spread0/1Hits multiple targets (doubles)
q.move.is_protect0/1Is a protection move
q.move.hits_ally0/1Would this move hit our ally (doubles)
q.move.likely_blocked_by_protect0/1Would this move be blocked if the opponent uses Protect?
q.move.is_good_timingdouble (0.0—1.0)Heuristic for whether this is a good time to use this move
q.move.better_target_exists0/1Is there a better target for this move? (doubles)
q.move.is_good_fake_out_target0/1Is this a good target for Fake Out?
q.move.opponent_reaction_penaltydoublePenalty for predictable moves the opponent can capitalize on

General battle state. Used as q.battle.<property>.

QueryReturnsDescription
q.battle.turndoubleCurrent turn number
q.battle.formatstringBattle format name
q.battle.is_doubles0/1Whether this is a doubles battle
q.battle.weatherstringCurrent weather (e.g., “RainDance”, “SunnyDay”), or ""
q.battle.has_weather(name)0/1Check for specific weather
q.battle.terrainstringCurrent terrain, or ""
q.battle.has_terrain(name)0/1Check for specific terrain
q.battle.hazards_on_our_sidestructHazard data for our side. See Hazards.
q.battle.hazards_on_enemy_sidestructHazard data for the enemy side
q.battle.is_opponent_switching0/1Whether the opponent is being forced to switch (currently always 0)
q.battle.has_trick_room0/1Whether Trick Room is active

Accessed via q.battle.hazards_on_our_side.<hazard> or q.battle.hazards_on_enemy_side.<hazard>.

QueryReturnsDescription
.spikesdouble (0—3)Layers of Spikes
.toxic_spikesdouble (0—2)Layers of Toxic Spikes
.stealth_rock0/1Stealth Rock present
.sticky_web0/1Sticky Web present

AI memory of what has been revealed during battle. Used as q.memory.<property>.

QueryReturnsDescription
q.memory.opponent_revealed_movesarrayMoves the opponent has used (from memory)
q.memory.opponent_revealed_itemstringOpponent’s revealed item
q.memory.opponent_revealed_abilitystringOpponent’s revealed ability
q.memory.times_move_used(move)doubleHow many times a specific move has been used
q.memory.total_switchesdoubleTotal switches made during the battle
q.memory.opponent_switch_likelihooddouble (0.0—1.0)Estimated probability the opponent will switch

Type matchup analysis. Used as q.matchup.<property>.

QueryReturnsDescription
q.matchup.scoredouble (~-4 to +4)Type-based matchup score. Positive = we have type advantage. Based on STAB types only (not actual moves).
q.matchup.can_outspeed0/1Whether we outspeed the current target. Trick Room-aware — returns 1 if we move first regardless of Trick Room.
q.matchup.speed_tierdoubleSpeed ratio. >1 = we move first, <1 = they move first. Trick Room-aware — under Trick Room, the ratio is inverted (theirSpeed/ourSpeed) so >1 always means “I move first.”

Queries about your doubles partner. Used as q.ally.<property>. Returns empty values in singles.

QueryReturnsDescription
q.ally.idstringUUID
q.ally.speciesstringSpecies name
q.ally.current_hp_percentdouble (0.0—1.0)HP percentage
q.ally.typesarrayType names
q.ally.has_ability(name)0/1Ability check
q.ally.benefits_from_weather(weather)0/1Would ally benefit from this weather?
q.ally.is_setting_up0/1Used a setup move last turn
q.ally.will_ko_target0/1Ally is likely to KO the shared target
q.ally.is_targeting_same0/1Ally is targeting the same opponent
q.ally.resists_predicted_move0/1Ally resists the opponent’s likely attack
q.ally.is_protecting_or_redirecting0/1Ally is using Protect, Follow Me, etc.
q.ally.has_spread_move0/1Ally has a spread move

q.allies is an indexed array of all ally Pokemon (doubles). Each element has:

QueryReturnsDescription
q.allies[N].idstringUUID
q.allies[N].speciesstringSpecies name
q.allies[N].current_hp_percentdouble (0.0—1.0)HP percentage

Queries about a Pokemon being considered for switch-in. Only available during switch evaluation. Used as q.switch_candidate.<property>.

QueryReturnsDescription
q.switch_candidate.idstringUUID
q.switch_candidate.speciesstringSpecies name
q.switch_candidate.leveldoubleLevel
q.switch_candidate.current_hpdoubleCurrent HP
q.switch_candidate.max_hpdoubleMax HP
q.switch_candidate.current_hp_percentdouble (0.0—1.0)HP percentage
q.switch_candidate.typesarrayType names
q.switch_candidate.abilitystringAbility name
q.switch_candidate.matchup_scoredoubleType matchup score vs current opponent (same formula as q.matchup.score)
q.switch_candidate.has_move(name)0/1Has a specific move
q.switch_candidate.sets_weather0/1Has a weather-setting ability (Drizzle, Drought, Sand Stream, Snow Warning)
q.switch_candidate.sets_terrain0/1Has a terrain-setting ability (Grassy/Electric/Psychic/Misty Surge, Hadron Engine)

Field conditions (weather, terrain, screens, etc.). Used as q.field.<property>.

QueryReturnsDescription
q.field.weatherstringCurrent weather name
q.field.has_weather(name)0/1Specific weather check
q.field.terrainstringCurrent terrain name
q.field.has_terrain(name)0/1Specific terrain check
q.field.has_electric_terrain0/1Electric Terrain active
q.field.has_grassy_terrain0/1Grassy Terrain active
q.field.has_psychic_terrain0/1Psychic Terrain active
q.field.has_misty_terrain0/1Misty Terrain active
q.field.has_trick_room0/1Trick Room active
q.field.has_tailwind_ally0/1Tailwind on our side
q.field.has_tailwind_opponent0/1Tailwind on opponent’s side
q.field.has_light_screen_ally0/1Light Screen on our side
q.field.has_reflect_ally0/1Reflect on our side
q.field.has_aurora_veil_ally0/1Aurora Veil on our side
q.field.has_light_screen_opponent0/1Light Screen on opponent’s side
q.field.has_reflect_opponent0/1Reflect on opponent’s side
q.field.has_aurora_veil_opponent0/1Aurora Veil on opponent’s side
q.field.has_screens_ally0/1Any screen on our side
q.field.has_screens_opponent0/1Any screen on opponent’s side
q.field.has_gravity0/1Gravity active
q.field.has_mud_sport0/1Mud Sport active
q.field.has_water_sport0/1Water Sport active
q.field.has_preferred_weather0/1Current weather benefits our Pokemon
q.field.has_preferred_terrain0/1Current terrain benefits our Pokemon

Information about the AI’s whole team. Used as q.team.<property>.

QueryReturnsDescription
q.team.remaining_countdoubleNumber of living Pokemon on the team
q.team.has_intimidate_available0/1Whether an available switch-in has Intimidate
q.team.has_weather_abuser0/1Has a Pokemon that benefits from the current weather
q.team.has_terrain_abuser0/1Has a Pokemon that benefits from the current terrain
q.team.wants_weather0/1Any team member wants a specific weather
q.team.wants_terrain0/1Any team member wants a specific terrain
q.team.wants_trick_room0/1Any team member is slow enough to want Trick Room
q.team.wants_max_weather0/1Team has many weather abusers

Information about the AI’s battle bag. Used as q.bag.<property>.

QueryReturnsDescription
q.bag.enabled0/1Whether the bag is usable
q.bag.remaining_usesdoubleTotal remaining item uses this battle
q.bag.has_healing_item0/1Has a HEALING category item available
q.bag.has_status_cure0/1Has a STATUS_CURE item available
q.bag.has_revive0/1Has a REVIVE item available
q.bag.has_stat_boost0/1Has a STAT_BOOST item available
q.bag.remaining_quantity(itemId)doubleRemaining quantity of a specific item
q.bag.can_use_item(itemId)0/1Whether a specific item can be used right now

Lookup held item properties from the HeldItemEffectsRegistry. Used as q.item.<property>(itemName).

QueryReturnsDescription
q.item.boosts_type(name, type)0/1Whether item boosts the given type
q.item.type_boost_multiplier(name, type)doubleType boost multiplier from item
q.item.boosted_type(name)stringType boosted by the item
q.item.has_category(name, cat)0/1Whether item has a specific effect category
q.item.categories(name)arrayAll effect categories of the item
q.item.is_choice(name)0/1Is a Choice item
q.item.is_type_boost(name)0/1Boosts a specific type
q.item.is_berry(name)0/1Is a berry
q.item.is_consumable(name)0/1Is consumable
q.item.stat_multiplier(name, stat)doubleStat multiplier from item
q.item.restricts_move(name)0/1Whether item restricts move choice
q.item.recoil(name)doubleRecoil multiplier
q.item.has_property(name, prop)0/1Whether item has a named property
q.item.property(name, prop)doubleNumeric property value
q.item.property_string(name, prop)stringString property value

The AI’s current personality values. Used as q.personality.<property>.

QueryReturnsDescription
q.personality.aggressiondouble (0.0—1.0)Aggression level
q.personality.risk_tolerancedouble (0.0—1.0)Risk tolerance
q.personality.setup_preferencedouble (0.0—1.0)Setup move preference
q.personality.switchinessdouble (0.0—1.0)Switch frequency
q.personality.item_conservatismdouble (0.0—1.0)Item conservatism

Aggregate queries accessed directly on q.*.

QueryReturnsDescription
q.opponents_countdoubleNumber of active opponents
q.opponent_remaining_countdoubleTotal remaining opponent Pokemon (including bench)
q.opponents_faster_countdoubleNumber of opponents faster than us
q.opponents_physical_countdoubleNumber of opponents that are physical attackers
q.opponent_has_spread_move0/1Any opponent has a spread move
q.opponent_has_priority0/1Any opponent has a priority move
q.opponent_has_special_threat0/1Any opponent has Special Attack > 100
q.opponent_is_setting_up0/1Any opponent used a setup move last turn

MoLang uses a simple expression syntax for conditions and value expressions.

q.pokemon.current_hp_percent < 0.5 // less than
q.pokemon.current_hp_percent > 0.5 // greater than
q.pokemon.current_hp_percent == 0.5 // equal
q.pokemon.current_hp_percent >= 0.5 // greater or equal
q.pokemon.current_hp_percent <= 0.5 // less or equal
q.pokemon.current_hp_percent < 0.5 && q.target.has_status == 0 // AND
q.pokemon.current_hp_percent < 0.3 || q.pokemon.has_status // OR
!q.target.has_status // NOT

Boolean values use 0 = false and anything > 0 = true. So q.target.has_status alone works as a boolean check without needing == 1.

q.move.power * q.move.type_effectiveness
q.pokemon.current_hp_percent * 100
q.target.current_hp_percent * 2.5
q.pokemon.has_type('fire')
q.pokemon.has_move('earthquake')
q.target.has_revealed_ability('levitate')

To make a rule always apply, use "1" as the condition:

{
"condition": "1"
}

The AI uses a single MoLang runtime per battle actor that persists across turns. You can use t.xxx temporary variables in conditions to track state across turns:

{
"id": "escalating_aggression",
"condition": "t.turns_without_ko = (t.turns_without_ko ?? 0) + 1; t.turns_without_ko > 3",
"action_type": "move",
"move_filter": { "categories": ["damage"] },
"bias_multiplier": 2.0,
"score_bonus": 50.0
}

All q.* queries are refreshed each decision (they reflect current battle state). Only t.* and v.* variables persist across turns on the same actor.