Skip to content

Move Scoring & Switch Conditions

Move scoring rules modify the score of individual moves during evaluation. Switch conditions control when and how the AI considers switching Pokemon. Together, these two systems handle the fine-grained decision logic that runs before action priorities apply their broader strategic rules.

Unlike action priorities (which apply once per action type), move scoring rules are evaluated for each move individually. They are the primary way to teach the AI about type effectiveness, immunities, accuracy, and other per-move factors.

{
"move_scoring_rules": [
{
"id": "stab_bonus",
"condition": "q.move.is_stab",
"score_modifier": {
"type": "multiply",
"value": "1.5"
},
"priority": 20
}
]
}
FieldJSON KeyTypeDefaultDescription
IDidstringRequiredUnique name.
ConditionconditionMolangRequiredWhen this evaluates to >0, the modifier is applied. Use "1" to mean “always.”
Move Conditionmove_conditionMolang (optional)nullAdditional condition with access to q.move.* queries.
Score Modifierscore_modifierobjectRequiredHow to modify the score. See Score Modifier Types below.
Prioritypriorityint0Reserved for future sorting. Currently, rules are applied in definition order.

Each rule’s score_modifier has a type and a value. The value field is a Molang expression, so it can reference queries dynamically.

TypeBehaviorExample
multiplynew_score = old_score x value\{"type": "multiply", "value": "1.5"\}
addnew_score = old_score + value\{"type": "add", "value": "50"\}
setnew_score = value (ignores old score)\{"type": "set", "value": "0"\}
scriptnew_score = value (Molang expression returns the final value)\{"type": "script", "value": "q.move.power * q.move.type_effectiveness"\}

Type Effectiveness — Always factor in type matchups:

{
"id": "type_effectiveness",
"condition": "1",
"score_modifier": { "type": "multiply", "value": "q.move.type_effectiveness" },
"priority": 10
}

Immunity Check — Zero out moves that the target is immune to:

{
"id": "immunity_check",
"condition": "q.move.type_effectiveness == 0",
"score_modifier": { "type": "set", "value": "0" },
"priority": 100
}

Predicted KO — Heavily boost moves that can knock out the target:

{
"id": "predicted_ko",
"condition": "q.move.predicted_damage_percent >= q.target.current_hp_percent",
"score_modifier": { "type": "multiply", "value": "3.0" },
"priority": 50
}

Accuracy Penalty — Penalize inaccurate moves proportionally:

{
"id": "accuracy_penalty",
"condition": "q.move.accuracy < 100 && q.move.accuracy > 0",
"score_modifier": { "type": "multiply", "value": "q.move.accuracy / 100" },
"priority": 5
}

Status Redundant — Do not use status moves on already-statused targets:

{
"id": "status_redundant",
"condition": "q.move.is_status && q.target.has_status",
"score_modifier": { "type": "multiply", "value": "0.05" },
"priority": 60
}

Ability Immunity — Respect ability-based immunities (e.g., Flash Fire):

{
"id": "flash_fire_check",
"condition": "q.target.revealed_ability == 'flashfire' && q.move.type == 'fire'",
"score_modifier": { "type": "set", "value": "0" },
"priority": 95
}

Switch conditions define when and how the AI considers switching Pokemon. They are evaluated during switch scoring — each condition checks the currently active Pokemon and optionally filters which bench Pokemon are valid switch targets.

{
"switch_conditions": [
{
"id": "bad_matchup",
"condition": "q.pokemon.under_threat > 0.4 && q.pokemon.current_hp_percent > 0.4",
"target_condition": "q.switch_candidate.matchup_score > 1",
"priority": 60,
"bias_multiplier": 1.5
}
]
}
FieldJSON KeyTypeDefaultDescription
IDidstringRequiredUnique name.
ConditionconditionMolangRequiredEvaluated for the currently active Pokemon. Uses q.pokemon.* queries.
Target Conditiontarget_conditionMolang (optional)nullEvaluated for each switch candidate. Only candidates where this passes are considered. Uses q.switch_candidate.* queries.
Prioritypriorityint0Reserved for future sorting. Currently, conditions are applied in definition order.
Bias Multiplierbias_multiplierdouble1.2Multiplied with the switch candidate’s score. Use <1.0 to discourage switching, 0.0 to prevent it entirely.

Never Switch When Trapped — Respect trapping effects:

{
"id": "no_switch_trapped",
"condition": "q.pokemon.is_trapped",
"priority": 200,
"bias_multiplier": 0.0
}

Do Not Abandon Boosted Pokemon — Discourage switching away from Pokemon with significant stat boosts:

{
"id": "no_switch_boosted",
"condition": "q.pokemon.stat_boosts.atk >= 2 || q.pokemon.stat_boosts.spa >= 2",
"priority": 90,
"bias_multiplier": 0.2
}

Preserve Low HP Pokemon — Encourage switching out a weakened Pokemon that is still under threat, preserving it for later:

{
"id": "preserve_low_hp",
"condition": "q.pokemon.current_hp_percent < 0.3 && q.pokemon.under_threat > 0.25",
"priority": 75,
"bias_multiplier": 1.8
}