• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Quick Research & Development Thread

knizz

192
Posts
16
Years
  • Seen Oct 28, 2020
Some hwords have no opcode in Thumb.
If you try to decompile one of this hwords the output is [???].

Maybe it is a grafik or an ARM code.

That's what I thought at first too. But it all makes sense:
  • The function pushes registers in the first line
  • The function pops registers in the last line
  • The registers are popped to the positions they were pushed from except for lr/pc of course.
  • The stack-pointer is decreased and then used to the limit. (Why allocate more or less?)
  • The cmp-opcode is followed by a beq-opcode.
  • The functions called from this function are valid too.

It *has* to be THUMB-Code!
 

JPAN

pokemon rom researcher
104
Posts
15
Years
  • Seen Jul 2, 2016
I found something that bugs a lot of people, the fact HM moves cannot be deleted, can be easily erased on Fire Red.
There are two main routines that check if an attack is an HM or not:
one for the battle routine at 0x80441B8;
one for the in-screen move learning at 0x08125A90.
Both routines check for HMs in different locations.
The first checks if the attack given is part of a non-deletion list at 0x0825e014, ended in FFFF, and searches through it until it reaches the ending value, or finding a valid attack. Here's the code:
Code:
ROM:080441B8 ; =============== S U B R O U T I N E =======================================
ROM:080441B8
ROM:080441B8
ROM:080441B8 Battle_HM_set                           ; CODE XREF: sub_80CE8DC+A80p
ROM:080441B8                 PUSH    {R4,LR}
ROM:080441BA                 LSLS    R0, R0, #0x10
ROM:080441BC                 LSRS    R3, R0, #0x10        ;given attack stored
ROM:080441BE                 LDR     R2, =unk_825E014        ;list location
ROM:080441C0                 LDRH    R0, [R2]
ROM:080441C2                 LDR     R1, =0xFFFF
ROM:080441C4                 CMP     R0, R1
ROM:080441C6                 BEQ     loc_80441EA          ;is end of list
ROM:080441C8                 MOVS    R4, R1
ROM:080441CA                 ADDS    R1, R2, #0
ROM:080441CC
ROM:080441CC loc_80441CC                             ; CODE XREF: Battle_HM_set+30j
ROM:080441CC                 LDRH    R0, [R2]
ROM:080441CE                 ADDS    R1, #2
ROM:080441D0                 ADDS    R2, #2
ROM:080441D2                 CMP     R0, R3
ROM:080441D4                 BNE     loc_80441E4
ROM:080441D6                 MOVS    R0, #1        ;is same attack, undeletable
ROM:080441D8                 B       loc_80441EC
ROM:080441D8 ; ---------------------------------------------------------------------------
ROM:080441DA                 DCB    0
ROM:080441DB                 DCB    0
ROM:080441DC off_80441DC     DCD unk_825E014         ; DATA XREF: Battle_HM_set+6r
ROM:080441E0 dword_80441E0   DCD 0xFFFF              ; DATA XREF: Battle_HM_set+Ar
ROM:080441E4 ; ---------------------------------------------------------------------------
ROM:080441E4
ROM:080441E4 loc_80441E4                             ; CODE XREF: Battle_HM_set+1Cj
ROM:080441E4                 LDRH    R0, [R1]
ROM:080441E6                 CMP     R0, R4
ROM:080441E8                 BNE     loc_80441CC    ;new end_of_list check
ROM:080441EA
ROM:080441EA loc_80441EA                             ; CODE XREF: Battle_HM_set+Ej
ROM:080441EA                 MOVS    R0, #0      ;ended list, attack deletable
ROM:080441EC
ROM:080441EC loc_80441EC                             ; CODE XREF: Battle_HM_set+20j
ROM:080441EC                 POP     {R4}
ROM:080441EE                 POP     {R1}
ROM:080441F0                 BX      R1
The other searches for them at 0x0845A80C, the TM attack list. It does so by looking over the TMs at position 50+
Code:
ROM:08125A90 ; =============== S U B R O U T I N E =======================================
ROM:08125A90
ROM:08125A90
ROM:08125A90 Check_for_HM                            ; CODE XREF: ROM:0813939Ep
ROM:08125A90                 PUSH    {LR}
ROM:08125A92                 LSLS    R0, R0, #0x10
ROM:08125A94                 LSRS    R2, R0, #0x10
ROM:08125A96                 MOVS    R1, #0
ROM:08125A98                 LDR     R3, =TM_List        ;Location for all TM Attacks
ROM:08125A9A
ROM:08125A9A loc_8125A9A                             ; CODE XREF: Check_for_HM+28j
ROM:08125A9A                 MOVS    R0, R1
ROM:08125A9C                 ADDS    R0, #0x32
ROM:08125A9E                 LSLS    R0, R0, #1
ROM:08125AA0                 ADDS    R0, R0, R3
ROM:08125AA2                 LDRH    R0, [R0]             ;loads HM required by R1
ROM:08125AA4                 CMP     R0, R2
ROM:08125AA6                 BNE     loc_8125AB0
ROM:08125AA8                 MOVS    R0, #1            ;if equal, undeletable, return 1
ROM:08125AAA                 B       loc_8125ABC
ROM:08125AAA ; ---------------------------------------------------------------------------
ROM:08125AAC off_8125AAC     DCD TM_List             ; DATA XREF: Check_for_HM+8r
ROM:08125AB0 ; ---------------------------------------------------------------------------
ROM:08125AB0
ROM:08125AB0 loc_8125AB0                             ; CODE XREF: Check_for_HM+16j
ROM:08125AB0                 ADDS    R0, R1, #1
ROM:08125AB2                 LSLS    R0, R0, #0x18
ROM:08125AB4                 LSRS    R1, R0, #0x18
ROM:08125AB6                 CMP     R1, #6         ;maximum TM checking
ROM:08125AB8                 BLS     loc_8125A9A
ROM:08125ABA                 MOVS    R0, #0       ;not any TM, deletable
ROM:08125ABC
ROM:08125ABC loc_8125ABC                             ; CODE XREF: Check_for_HM+1Aj
ROM:08125ABC                 POP     {R1}
ROM:08125ABE                 BX      R1

