diff options
-rw-r--r-- | Add-a-new-TM.md | 272 | ||||
-rw-r--r-- | Tutorials.md | 1 | ||||
-rw-r--r-- | screenshots/tm51-aeroblast.png | bin | 0 -> 2247 bytes |
3 files changed, 273 insertions, 0 deletions
diff --git a/Add-a-new-TM.md b/Add-a-new-TM.md new file mode 100644 index 0000000..7bd4eba --- /dev/null +++ b/Add-a-new-TM.md @@ -0,0 +1,272 @@ +This tutorial is for how to add a new TM. As an example, we'll add TM51 Aeroblast. + + +## Contents + +1. [Define constants with `add_tm`](#1-define-constants-with-add_tm) +2. [Define standard item data](#2-define-standard-item-data) +3. [Update the TM/HM move table](#3-update-the-tm-hm-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) + + +## 1. Define constants with `add_tm` + +Edit [constants/item_constants.asm](../blob/master/constants/item_constants.asm): + +```diff + add_tm: MACRO + if !DEF(TM01) + TM01 = const_value + enum_start 1 + endc + define _\@_1, "TM_\1" + const _\@_1 + enum \1_TMNUM + ENDM + + ; see data/moves/tmhm_moves.asm for moves + add_tm DYNAMICPUNCH ; bf + ... + add_tm NIGHTMARE ; f2 ++ add_tm AEROBLAST + NUM_TMS = const_value - TM01 - 2 ; discount ITEM_C3 and ITEM_DC +``` + +The `add_tm` macro will simultaneously define the next item constant `TM_AEROBLAST` and the `TMNUM` constant `AEROBLAST_TMNUM` (equal to 51). The item constant is used for `giveitem` scripts, in Mart inventories, etc. The `TMNUM` constant is not used directly, but gets referred to by the `tmhm` learnsets in Pokémon base data. (We'll get to that later.) + + +## 2. Define standard item data + +First of all, unlike standard items, we don't need to edit [data/items/descriptions.asm](../blob/master/data/items/descriptions.asm) or [data/items/item_effects.asm](../blob/master/data/items/item_effects.asm). The `ItemDescriptions` table already has dummy "?" descriptions for all the items from TM01 and up; and the `ItemEffects` table ends right before TM01 (since TMs and HMs don't use those effects anyway). + +Edit [data/items/names.asm](../blob/master/data/items/names.asm): + +```diff + db "TM50@" ++ db "TM51@" + db "HM01@" + ... + db "HM07@" + db "TERU-SAMA@" +- db "TERU-SAMA@" + db "TERU-SAMA@" + db "TERU-SAMA@" + db "TERU-SAMA@" + db "TERU-SAMA@" + db "?@" +``` + +Edit [data/items/attributes.asm](../blob/master/data/items/attributes.asm): + +```diff + ; TM50 + item_attribute 2000, HELD_NONE, 0, CANT_SELECT, TM_HM, ITEMMENU_PARTY, ITEMMENU_NOUSE ++; TM51 ++ item_attribute 2000, HELD_NONE, 0, CANT_SELECT, TM_HM, ITEMMENU_PARTY, ITEMMENU_NOUSE + ; HM01 + item_attribute 0, HELD_NONE, 0, CANT_SELECT | CANT_TOSS, TM_HM, ITEMMENU_PARTY, ITEMMENU_NOUSE + ... + ; HM07 + item_attribute 0, HELD_NONE, 0, CANT_SELECT | CANT_TOSS, TM_HM, ITEMMENU_PARTY, ITEMMENU_NOUSE + ; ITEM_FA + item_attribute $9999, HELD_NONE, 0, NO_LIMITS, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE +-; $fb +- item_attribute $9999, HELD_NONE, 0, NO_LIMITS, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE + ; $fc + item_attribute $9999, HELD_NONE, 0, NO_LIMITS, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE + ; $fd + item_attribute $9999, HELD_NONE, 0, NO_LIMITS, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE + ; $fe + item_attribute $9999, HELD_NONE, 0, NO_LIMITS, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE + ; $ff + item_attribute $9999, HELD_NONE, 0, NO_LIMITS, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE + ; $00 + item_attribute $9999, HELD_NONE, 0, NO_LIMITS, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE +``` + +Notice how the `ItemNames` and `ItemAttributes` both already had the maximum 256 entries, so we had to remove dummy entries to add the TM51 ones. And there aren't many dummy entries; 251 items are defined, from $00 to $FA. If you want a lot of new TMs, you'll have to remove some unused items. There are 26 unused <code>ITEM_<i>XX</i></code> constants, counting `ITEM_C3` and `ITEM_DC`, which interrupt the sequence of TMs and need [a bit of special handling](../blob/master/docs/design_flaws.md#item_c3-and-item_dc-break-up-the-continuous-sequence-of-tm-items) to remove. + + +## 3. Update the TM/HM move table + +Edit [data/moves/tmhm_moves.asm](../blob/master/data/moves/tmhm_moves.asm): + +```diff + TMHMMoves: ; 1167a + ; entries correspond to *_TMNUM enums (see constants/item_constants.asm) + ; TMs + db DYNAMICPUNCH + ... + db NIGHTMARE ++ db AEROBLAST +``` + +This associates the `AEROBLAST_TMNUM` TM/HM constant with the `AEROBLAST` move constant. + + +## 4. Add the TM to base learnsets + +So far we've created a TM51 item and assigned it a move, but nothing can learn it. Edit the `tmhm` entries in [data/pokemon/base_stats/](../blob/master/data/pokemon/base_stats/): + +- [lugia.asm](../blob/master/data/pokemon/base_stats/lugia.asm): `..., NIGHTMARE, FLY, ...` → `..., NIGHTMARE, AEROBLAST, FLY, ...` +- [mew.asm](../blob/master/data/pokemon/base_stats/mew.asm): `..., NIGHTMARE, CUT, ...` → `..., NIGHTMARE, AEROBLAST, CUT, ...` + +The learnable moves have to be in the correct order. The `tmhm` macro appends "`_TMNUM`" to all of those while doing its thing, so if you had `add_tm AEROBLAST` associated with `SACRED_FIRE` in `TMHMMoves`, you'd still have to use "`AEROBLAST`" in the base learnsets. + +Anyway, that's all: + + + + +## 5. Adding many 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). + +Here's the macro as-is: + +``` +tmhm: MACRO +; used in data/pokemon/base_stats/*.asm +tms1 = 0 ; TM01-TM24 (24) +tms2 = 0 ; TM25-TM48 (24) +tms3 = 0 ; TM49-TM50 + HM01-HM07 + MT01-MT03 (12/24) +rept _NARG + if DEF(\1_TMNUM) + if \1_TMNUM < 24 + 1 +tms1 = tms1 | (1 << ((\1_TMNUM) - 1)) + elif \1_TMNUM < 48 + 1 +tms2 = tms2 | (1 << ((\1_TMNUM) - 1 - 24)) + else +tms3 = tms3 | (1 << ((\1_TMNUM) - 1 - 48)) + endc + else + fail "\1 is not a TM, HM, or move tutor move" + endc + shift +endr +rept 3 ; TM01-TM24 (24/24) + db tms1 & $ff +tms1 = tms1 >> 8 +endr +rept 3 ; TM25-TM48 (24/24) + db tms2 & $ff +tms2 = tms2 >> 8 +endr +rept 2 ; TM49-TM50 + HM01-HM07 + MT01-MT03 (12/16) + db tms3 & $ff +tms3 = tms3 >> 8 +endr +ENDM +``` + +Basically it defines three variables `tms1`, `tms2`, and `tms3`, each of which can hold up to three bytes (that's 24 bits), and sets their bits according to which moves were listed; then it outputs those variables one byte at a time with `db` statements. Three variables with 24 bits each are sufficient for 72 learnable moves, but only eight `db`s are output, so beyond 64 moves we already have to update `tmhm`. + +Here's how to output a ninth byte, allowing up to 72 learnable moves: + +```diff + rept 3 ; TM01-TM24 (24/24) + db tms1 & $ff + tms1 = tms1 >> 8 + endr + rept 3 ; TM25-TM48 (24/24) + db tms2 & $ff + tms2 = tms2 >> 8 + endr +-rept 2 ; TM49-TM50 + HM01-HM07 + MT01-MT03 (12/16) ++rept 3 ; TM49-TM72 (24/24) + db tms3 & $ff + tms3 = tms3 >> 8 + endr +``` + +Here's how to add a tenth byte (which also needs a fourth variable), allowing up to 80 learnable moves: + +```diff + tmhm: MACRO + ; used in data/pokemon/base_stats/*.asm + tms1 = 0 ; TM01-TM24 (24) + tms2 = 0 ; TM25-TM48 (24) + tms3 = 0 ; TM49-TM50 + HM01-HM07 + MT01-MT03 (12/24) ++tms4 = 0 ; TM73-TM96 (24/24) + rept _NARG + if DEF(\1_TMNUM) + if \1_TMNUM < 24 + 1 + tms1 = tms1 | (1 << ((\1_TMNUM) - 1)) + elif \1_TMNUM < 48 + 1 + tms2 = tms2 | (1 << ((\1_TMNUM) - 1 - 24)) +- else ++ elif \1_TMNUM < 72 + 1 + tms3 = tms3 | (1 << ((\1_TMNUM) - 1 - 48)) ++ else ++tms4 = tms3 | (1 << ((\1_TMNUM) - 1 - 72)) + endc + else + fail "\1 is not a TM, HM, or move tutor move" + endc + shift + endr + rept 3 ; TM01-TM24 (24/24) + db tms1 & $ff + tms1 = tms1 >> 8 + endr + rept 3 ; TM25-TM48 (24/24) + db tms2 & $ff + tms2 = tms2 >> 8 + endr +-rept 2 ; TM49-TM50 + HM01-HM07 + MT01-MT03 (12/16) ++rept 3 + db tms3 & $ff + tms3 = tms3 >> 8 + endr ++rept 1 ++ db tms4 & $ff ++tms4 = tms4 >> 8 ++endr + ENDM +``` + +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. + +First edit all the base data files, removing these three lines from each: + +- `db 100 ; unknown 1` +- `db 5 ; unknown 2` +- `db 0, 0, 0, 0 ; padding` + +Then edit [wram.asm](../blob/master/wram.asm): + +```diff + ; corresponds to the data/pokemon/base_stats/*.asm contents + wCurBaseData:: ; d236 + wBaseDexNo:: db ; d236 + wBaseStats:: ; d237 + wBaseHP:: db ; d237 + wBaseAttack:: db ; d238 + wBaseDefense:: db ; d239 + wBaseSpeed:: db ; d23a + wBaseSpecialAttack:: db ; d23b + wBaseSpecialDefense:: db ; d23c + wBaseType:: ; d23d + wBaseType1:: db ; d23d + wBaseType2:: db ; d23e + wBaseCatchRate:: db ; d23f + wBaseExp:: db ; d240 + wBaseItems:: ; d241 + wBaseItem1:: db ; d241 + wBaseItem2:: db ; d242 + wBaseGender:: db ; d243 +-wBaseUnknown1:: db ; d244 + wBaseEggSteps:: db ; d245 +-wBaseUnknown2:: db ; d246 + wBasePicSize:: db ; d247 +-wBasePadding:: ds 4 ; d248 + wBaseGrowthRate:: db ; d24c + wBaseEggGroups:: db ; d24d + wBaseTMHM:: flag_array NUM_TM_HM_TUTOR ; d24e + wCurBaseDataEnd:: +``` + +That gives you enough free space for seven extra base data bytes per Pokémon. Plus the eight that are already used for learnable moves, that's up to 15 `tmhm` bytes, which would allow 120 learnable moves: easily enough for the 100 TMs of Gen 7, plus HMs and tutors. diff --git a/Tutorials.md b/Tutorials.md index 4d06e28..9e80d66 100644 --- a/Tutorials.md +++ b/Tutorials.md @@ -11,6 +11,7 @@ Tutorials may use diff syntax to show edits: - [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) - [Music song](Add-a-new-music-song) **Upgrades to existing features:** diff --git a/screenshots/tm51-aeroblast.png b/screenshots/tm51-aeroblast.png Binary files differnew file mode 100644 index 0000000..49bf0d7 --- /dev/null +++ b/screenshots/tm51-aeroblast.png |