summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Add-a-new-TM.md272
-rw-r--r--Tutorials.md1
-rw-r--r--screenshots/tm51-aeroblast.pngbin0 -> 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:
+
+![Screenshot](screenshots/tm51-aeroblast.png)
+
+
+## 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
new file mode 100644
index 0000000..49bf0d7
--- /dev/null
+++ b/screenshots/tm51-aeroblast.png
Binary files differ