So, how to "fix" it? Well, change 080441D6 to 00 and 08125AA8 to 00 to make no attack undeletable.
If, on the other hand, you have a wish to prevent the player from deleting random attacks, simply repoint the list to a location where your attacks fit (plus the 0xffff part), and change the following addresses:
0x08125A9C to 00 (one byte only)
0x08125AAC to your list pointer reversed
0x08125AB6 to the number of attacks you placed -2 (to a max of 101 undeletable attacks)

If, for some reason, you wish to make all attacks undeletable, change
080441EA to 00
08125ABA to 00

Hope this helps those hacks who want to get rid of HMs.
 

Saxisai

Unbeatable 3's-Unstopable Trio
62
Posts
16
Years
I don't know if this belongs here but I didn't know where else to post it.

Has anyone thought of a way to hack the pal park in the generation iv games?
 

Sierraffinity

Desperately trying to retire from ROM hacking
1,069
Posts
16
Years
Here's one thing that troubles everyone: badge hacking.
I'm talking about hacking what levels of obedience, what HM is usable, and things like that.
I'm sure that SOMEONE has done it and, hopefully, they can share it, here, with us.
 

colcolstyles

Yours truly
1,588
Posts
15
Years
Here's one thing that troubles everyone: badge hacking.
I'm talking about hacking what levels of obedience, what HM is usable, and things like that.
I'm sure that SOMEONE has done it and, hopefully, they can share it, here, with us.

I would guess that the code is spread throughout the ROM. For example, in this post, JPAN revealed that he found the routine which, during a battle, checks the player's acquired badges. However, the routine which checks what badges the player has in order to prevent the player from using Surf too early, for example, is probably located elsewhere. I don't know if the badge flags are at a fixed address in the RAM or not but if they are, you should put a break-on-read on those addresses and then disassemble the routines around wherever the game breaks.
 

Sierraffinity

