- 239
- Posts
- 9
- Years
- Seen Apr 17, 2025
I haven't seen an actual tutorial on how to do this, so I figured I would make a step-by-step one to help out any users who might have difficulty. It might work better in a tool, but this gives users the ability to accommodate to their own item ID needs.
Here is a GIF of what the second option looks like
First off, this tutorial is based off of the research and assembly done by Jambo51, and further development from this post, and credit goes to Taの境界 for the initial routines, some of which are optimized/altered here.
Note:
This method allows for a total of 128 TMs/HMs. These TMs have to be in consecutive order with an allowable gap between items. For example, keeping the first 58 TMs/HMs, and starting TMs 51-128 at item ID 375, just after Sapphire). You can play around with the item IDs however you like, but I would recommend having TMs 1-58 in the original location (overwriting HMs 1-8 is fine), and having as small of a gap between TM 58 and TM59 as possible, as it looks the best graphically speaking.
Tools Needed:
Hex Editor
Assembly Compiler (HackMew's is found here)
Step 1: Expanding Items
Step 1a: Repoint Item Data
The original item data is located at 3DB028. There are 375 items, 44 bytes each, for a total of 16500 bytes. (this page contains info on the item data structure)
Take the number of total items you want, and multiply by 44. This is the number of bytes of free space you will now need (eg. you want 400 items: 400*44 = 17600 bytes)
Repoint this data to free space.
Find all pointers (eg. instances of 28 b0 3d 08) and replace with a pointer to your new item data (eg. if you repointed the data to 0x902364, replace all instances of 28 b0 3d 08 with 64 23 90 08)
Step 1b: Repoint Item Images/Palettes
The original data is located at 3D4294. It is laid out as follows: [pointer to image] [pointer to image palette]
So each entry is 8 bytes * 375 items = 3000 bytes long.
Again, take the total number of items you want and multiply by 8 to get the amount of free space you will need (eg. 400 items * 8 = 3200 bytes)
There is only 1 pointer to this data, at 0x9899C. Replace the original pointer with a pointer to your new image/palette data
Step 1c: Remove/Change Limiters
At 0x9a8ae, replace 81 42 01 D8 with 00 00 00 00
At 0x98998, replace 77 01 with your new number of items in hexadecimal, little endian form. For example, if you have 400 items, 400 = 0x190 --> 90 01
Step 2: New TM Moves and Names
This is where is starts getting a bit complicated for generic item IDs.
There are two assembly routines below. The first is the original by Taの境界, and keeps the HMs in the original item ID slots. This somewhat complicates the TM compatibility table (as learning TM51 will be the 59th bit and so forth), and may affect the order of your TMs and HMs, so I would recommend having all TMs in consecutive order with the HMs on the tail end.
To make TM numbers 3 digits long, insert 03 at 0x131db6
To make HM numbers 2 digits long, insert 02 at 0x131d7c
To adjust TM/HM ordering, play with value at 0x9a600. It is currently 0xA9, or TM50 item ID / 2. Setting to the item ID of your FIRST TM / 2 will cause HMs to appear after TMs in the bag.
First Option: If you want to keep HMs 01-08 in their respective move IDs (so order goes TM01,...,HM01,....,HM08,TM51,...,TM120), follow this section:
I will leave the code by Taの境界 the same, as it is already developed for this scenario:
To fix the TM numbers:
1. follow comment instructions in below routine
2. Insert the routine in free space (Note that you must insert the routine at an offset ending in 0,4,8, or C (thumb-aligned offset)
3. insert 01 48 00 47 00 00 (xx+1) xx xx 08 at 0x131D5A. (xx+1) xx xx 08 is the reverse pointer to where you inserted this routine +1 (eg. if you insert at 0x902364, the reverse pointer becomes 65 23 90 08).
To fix the TM move indices:
1. Follow routine instructions
2. Change tm_table address, 0x08YYYYYY, to your new TM Move ID address
2. Compile and insert the following routine into free space (thumb-aligned offset aka ending in 0,4,8, or C)
3. insert 00 49 08 47 (xx+1) xx xx 08 at 0x125A78, where (xx+1) xx xx 08 is the reverse pointer to where you inserted this routine
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Second Option: If you want your TMs in consecutive order with the HMs at the very end (eg. TM01,...,TM120,HM01,...,HM08), follow these instructions:
The following routine gets the move ID from a given item ID (TM ID) value.
Instructions:
1. Follow routine instructions (see below for an example)
2. Insert this routine into free space at a thumb-aligned offset (ending in 0,4,8, or C)
3. Insert 01 48 00 47 00 00 (xx+1) xx xx 08 at 0x131D5A. (xx+1) xx xx 08 is the reverse pointer to where you inserted this routine +1 (eg. if you insert at 0x902364, the reverse pointer becomes 65 23 90 08).
For example, if I have TMs 01-58 in the same item IDs as the original TM 01 - HM08 item IDs and have started with TM59 - TM120 at item ID 375 (just after Sapphire) followed by HM01 - HM08 at item IDs 437 - 444
Eg. As so:
Item ID TM No.
289 TM01
290 TM02
291 TM03
292 TM04
293 TM05
294 TM06
295 TM07
296 TM08
297 TM09
298 TM10
299 TM11
300 TM12
301 TM13
302 TM14
303 TM15
304 TM16
305 TM17
306 TM18
307 TM19
308 TM20
309 TM21
310 TM22
311 TM23
312 TM24
313 TM25
314 TM26
315 TM27
316 TM28
317 TM29
318 TM30
319 TM31
320 TM32
321 TM33
322 TM34
323 TM35
324 TM36
325 TM37
326 TM38
327 TM39
328 TM40
329 TM41
330 TM42
331 TM43
332 TM44
333 TM45
334 TM46
335 TM47
336 TM48
337 TM49
338 TM50
339 TM51
340 TM52
341 TM53
342 TM54
343 TM55
344 TM56
345 TM57
346 TM58
~ ~
375 TM59
376 TM60
377 TM61
378 TM62
379 TM63
380 TM64
381 TM65
382 TM66
383 TM67
384 TM68
385 TM69
386 TM70
387 TM71
388 TM72
389 TM73
390 TM74
391 TM75
392 TM76
393 TM77
394 TM78
395 TM79
396 TM80
397 TM81
398 TM82
399 TM83
400 TM84
401 TM85
402 TM86
403 TM87
404 TM88
405 TM89
406 TM90
407 TM91
408 TM92
409 TM93
410 TM94
411 TM95
412 TM96
413 TM97
414 TM98
415 TM99
416 TM100
417 TM101
418 TM102
419 TM103
420 TM104
421 TM105
422 TM106
423 TM107
424 TM108
425 TM109
426 TM110
427 TM111
428 TM112
429 TM113
430 TM114
431 TM115
432 TM116
433 TM117
434 TM118
435 TM119
436 TM120
437 HM01
438 HM02
439 HM03
440 HM04
441 HM05
442 HM06
443 HM07
444 HM08
Then:
1. 0xXX (first HM) would become 0xDA (keeping the add r0, #0x1 line) -> 0xda * 2 + 1 = 437
2. 0xYY (first TM after item gap) would become 0xBB -> 0xbb * 2 + 1 = 375
3. 0xZZ (num items between TMs) would become 375 - 346 = 29 = 0x1D
4. 0xWW (num items between new HM01 and old HM01) would become 437 - 338 = 99 = 0x63
Note: For the best graphics, I would have TMs 01-75 replace all items up to TM Case, and then start TM 76-128 at item ID 366 (just leaving TM case and Berry Case. These are complicated to repoint, while all other items are simple to repoint to a new item ID. Note that there is a function call (0x9a824) at 0x6a64a that appears to check the item IDs of some of these items. I found no problem with nop-ing out of it, but I have not tested the results fully)
This next routine loads the TM move IDs:
Instructions:
1. replace 0xXX and 0xYY with appropriate vals (see comments)
2. replace 0x08XXXXXX with address of new tm move table
3. compile and insert into thumb-aligned free space (ending in 0,4,8, or C)
4. insert 00 49 08 47 (xx+1) xx xx 08 at 0x125A78, where (xx+1) xx xx 08 is reverse pointer to this routine +1 (eg. inserted at 0x908374 --> 75 83 90 08)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Third Option: Repoint ALL TM data so all TMs are in consecutive order (no item gap)
This routine gets the move ID from the TM move table:
Instructions:
1. change 0xXX to first TM item ID / 2
2. change 0x08XXXXXX to address of repointed TM move table
3. Compile and insert into free space (thumb aligned so that the offset ends in 0,4,8, or C)
4. insert 00 49 08 47 (xx+1) xx xx 08 at 0x125A78, where (xx+1) xx xx 08 is the reverse pointer to the offset +1 (eg. if inserted at 0x904378, --> 79 43 90 08)
This next routine adjusts the TM number in the bag.
Instructions:
1. Fix 0xXX, 0xYY, 0xZZ based on appropriate item IDs
2. compile and insert into free space at a thumb-aligned offset (ends in 0,4,8, or C)
3. insert 01 48 00 47 00 00 (xx+1) xx xx 08 at 0x131D5A, where (xx+1) xx xx 08 is the reverse pointer to this routine +1 (eg. inserted at 0x906714 --> 15 67 90 08)
Step 3: TM Compatability
Step 3a: New Compatibility Table
With 128 TMs/HMs, the new comparability will take 16 bytes per entry. The old data is useless, so find free space in your ROM equivalent to (num_pokemon * 16 bytes each). This routine includes checks for species ID 0x0 and the ??? pokemon between Celebi and Treecko. Therefore, the first entry corresponds to species ID 0x1 and entry 0xFC corresponds to Treecko. If you've managed to use these pokemon species, make sure you edit the routine to accommodate those species IDs
Instructions:
1. replace 0x08XXXXXX with address of new compatibility table address
2a. replace 0xXX with the TM number before the item gap + the number of items in the gap. For example, if you have HM08 or TM58 as item ID 346 and 375 as TM51 or TM59, then 0xXX = 58 + 28 = 0x56)
2b. replace 0xYY with number of items in the gap. eg. from the example in 2a 0xYY would be 28 or 0x1C
3. compile and insert the routine into thumb-aligned free space
4. insert 00 48 00 47 (xx+1) xx xx 08 at 0x43C40
The new TM compatibility is broken into 4 words (4 bytes each), where the first word corresponds to TMs 1-32, then 33-64, and so on. Each bit starting from the far right corresponds to a TM.
For example, if you want to learn TMs 3, 7, 20, 54, 87, and 102:
1-32: 00000000000010000000000001000100
33-64: 00000000001000000000000000000000
65-96: 00000000010000000000000000000000
97-128: 00000000000000000000000000100000
becomes, in hex: [00 08 00 44] [00 20 00 00] [00 40 00 00] [00 00 00 20]
reversing each part and combining:
44 00 08 00 00 00 20 00 00 00 40 00 20 00 00 00
Step 4: Remove TM animation
These routines work perfectly except when replacing an old move with a TM-learned move the game will freeze on the TM use animation. To remove:
1.insert 00 00 at 0x11CE6E
2. insert 00 F0 0E FA at 0x11CA2C
3. insert 00 00 00 00 00 00 00 00 00 00 00 00 44 E0 at 0x11CD9E
Step 5: Expand Bag Item Limit
You'll need JPANs save block hack to allow the item data to save in free RAM.
If you only want to expand the number of TMs, use this routine:
Instructions:
1. change free RAM to your own location
2. compile and insert into a thumb-aligned offset
3. insert 01 48 00 47 00 00 (xx+1 xx xx 08 at 0x99E6A
If you want to expand all the bag items, use this routine:
Instructions:
1. set freeRAM to your own address
2. set number of items you want expanded
3. compile and insert into free space (thumb-aligned offset)
4. 00 48 00 47 (xx+1) xx xx 08 at 99e50
Some Notes:
1. If you add new HMs and the associated move name is 13 characters long, it will string together the next HM name. Here is a fix for this problem:
Instructions:
1. compile and insert into free space
2. insert 00 48 00 47 (xx+1) xx xx 08 at 0x8dac
2. I tried to make this as easy to follow as possible. Please post comments with questions or any bugs/issues you find. There may be mistakes since I copied a lot of data down...
3. If you are adding new HM moves, see this post for adding new field moves. Eg. Rock Climb
Here is a GIF of what the second option looks like
First off, this tutorial is based off of the research and assembly done by Jambo51, and further development from this post, and credit goes to Taの境界 for the initial routines, some of which are optimized/altered here.
Note:
This method allows for a total of 128 TMs/HMs. These TMs have to be in consecutive order with an allowable gap between items. For example, keeping the first 58 TMs/HMs, and starting TMs 51-128 at item ID 375, just after Sapphire). You can play around with the item IDs however you like, but I would recommend having TMs 1-58 in the original location (overwriting HMs 1-8 is fine), and having as small of a gap between TM 58 and TM59 as possible, as it looks the best graphically speaking.
Tools Needed:
Hex Editor
Assembly Compiler (HackMew's is found here)
Step 1: Expanding Items
Spoiler:
Step 1a: Repoint Item Data
The original item data is located at 3DB028. There are 375 items, 44 bytes each, for a total of 16500 bytes. (this page contains info on the item data structure)
Take the number of total items you want, and multiply by 44. This is the number of bytes of free space you will now need (eg. you want 400 items: 400*44 = 17600 bytes)
Repoint this data to free space.
Find all pointers (eg. instances of 28 b0 3d 08) and replace with a pointer to your new item data (eg. if you repointed the data to 0x902364, replace all instances of 28 b0 3d 08 with 64 23 90 08)
Step 1b: Repoint Item Images/Palettes
The original data is located at 3D4294. It is laid out as follows: [pointer to image] [pointer to image palette]
So each entry is 8 bytes * 375 items = 3000 bytes long.
Again, take the total number of items you want and multiply by 8 to get the amount of free space you will need (eg. 400 items * 8 = 3200 bytes)
There is only 1 pointer to this data, at 0x9899C. Replace the original pointer with a pointer to your new image/palette data
Step 1c: Remove/Change Limiters
At 0x9a8ae, replace 81 42 01 D8 with 00 00 00 00
At 0x98998, replace 77 01 with your new number of items in hexadecimal, little endian form. For example, if you have 400 items, 400 = 0x190 --> 90 01
Step 2: New TM Moves and Names
Spoiler:
This is where is starts getting a bit complicated for generic item IDs.
There are two assembly routines below. The first is the original by Taの境界, and keeps the HMs in the original item ID slots. This somewhat complicates the TM compatibility table (as learning TM51 will be the 59th bit and so forth), and may affect the order of your TMs and HMs, so I would recommend having all TMs in consecutive order with the HMs on the tail end.
To make TM numbers 3 digits long, insert 03 at 0x131db6
To make HM numbers 2 digits long, insert 02 at 0x131d7c
To adjust TM/HM ordering, play with value at 0x9a600. It is currently 0xA9, or TM50 item ID / 2. Setting to the item ID of your FIRST TM / 2 will cause HMs to appear after TMs in the bag.
First Option: If you want to keep HMs 01-08 in their respective move IDs (so order goes TM01,...,HM01,....,HM08,TM51,...,TM120), follow this section:
Spoiler:
I will leave the code by Taの境界 the same, as it is already developed for this scenario:
To fix the TM numbers:
1. follow comment instructions in below routine
2. Insert the routine in free space (Note that you must insert the routine at an offset ending in 0,4,8, or C (thumb-aligned offset)
3. insert 01 48 00 47 00 00 (xx+1) xx xx 08 at 0x131D5A. (xx+1) xx xx 08 is the reverse pointer to where you inserted this routine +1 (eg. if you insert at 0x902364, the reverse pointer becomes 65 23 90 08).
Spoiler:
Code:
.text
.align 2
.thumb
.thumb_func
.global tm_name
main:
mov r0, #0xXX @(TM51 item ID - 1) / 2 (eg. if 375 -> 0xXX = 0xBB)
lsl r0, r0, #0x1
cmp r6, r0
bhi new_tm @if item ID of TM51 is even, change to bge
mov r0, #0xA9 @TM50 item ID / 2
lsl r0, r0, #0x1
cmp r6, r0
bls old_tm
ldr r1, temp
ldr r0, return1
bx r0
new_tm:
ldr r1, text_no
mov r0, r5
bl refresh
ldr r4, ram
ldr r0, value
ldr r1, return3
bx r1
old_tm:
ldr r1, return2
bx r1
refresh:
ldr r2, routine
bx r2
.align 2
text_no: .word 0x08416226
routine: .word 0x08008DA5
temp: .word 0x08463178
return1: .word 0x08131D65
return2: .word 0x08131DA5
ram: .word 0x02021CD0
value: .word 0xFFFFFEBC
return3: .word 0x08131DB1
To fix the TM move indices:
1. Follow routine instructions
2. Change tm_table address, 0x08YYYYYY, to your new TM Move ID address
2. Compile and insert the following routine into free space (thumb-aligned offset aka ending in 0,4,8, or C)
3. insert 00 49 08 47 (xx+1) xx xx 08 at 0x125A78, where (xx+1) xx xx 08 is the reverse pointer to where you inserted this routine
Spoiler:
Code:
.text
.align 2
.thumb
.thumb_func
.global TM_index
main:
mov r1, #0xXX @(new first TM item index-1) / 2 (eg. 0xBB if item 375
lsl r1, r1, #0x1
cmp r0, r1
bhi newtm @if TM51 item ID is an even number, change to bge
mov r1, #0x90 @(TM01 location - 1) / 2
lsl r1, r1, #0x1
add r1, r1, #0x1
sub r0, r0 ,r1
lsl r0, r0, #0x1
b exit
newtm:
add r1, r1, #0x1
sub r0, r0, r1
lsl r0, r0, #0x1
add r0, r0, #0x74 @116 / 2 -> 51st move ID
exit:
ldr r1, tm_table
add r0, r0, r1
ldrh r0, [r0]
bx lr
.align
tm_table: .word 0x08YYYYYY
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Second Option: If you want your TMs in consecutive order with the HMs at the very end (eg. TM01,...,TM120,HM01,...,HM08), follow these instructions:
Spoiler:
The following routine gets the move ID from a given item ID (TM ID) value.
Instructions:
1. Follow routine instructions (see below for an example)
2. Insert this routine into free space at a thumb-aligned offset (ending in 0,4,8, or C)
3. Insert 01 48 00 47 00 00 (xx+1) xx xx 08 at 0x131D5A. (xx+1) xx xx 08 is the reverse pointer to where you inserted this routine +1 (eg. if you insert at 0x902364, the reverse pointer becomes 65 23 90 08).
For example, if I have TMs 01-58 in the same item IDs as the original TM 01 - HM08 item IDs and have started with TM59 - TM120 at item ID 375 (just after Sapphire) followed by HM01 - HM08 at item IDs 437 - 444
Eg. As so:
Spoiler:
Item ID TM No.
289 TM01
290 TM02
291 TM03
292 TM04
293 TM05
294 TM06
295 TM07
296 TM08
297 TM09
298 TM10
299 TM11
300 TM12
301 TM13
302 TM14
303 TM15
304 TM16
305 TM17
306 TM18
307 TM19
308 TM20
309 TM21
310 TM22
311 TM23
312 TM24
313 TM25
314 TM26
315 TM27
316 TM28
317 TM29
318 TM30
319 TM31
320 TM32
321 TM33
322 TM34
323 TM35
324 TM36
325 TM37
326 TM38
327 TM39
328 TM40
329 TM41
330 TM42
331 TM43
332 TM44
333 TM45
334 TM46
335 TM47
336 TM48
337 TM49
338 TM50
339 TM51
340 TM52
341 TM53
342 TM54
343 TM55
344 TM56
345 TM57
346 TM58
~ ~
375 TM59
376 TM60
377 TM61
378 TM62
379 TM63
380 TM64
381 TM65
382 TM66
383 TM67
384 TM68
385 TM69
386 TM70
387 TM71
388 TM72
389 TM73
390 TM74
391 TM75
392 TM76
393 TM77
394 TM78
395 TM79
396 TM80
397 TM81
398 TM82
399 TM83
400 TM84
401 TM85
402 TM86
403 TM87
404 TM88
405 TM89
406 TM90
407 TM91
408 TM92
409 TM93
410 TM94
411 TM95
412 TM96
413 TM97
414 TM98
415 TM99
416 TM100
417 TM101
418 TM102
419 TM103
420 TM104
421 TM105
422 TM106
423 TM107
424 TM108
425 TM109
426 TM110
427 TM111
428 TM112
429 TM113
430 TM114
431 TM115
432 TM116
433 TM117
434 TM118
435 TM119
436 TM120
437 HM01
438 HM02
439 HM03
440 HM04
441 HM05
442 HM06
443 HM07
444 HM08
Then:
1. 0xXX (first HM) would become 0xDA (keeping the add r0, #0x1 line) -> 0xda * 2 + 1 = 437
2. 0xYY (first TM after item gap) would become 0xBB -> 0xbb * 2 + 1 = 375
3. 0xZZ (num items between TMs) would become 375 - 346 = 29 = 0x1D
4. 0xWW (num items between new HM01 and old HM01) would become 437 - 338 = 99 = 0x63
Note: For the best graphics, I would have TMs 01-75 replace all items up to TM Case, and then start TM 76-128 at item ID 366 (just leaving TM case and Berry Case. These are complicated to repoint, while all other items are simple to repoint to a new item ID. Note that there is a function call (0x9a824) at 0x6a64a that appears to check the item IDs of some of these items. I found no problem with nop-ing out of it, but I have not tested the results fully)
Spoiler:
Code:
.text
.align 2
.thumb
.thumb_func
.global TM_names
main:
mov r0, #0xXX @first HM item ID / 2 (eg. 405 = 0xca * 2 + 1)
lsl r0, r0, #0x1
add r0, #0x1 @if HM01 item ID is odd. Otherwise, remove this line
cmp r6, r0
bge HMItem @item ID >= first HM item ID
TMItem:
ldr r1, =(0x08416226)
mov r0, r5
bl refresh
ldr r4, .RAM
ldr r0, =(0xfffffee0)
add r1, r6, r0 @TM num
mov r0, #0xYY @First TM item ID after item gap / 2
lsl r0, r0, #0x1
add r0, #0x1 @keep this line if item ID is odd
cmp r6, r0
blt orderTM
sub r1, #0xZZ @number of items in gap
orderTM:
mov r0, r4
ldr r2, =(0x08131db4 +1)
bx r2
HMItem:
ldr r1, =(0x08463178)
mov r0, r5
bl refresh
ldr r1, =(0x08416226)
mov r0, r5
bl refresh
ldr r4, .RAM
ldr r0, =(0xfffffeae)
add r1, r6, r0
sub r1, #0xWW @item ID difference between NEW HM01 and OLD HM01
ldr r0, =(0x08131d78 +1)
bx r0
refresh:
ldr r2, =(0x08008DA4 +1)
bx r2
.align 2
.RAM: .word 0x02021CD0
This next routine loads the TM move IDs:
Instructions:
1. replace 0xXX and 0xYY with appropriate vals (see comments)
2. replace 0x08XXXXXX with address of new tm move table
3. compile and insert into thumb-aligned free space (ending in 0,4,8, or C)
4. insert 00 49 08 47 (xx+1) xx xx 08 at 0x125A78, where (xx+1) xx xx 08 is reverse pointer to this routine +1 (eg. inserted at 0x908374 --> 75 83 90 08)
Spoiler:
Code:
.text
.align 2
.thumb
.thumb_func
.global TM_moves
main:
push {r2}
mov r2, #0xXX @(item ID of first TM - 1) / 2. If kept the same, should be 0x90
lsl r2, r2, #0x1
add r2, #0x1 @remove this line if even item number
mov r1, #0xXX @first TM ID after gap / 2 (eg. 375 -> 0xBB)
lsl r1, r1, #0x1
add r1, #0x1 @remove this line if first TM after gap ID is even
cmp r0, r1
blt getmove
jump:
add r2, #0xYY @number of items in gap (eg. if TM58 is 363 and TM59 is 366, 0xYY = 0x2)
getmove:
sub r0, r0, r2 @TM number
pop {r2}
lsl r0, r0, #0x1
ldr r1, .table
add r0, r0, r1
ldrh r0, [r0]
bx lr
.align 2
.table: .word 0x08XXXXXX
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Third Option: Repoint ALL TM data so all TMs are in consecutive order (no item gap)
Spoiler:
This routine gets the move ID from the TM move table:
Instructions:
1. change 0xXX to first TM item ID / 2
2. change 0x08XXXXXX to address of repointed TM move table
3. Compile and insert into free space (thumb aligned so that the offset ends in 0,4,8, or C)
4. insert 00 49 08 47 (xx+1) xx xx 08 at 0x125A78, where (xx+1) xx xx 08 is the reverse pointer to the offset +1 (eg. if inserted at 0x904378, --> 79 43 90 08)
Spoiler:
Code:
.text
.align 2
.thumb
.thumb_func
.global TM_moves
main:
mov r1, #0xXX @first TM ID / 2, eg. 375 = 0xBB
lsl r1, r1, #0x1
add r1, r1, #0x1 @remove this line if TM ID is [U]even[/U]
sub r0, r0, r1 @TM #
lsl r0, r0, #0x1
ldr r1, .table
add r0, r0, r1
ldrh r0, [r0]
bx lr
.align 2
.table: .word 0x08XXXXXX
This next routine adjusts the TM number in the bag.
Instructions:
1. Fix 0xXX, 0xYY, 0xZZ based on appropriate item IDs
2. compile and insert into free space at a thumb-aligned offset (ends in 0,4,8, or C)
3. insert 01 48 00 47 00 00 (xx+1) xx xx 08 at 0x131D5A, where (xx+1) xx xx 08 is the reverse pointer to this routine +1 (eg. inserted at 0x906714 --> 15 67 90 08)
Spoiler:
Code:
main:
mov r0, #0xXX @HM01 item ID / 2 (eg. HM01 is 495, so 0xXX = 0xF7)
lsl r0, r0, #0x1
add r0, #0x1 @remove this line is first HM item ID is even
cmp r6, r0
bge HMItem
TMItem:
ldr r1, =(0x08416226)
mov r0, r5
bl refresh
ldr r4, .RAM
ldr r0, =(0xfffffee0)
add r1, r6, r0
sub r1, #0xYY @num of items between NEW TM01 and OLD TM01 (eg. 375 - 289 = 86 = 0x56)
mov r0, r4
ldr r2, =(0x08131db4 +1)
bx r2
HMItem:
ldr r1, =(0x08463178)
mov r0, r5
bl refresh
ldr r1, =(0x08416226)
mov r0, r5
bl refresh
ldr r4, .RAM
ldr r0, =(0xfffffeae)
add r1, r6, r0
sub r1, #0xZZ @item ID of NEW HM01 - OLD HM01 (eg. 495 - 339 = 156 = 0x9C)
ldr r0, =(0x08131d78 +1)
bx r0
refresh:
ldr r2, =(0x08008DA4 +1)
bx r2
.align 2
.RAM: .word 0x02021CD0
Step 3: TM Compatability
Spoiler:
Step 3a: New Compatibility Table
With 128 TMs/HMs, the new comparability will take 16 bytes per entry. The old data is useless, so find free space in your ROM equivalent to (num_pokemon * 16 bytes each). This routine includes checks for species ID 0x0 and the ??? pokemon between Celebi and Treecko. Therefore, the first entry corresponds to species ID 0x1 and entry 0xFC corresponds to Treecko. If you've managed to use these pokemon species, make sure you edit the routine to accommodate those species IDs
Instructions:
1. replace 0x08XXXXXX with address of new compatibility table address
2a. replace 0xXX with the TM number before the item gap + the number of items in the gap. For example, if you have HM08 or TM58 as item ID 346 and 375 as TM51 or TM59, then 0xXX = 58 + 28 = 0x56)
2b. replace 0xYY with number of items in the gap. eg. from the example in 2a 0xYY would be 28 or 0x1C
3. compile and insert the routine into thumb-aligned free space
4. insert 00 48 00 47 (xx+1) xx xx 08 at 0x43C40
Code:
.text
.align 2
.thumb
.thumb_func
.global tm_compatability
get_compat_start:
mov r3, r1 @r3 = species ID
sub r3, #0x1 @start table at 0 (aka ignore stupid 0th species)
check_glitch_mons:
cmp r3, #0xFC @first glitch pokemon species ID
blt get_table_entry
sub r3, #0x19 @25 glitch pokes (eg. Treecko becomes entry 0xFC in compatability table)
get_table_entry:
lsl r3, r3, #0x4 @16 * (species ID -1)
ldr r1, .table
add r3, r1, r3 @table start + 16*species = start of selected species compatability
mov r2, #0x1
@if used third option where all TMs are in consecutive order with no gap
@remove check_gap and newtm
check_gap:
cmp r4, #0xXX
blt check @if r4 < 0xXX, TM is in consecutive order
newtm:
sub r4, #0xYY @num items in TM gap
check:
cmp r4, #0x1f @ 31 -> 0-31
bls first_32
cmp r4, #0x3f @ 63 -> 32-63
bls first_64
cmp r4, #0x5f @ 95 -> 63-95
bls first_96
last_word: @ 96-128
sub r4, #0x60
lsl r2, r4
add r3, #0xC @last word in table address
b get_compat_word
first_96:
sub r4, #0x40
lsl r2, r4
add r3, #0x8
b get_compat_word
first_64:
sub r4, #0x20
lsl r2, r4
add r3, #0x4
b get_compat_word
first_32:
lsl r2, r4
get_compat_word:
ldr r0, [r3]
and r0, r2
exit:
pop {r4-r5}
pop {r1}
bx r1
.align 2
.table: .word 0x08XXXXXX @tm compatability table
The new TM compatibility is broken into 4 words (4 bytes each), where the first word corresponds to TMs 1-32, then 33-64, and so on. Each bit starting from the far right corresponds to a TM.
For example, if you want to learn TMs 3, 7, 20, 54, 87, and 102:
1-32: 00000000000010000000000001000100
33-64: 00000000001000000000000000000000
65-96: 00000000010000000000000000000000
97-128: 00000000000000000000000000100000
becomes, in hex: [00 08 00 44] [00 20 00 00] [00 40 00 00] [00 00 00 20]
reversing each part and combining:
44 00 08 00 00 00 20 00 00 00 40 00 20 00 00 00
Here is a python program I wrote for compatibility. It takes in a list of TM numbers (eg. 1 4 8 12 54 100) and spits out the hex string in little endian for you to easily insert into your ROM. Each step is laid out for you to easily edit to your desire and/or debug. Be aware that it will not stop you if you list a number outside of the range 1-128.
Spoiler:
Code:
inp = raw_input("Enter TM list: ").split(' ') #list of numbers separated by space
tms = [0] * 128 #base bitfield
#get TM data into bitfields
for i in range(len(inp)):
ind = int(inp[i]) - 1
tms[ind] = 1
first_word = list(reversed(tms[0:32]))
second_word = list(reversed(tms[32:64]))
third_word = list(reversed(tms[64:96]))
fourth_word = list(reversed(tms[96:128]))
#convert lists to binary strings
tms32 = ''
tms64 = ''
tms96 = ''
tms128 = ''
for i in first_word:
tms32 += str(i)
for i in second_word:
tms64 += str(i)
for i in third_word:
tms96 += str(i)
for i in fourth_word:
tms128 += str(i)
#get big endian hex values
hex32_fwd = '{:0{}X}'.format(int(tms32, 2), len(tms32) // 4)
hex64_fwd = '{:0{}X}'.format(int(tms64, 2), len(tms64) // 4)
hex96_fwd = '{:0{}X}'.format(int(tms96, 2), len(tms96) // 4)
hex128_fwd = '{:0{}X}'.format(int(tms128, 2), len(tms128) // 4)
#transform into little endian hex
hex32 = ''
hex64 = ''
hex96 = ''
hex128 = ''
for i in range(0,8):
if i % 2 == 1: #odd num
x = 8 - i #odd index
else:
x = 6 - i #even index
hex32 += str(list(hex32_fwd)[x])
hex64 += str(list(hex64_fwd)[x])
hex96 += str(list(hex96_fwd)[x])
hex128 += str(list(hex128_fwd)[x])
print str(hex32 + hex64 + hex96 + hex128)
Step 4: Remove TM animation
Spoiler:
These routines work perfectly except when replacing an old move with a TM-learned move the game will freeze on the TM use animation. To remove:
1.insert 00 00 at 0x11CE6E
2. insert 00 F0 0E FA at 0x11CA2C
3. insert 00 00 00 00 00 00 00 00 00 00 00 00 44 E0 at 0x11CD9E
Step 5: Expand Bag Item Limit
Spoiler:
You'll need JPANs save block hack to allow the item data to save in free RAM.
If you only want to expand the number of TMs, use this routine:
Instructions:
1. change free RAM to your own location
2. compile and insert into a thumb-aligned offset
3. insert 01 48 00 47 00 00 (xx+1 xx xx 08 at 0x99E6A
Spoiler:
Code:
.text
.align 2
.thumb
.thumb_func
.global tm_slots_hack
main:
ldr r0, ram
str r0, [r1, #0x18]
mov r0, #0x80
strb r0, [r1, #0x1c]
ldr r0, return
bx r0
.align
ram:.word 0x0203cXXX
return:.word 0x08099e74+1
If you want to expand all the bag items, use this routine:
Instructions:
1. set freeRAM to your own address
2. set number of items you want expanded
3. compile and insert into free space (thumb-aligned offset)
4. 00 48 00 47 (xx+1) xx xx 08 at 99e50
Spoiler:
Code:
.text
.align 2
.thumb
.thumb_func
.global pocket_size_limiters
.equ freeRAM, 0x0203cXXX
.equ NumMainPocketItems, XX
.equ NumKeyItems, XX
.equ NumPokeballs, XX
.equ NumTMs, XXX
.equ NumBerries, XX
MainPocket:
ldr r0, .MainPocketRAM @start of expanded item data
str r0, [r1] @store new RAM pocket data address into DMA memory
mov r0, #0x4B @75 main pocket items
strb r0, [r1, #0x4]
KeyItems:
ldr r0, =(freeRAM + (4*NumMainPocketItems))
str r0, [r1, #0x8]
mov r0, #NumKeyItems
strb r0, [r1, #0xC]
PokeballsPocket:
ldr r0, =(freeRAM + (4*NumMainPocketItems) + (4*NumKeyItems))
str r0, [r1, #0x10]
mov r0, #NumPokeballs
strb r0, [r1, #0x14] @store limiter
TMsPocket:
ldr r0, =(freeRAM + (4*NumMainPocketItems) + (4*NumKeyItems) + (4*NumPokeballs))
str r0, [r1, #0x18]
mov r0, #NumTMs
strb r0, [r1, #0x1C] @store 128 into TM pocket limiter
BerriesPocket:
ldr r0, =(freeRAM + (4*NumMainPocketItems) + (4*NumKeyItems) + (4*NumPokeballs) + (4*NumTMs))
str r0, [r1, #0x20]
add r1, #0x24
mov r0, #NumBerries
strb r0, [r1]
bx lr
.align 2
.MainPocketRAM: .word freeRAM
Some Notes:
1. If you add new HMs and the associated move name is 13 characters long, it will string together the next HM name. Here is a fix for this problem:
Instructions:
1. compile and insert into free space
2. insert 00 48 00 47 (xx+1) xx xx 08 at 0x8dac
Spoiler:
Code:
.text
.align 2
.thumb
.thumb_func
.global NameLimit
Main:
push {r3}
mov r3, #0x0
Loop:
ldrb r0, [r2]
cmp r0, #0xFF
beq Exit
cmp r3, #0xF
beq Exit
add r3, #0x1
add r2, #0x1
b Loop
Exit:
mov r0, r2
bl SubRout
pop {r3}
pop {r1}
bx r1
SubRout:
push {lr}
mov r3, r0
b InnerLoop
OuterLoop:
strb r2, [r3]
add r3, #0x1
add r1, #0x1
InnerLoop:
ldrb r2, [r1]
mov r0, r2
cmp r0, #0xFF
bne OuterLoop
ExitLoop:
mov r0, #0xFF
strb r0, [r3]
mov r0, r3
pop {r1}
bx r1
.align 2
2. I tried to make this as easy to follow as possible. Please post comments with questions or any bugs/issues you find. There may be mistakes since I copied a lot of data down...
3. If you are adding new HM moves, see this post for adding new field moves. Eg. Rock Climb
Last edited: