diff options
-rw-r--r-- | Add-a-new-Pokémon.md | 86 | ||||
-rw-r--r-- | Add-a-new-TM.md | 12 | ||||
-rw-r--r-- | Add-a-new-music-song.md | 4 | ||||
-rw-r--r-- | Add-a-new-trainer-class.md | 403 | ||||
-rw-r--r-- | Tutorials.md | 1 | ||||
-rw-r--r-- | screenshots/gfx-trainers-parasol_lady.png | bin | 0 -> 530 bytes | |||
-rw-r--r-- | screenshots/parasol-lady-sue.png | bin | 0 -> 2780 bytes |
7 files changed, 458 insertions, 48 deletions
diff --git a/Add-a-new-Pokémon.md b/Add-a-new-Pokémon.md index bbf1b7f..7a26e26 100644 --- a/Add-a-new-Pokémon.md +++ b/Add-a-new-Pokémon.md @@ -11,8 +11,8 @@ This tutorial is for how to add a new species of Pokémon, allowing up to 253 sp 6. [Define its cry](#6-define-its-cry) 7. [Define its icon](#7-define-its-icon) 8. [Define its Pokédex entry](#8-define-its-pokédex-entry) -9. [Define its footprint](#9-define-its-footprint) -10. [Define its sprites and animation](#10-define-its-sprites-and-animation) +9. [Design its footprint](#9-design-its-footprint) +10. [Design its sprites and animation](#10-design-its-sprites-and-animation) 11. [Include and point to the sprite and animation data](#11-include-and-point-to-the-sprite-and-animation-data) 12. [Adding up to 253 Pokémon](#12-adding-up-to-253-pokémon) @@ -88,17 +88,7 @@ All the names are exactly 10 characters long, with "@" as padding. Names that ar ## 3. Define its base data -Edit [data/pokemon/base_stats.asm](../blob/master/data/pokemon/base_stats.asm): - -```diff - BaseData:: - INCLUDE "data/pokemon/base_stats/bulbasaur.asm" - ... - INCLUDE "data/pokemon/base_stats/celebi.asm" -+INCLUDE "data/pokemon/base_stats/munchlax.asm" -``` - -Then create **data/pokemon/base_stats/munchlax.asm**; you can start with [data/pokemon/base_stats/snorlax.asm](../blob/master/data/pokemon/base_stats/snorlax.asm) as a guide. +Create **data/pokemon/base_stats/munchlax.asm**; you can start with [data/pokemon/base_stats/snorlax.asm](../blob/master/data/pokemon/base_stats/snorlax.asm) as a guide. There's a lot of base data here: @@ -157,6 +147,16 @@ From top to bottom, what it all means: - **egg groups:** The two egg groups this Pokémon is in. Two Pokémon have to share an Egg group to breed. The 15 valid Egg groups (including `EGG_NONE` for sterile Pokémon like babies and legendaries) are defined in [constants/pokemon_data_constants.asm](../blob/master/constants/pokemon_data_constants.asm). - **TM/HM learnset:** A list of which TMs, HMs, and tutor moves this Pokémon can learn, passed to the `tmhm` macro. Valid values are defined in [constants/item_constants.asm](../blob/master/constants/item_constants.asm) with the `add_tm`, `add_hm`, and `add_mt` macros. +Then edit [data/pokemon/base_stats.asm](../blob/master/data/pokemon/base_stats.asm): + +```diff + BaseData:: + INCLUDE "data/pokemon/base_stats/bulbasaur.asm" + ... + INCLUDE "data/pokemon/base_stats/celebi.asm" ++INCLUDE "data/pokemon/base_stats/munchlax.asm" +``` + ## 4. Define its evolutions and level-up learnset @@ -286,6 +286,25 @@ If you want a custom icon, you can define a new `ICON_*` constant, create a two- ## 8. Define its Pokédex entry +Create **data/pokemon/dex_entries/munchlax.asm**: + +```diff ++ db "BIG EATER@" ; species name ++ dw 200, 2315 ; height, weight ++ ++ db "In its desperation" ++ next "to gulp down food," ++ next "it forgets about" ++ ++ page "the food it has" ++ next "hidden under its" ++ next "fur.@" +``` + +- The species name can be up to 10 characters (technically 11 will still fit in the Pokédex window). Be sure to end it with a "@". +- The height and weight values are in imperial units. 200 = 2 feet 0 inches; 2315 = 231.5 pounds. +- The entry text is in two pages; the first starts with `db`, the second with `page`. Each page can fit three lines with 18 characters each. Here it's visual size that matters—`"#MON"` counts as 7 characters because it prints as "POKéMON". Again, be sure to end it with a "@". + Edit [data/pokemon/dex_entry_pointers.asm](../blob/master/data/pokemon/dex_entry_pointers.asm): ```diff @@ -312,25 +331,6 @@ Then edit [data/pokemon/dex_entries.asm](../blob/master/data/pokemon/dex_entries Each of the four sections in dex_entries.asm holds 64 Pokédex entries. Each section is in a different ROM bank, decided by which range the Pokémon's species ID is in: 1–64, 65–128, 129–192, or 193–256. The order of entries within each section doesn't actually matter, since they're accessed directly via `PokedexDataPointerTable`, but avoid confusion and just keep them in numerical order. -Create **data/pokemon/dex_entries/munchlax.asm**: - -```diff -+ db "BIG EATER@" ; species name -+ dw 200, 2315 ; height, weight -+ -+ db "In its desperation" -+ next "to gulp down food," -+ next "it forgets about" -+ -+ page "the food it has" -+ next "hidden under its" -+ next "fur.@" -``` - -- The species name can be up to 10 characters (technically 11 will still fit in the Pokédex window). Be sure to end it with a "@". -- The height and weight values are in imperial units. 200 = 2 feet 0 inches; 2315 = 231.5 pounds. -- The entry text is in two pages; the first starts with `db`, the second with `page`. Each page can fit three lines with 18 characters each. Here it's visual size that matters—`"#MON"` counts as 7 characters because it prints as "POKéMON". Again, be sure to end it with a "@". - Now the Pokédex entry exists, and will be listed correctly in "Old Pokédex Mode" (the Gen 2 equivalent of national order). But we need to define the new Pokémon's place in "New Pokédex Mode (regional order) and "A to Z Mode" (alphabetical order). Edit [data/pokemon/dex_order_new.asm](../blob/master/data/pokemon/dex_order_new.asm): @@ -365,9 +365,15 @@ Then edit [data/pokemon/dex_order_new.asm](../blob/master/data/pokemon/dex_order That's all for the Pokédex. -## 9. Define its footprint +## 9. Design its footprint -Edit [gfx/footprints.asm](../blob/master/gfx/footprints.asm): +Create **gfx/footprints/munchlax.png**: + + + +Running `make` will automatically create munchlax.1bpp from munchlax.png. Since it's a 1bpp file (**one** **b**it **p**er **p**ixel) you can only use black and white in the image. + +Then edit [gfx/footprints.asm](../blob/master/gfx/footprints.asm): ```diff ; Footprints are 2x2 tiles each, but are stored as a 16x64-tile image @@ -406,14 +412,8 @@ Edit [gfx/footprints.asm](../blob/master/gfx/footprints.asm): Notice how the footprints are broken into top and bottom halves; you may want to [correct this design flaw](../blob/master/docs/design_flaws.md#footprints-are-split-into-top-and-bottom-halves). (It won't have a visible consequence on the game, but it makes for cleaner code and data.) -Create **gfx/footprints/munchlax.png**: - - - -Running `make` will automatically create munchlax.1bpp from munchlax.png. Since it's a 1bpp file (**one** **b**it **p**er **p**ixel) you can only use black and white in the image. - -## 10. Define its sprites and animation +## 10. Design its sprites and animation This is a bit complicated. We need a front sprite with an animation sequence; a back sprite; and normal and shiny color palettes for both. @@ -451,7 +451,7 @@ Now create **gfx/pokemon/munchlax/anim.asm**: + endanim ``` -And **gfx/pokemon/munchlax/anim_idle.asm**: +And finally **gfx/pokemon/munchlax/anim_idle.asm**: ```diff + frame 1, 08 @@ -515,7 +515,7 @@ Edit [gfx/pics.asm](../blob/master/gfx/pics.asm): (If you *don't* fix the `dba_pic` design flaw, you'll have to put your sprites in the "Pics" sections, which are compatible with `dba_pic`. "Pics 19" isn't used for anything useful—all its contents are unused duplicates of "Pics 18"—so it's the easiest place to start adding new sprites. But if you have a lot of new sprites to add, you risk overflowing the banks, and it's hard to fit sprites within fixed bank limits. By using just `dba`, you can create new `SECTION`s with a few sprites each, that will automatically be placed wherever they can fit in the ROM.) -Edit [data/pokemon/palettes.asm](../blob/master/data/pokemon/palettes.asm): +Anyway, edit [data/pokemon/palettes.asm](../blob/master/data/pokemon/palettes.asm): ```diff PokemonPalettes: ; a8ce diff --git a/Add-a-new-TM.md b/Add-a-new-TM.md index 0e41f46..7e3fdb0 100644 --- a/Add-a-new-TM.md +++ b/Add-a-new-TM.md @@ -7,7 +7,7 @@ This tutorial is for how to add a new TM. As an example, we'll add TM51 Aeroblas 2. [Define standard item data](#2-define-standard-item-data) 3. [Update the TM/HM move table](#3-update-the-tmhm-move-table) 4. [Add the TM to base learnsets](#4-add-the-tm-to-base-learnsets) -5. [Adding many new TMs](#5-adding-many-new-tms) +5. [Adding up to 120 new TMs](#5-adding-up-to-120-new-tms) ## 1. Define constants with `add_tm` @@ -119,7 +119,7 @@ Anyway, that's all:  -## 5. Adding many new TMs +## 5. Adding up to 120 new TMs There are 50 TMs, 7 HMs, and 3 tutor moves; they each have an associated `*_TMNUM` constant, from 1 to 60. Adding TM51 Aeroblast brings the total to 61. If you end up with more than 64 learnable moves, you'll have to start updating the `tmhm` macro in [data/pokemon/base_stats.asm](../blob/master/data/pokemon/base_stats.asm). @@ -228,7 +228,13 @@ Here's how to add a tenth byte (which also needs a fourth variable), allowing up You can probably continue the pattern from here. The fourth variable `tms4` will let you output 10, 11, or 12 bytes; then if you need more than 96 learnable moves, you can add a fifth variable and output 13, 14, or 15 bytes for up to 120 learnable moves; and so on. -Actually, as soon as you add that tenth byte, the base data will become too large to fit in a ROM bank. You'll get an error when you run `make`: "Section 'bank14' is too big (max size = 0x4000 bytes)." One way to fix this is to remove the six unknown/padding bytes from all the base data. +Actually, as soon as you add that tenth byte, the base data will become too large to fit in a ROM bank. You'll get an error when you run `make`: + +``` +error: Section 'bank14' is too big (max size = 0x4000 bytes). +``` + +One way to fix this is to remove the six unknown/padding bytes from all the base data. First edit all the base data files, removing these three lines from each: diff --git a/Add-a-new-music-song.md b/Add-a-new-music-song.md index 06b7308..89d01d4 100644 --- a/Add-a-new-music-song.md +++ b/Add-a-new-music-song.md @@ -3,13 +3,13 @@ This tutorial is for how to add a new music song. As an example, we'll add the [ ## Contents -1. [Define a `MUSIC_*` constant](#1-define-a-music_-constant) +1. [Define a music constant](#1-define-a-music-constant) 2. [Create a file for the song](#2-create-a-file-for-the-song) 3. [Update the music pointers](#3-update-the-music-pointers) 4. [Include the new file in the ROM](#4-include-the-new-file-in-the-rom) -## 1. Define a `MUSIC_*` constant +## 1. Define a music constant Edit [constants/music_constants.asm](../blob/master/constants/music_constants.asm): diff --git a/Add-a-new-trainer-class.md b/Add-a-new-trainer-class.md new file mode 100644 index 0000000..e52a019 --- /dev/null +++ b/Add-a-new-trainer-class.md @@ -0,0 +1,403 @@ +This tutorial is for how to add a new trainer class. As an example, we'll add the Parasol Lady class. + + +## Contents + +1. [Define a trainer class constant](#1-define-a-trainer-class-constant) +2. [Give them a name](#2-give-them-a-name) +3. [Define their attributes](#3-define-their-attributes) +4. [Define their DVs](#4-define-their-dvs) +5. [Define their encounter music](#5-define-their-encounter-music) +6. [Define their individual parties](#6-define-their-individual-parties) +7. [Design their sprite](#7-design-their-sprite) +8. [Define their Battle Tower sprite and gender](#8-define-their-battle-tower-sprite-and-gender) +9. [Fix bank overflow errors](#9-fix-bank-overflow-errors) + + +## 1. Define a trainer class constant + +Edit [constants/trainer_constants.asm](../blob/master/constants/trainer_constants.asm): + +```diff + ; trainer class ids + ; `trainerclass` indexes are for: + ; - TrainerClassNames (see data/trainers/class_names.asm) + ; - TrainerClassAttributes (see data/trainers/attributes.asm) + ; - TrainerClassDVs (see data/trainers/dvs.asm) + ; - TrainerGroups (see data/trainers/party_pointers.asm) + ; - TrainerEncounterMusic (see data/trainers/encounter_music.asm) + ; - TrainerPicPointers (see data/trainers/pic_pointers.asm) + ; - TrainerPalettes (see data/trainers/palettes.asm) + ; - BTTrainerClassSprites (see data/trainers/sprites.asm) + ; - BTTrainerClassGenders (see data/trainers/genders.asm) + ; trainer constants are Trainers indexes, for the sub-tables of TrainerGroups (see data/trainers/parties.asm) + enum_start + CHRIS EQU __enum__ + trainerclass TRAINER_NONE ; 0 + ... + + KRIS EQU __enum__ + trainerclass FALKNER ; 1 + const FALKNER1 + + ... + + trainerclass MYSTICALMAN ; 43 + const EUSINE + ++ trainerclass PARASOL_LADY ++ const SUE + + NUM_TRAINER_CLASSES EQU __enum__ +``` + +The `trainerclass` macro defines the next trainer class constant, and prepares to define a sequence of constants for individual trainers. Here we've defined `SUE` as the only Parasol Lady. + +(Note the `CHRIS` and `KRIS` constants, equal to 0 and 1 respectively; they're used for getting the correct color palette when displaying the player's sprite in the introduction and on the trainer card. `KRIS` is equal to `FALKNER`, which is why they share a palette.) + +Be careful when naming trainer constants; either make them unique, or make them unambiguous (like `BUG_CATCHER_BENNY` and `BIKER_BENNY`). I once made a trainer constant `SPARK` and caused a bug because `SPARK` was already a move constant. (That's why `BLACKBELT_T` and `PSYCHIC_T` have the `_T` suffix, since `BLACKBELT` is an item and `PSYCHIC` is a type.) + +Next we'll add data for the new `PARASOL_LADY` class to all those tables mentioned in the top comment. + + +## 2. Give them a name + +Edit [data/trainers/class_names.asm](../blob/master/data/trainers/class_names.asm): + +```diff + TrainerClassNames:: ; 2c1ef + ; entries correspond to trainer classes (see constants/trainer_constants.asm) + db "LEADER@" + ... + db "MYSTICALMAN@" ++ db "PARASOL LADY@" +``` + +A name can be up to 12 characters long, plus a "@" at the end. Note that the trainer class and individual name will get printed on one line in phrases like "PARASOL LADY SUE wants to battle!" so make sure the whole phrase will fit in 18 characters. + + +## 3. Define their attributes + +Edit [data/trainers/attributes.asm](../blob/master/data/trainers/attributes.asm): + +```diff + TrainerClassAttributes: ; 3959c + ; entries correspond to trainer classes (see constants/trainer_constants.asm) + + ; Falkner + db NO_ITEM, NO_ITEM ; items + db 25 ; base reward + dw AI_BASIC | AI_SETUP | AI_SMART | AI_AGGRESSIVE | AI_CAUTIOUS | AI_STATUS | AI_RISKY + dw CONTEXT_USE | SWITCH_SOMETIMES + + ... + + ; Mysticalman + db NO_ITEM, NO_ITEM ; items + db 25 ; base reward + dw AI_BASIC | AI_SETUP | AI_SMART | AI_AGGRESSIVE | AI_CAUTIOUS | AI_STATUS | AI_RISKY + dw CONTEXT_USE | SWITCH_SOMETIMES ++ ++; Parasol Lady ++ db NO_ITEM, NO_ITEM ; items ++ db 10 ; base reward ++ dw AI_BASIC | AI_TYPES | AI_OPPORTUNIST | AI_STATUS ++ dw CONTEXT_USE | SWITCH_SOMETIMES + + ; 39771 +``` + +"Attributes" encompass a number of different properties: + +- **items:** Two items, each of which a trainer can use once. They may be the same item or `NO_ITEM`. The AI engine has to know how to use the items, as defined by `AI_Items` in [engine/battle/ai/items.asm](../blob/master/engine/battle/ai/items.asm). +- **base reward:** The base monetary reward for beating a trainer. The reward amount is 4×*B*×*L*, where *B* is the base reward and *L* is the level of the last Pokémon they used. +- **AI flags (move weights):** Bit flags that control how the trainer's AI chooses a move to use. Valid flags: + - `NO_AI`: + - `AI_BASIC`: + - `AI_SETUP`: + - `AI_TYPES`: + - `AI_OFFENSIVE`: + - `AI_SMART`: + - `AI_OPPORTUNIST`: + - `AI_AGGRESSIVE`: + - `AI_CAUTIOUS`: + - `AI_STATUS`: + - `AI_RISKY`: +- **AI flags (item/switch):** Bit flags that control how the trainer's AI chooses to use an item or switch Pokémon instead of attacking. Combine one `*_USE` flag and one `SWITCH_*` flag. Valid flags: + - `CONTEXT_USE`: + - `UNKNOWN_USE`: + - `ALWAYS_USE`: + - `SWITCH_SOMETIMES`: + - `SWITCH_RARELY`: + - `SWITCH_OFTEN`: + + +## 4. Define their DVs + +Edit [data/trainers/dvs.asm](../blob/master/data/trainers/dvs.asm): + +```diff + TrainerClassDVs: ; 270d6 + ; entries correspond to trainer classes (see constants/trainer_constants.asm) + ; Atk Spd + ; Def Spc + db $9A, $77 ; falkner + ... + db $98, $88 ; mysticalman ++ db $78, $88 ; parasol lady + ; 2715c +``` + +The four digits define, in order, the Attack, Defense, Speed, and Special DVs for all the trainer class's Pokémon. (Remember, in Gen 2 there was one DV for both Special Attack and Special Defense; and bits from all four DVs were combined to calculate HP.) + +So that trainers' genders would correspond with those of their Pokémon, female trainer classes tend to have low Attack DVs (since gender in Gen 2 was determined by the Attack and Speed DVs, primarily Attack). Gym Leaders are mostly an exception to this rule. + + +## 5. Define their encounter music + +Edit [data/trainers/encounter_music.asm](../blob/master/data/trainers/encounter_music.asm): + +```diff + TrainerEncounterMusic:: + ; entries correspond to trainer classes (see constants/trainer_constants.asm) + db MUSIC_HIKER_ENCOUNTER ; none + ... + db MUSIC_HIKER_ENCOUNTER ; mysticalman + db MUSIC_BEAUTY_ENCOUNTER ; parasol lady +- db MUSIC_HIKER_ENCOUNTER +- db MUSIC_HIKER_ENCOUNTER +- db MUSIC_HIKER_ENCOUNTER +``` + +There aren't many to choose from; it's usually `MUSIC_YOUNGSTER_ENCOUNTER` or `MUSIC_HIKER_ENCOUNTER` for male trainers, `MUSIC_LASS_ENCOUNTER` or `MUSIC_BEAUTY_ENCOUNTER` for female ones, plus some more specialized `MUSIC_*_ENCOUNTER` tunes. + +Notice that we removed three extra `MUSIC_HIKER_ENCOUNTER`s at the end without any corresponding trainer classes. + +If you want different music to play *during* battle, you'll need to edit `PlayBattleMusic` in [engine/battle/start_battle.asm](../blob/master/engine/battle/start_battle.asm). It's a series of [hard-coded logic](Hard-coded-logic#trainer-classes-with-different-battle-music) checks for various conditions under which to play special battle music. Decide carefully where to place a check for your new condition—like whether `[wOtherTrainerClass]` is `PARASOL_LADY`, or whether `[wOtherTrainerClass]` is `PARASOL_LADY` *and* `[wOtherTrainerID]` is `SUE`—so that you don't break assumptions made by the other checks. + + +## 6. Define their individual parties + +Edit [data/trainers/party_pointers.asm](../blob/master/data/trainers/party_pointers.asm): + +```diff + TrainerGroups: ; 0x39999 + ; entries correspond to trainer classes (see constants/trainer_constants.asm) + dw FalknerGroup + ... + dw MysticalmanGroup ++ dw ParasolLadyGroup +``` + +Then edit [data/trainers/parties.asm](../blob/master/data/trainers/parties.asm): + +```diff + FalknerGroup: + ; FALKNER (1) + db "FALKNER@", TRAINERTYPE_MOVES + db 7, PIDGEY, TACKLE, MUD_SLAP, NO_MOVE, NO_MOVE + db 9, PIDGEOTTO, TACKLE, MUD_SLAP, GUST, NO_MOVE + db -1 ; end + + + ... + + + MysticalmanGroup: + ; MYSTICALMAN (1) + db "EUSINE@", TRAINERTYPE_MOVES + db 23, DROWZEE, DREAM_EATER, HYPNOSIS, DISABLE, CONFUSION + db 23, HAUNTER, LICK, HYPNOSIS, MEAN_LOOK, CURSE + db 25, ELECTRODE, SCREECH, SONICBOOM, THUNDER, ROLLOUT + db -1 ; end ++ ++ ++ParasolLadyGroup: ++ ; PARASOL_LADY (1) ++ db "SUE@", TRAINERTYPE_NORMAL ++ db 28, GOLDEEN ++ db 30, GOLDUCK ++ db -1 ; end +``` + +The comment at the top of parties.asm explains the data structure: + +``` +; Trainer data structure: +; - db "NAME@", TRAINERTYPE_* constant +; - 1 to 6 Pokémon: +; * for TRAINERTYPE_NORMAL: db level, species +; * for TRAINERTYPE_ITEM: db level, species, item +; * for TRAINERTYPE_MOVES: db level, species, 4 moves +; * for TRAINERTYPE_ITEM_MOVES: db level, species, item, 4 moves +; - db -1 ; end +``` + + +## 7. Design their sprite + +Create **gfx/trainers/parasol_lady.png**: + + + +Trainer sprites are all 56x56 pixels, and use four colors: white, black, and two arbitrary hues. + +Next edit [data/trainers/pic_pointers.asm](../blob/master/data/trainers/pic_pointers.asm): + +```diff + TrainerPicPointers:: + ; entries correspond to trainer classes (see constants/trainer_constants.asm) + dba_pic FalknerPic + ... + dba_pic MysticalmanPic ++ dba_pic ParasolLadyPic +``` + +We have to use `dba_pic` here instead of a standard `dba`—declaring the bank and address of `ParasolLadyPic`—because of [this design flaw](../blob/master/docs/design_flaws.md#pic-banks-are-offset-by-pics_fix). I strongly recommend removing the whole `FixPicBank` routine from [engine/gfx/load_pics.asm](../blob/master/engine/gfx/load_pics.asm), including both calls to it in that file, and just using `dba` here; then you'll be able to `INCBIN` sprites in arbitrary banks. + +Edit [gfx/pics.asm](../blob/master/gfx/pics.asm): + +```diff + SECTION "Pics 19", ROMX + +-; Seems to be an accidental copy of the previous bank +- +-INCBIN "gfx/pokemon/spinarak/back.2bpp.lz" +-... +-INCBIN "gfx/pokemon/unown_r/back.2bpp.lz" ++ParasolLadyPic: INCBIN "gfx/trainers/parasol_lady.2bpp.lz" +``` + +(If you *don't* fix the `dba_pic` design flaw, you'll have to put your sprites in the "Pics" sections, which are compatible with `dba_pic`. "Pics 19" isn't used for anything useful—all its contents are unused duplicates of "Pics 18"—so it's the easiest place to start adding new sprites. But if you have a lot of new sprites to add, you risk overflowing the banks, and it's hard to fit sprites within fixed bank limits. By using just `dba`, you can create new `SECTION`s with a few sprites each, that will automatically be placed wherever they can fit in the ROM.) + +Anyway, edit [data/trainers/palettes.asm](../blob/master/data/trainers/palettes.asm): + +```diff + TrainerPalettes: ; b0ce + ; entries correspond to trainer classes + + PlayerPalette: ; Chris uses the same colors as Cal + INCLUDE "gfx/trainers/cal.pal" + KrisPalette: ; Kris shares Falkner's palette + INCLUDE "gfx/trainers/falkner.pal" + ... + INCLUDE "gfx/trainers/mysticalman.pal" ++INCLUDE "gfx/trainers/parasol_lady.pal" + ; b1de +``` + +parasol_lady.2bpp.lz and parasol_lady.pal will be automatically generated from parasol_lady.png when you run `make`. + + +## 8. Define their Battle Tower sprite and gender + +If a trainer class is used in Battle Tower, as defined in [data/battle_tower/classes.asm](../blob/master/data/battle_tower/classes.asm), it will need a defined sprite and gender. The sprite is used when the trainer walks into the room, and their gender determines what they say. Even if you don't add a Parasol Lady to the Battle Tower roster, it's helpful to keep the data tables up-to-date. + +Edit [data/trainers/sprites.asm](../blob/master/data/trainers/sprites.asm): + +```diff + BTTrainerClassSprites: + ; entries correspond to trainer classes + db SPRITE_FALKNER + ... + db SPRITE_ROCKET_GIRL ++ db SPRITE_SUPER_NERD ++ db SPRITE_TEACHER +``` + +Valid sprites are in [constants/sprite_constants.asm](../blob/master/constants/sprite_constants.asm). They're for the 16x16 overworld sprites, not the 56x56 battle sprites. Adding a custom sprite is beyond the scope of this tutorial. + +Notice that there was no sprite for `MYSTICALMAN`, so we had to add one so that `SPRITE_TEACHER` would correspond with `PARASOL_LADY`. + +Anyway, edit [data/trainers/genders.asm](../blob/master/data/trainers/genders.asm): + +```diff + BTTrainerClassGenders: ; 11f2f0 + ; entries correspond to trainer classes + db MALE ; FALKNER + ... + db FEMALE ; GRUNTF ++ db MALE ; MYSTICALMAN ++ db FEMALE ; PARASOL_LADY + ; 11f332 +``` + +Again, we had to add data for `MYSTICALMAN` to reach the slot for `PARASOL_LADY`. + +Also edit [data/trainers/gendered_trainers.asm](../blob/master/data/trainers/gendered_trainers.asm): + +```diff + FemaleTrainers: ; 4e976 + db MEDIUM + db LASS + db BEAUTY + db SKIER + db TEACHER + db SWIMMERF + db PICNICKER + db KIMONO_GIRL + db POKEFANF + db COOLTRAINERF ++ db PARASOL_LADY + .End +``` + +For whatever reason, trainers' gender is checked in two redundant ways, so we just have to keep both tables up-to-date. + + +## 9. Fix bank overflow errors + +We're done adding the Parasol Lady data, but `make` won't compile the ROM: + +``` +error: Unable to place 'Pics 3' (ROMX section) at $40CC in bank $4A +``` + +But we didn't change anything in "Pics 3", so why is this happening? + +As defined in [pokecrystal.link](../blob/master/pokecrystal.link), the "Trainer Pic Pointers" and "Pics 3" sections are both in bank $4A: + +``` +ROMX $4a + "Trainer Pic Pointers" + "Pics 3" +``` + +It turns out that adding `dba_pic ParasolLadyPic` to the `TrainerPicPointers` table was a little too much data for that bank. To fix this, we'll need to move some data our of bank $4A. "Trainer Pic Pointers" has to be as large as it is, but "Pics 3" is an arbitrary set of sprites, so we can move one of those. + +Edit [gfx/pics.asm](../blob/master/gfx/pics.asm) again: + +```diff + SECTION "Pics 3", ROMX + + SteelixFrontpic: INCBIN "gfx/pokemon/steelix/front.animated.2bpp.lz" + AlakazamFrontpic: INCBIN "gfx/pokemon/alakazam/front.animated.2bpp.lz" + GyaradosFrontpic: INCBIN "gfx/pokemon/gyarados/front.animated.2bpp.lz" + KangaskhanFrontpic: INCBIN "gfx/pokemon/kangaskhan/front.animated.2bpp.lz" + RhydonFrontpic: INCBIN "gfx/pokemon/rhydon/front.animated.2bpp.lz" + GolduckFrontpic: INCBIN "gfx/pokemon/golduck/front.animated.2bpp.lz" + RhyhornFrontpic: INCBIN "gfx/pokemon/rhyhorn/front.animated.2bpp.lz" + PidgeotFrontpic: INCBIN "gfx/pokemon/pidgeot/front.animated.2bpp.lz" + SlowbroFrontpic: INCBIN "gfx/pokemon/slowbro/front.animated.2bpp.lz" + ButterfreeFrontpic: INCBIN "gfx/pokemon/butterfree/front.animated.2bpp.lz" + WeezingFrontpic: INCBIN "gfx/pokemon/weezing/front.animated.2bpp.lz" + CloysterFrontpic: INCBIN "gfx/pokemon/cloyster/front.animated.2bpp.lz" + SkarmoryFrontpic: INCBIN "gfx/pokemon/skarmory/front.animated.2bpp.lz" + DewgongFrontpic: INCBIN "gfx/pokemon/dewgong/front.animated.2bpp.lz" + VictreebelFrontpic: INCBIN "gfx/pokemon/victreebel/front.animated.2bpp.lz" + RaichuFrontpic: INCBIN "gfx/pokemon/raichu/front.animated.2bpp.lz" + PrimeapeFrontpic: INCBIN "gfx/pokemon/primeape/front.animated.2bpp.lz" +-OmastarBackpic: INCBIN "gfx/pokemon/omastar/back.2bpp.lz" + ; 12bffe + + ... + + SECTION "Pics 19", ROMX + + ParasolLadyPic: INCBIN "gfx/trainers/parasol_lady.2bpp.lz" ++OmastarBackpic: INCBIN "gfx/pokemon/omastar/back.2bpp.lz" +``` + +Now we're done! You can write an event script that uses Parasol Lady Sue just like any other trainer. + + diff --git a/Tutorials.md b/Tutorials.md index 8e64d6d..84da5fd 100644 --- a/Tutorials.md +++ b/Tutorials.md @@ -10,6 +10,7 @@ Tutorials may use diff syntax to show edits: **How to add a new…** - [Pokémon species](Add-a-new-Pokémon) +- [Trainer class](Add-a-new-trainer-class) - [Type (Fairy)](Add-a-new-Fairy-type) - [Item (including a healing item, held item, Poké Ball, evolution stone, Town Map, etc)](Add-different-kinds-of-new-items) - [TM (up to 120 TMs)](Add-a-new-TM) diff --git a/screenshots/gfx-trainers-parasol_lady.png b/screenshots/gfx-trainers-parasol_lady.png Binary files differnew file mode 100644 index 0000000..2e28c4a --- /dev/null +++ b/screenshots/gfx-trainers-parasol_lady.png diff --git a/screenshots/parasol-lady-sue.png b/screenshots/parasol-lady-sue.png Binary files differnew file mode 100644 index 0000000..87b435b --- /dev/null +++ b/screenshots/parasol-lady-sue.png |