Desperately trying to retire from ROM hacking
1,069
Posts
16
Years
I would guess that the code is spread throughout the ROM. For example, in this post, JPAN revealed that he found the routine which, during a battle, checks the player's acquired badges. However, the routine which checks what badges the player has in order to prevent the player from using Surf too early, for example, is probably located elsewhere. I don't know if the badge flags are at a fixed address in the RAM or not but if they are, you should put a break-on-read on those addresses and then disassemble the routines around wherever the game breaks.
The flag locations are probably DMA-protected, as with the variables...
Any other ideas?
 

colcolstyles

Yours truly
1,588
Posts
15
Years
The flag locations are probably DMA-protected, as with the variables...
Any other ideas?

You could disassemble the routine that is executed when a 'checkflag' command is encountered in a script in order to try to find where the flags are located. I've never worked with flags on the ASM-level before so I'm afraid I can't be of much help.
 

Sierraffinity

Desperately trying to retire from ROM hacking
1,069
Posts
16
Years
Hm... Turns out, the checkflag routine (the actual one that does the calculations) is run a lot of times in the OW (I know, duh, the people event flags) so I got the flag location (or at least, the memory pointer to it). In Emerald, it's at the address pointed at by 0x03005D8C plus 0x1270.
Now, I have to find the bit that designates the badge flags..
EDIT: 0x0809C7EC in Emerald contains the surf-check-routine... at least for the tile. I'm not sure about the PKMN menu one.
EDIT2: 0x081B54E8 (again, in Emerald) contains the badge-check-routine for the menu. I'm trying to find out where the numbers to add to the first badge are obtained from...
EDIT3: Well, apparently they're loaded from 0x02000020, but I can't find how it gets the value...
Anybody, feel free to help me out with this. :/
EDIT4: Well, I hacked the routine and made it load different flag numbers for each of the old badge+base number. And it works! :D
To get all of the flags to work out on the field, however, you'll need to edit all of the scripts for, say, Rock Smash, Strength, and Cut so that they have the new flags. And then you'll need to hack the surf routine, like I said above.
Also, with the Set Disobedience findings, all we need to control the badges completely is to find out where the Attack/Defense... stats are increased.Even though that doesn't matter much, it would still be cool to be able to control the badges completely.
 
Last edited:

JPAN

pokemon rom researcher
104
Posts
15
Years
  • Seen Jul 2, 2016
I found something disturbing. There are no variables above the first 0x4000 set. Variables nearing the 0x5000 set start by overwriting the pokemon data at the Breeding center, and variables from 0x5ef4 to 0x7fff are inside Box space, meaning that there is nearly no variables usable in-game.
The reason we can use those variable spaces is because the game has no variable check for values other than 0x4000 and 0x8000. So, up until now, all variables we use in the upper scale are permanently damaging the game file.
Also, trainer flags correspond to the normal flags 0x500 to 0x700.
 
1,323
Posts
16
Years
  • Seen Dec 9, 2023
I found something disturbing. There are no variables above the first 0x4000 set. Variables nearing the 0x5000 set start by overwriting the pokemon data at the Breeding center, and variables from 0x5ef4 to 0x7fff are inside Box space, meaning that there is nearly no variables usable in-game.
The reason we can use those variable spaces is because the game has no variable check for values other than 0x4000 and 0x8000. So, up until now, all variables we use in the upper scale are permanently damaging the game file.
Also, trainer flags correspond to the normal flags 0x500 to 0x700.
I really hope that's just FR/LG... because I'm generally using variables from 0x5000 to 0x7FFF in my hack.
 

JPAN

pokemon rom researcher
104
Posts
15
Years
  • Seen Jul 2, 2016
I really hope that's just FR/LG... because I'm generally using variables from 0x5000 to 0x7FFF in my hack.
I've searched the other ROM versions for it, and I have bad news:
In Emerald, from 0x5536 forward affect the Boxes, and at Ruby, although not directly problematic, from 0x55a0 the variables aren't saved, and from 0x415c, you start overwriting names, sayings and Overworld data.
This fact has made me think, how can we get usable, permanent variables? So, I've studied the FlashRom write routines, and found something interesting, and since I was on a multi-ROM streak, I confirmed it for Ruby, Fire Red and Emerald.

