This tutorial is for how to add a new TM or HM. As an example, we'll add TM51 Aeroblast and HM08 Softboiled. (I'm using Softboiled as an HM example because it already has a field effect outside of battle. Creating new field-effect moves is beyond the scope of this tutorial.) ## Contents 1. [Define constants with `add_tm` or `add_hm`](#1-define-constants-with-add_tm-or-add_hm) 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 or HM to base learnsets](#4-add-the-tm-or-hm-to-base-learnsets) 5. [Make the HM move unforgettable](#5-make-the-hm-move-unforgettable) 6. [Adding up to 120 new TMs or HMs](#6-adding-up-to-120-new-tms-or-hms) ## 1. Define constants with `add_tm` or `add_hm` Edit [constants/item_constants.asm](../blob/master/constants/item_constants.asm): ```diff add_tm: MACRO if !DEF(TM01) TM01 EQU 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 EQU const_value - TM01 - 2 ; discount ITEM_C3 and ITEM_DC add_hm: MACRO if !DEF(HM01) HM01 EQU const_value endc define _\@_1, "HM_\1" const _\@_1 enum \1_TMNUM ENDM add_hm CUT ; f3 ... add_hm WATERFALL ; f9 + add_hm SOFTBOILED NUM_HMS EQU const_value - HM01 ``` The `add_tm` and `add_hm` macros simultaneously define the next item constant (`TM_AEROBLAST` and `HM_SOFTBOILED` respectively) and the next `TMNUM` constant (`AEROBLAST_TMNUM` and `SOFTBOILED_TMNUM`). The item constants are used for `giveitem` scripts, in Mart inventories, etc. The `TMNUM` constants are not used directly, but get referred to by the `tmhm` learnsets in Pokémon base data. (We'll see how that works later.) (This also demonstrates why Rock Smash would be an inconvenient example for adding a new HM. TM08 is already Rock Smash, and we can't define `ROCK_SMASH_TMNUM` twice, so we would have to do the extra work of replacing TM08 with some other move.) ## 2. Define standard item data First of all, unlike [regular items](Add-a-new-item), 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 "HM08@" db "TERU-SAMA@" - db "TERU-SAMA@" - db "TERU-SAMA@" db "TERU-SAMA@" db "TERU-SAMA@" db "TERU-SAMA@" db "?@" ``` And 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 3000, 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 +; HM08 + 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 fit TM51 and HM08. And there aren't many dummy entries; 251 items are defined, from $00 to $FA. If you want a lot of new TMs or HMs, you'll have to remove some unused items. There are 26 unused ITEM_XX 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: ; entries correspond to *_TMNUM enums (see constants/item_constants.asm) ; TMs db DYNAMICPUNCH ... db NIGHTMARE + db AEROBLAST ; HMs db CUT ... db WATERFALL + db SOFTBOILED ``` This associates the `AEROBLAST_TMNUM` TM/HM constant with the `AEROBLAST` move constant, and the `SOFTBOILED_TMNUM` TM/HM constant with the `SOFTBOILED` move constant. ## 4. Add the TM or HM to base learnsets So far we've created items for TM51 and HM08 and assigned their moves, but the items aren't compatible with any Pokémon. So edit the `tmhm` entries in [data/pokemon/base_stats/\*.asm](../blob/master/data/pokemon/base_stats/): - [chansey.asm](../blob/master/data/pokemon/base_stats/chansey.asm): `..., FLASH, FLAMETHROWER, ...` → `..., FLASH, SOFTBOILED, FLAMETHROWER, ...` - [blissey.asm](../blob/master/data/pokemon/base_stats/blissey.asm): `..., FLASH, FLAMETHROWER, ...` → `..., FLASH, SOFTBOILED, FLAMETHROWER, ...` - [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, ..., WATERFALL, FLAMETHROWER, ...` → `..., NIGHTMARE, AEROBLAST, CUT, ..., WATERFALL, SOFTBOILED, FLAMETHROWER, ...` The learnable moves have to be in the same order as the `add_tm` and `add_hm` lines, since that's what they're referencing: the `tmhm` macro turns `NIGHTMARE` into `NIGHTMARE_TMNUM`, `SOFTBOILED` into `SOFTBOILED_TMNUM`, etc, and then processes them to efficiently store learnsets. (We'll get to the details of how it works next.) ## 5. Make the HM move unforgettable Edit [home/hm_moves.asm](../blob/master/home/hm_moves.asm): ```diff .HMMoves: db CUT db FLY db SURF db STRENGTH db FLASH db WATERFALL db WHIRLPOOL + db SOFTBOILED db -1 ; end ``` Now Softboiled can't be forgotten except via the Move Deleter in Blackthorn City. Anyway, that's all: ![Screenshot](screenshots/tm51-aeroblast-hm08-softboiled.png) ## 6. Adding up to 120 new TMs or HMs There are 50 TMs, 7 HMs, and 3 tutor moves; they each have an associated `*_TMNUM` constant, from 1 to 60. Adding TM51 Aeroblast and HM08 Softboiled brings the total to 62. 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-TM80 (8/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 ; TM49-TM72 (24/24) db tms3 & $ff tms3 = tms3 >> 8 endr +rept 1 ; TM73-TM80 (8/24) + 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`: ``` 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 [data/pokemon/base_stats/\*.asm](../blob/master/data/pokemon/base_stats/) 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. If you somehow need *even more* than that, you can figure out how to save more bytes by packing the base data more compactly.