-
Notifications
You must be signed in to change notification settings - Fork 806
Regional forms
This tutorial, adapted from Pokémon Fool's Gold, will show you how to add rudimentary regional variants. The trick is that, internally, the regional forms are entirely different species-- however, we pull a couple of tricks to make it seem like it's just the same mon. However, it's not a perfect solution-- if there's a more "proper" way of adding forms, please add it :)
As an example, we'll use Hisuian Typhlosion.
Follow this tutorial, adding the species constant TYPHLOSION_H
. Make all of the data according to Hisuian Typhlosion: giving it new sprites, making it Fire/Ghost type, etc. We'll handle its evolution data later... for now, just make it an isolated single-stage mon. I recommend putting the constant at the end of the list, where Munchlax is in the tutorial. On that same note, I highly recommend implementing this one, too, so that it lands after regular Typhlosion in the Old dex order. Similarly, in the New dex order and alphabetical sorting, put Hisuian Typhlosion after regular Typhlosion.
For the "illusion" of forms to work, regular Typhlosion and Hisuian Typhlosion need to have the same dex number-- otherwise, the jig will be up!
Currently, dex numbers are simply generated based on the pokemon_constants.asm
order. However, if we instead make dex numbers work like names-- that is, assigning each species a string to use as a "number"-- we can include two species with the same number.
Edit main.asm:
SECTION "bank24", ROMX
INCLUDE "engine/phone/phone.asm"
INCLUDE "engine/rtc/timeset.asm"
INCLUDE "engine/pokegear/pokegear.asm"
INCLUDE "engine/events/fish.asm"
INCLUDE "engine/games/slot_machine.asm"
+INCLUDE "data/pokemon/dex_numbers.asm"
Create data/pokemon/dex_numbers.asm:
+PokemonNumbers::
+ db "001@@"
+ db "002@@"
+ db "003@@"
+ ...
+ db "249@@"
+ db "250@@"
+ db "251@@"
+ db "157@@"
+ db "???@@"
+ db "???@@"
+ db "???@@"
+ db "???@@"
There are three things of note here: One, the last line is 157, corresponding to Hisuian Typhlosion; two, there are a few extra spots at the end to account for the rest of the spaces (data/pokemon/names.asm does something similar); and three, there are two padding @'s instead of just one; this is in case you want to add an extra symbol to mark a regional form, like 157h, as is done in Fool's Gold.
Edit home/names.asm:
GetPokemonName::
...
pop hl
pop af
rst Bankswitch
ret
+GetPokemonNumber::
+ ldh a, [hROMBank]
+ push af
+ push hl
+ ld a, BANK(PokemonNumbers)
+ rst Bankswitch
+
+ ld a, [wNamedObjectIndexBuffer]
+ dec a
+ ld d, 0
+ ld e, a
+ ld h, 0
+ ld l, a
+ add hl, hl ; hl = hl * 4
+ add hl, hl ; hl = hl * 4
+ add hl, de ; hl = (hl*4) + de
+ ld de, PokemonNumbers
+ add hl, de
+
+ ld de, wStringBuffer1
+ push de
+ ld bc, 4
+ call CopyBytes
+ ld hl, wStringBuffer1 + 4
+ ld [hl], "@"
+ pop de
+
+ pop hl
+ pop af
+ rst Bankswitch
+ ret
Now, we need to actually use the new dex number system in the relevant places: the Old Pokédex mode list, the Pokédex entry, the stats screen, and the Hall of Fame.
Edit engine/pokedex/pokedex.asm:
Pokedex_PrintNumberIfOldMode:
ld a, [wCurDexMode]
cp DEXMODE_OLD
jr z, .printnum
ret
.printnum
push hl
ld de, -SCREEN_WIDTH
add hl, de
ld de, wTempSpecies
- lb bc, PRINTNUM_LEADINGZEROS | 1, 3
- call PrintNum
+ push hl
+ call GetPokemonNumber
+ pop hl
+ call PlaceString
pop hl
ret
Edit engine/pokedex/pokedex_2.asm:
DisplayDexEntry:
...
; Print dex number
hlcoord 2, 8
ld a, $5c ; No
ld [hli], a
ld a, $5d ; .
ld [hli], a
ld de, wTempSpecies
- lb bc, PRINTNUM_LEADINGZEROS | 1, 3
- call PrintNum
+ call GetPokemonNumber
+ hlcoord 4, 8
+ call PlaceString
Edit engine/pokemon/stats_screen.asm:
StatsScreen_InitUpperHalf:
...
ld [hl], "№"
inc hl
ld [hl], "."
inc hl
hlcoord 10, 0
- lb bc, PRINTNUM_LEADINGZEROS | 1, 3
- ld de, wDeciramBuffer
- call PrintNum
+ call GetPokemonNumber
+ call PlaceString
hlcoord 14, 0
Edit engine/events/halloffame.asm:
DisplayHOFMon:
...
ld a, "№"
ld [hli], a
ld [hl], "<DOT>"
hlcoord 3, 13
- ld de, wDeciramBuffer
- lb bc, PRINTNUM_LEADINGZEROS | 1, 3
- call PrintNum
+ call GetPokemonNumber
+ call PlaceString
Now, Hisuian Typhlosion is in the game, and both it and its regular counterpart correctly display as #157, but there's no way to get it by evolution! For some Pokémon, this may be desirable, such as standalone lines, but for others, there should be a way to evolve into the regional form. Since Hisui does not exist in Crystal, what we can do is make Quilava evolve into regular Typhlosion in Johto, and Hisuian Typhlosion in Kanto.
Edit constants/pokemon_data_constants.asm:
; evolution types (used in data/pokemon/evos_attacks.asm)
const_def 1
const EVOLVE_LEVEL
const EVOLVE_ITEM
const EVOLVE_TRADE
const EVOLVE_HAPPINESS
const EVOLVE_STAT
+ const EVOLVE_LEVEL_REGION
Edit engine/pokemon/evolve.asm:
(Note that you will probably have to change some jr
's to jp
.)
EvolveAfterBattle_MasterLoop:
...
ld a, b
cp EVOLVE_LEVEL
jp z, .level
cp EVOLVE_HAPPINESS
jr z, .happiness
+
+ cp EVOLVE_LEVEL_REGION
+ jp z, .level_region
...
.item
ld a, [hli]
ld b, a
ld a, [wCurItem]
cp b
jp nz, .dont_evolve_3
ld a, [wForceEvolution]
and a
jp z, .dont_evolve_3
ld a, [wLinkMode]
and a
jp nz, .dont_evolve_3
jr .proceed
+.level_region
+ ld a, [hli]
+ ld b, a
+ ld a, [wTempMonLevel]
+ cp b
+ jp c, .dont_evolve_2
+ call IsMonHoldingEverstone
+ jp z, .dont_evolve_2
+
+ push hl
+ farcall RegionCheck ; returns 1 in e if in Kanto; returns 0 in e if in Johto
+ ld a, e
+ and a
+ pop hl
+
+ jr nz, .kanto
+
+ inc hl
+
+.kanto
+ jr .proceed
Now, all that's left is to actually use the new evolution method!
Edit data/pokemon/evos_attacks.asm:
QuilavaEvosAttacks:
- db EVOLVE_LEVEL, 36, TYPHLOSION
+ db EVOLVE_LEVEL_REGION, 36, TYPHLOSION_H, TYPHLOSION
db 0 ; no more evolutions
db 1, TACKLE
db 1, LEER
db 1, SMOKESCREEN
db 6, SMOKESCREEN
db 12, EMBER
db 21, QUICK_ATTACK
db 31, FLAME_WHEEL
db 42, SWIFT
db 54, FLAMETHROWER
db 0 ; no more level-up moves
And that's all there is to it! Quilava will now evolve into Hisuian Typhlosion in Kanto, and regular Typhlosion in Johto.
One important thing to know is that RegionCheck
doesn't count all of "Kanto" as Kanto for evolution purposes-- notably, any area between New Bark Town and the Pokémon League will count as Johto. This is the same function that is used for battle music, so you can tell which areas are which based on that.