The Pokemon games, as we know, use a 128K Flash ROM, that can be accessed by using the correct key at the 0x0e00xxxx addresses. A 128kB Flash has a total of 0x20000 possible addresses, so it uses a Bank system to allow access to the full memory. More details can be find at this useful document here.

The save File is always written in 4kB blocks (0x1000 addresses), so the pokemon Game considers a Block to be a set of 0x1000 bytes of information. Those blocks always have the same configuration:
0x0 - 0xf80 -> Data to store. (maximum spotted, can be less)
0xff4 -> Block number
0xff6 -> Checksum, calculated by adding all words in the copyed memory, then adding both Upper and lower halfword toguether.
0xff8 -> Seems like a pointer, but needs further investigation
0xffc -> a byte that seems to indicate how many saves since last load.

The Games seem to use a round-Robin list to change the location of the Save data at each save, most likely to avoid chip degradation and unfortunate hacking attempts. Emerald and Fire Red have two lists (ruby is not confirmed), that have this Saving pattern:
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d
0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b
The game has a complex pattern of choosing the start. I'll leave you with examples:
Code:
07 08 09 0a 0b 0c 0d 00 01 02 03 04 05 06
16 17 18 19 1a 1b 0e 0f 10 11 12 13 14 15
09 0a 0b 0c 0d 00 01 02 03 04 05 06 07 08
18 19 1a 1b 0e 0f 10 11 12 13 14 15 16 17
0b 0c 0d 00 01 02 03 04 05 06 07 08 09 0a
1a 1b 0e 0f 10 11 12 13 14 15 16 17 18 19
The only data saved on these blocks are the data that in Fire Red and Emerald are located in the Dynamic pointers at 0x3005008, 0x300500c and 0x3005010.

The Fire Red Table is as follows
Code:
0x0 - Personal Data (at 0x300500c) Size: 0xf24
0x1 to 0x4 - Map Data (at 0x03005008) Size: 0xf80*3 + 0xee8 = 0x3d68
0x5 to 0xd - Box Data (at 0x03005010) Size: 0xf80*8 + 0x7d0 = 0x83d0
Both Ruby and Emerald have similar tables, although the sizes of the ending packets may vary between ROMs. Layout is always this one.

Now, why does this matter? Well, if you notice the lists presented, you can see that blocks 1c, 1d, 1e and 1f are not used, and that is true.
So, if anyone wants, we can use this area to save and load our own pieces of data, just like the game.
That can be used to increase the number of seen-caught pokemon, get some real empty Variables we can use, and even save our own data structures that we need to fit in pre-used variables to use.

As a complementary note, I will now post the location of the "Save block" Routine in the three mainly used US versions
Code:
Ruby -> 0x081DFE74
Fire Red -> 0x081DF070
Emerald -> 0x082E20AC
 

Sierraffinity

Desperately trying to retire from ROM hacking
1,069
Posts
16
Years
I've searched the other ROM versions for it, and I have bad news:
In Emerald, from 0x5536 forward affect the Boxes, and at Ruby, although not directly problematic, from 0x55a0 the variables aren't saved, and from 0x415c, you start overwriting names, sayings and Overworld data.
This fact has made me think, how can we get usable, permanent variables? So, I've studied the FlashRom write routines, and found something interesting, and since I was on a multi-ROM streak, I confirmed it for Ruby, Fire Red and Emerald.

The Pokemon games, as we know, use a 128K Flash ROM, that can be accessed by using the correct key at the 0x0e00xxxx addresses. A 128kB Flash has a total of 0x20000 possible addresses, so it uses a Bank system to allow access to the full memory. More details can be find at this useful document here.

The save File is always written in 4kB blocks (0x1000 addresses), so the pokemon Game considers a Block to be a set of 0x1000 bytes of information. Those blocks always have the same configuration:
0x0 - 0xf80 -> Data to store. (maximum spotted, can be less)
0xff4 -> Block number
0xff6 -> Checksum, calculated by adding all words in the copyed memory, then adding both Upper and lower halfword toguether.
0xff8 -> Seems like a pointer, but needs further investigation
0xffc -> a byte that seems to indicate how many saves since last load.

