-
Notifications
You must be signed in to change notification settings - Fork 995
Trainer Class
Adding a new trainer class is fairly straightforward. A lot the changes are just for specifying information about the new trainer you'd like to add. For example, their name, what A.I. they'll have, what the Pokemon teams will be, etc... Although, slight code modification is necessary to allow for the new sprites to be loaded.
This tutorial will specifically replace the unused classes, UNUSED_JUGGLER and CHIEF. If you want to add more than this you can repeat the process but add them at the end of the each list if you'd like.
constants\trainer_constants.asm:
DEF OPP_ID_OFFSET EQU 200
MACRO trainer_const
const \1
DEF OPP_\1 EQU OPP_ID_OFFSET + \1
ENDM
; trainer class ids
; indexes for:
; - TrainerNames (see data/trainers/names.asm)
; - TrainerNamePointers (see data/trainers/name_pointers.asm)
; - TrainerDataPointers (see data/trainers/parties.asm)
; - TrainerPicAndMoneyPointers (see data/trainers/pic_pointers_money.asm)
; - TrainerAIPointers (see data/trainers/ai_pointers.asm)
; - TrainerClassMoveChoiceModifications (see data/trainers/move_choices.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
trainer_const BURGLAR ; $0B
trainer_const ENGINEER ; $0C
- trainer_const UNUSED_JUGGLER ; $0D
+ trainer_const NEW_TRAINER1 ; $0D
trainer_const FISHER ; $0E
trainer_const SWIMMER ; $0F
trainer_const CUE_BALL ; $10
trainer_const GAMBLER ; $11
trainer_const BEAUTY ; $12
trainer_const PSYCHIC_TR ; $13
trainer_const ROCKER ; $14
trainer_const JUGGLER ; $15
trainer_const TAMER ; $16
trainer_const BIRD_KEEPER ; $17
trainer_const BLACKBELT ; $18
trainer_const RIVAL1 ; $19
trainer_const PROF_OAK ; $1A
- trainer_const CHIEF ; $1B
+ trainer_const NEW_TRAINER2 ; $1B
trainer_const SCIENTIST ; $1C
trainer_const GIOVANNI ; $1D
trainer_const ROCKET ; $1E
trainer_const COOLTRAINER_M ; $1F
trainer_const COOLTRAINER_F ; $20
trainer_const BRUNO ; $21
trainer_const BROCK ; $22
trainer_const MISTY ; $23
trainer_const LT_SURGE ; $24
trainer_const ERIKA ; $25
trainer_const KOGA ; $26
trainer_const BLAINE ; $27
trainer_const SABRINA ; $28
trainer_const GENTLEMAN ; $29
trainer_const RIVAL2 ; $2A
trainer_const RIVAL3 ; $2B
trainer_const LORELEI ; $2C
trainer_const CHANNELER ; $2D
trainer_const AGATHA ; $2E
trainer_const LANCE ; $2F
DEF NUM_TRAINERS EQU const_value - 1
Note that we've moved the position of the trainer that is replacing the UNUSED_JUGGLER
to be below PROF_OAK
. This is important when we need to modify the code for loading
data\trainers\ai_pointers.asm:
TrainerAIPointers:
table_width 3, TrainerAIPointers
; one entry per trainer class
; first byte, number of times (per Pokémon) it can occur
; next two bytes, pointer to AI subroutine for trainer class
; subroutines are defined in engine/battle/trainer_ai.asm
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
- dbw 3, JugglerAI ; unused_juggler
+ dbw 3, GenericAI ; new trainer1
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, GenericAI
dbw 3, JugglerAI ; juggler
dbw 3, GenericAI
dbw 3, GenericAI
dbw 2, BlackbeltAI ; blackbelt
dbw 3, GenericAI ; rival1
dbw 3, GenericAI
- dbw 1, GenericAI ; chief
+ dbw 3, GenericAI ; new trainer2
dbw 3, GenericAI
dbw 1, GiovanniAI ; giovanni
dbw 3, GenericAI
dbw 2, CooltrainerMAI ; cooltrainerm
dbw 1, CooltrainerFAI ; cooltrainerf
dbw 2, BrunoAI ; bruno
dbw 5, BrockAI ; brock
dbw 1, MistyAI ; misty
dbw 1, LtSurgeAI ; surge
dbw 1, ErikaAI ; erika
dbw 2, KogaAI ; koga
dbw 2, BlaineAI ; blaine
dbw 1, SabrinaAI ; sabrina
dbw 3, GenericAI
dbw 1, Rival2AI ; rival2
dbw 1, Rival3AI ; rival3
dbw 2, LoreleiAI ; lorelei
dbw 3, GenericAI
dbw 2, AgathaAI ; agatha
dbw 1, LanceAI ; lance
assert_table_length NUM_TRAINERS
Encounter Types: for default Male/Gym trainers encounter music, just not put in any list.
data\trainers\encounter_types.asm:
FemaleTrainerList::
db OPP_LASS
db OPP_JR_TRAINER_F
db OPP_BEAUTY
db OPP_COOLTRAINER_F
db -1 ; end
EvilTrainerList::
- db OPP_UNUSED_JUGGLER
db OPP_GAMBLER
db OPP_ROCKER
db OPP_JUGGLER
- db OPP_CHIEF
db OPP_SCIENTIST
db OPP_GIOVANNI
db OPP_ROCKET
db -1 ; end
data\trainers\move_choices.asm:
MACRO move_choices
IF _NARG
db \# ; all args
ENDC
db 0 ; end
DEF list_index += 1
ENDM
; move choice modification methods that are applied for each trainer class
TrainerClassMoveChoiceModifications:
list_start TrainerClassMoveChoiceModifications
move_choices ; YOUNGSTER
move_choices 1 ; BUG CATCHER
move_choices 1 ; LASS
move_choices 1, 3 ; SAILOR
move_choices 1 ; JR_TRAINER_M
move_choices 1 ; JR_TRAINER_F
move_choices 1, 2, 3 ; POKEMANIAC
move_choices 1, 2 ; SUPER_NERD
move_choices 1 ; HIKER
move_choices 1 ; BIKER
move_choices 1, 3 ; BURGLAR
move_choices 1 ; ENGINEER
- move_choices 1, 2 ; UNUSED_JUGGLER
+ move_choices 1, 2, 3 ; NEW_TRAINER1
move_choices 1, 3 ; FISHER
move_choices 1, 3 ; SWIMMER
move_choices ; CUE_BALL
move_choices 1 ; GAMBLER
move_choices 1, 3 ; BEAUTY
move_choices 1, 2 ; PSYCHIC_TR
move_choices 1, 3 ; ROCKER
move_choices 1 ; JUGGLER
move_choices 1 ; TAMER
move_choices 1 ; BIRD_KEEPER
move_choices 1 ; BLACKBELT
move_choices 1 ; RIVAL1
move_choices 1, 3 ; PROF_OAK
- move_choices 1, 2 ; CHIEF
+ move_choices 1 ; NEW_TRAINER2
move_choices 1, 2 ; SCIENTIST
move_choices 1, 3 ; GIOVANNI
move_choices 1 ; ROCKET
move_choices 1, 3 ; COOLTRAINER_M
move_choices 1, 3 ; COOLTRAINER_F
move_choices 1 ; BRUNO
move_choices 1 ; BROCK
move_choices 1, 3 ; MISTY
move_choices 1, 3 ; LT_SURGE
move_choices 1, 3 ; ERIKA
move_choices 1, 3 ; KOGA
move_choices 1, 3 ; BLAINE
move_choices 1, 3 ; SABRINA
move_choices 1, 2 ; GENTLEMAN
move_choices 1, 3 ; RIVAL2
move_choices 1, 3 ; RIVAL3
move_choices 1, 2, 3 ; LORELEI
move_choices 1 ; CHANNELER
move_choices 1 ; AGATHA
move_choices 1, 3 ; LANCE
assert_list_length NUM_TRAINERS
data\trainers\name_pointers.asm:
TrainerNamePointers:
; These are only used for trainers' defeat speeches.
; They were originally shortened variants of the trainer class names
; in the Japanese versions, but are now redundant with TrainerNames.
table_width 2, TrainerNamePointers
dw .YoungsterName
dw .BugCatcherName
dw .LassName
dw wTrainerName
dw .JrTrainerMName
dw .JrTrainerFName
dw .PokemaniacName
dw .SuperNerdName
dw wTrainerName
dw wTrainerName
dw .BurglarName
dw .EngineerName
- dw .UnusedJugglerName
+ dw wTrainerName
dw wTrainerName
dw .SwimmerName
dw wTrainerName
dw wTrainerName
dw .BeautyName
dw wTrainerName
dw .RockerName
dw .JugglerName
dw wTrainerName
dw wTrainerName
dw .BlackbeltName
dw wTrainerName
dw .ProfOakName
- dw .ChiefName
+ dw wTrainerName
dw .ScientistName
dw wTrainerName
dw .RocketName
dw .CooltrainerMName
dw .CooltrainerFName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
dw wTrainerName
assert_table_length NUM_TRAINERS
.YoungsterName: db "YOUNGSTER@"
.BugCatcherName: db "BUG CATCHER@"
.LassName: db "LASS@"
.JrTrainerMName: db "JR.TRAINER♂@"
.JrTrainerFName: db "JR.TRAINER♀@"
.PokemaniacName: db "POKéMANIAC@"
.SuperNerdName: db "SUPER NERD@"
.BurglarName: db "BURGLAR@"
.EngineerName: db "ENGINEER@"
-.UnusedJugglerName: db "JUGGLER@"
.SwimmerName: db "SWIMMER@"
.BeautyName: db "BEAUTY@"
.RockerName: db "ROCKER@"
.JugglerName: db "JUGGLER@"
.BlackbeltName: db "BLACKBELT@"
.ProfOakName: db "PROF.OAK@"
-.ChiefName: db "CHIEF@"
.ScientistName: db "SCIENTIST@"
.RocketName: db "ROCKET@"
.CooltrainerMName: db "COOLTRAINER♂@"
.CooltrainerFName: db "COOLTRAINER♀@"
TrainerNames::
list_start TrainerNames
li "YOUNGSTER"
li "BUG CATCHER"
li "LASS"
li "SAILOR"
li "JR.TRAINER♂"
li "JR.TRAINER♀"
li "POKéMANIAC"
li "SUPER NERD"
li "HIKER"
li "BIKER"
li "BURGLAR"
li "ENGINEER"
- li "JUGGLER"
+ li "NEW TRAINER1"
li "FISHERMAN"
li "SWIMMER"
li "CUE BALL"
li "GAMBLER"
li "BEAUTY"
li "PSYCHIC"
li "ROCKER"
li "JUGGLER"
li "TAMER"
li "BIRD KEEPER"
li "BLACKBELT"
li "RIVAL1"
li "PROF.OAK"
- li "CHIEF"
+ li "NEW TRAINER2"
li "SCIENTIST"
li "GIOVANNI"
li "ROCKET"
li "COOLTRAINER♂"
li "COOLTRAINER♀"
li "BRUNO"
li "BROCK"
li "MISTY"
li "LT.SURGE"
li "ERIKA"
li "KOGA"
li "BLAINE"
li "SABRINA"
li "GENTLEMAN"
li "RIVAL2"
li "RIVAL3"
li "LORELEI"
li "CHANNELER"
li "AGATHA"
li "LANCE"
assert_list_length NUM_TRAINERS
TrainerDataPointers:
table_width 2, TrainerDataPointers
dw YoungsterData
dw BugCatcherData
dw LassData
dw SailorData
dw JrTrainerMData
dw JrTrainerFData
dw PokemaniacData
dw SuperNerdData
dw HikerData
dw BikerData
dw BurglarData
dw EngineerData
- dw UnusedJugglerData
+ dw NewTrainer1Data
dw FisherData
dw SwimmerData
dw CueBallData
dw GamblerData
dw BeautyData
dw PsychicData
dw RockerData
dw JugglerData
dw TamerData
dw BirdKeeperData
dw BlackbeltData
dw Green1Data
dw ProfOakData
- dw ChiefData
+ dw NewTrainer2Data
dw ScientistData
dw GiovanniData
...
...
EngineerData:
; Unused
db 21, VOLTORB, MAGNEMITE, 0
; Route 11
db 21, MAGNEMITE, 0
db 18, MAGNEMITE, MAGNEMITE, MAGNETON, 0
-UnusedJugglerData:
-; none
+NewTrainer1Data:
+ db 5, CATERPIE, 0
FisherData:
...
...
ProfOakData:
; Unused
db $FF, 66, TAUROS, 67, EXEGGUTOR, 68, ARCANINE, 69, BLASTOISE, 70, GYARADOS, 0
db $FF, 66, TAUROS, 67, EXEGGUTOR, 68, ARCANINE, 69, VENUSAUR, 70, GYARADOS, 0
db $FF, 66, TAUROS, 67, EXEGGUTOR, 68, ARCANINE, 69, CHARIZARD, 70, GYARADOS, 0
-ChiefData:
-; none
+NewTrainer2Data:
+ db $FF, 50, CHARIZARD, 50, BLASTOISE, 0
ScientistData:
data\trainers\pic_pointers_money.asm:
MACRO pic_money
dw \1
bcd3 \2
ENDM
TrainerPicAndMoneyPointers::
table_width 5, TrainerPicAndMoneyPointers
; pic pointer, base reward money
; money received after battle = base money × level of last enemy mon
pic_money YoungsterPic, 1500
pic_money BugCatcherPic, 1000
pic_money LassPic, 1500
pic_money SailorPic, 3000
pic_money JrTrainerMPic, 2000
pic_money JrTrainerFPic, 2000
pic_money PokemaniacPic, 5000
pic_money SuperNerdPic, 2500
pic_money HikerPic, 3500
pic_money BikerPic, 2000
pic_money BurglarPic, 9000
pic_money EngineerPic, 5000
- pic_money JugglerPic, 3500
+ pic_money NewTrainer1Pic, 500
pic_money FisherPic, 3500
pic_money SwimmerPic, 500
pic_money CueBallPic, 2500
pic_money GamblerPic, 7000
pic_money BeautyPic, 7000
pic_money PsychicPic, 1000
pic_money RockerPic, 2500
pic_money JugglerPic, 3500
pic_money TamerPic, 4000
pic_money BirdKeeperPic, 2500
pic_money BlackbeltPic, 2500
pic_money Rival1Pic, 3500
pic_money ProfOakPic, 9900
- pic_money ChiefPic, 3000
+ pic_money NewTrainer2Pic, 9900
pic_money ScientistPic, 5000
pic_money GiovanniPic, 9900
pic_money RocketPic, 3000
pic_money CooltrainerMPic, 3500
pic_money CooltrainerFPic, 3500
pic_money BrunoPic, 9900
pic_money BrockPic, 9900
pic_money MistyPic, 9900
pic_money LtSurgePic, 9900
pic_money ErikaPic, 9900
pic_money KogaPic, 9900
pic_money BlainePic, 9900
pic_money SabrinaPic, 9900
pic_money GentlemanPic, 7000
pic_money Rival2Pic, 6500
pic_money Rival3Pic, 9900
pic_money LoreleiPic, 9900
pic_money ChannelerPic, 3000
pic_money AgathaPic, 9900
pic_money LancePic, 9900
assert_table_length NUM_TRAINERS
Now, if you want to create new trainer class sprites, you need to create a new SECTION to them.
...
ld d, a ; de contains pointer to trainer pic
ld a, [wLinkState]
and a
- ld a, BANK("Pics 6") ; this is where all the trainer pics are (not counting Red's)
- jr z, .loadSprite
+ jr nz, .useRed
+ ld a, [wTrainerClass]
+ cp PROF_OAK ; first trainer class in "Trainer Pics 2"
+ ld a, BANK("Trainer Pics 2")
+ jr nc, .loadSprite
+ ld a, BANK("Trainer Pics 1")
+ jr .loadSprite
+.useRed
ld a, BANK(RedPicFront)
.loadSprite
call UncompressSpriteFromDE
...
...
-SECTION "Pics 6", ROMX
+SECTION "Trainer Pics 1", ROMX
YoungsterPic:: INCBIN "gfx/trainers/youngster.pic"
BugCatcherPic:: INCBIN "gfx/trainers/bugcatcher.pic"
LassPic:: INCBIN "gfx/trainers/lass.pic"
SailorPic:: INCBIN "gfx/trainers/sailor.pic"
JrTrainerMPic:: INCBIN "gfx/trainers/jr.trainerm.pic"
JrTrainerFPic:: INCBIN "gfx/trainers/jr.trainerf.pic"
PokemaniacPic:: INCBIN "gfx/trainers/pokemaniac.pic"
SuperNerdPic:: INCBIN "gfx/trainers/supernerd.pic"
HikerPic:: INCBIN "gfx/trainers/hiker.pic"
BikerPic:: INCBIN "gfx/trainers/biker.pic"
BurglarPic:: INCBIN "gfx/trainers/burglar.pic"
EngineerPic:: INCBIN "gfx/trainers/engineer.pic"
FisherPic:: INCBIN "gfx/trainers/fisher.pic"
SwimmerPic:: INCBIN "gfx/trainers/swimmer.pic"
CueBallPic:: INCBIN "gfx/trainers/cueball.pic"
GamblerPic:: INCBIN "gfx/trainers/gambler.pic"
BeautyPic:: INCBIN "gfx/trainers/beauty.pic"
PsychicPic:: INCBIN "gfx/trainers/psychic.pic"
RockerPic:: INCBIN "gfx/trainers/rocker.pic"
JugglerPic:: INCBIN "gfx/trainers/juggler.pic"
TamerPic:: INCBIN "gfx/trainers/tamer.pic"
BirdKeeperPic:: INCBIN "gfx/trainers/birdkeeper.pic"
BlackbeltPic:: INCBIN "gfx/trainers/blackbelt.pic"
Rival1Pic:: INCBIN "gfx/trainers/rival1.pic"
+NameHere1Pic:: INCBIN "gfx/trainers/newtrainer1.pic"
+SECTION "Trainer Pics 2", ROMX
ProfOakPic:: INCBIN "gfx/trainers/prof.oak.pic"
-ChiefPic::
ScientistPic:: INCBIN "gfx/trainers/scientist.pic"
GiovanniPic:: INCBIN "gfx/trainers/giovanni.pic"
RocketPic:: INCBIN "gfx/trainers/rocket.pic"
CooltrainerMPic:: INCBIN "gfx/trainers/cooltrainerm.pic"
CooltrainerFPic:: INCBIN "gfx/trainers/cooltrainerf.pic"
BrunoPic:: INCBIN "gfx/trainers/bruno.pic"
BrockPic:: INCBIN "gfx/trainers/brock.pic"
MistyPic:: INCBIN "gfx/trainers/misty.pic"
LtSurgePic:: INCBIN "gfx/trainers/lt.surge.pic"
ErikaPic:: INCBIN "gfx/trainers/erika.pic"
KogaPic:: INCBIN "gfx/trainers/koga.pic"
BlainePic:: INCBIN "gfx/trainers/blaine.pic"
SabrinaPic:: INCBIN "gfx/trainers/sabrina.pic"
GentlemanPic:: INCBIN "gfx/trainers/gentleman.pic"
Rival2Pic:: INCBIN "gfx/trainers/rival2.pic"
Rival3Pic:: INCBIN "gfx/trainers/rival3.pic"
LoreleiPic:: INCBIN "gfx/trainers/lorelei.pic"
ChannelerPic:: INCBIN "gfx/trainers/channeler.pic"
AgathaPic:: INCBIN "gfx/trainers/agatha.pic"
LancePic:: INCBIN "gfx/trainers/lance.pic"
+NameHere2Pic:: INCBIN "gfx/trainers/newtrainer2.pic"