Skip to main content
The trainer system manages all NPC trainers, their Pokémon teams, AI strategies, and prize money calculations.

Trainer Classes

All trainer classes are defined in constants/trainer_constants.asm:
const_def
trainer_const NOBODY         ; $00
trainer_const YOUNGSTER      ; $01
trainer_const BUG_CATCHER    ; $02
trainer_const LASS           ; $03
trainer_const SAILOR         ; $04
trainer_const JR_TRAINER_M   ; $05
trainer_const JR_TRAINER_F   ; $06
trainer_const POKEMANIAC     ; $07
trainer_const SUPER_NERD     ; $08
trainer_const HIKER          ; $09
trainer_const BIKER          ; $0A
There are 48 trainer classes (NUM_TRAINERS = 47, excluding NOBODY). The trainer_const macro automatically generates both the class ID and an opponent ID offset of 200.

Trainer Constant Macro

The macro creates two constants per trainer:
MACRO trainer_const
    const \1
    DEF OPP_\1 EQU OPP_ID_OFFSET + \1
ENDM

DEF OPP_ID_OFFSET EQU 200
Example: YOUNGSTER becomes:
  • YOUNGSTER = $01 (trainer class)
  • OPP_YOUNGSTER = 201 (opponent ID for battle system)

Trainer Data Structure

Trainer parties are defined in data/trainers/parties.asm with two formats:

Format 1: Same Level

All Pokémon at the same level:
; if first byte != $FF, then
;   first byte is level (of all pokemon on this team)
;   all the next bytes are pokemon species
;   null-terminated
YoungsterData:
; Route 3
    db 11, RATTATA, EKANS, 0
    db 14, SPEAROW, 0
; Mt. Moon 1F
    db 10, RATTATA, RATTATA, ZUBAT, 0
; Route 24
    db 14, RATTATA, EKANS, ZUBAT, 0

Format 2: Custom Levels

Each Pokémon has individual level:
; if first byte == $FF, then
;   first byte is $FF (obviously)
;   every next two bytes are a level and species
;   null-terminated
BrockData:
    db $FF, 12, GEODUDE, 14, ONIX, 0
Format 2 (starting with $FF) is typically used for Gym Leaders, Elite Four, and your Rival, where Pokémon have carefully balanced levels.

Trainer Data Pointers

Each trainer class has a pointer to its party data:
TrainerDataPointers:
    table_width 2
    dw YoungsterData
    dw BugCatcherData
    dw LassData
    dw SailorData
    dw JrTrainerMData
    dw JrTrainerFData
    dw PokemaniacData
    dw SuperNerdData
    dw HikerData
    ; ... more classes ...
    dw LanceData
    assert_table_length NUM_TRAINERS
1

Class ID Lookup

Game uses trainer class ID to index into TrainerDataPointers.
2

Party Selection

Within each class’s data, the game selects the specific trainer by index (e.g., “Youngster #3”).
3

Party Loading

Parses the party data format and loads Pokémon into battle.

Trainer Names

Trainer names are stored in data/trainers/names.asm as null-terminated strings. Each class gets:
  • A class name (“YOUNGSTER”, “LASS”, etc.)
  • Optional individual names for important trainers
Most regular trainers share a class name. Only significant trainers (Gym Leaders, Elite Four, Rival) have unique names.

Prize Money

Prize money calculation uses base values from data/trainers/pic_pointers_money.asm:
TrainerPicAndMoneyPointers:
    ; Format: trainer pic, base money
    dw YoungsterPic,    $0F  ; YOUNGSTER
    dw BugCatcherPic,   $0A  ; BUG_CATCHER
    dw LassPic,         $0F  ; LASS
    ; ... more trainers ...
Prize money formula:
Prize Money = Base Value × Highest Pokémon Level
Elite Four members and Gym Leaders have higher base values, resulting in larger payouts even though the formula is the same.

Trainer AI System

AI behavior is controlled by engine/battle/trainer_ai.asm with class-specific modifications.

AI Pointers

TrainerAIPointers:
    dw AI_Youngster    ; YOUNGSTER
    dw AI_BugCatcher   ; BUG_CATCHER
    dw AI_Lass         ; LASS
    ; ... more classes ...
Each AI routine can:
  • Evaluate type matchups
  • Prefer status moves in certain situations
  • Switch Pokémon strategically
  • Use healing items (some trainers only)

Move Choice Modifications

From data/trainers/move_choices.asm:
TrainerClassMoveChoiceModifications:
    ; Bit flags for AI behavior
    db 0             ; YOUNGSTER (no special AI)
    db 1 | 2         ; BUG_CATCHER (prefers super effective)
    db 0             ; LASS
    db 1 | 2 | 4     ; SAILOR (advanced AI)
  • Bit 0 (1): Prefer moves that are super effective
  • Bit 1 (2): Avoid moves that are not very effective
  • Bit 2 (4): Prefer status moves when appropriate
  • Bit 3 (8): Prefer moves with high power
Not all trainer classes have sophisticated AI. Early-game trainers (Youngster, Lass) have minimal AI, while late-game trainers use multiple AI flags.

Trainer DVs

From constants/battle_constants.asm, trainer Pokémon use fixed DVs:
DEF ATKDEFDV_TRAINER EQU $98
DEF SPDSPCDV_TRAINER EQU $88
These values translate to:
  • Attack DV: 9
  • Defense DV: 8
  • Speed DV: 8
  • Special DV: 8
  • HP DV: 8 (calculated from other DVs)
Trainer Pokémon have slightly above-average DVs (8-9 out of 15), making them stronger than typical wild Pokémon but not perfect.

Rival Battles

The Rival is special, with three separate class IDs for different points in the game:
trainer_const RIVAL1         ; $19 - Early game
trainer_const RIVAL2         ; $2A - Mid game
trainer_const RIVAL3         ; $2B - Late game & Champion
Each class has different party configurations depending on:
  • Which starter the player chose
  • Current point in the story
  • Location of the battle

Rival Party Structure

The Rival’s team adapts based on the player’s starter:
  • If player chose Bulbasaur, Rival has Charmander
  • If player chose Charmander, Rival has Squirtle
  • If player chose Squirtle, Rival has Bulbasaur

Special Trainers

Professor Oak

trainer_const PROF_OAK       ; $1A
Has party data defined but is never fought in normal gameplay. His team exists in the code for debug/testing purposes.

Giovanni

trainer_const GIOVANNI       ; $1D
Battled multiple times with progressively stronger teams:
  • Team Rocket Hideout
  • Silph Co.
  • Viridian Gym (final battle)

Team Rocket Grunts

trainer_const ROCKET         ; $1E
The most common enemy class, with numerous generic grunts throughout the game.

Trainer Encounter Flags

Each trainer has a unique event flag that tracks whether they’ve been defeated. This prevents re-battling and is used to give rewards. When a trainer is defeated:
  1. Their event flag is set
  2. Prize money is awarded
  3. Their dialogue changes to post-battle text
  4. They no longer trigger battles when approached

Battle Engine

How trainer battles work

Pokémon

Trainer Pokémon stats

Reference

Trainer constants

Data Structures

Trainer party formats

Key Files

  • constants/trainer_constants.asm - Trainer class IDs
  • data/trainers/parties.asm - All trainer party data
  • data/trainers/names.asm - Trainer class names
  • data/trainers/pic_pointers_money.asm - Sprites and prize money
  • data/trainers/ai_pointers.asm - AI routine pointers
  • data/trainers/move_choices.asm - AI behavior flags
  • engine/battle/trainer_ai.asm - AI implementation

Build docs developers (and LLMs) love