The Games seem to use a round-Robin list to change the location of the Save data at each save, most likely to avoid chip degradation and unfortunate hacking attempts. Emerald and Fire Red have two lists (ruby is not confirmed), that have this Saving pattern:
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d
0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b
The game has a complex pattern of choosing the start. I'll leave you with examples:
Code:
07 08 09 0a 0b 0c 0d 00 01 02 03 04 05 06
16 17 18 19 1a 1b 0e 0f 10 11 12 13 14 15
09 0a 0b 0c 0d 00 01 02 03 04 05 06 07 08
18 19 1a 1b 0e 0f 10 11 12 13 14 15 16 17
0b 0c 0d 00 01 02 03 04 05 06 07 08 09 0a
1a 1b 0e 0f 10 11 12 13 14 15 16 17 18 19
The only data saved on these blocks are the data that in Fire Red and Emerald are located in the Dynamic pointers at 0x3005008, 0x300500c and 0x3005010.

The Fire Red Table is as follows
Code:
0x0 - Personal Data (at 0x300500c) Size: 0xf24
0x1 to 0x4 - Map Data (at 0x03005008) Size: 0xf80*3 + 0xee8 = 0x3d68
0x5 to 0xd - Box Data (at 0x03005010) Size: 0xf80*8 + 0x7d0 = 0x83d0
Both Ruby and Emerald have similar tables, although the sizes of the ending packets may vary between ROMs. Layout is always this one.

Now, why does this matter? Well, if you notice the lists presented, you can see that blocks 1c, 1d, 1e and 1f are not used, and that is true.
So, if anyone wants, we can use this area to save and load our own pieces of data, just like the game.
That can be used to increase the number of seen-caught pokemon, get some real empty Variables we can use, and even save our own data structures that we need to fit in pre-used variables to use.

As a complementary note, I will now post the location of the "Save block" Routine in the three mainly used US versions
Code:
Ruby -> 0x081DFE74
Fire Red -> 0x081DF070
Emerald -> 0x082E20AC
JPAN, in Emerald, what variables are safe, then? Anything under 0x5536, or are there other used places?
 

JPAN

pokemon rom researcher
104
Posts
15
Years
  • Seen Jul 2, 2016
JPAN, in Emerald, what variables are safe, then? Anything under 0x5536, or are there other used places?
The main problem here is that it's impossible to truly know which are safe at this point. I would bet the ones originaly used by the game outside the ASM Routines(0x4050-0x40c0) should be safe, but the area saved is widely unknown. The Variables are stored between People data on the OW and the Breeding Daycare store. But that area is large, and filled with used data. As they are indirectly referenced in-game, it may take a long while to find all possibilities out.
 

Sierraffinity

Desperately trying to retire from ROM hacking
1,069
Posts
16
Years
The main problem here is that it's impossible to truly know which are safe at this point. I would bet the ones originaly used by the game outside the ASM Routines(0x4050-0x40c0) should be safe, but the area saved is widely unknown. The Variables are stored between People data on the OW and the Breeding Daycare store. But that area is large, and filled with used data. As they are indirectly referenced in-game, it may take a long while to find all possibilities out.
Wow, this is really bad...
I wish I could help, but I can barely do anything in ASM.

Also, up to what point are the 0x5000 variables okay, would you say?
 

JPAN

pokemon rom researcher
104
Posts
15
Years
  • Seen Jul 2, 2016
Wow, this is really bad...
I wish I could help, but I can barely do anything in ASM.

Also, up to what point are the 0x5000 variables okay, would you say?
I think what would be best right now is to choose variables in an area you are not going to use. For instance, if your hack doesn't use the breeding center, you can use 0x4e4a to 0x4ed6. The 0x5000 variable is located in a location that is unknown, so I can't say what it will break, if it breaks anything at all.

On a more positive sidenote, I managed to make the game save a location of my choice to the 1f bank, and it affected nothing adversly, so it should be possible to recreate the variables there, with some work.
 

Sierraffinity

