Skip to content

Quick Start

This guide walks you through creating your first custom trainer AI, assigning it to an NPC, and testing it. You will have a working config in under five minutes.

  • Smart Trainers installed on your server (see Installation & Setup)
  • A datapack (either an existing one or a new one in your world’s datapacks/ folder)
  • An NPC trainer to assign the AI to

Create a new file at:

data/<your_namespace>/battle_ai/my_trainer.json

For example, if your datapack namespace is mypack:

data/mypack/battle_ai/my_trainer.json

Paste the following content:

{
"parent": "smart_trainers:medium",
"personality": {
"enabled": true,
"trait_variance": 0.1
},
"action_priorities": [
{
"id": "heal_when_low",
"condition": "q.pokemon.current_hp_percent < 0.3",
"action_type": "move",
"move_filter": { "categories": ["heal"] },
"priority": 80,
"bias_multiplier": 2.5,
"score_bonus": 100.0
}
]
}

This creates a trainer that:

  • Inherits from medium — gets skill level 3, STAB bonuses, type effectiveness scoring, and basic switch logic from the built-in preset
  • Has personality variance — slight randomness so it does not play identically every battle
  • Prioritizes healing — when below 30% HP, strongly favors healing moves like Recover or Roost

Let’s break down what each part of the config does.

Inheritance. Your config starts with everything from the medium preset and only overrides what you specify. This single line gives your trainer:

  • Skill level 3 (picks randomly ~20% of the time)
  • STAB and type effectiveness scoring
  • Switch logic for bad matchups
  • Priority move finishing

You only need to add what makes your trainer unique.

Controls how “human” the AI feels. With trait_variance: 0.1, the trainer’s aggression, risk tolerance, and other traits shift slightly between battles. Two fights against the same trainer will play out a little differently.

FieldValueEffect
enabledtruePersonality traits influence scoring
trait_variance0.1Each trait can deviate up to 10% from its base value

The most powerful tool for defining trainer behavior. Each rule boosts or penalizes specific actions when a condition is met.

FieldValuePurpose
id"heal_when_low"Unique name for debug logs
condition"q.pokemon.current_hp_percent < 0.3"Triggers when HP is below 30%
action_type"move"Applies to move actions
move_filter\{ "categories": ["heal"] \}Only affects healing moves
priority80Evaluated before lower-priority rules
bias_multiplier2.5Multiplies the move’s score by 2.5
score_bonus100.0Adds 100 points to the score

Set your NPC trainer’s AI config to the resource ID of your file:

mypack:my_trainer

The resource ID is derived from the file path: data/mypack/battle_ai/my_trainer.json becomes mypack:my_trainer.

  1. Run /reload in-game to load your new config
  2. Challenge the NPC trainer to a battle
  3. Watch how it behaves — it should fight competently with type awareness and prioritize healing when its Pokemon get low

For detailed insight into the AI’s decision-making, enable debug mode. This prints every score, rule match, and final ranking to chat each turn so you can see exactly why the AI chose a particular action.

Debug output shows you:

  • The score for each available move after all rules are applied
  • Which action priority rules triggered and their effect
  • Which gimmick rules were evaluated
  • The final candidate pool and selected action

This is invaluable for tuning your configs — if the AI is not using Swords Dance when you expect it to, debug mode will show you exactly why another action scored higher.

Once your basic config works, try adding more behavior. Here are common patterns:

{
"id": "swords_dance_when_safe",
"condition": "q.pokemon.current_hp_percent > 0.8 && q.pokemon.under_threat < 0.3",
"action_type": "move",
"move_filter": { "names": ["swordsdance"] },
"priority": 90,
"bias_multiplier": 3.0,
"score_bonus": 120.0
}

When the Pokemon is healthy (above 80% HP) and not threatened, it strongly favors using Swords Dance. The high score_bonus of 120 makes it competitive with strong STAB attacks.

{
"id": "stop_boosting_at_plus_4",
"condition": "q.pokemon.stat_boosts.atk >= 4 || q.pokemon.stat_boosts.spa >= 4",
"action_type": "move",
"move_filter": { "categories": ["buff"] },
"priority": 200,
"bias_multiplier": 0.0,
"score_bonus": -200.0
}

Prevents the AI from endlessly setting up. Once Attack or Special Attack is at +4, buff moves are completely suppressed. The high priority (200) ensures this overrides any other rule that might encourage boosting.

{
"id": "switch_under_threat",
"condition": "q.pokemon.under_threat > 0.5 && q.pokemon.current_hp_percent > 0.3",
"action_type": "switch",
"priority": 70,
"bias_multiplier": 2.5,
"score_bonus": 60.0
}

When the active Pokemon is heavily threatened but still has enough HP to be worth preserving, the AI favors switching to a better matchup.

{
"id": "toxic_on_walls",
"condition": "!q.target.has_status && q.target.defence > 100 && q.target.special_defence > 100",
"action_type": "move",
"move_filter": { "names": ["toxic"] },
"priority": 85,
"bias_multiplier": 3.0,
"score_bonus": 100.0
}

If the opponent is a bulky wall with no status condition, the AI prioritizes using Toxic to wear it down.

You can inherit from any of these presets to get a head start:

PresetResource IDSkillDescription
Randomsmart_trainers:random0Pure random move selection
Easysmart_trainers:easy2Basic type awareness, occasionally random
Mediumsmart_trainers:medium3STAB bonus, type effectiveness, switches on bad matchups
Hardsmart_trainers:hard4Full damage prediction, hazard setup, ability immunities
Expertsmart_trainers:expert5Tight margin, KO prediction, gimmick rules
Championsmart_trainers:champion5Setup sweeps, strategic healing, Will-o-Wisp
VGC Mastersmart_trainers:vgc_master5Doubles-optimized with Fake Out, Protect, speed control
Gen 4 Cynthiasmart_trainers:gen4_cynthia5Recreation of Champion Cynthia from Pokemon Platinum

When you set "parent": "smart_trainers:medium", your config inherits all fields from the medium preset. Only fields you explicitly specify are overridden:

  • Scalar values (like move_bias, max_select_margin): your value replaces the parent’s
  • Object values (like skill, personality): your object replaces the parent’s entire object
  • Rule lists (like action_priorities, switch_conditions): your rules are prepended to the parent’s rules — they do not replace them

This means a 10-line config file can inherit hundreds of lines of battle logic. Inheritance chains work too — a config can inherit from a parent that inherits from a grandparent.

Now that you have a working custom trainer, explore the full configuration options: