Advertiser Content

Tutorial [FR] Expanding TMs/HMs

Started by ghoulslash October 21st, 2017 3:27 PM
  • 3885 views
  • 13 replies
Male
Seen 1 Day Ago
Posted 5 Days Ago
129 posts
3.7 Years
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
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:

.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:

.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:

.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:

.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:

.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 even
	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:

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

.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:

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:

.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:

.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:

.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

Taの境界

Seen September 4th, 2019
Posted September 4th, 2019
22 posts
4.9 Years
Surprisingly someone doing this thread while credit to me, you should also credit to Jambo51 as I figured out how he manage to break that thing 3 years ago.
Not sure my code working but pretty sure that i wrote the things in faster way(and bad coding style),
Not hacking Fire Red anymore but I believe someone who really need this should plan to insert these routines with c.
Male
Seen 1 Day Ago
Posted 5 Days Ago
129 posts
3.7 Years
(I Like) It would be easier to create a patch.
My one hesitancy to do this would be that the data insertion might conflict with user's existing data, especially when the item data structure is so large.


Surprisingly someone doing this thread while credit to me, you should also credit to Jambo51 as I figured out how he manage to break that thing 3 years ago.
Not sure my code working but pretty sure that i wrote the things in faster way(and bad coding style),
Not hacking Fire Red anymore but I believe someone who really need this should plan to insert these routines with c.
Thanks for catching that, I'll update the initial post. I'm (slowly) learning how to hack in C currently so I may make/help make a tool to do just that at some point.
Male
Seen December 16th, 2018
Posted December 1st, 2018
41 posts
2.8 Years
First of all, thanks for sharing your routines in TM Expansion...
next, I am sure to implement this on my hack..

Last. I know this sounds very slowpoke. But, is there any possibility that the old compatibility will not be broken? Like there will be new sets of TM Compatibility..

for example:
TM 01 - HM 09 uses the old compatibility while TM 51 - TM 128 uses the new compatibility.

I know that the bit-reading is opposite from the previous way, correct me if I'm wrong. I'm still hoping the as-rare-as-shiny-pokemon possibility.

Taの境界

Seen September 4th, 2019
Posted September 4th, 2019
22 posts
4.9 Years
First of all, thanks for sharing your routines in TM Expansion...
next, I am sure to implement this on my hack..

Last. I know this sounds very slowpoke. But, is there any possibility that the old compatibility will not be broken? Like there will be new sets of TM Compatibility..

for example:
TM 01 - HM 09 uses the old compatibility while TM 51 - TM 128 uses the new compatibility.

I know that the bit-reading is opposite from the previous way, correct me if I'm wrong. I'm still hoping the as-rare-as-shiny-pokemon possibility.
possible but not practical, you can have 2 compatibility table with some code tweaking. You need to consider vanilla compatibility table has 64 TM/HM slot. Currently no tool could edit your kind of compatibility so I prefer to redo all.
Male
Seen December 16th, 2018
Posted December 1st, 2018
41 posts
2.8 Years
possible but not practical, you can have 2 compatibility table with some code tweaking. You need to consider vanilla compatibility table has 64 TM/HM slot. Currently no tool could edit your kind of compatibility so I prefer to redo all.
As expected. Doing that might be helpful but hard to do. Anyways, this research is awesome.
Male
Seen 1 Day Ago
Posted 5 Days Ago
129 posts
3.7 Years
As expected. Doing that might be helpful but hard to do. Anyways, this research is awesome.
While it would be easier to redo the entire table, there is no reason you could not split the table up. You could theoretically have as many compatability tables as you want for various game scenarios or freespace limitations. Of course, as Taの境界 said, you would need to tweak the TM_compat code a bit. You would need to add in another check for register r4 such that it branches to load a separate table if the TM index (value in r4) is greater than 64, for example.
Seen July 26th, 2019
Posted February 7th, 2019
3 posts
1.6 Years
I do all the steps in the tutorial and i have a problem:
The TM only appears in the TM case when i have recived all them.
I explain:
I made 2 scripts: In one of them i give to the player only 1 or 2 TM
In the second script i give to the player all the TM and HM

If i execute the first script, when i open the TM case, the game freeze. If i execute the second script, i have no problem, i open the TM case and all the TM and HM are there.
This happen to me no matter what TM i am giving in the first script.
If i execute the second script and after that i execute the first script, i open the TM case and i have no problem: i have all the TM and HM, and the TM given in the first script i got 2 of them.
So is like a problem of visualization of the TM, i tried change the RAM adress that i use in the step 5 but i got the same problem.

Do anyone else have this problem?
What did i do wrong?

EDIT:
I already discovered my error, in the modification of the byte in 9A600, i put the HM01 item ID instead of the TM01 Object ID.
So, when i put it well...i have no problem.

Again, sorry for the bad english.
Non-binary
United Kingdom
Seen 1 Day Ago
Posted June 4th, 2019
30 posts
258 Days
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)
How do I find this?
I don't know where the the tm move table is stored.

mattymannnn

Male
Seen 2 Days Ago
Posted 5 Days Ago
42 posts
1.5 Years
How do I find this?
I don't know where the the tm move table is stored.
You dont repoint the old one, you make a brand new table from scratch. The old TM table will not work at all because it uses 8 bytes per pokemon, whereas this one uses 16 bytes.
Advertiser Content