Desperately trying to retire from ROM hacking
1,069
Posts
16
Years
I think what would be best right now is to choose variables in an area you are not going to use. For instance, if your hack doesn't use the breeding center, you can use 0x4e4a to 0x4ed6. The 0x5000 variable is located in a location that is unknown, so I can't say what it will break, if it breaks anything at all.

On a more positive sidenote, I managed to make the game save a location of my choice to the 1f bank, and it affected nothing adversly, so it should be possible to recreate the variables there, with some work.
Amazing! Still, Game Freak needed to do better with the coding of the routine in the first place, even if they weren't planning on using those variables.

BTW, what would you suggest for a hack of Emerald that's used variables up to around, say, 0x5030? Would you recommend switching them all out (somehow), or will we see a fix in the near future?
 

JPAN

pokemon rom researcher
104
Posts
15
Years
  • Seen Jul 2, 2016
Amazing! Still, Game Freak needed to do better with the coding of the routine in the first place, even if they weren't planning on using those variables.

BTW, what would you suggest for a hack of Emerald that's used variables up to around, say, 0x5030? Would you recommend switching them all out (somehow), or will we see a fix in the near future?
Luckily, all Save functions seem identical (with the exceptions of a few pointers), so saving should be easily solved. Repointing variables to solve the problem should also be simple. It's the loading that will take a while to crack, as I've yet to find that function. Also, the new variables will be limited to 0x800 (one block), and finding 0x1000 bytes in the RAM that are free in a joint space should also be problematic.

But, for now, keep using that 0x5030 variables. A fix shouldn't be far out.
By the way, if you can find an empty RAM location with the needed space(should be near the end), it would make things easier.
 

Sierraffinity

Desperately trying to retire from ROM hacking
1,069
Posts
16
Years
Luckily, all Save functions seem identical (with the exceptions of a few pointers), so saving should be easily solved. Repointing variables to solve the problem should also be simple. It's the loading that will take a while to crack, as I've yet to find that function. Also, the new variables will be limited to 0x800 (one block), and finding 0x1000 bytes in the RAM that are free in a joint space should also be problematic.

But, for now, keep using that 0x5030 variables. A fix shouldn't be far out.
By the way, if you can find an empty RAM location with the needed space(should be near the end), it would make things easier.
How would you go about seeing if a RAM location is empty? Is there a special method, or do you just look and try to find a ton of 00s?
If the second one is right, try 0x02FF0000. Found it randomly.
 
1,323
Posts
16
Years
  • Seen Dec 9, 2023
I've searched the other ROM versions for it, and I have bad news:
In Emerald, from 0x5536 forward affect the Boxes, and at Ruby, although not directly problematic, from 0x55a0 the variables aren't saved, and from 0x415c, you start overwriting names, sayings and Overworld data.
This fact has made me think, how can we get usable, permanent variables? So, I've studied the FlashRom write routines, and found something interesting, and since I was on a multi-ROM streak, I confirmed it for Ruby, Fire Red and Emerald.
So in an Emerald hack, is it okay to use any variable below 0x5536? And would a 100% safe way is to use 0x4050-0x40C0?
 

JPAN

pokemon rom researcher
104
Posts
15
Years
  • Seen Jul 2, 2016
How would you go about seeing if a RAM location is empty? Is there a special method, or do you just look and try to find a ton of 00s?
If the second one is right, try 0x02FF0000. Found it randomly.
RAM only goes from 0x02000000 to 0x0203ffff. 0x0203f000 seems open in Emerald, but the only way to be sure is to search for the value 00 several times, with VBA, and try and see if the values closer to it change by doing different things (for example, fill a box with pokemon, and check if it touches there. Then try other things like teaching an attack, a wild battle, safari zone... If it remains 00 all that time, chances are it's safe).

So in an Emerald hack, is it okay to use any variable below 0x5536? And would a 100% safe way is to use 0x4050-0x40C0?
Like I said before, 0x5536 is the first box position. Lower than that it's the Map Data, that include several random events. The only variables you can use with certainty are the ones they used in-game. All others may either damage your save or be ok. So, use the any you want. Then, If when testing, you see it affected something (like battle frontier records, daycare center, "trendy phrase", Rival name), check if it's the variable. If so, try another.
 
Back
Top