ACE in G/S via stack corruption (compatible with all european versions and VC)
Posted by: Crystal_
Date: 2017-09-29 16:22:01
Step by step video (with updated and organized information in comparison to the third post): https://www.youtube.com/watch?v=b2tVVeZ7Th4
I've tested this in an english Silver ROM and spanish Gold ROM and given that the essential elements and key memory addresses were the same in both games, I assumed that it would also be the same in all other localizations. However, futher testing, and of course, a lot of polishing, would be required. The english versions don't need ACE since we already have coin case, so the goal was to find a method compatible with all other localizations.
First we need a 0xFF Pokemon in order to be able to draw Pokemon beyond the sixth slot. I'm not going to get into the details of how to achieve it.
When the 30th Pokemon is withdrawn to the party, it corrupts addresses between DF9A and DFB9. In particular, when the Pokemon's data is being copied from SRAM to those WRAM addresses, the stack pointer is at DFB3, and the 3rd and 4th PP slots of the Pokemon are copied to DFB3 and DFB4, respectively. Returning from the memory copy routine will bring the game to whatever stack pointer was spelled out by those two PP fields. Using PP ups, we can come up with any given address that we want, for example one that points to somewhere in the box names buffer.
Of course, after doing this, the stack is absolutely destroyed and there are no realistic hope of restoring it to anything playable. We can still do something though. We can hack ourselves a TM into the medicine bag pocket in SRAM that we can utilize later. This may look way too complicated but it doesn't necessarily have to be. First of all, SRAM bank 1 is already opened right now. We only have to overwrite A420 (medicine pocket item 1) with the id of the desired TM and fix the checksum at AD69-AD6A. If we set a fixed item #1 as an initial requirement (e.g. a Berry), we can calculate the necessary checksum shift. If the id's are relatively close, we might even be able to skip checking the checksum's high byte to simplify the needed script and hope the low byte doesn't overflow (literally anything we do will change the checksum upon saving anyway, so we can just try again until it works). Finally, we can trigger a safe reset or freeze, and upon restarting the game, we will have our TM in the medicine pocket. Note that the SRAM addresses mentioned here refer to spanish Gold/Silver; they may be different in other localizations.
Now it's supposed to be similar to coin case ACE in concept. We find a TM that jumps to a suitable place in WRAM (I think ACE with TM33 transferred from Red/Blue has been done already), and when we have it, we create some bootstrap code that for example redirects execution to box names or PC items.
These are the TM pointers in spanish G/S:
14FE - TM01
15CD
CA31
77F6
EAAF - TM04_X
D14F
02FA
FED0
C4B1
6E1E
9921 - TM10
CBD1
21A6
7857
5ECD
FA0F
D114
FA47
D119
03FE
20CA - TM20
FA6A
D002
01FE
20CA
FA6A
D002
214F
6C73
FE2A - TM28_X
28FF
B90F - TM30
0428
2323
F418
662A
116F
698A
E9D5
02FA
FED0
789F - TM40
12CA
786A
B8E0
FF21
46D0
4E23
5623
5E23
21CB
10CB - TM50
Again, this obviously needs a lot of polishing and coming up with bootstrap codes yet, as well as adapting it to each other localization, each of which may have different SRAM addresses and different wrong pocket TM pointers, as well as a different set of assembly instructions that can be spelled out with box names. So far I haven't bothered to check beyond the english and spanish versions, but the 3rd and 4th move PP of the 30th Pokemon being written to the stack pointer (DFB3-DFB4) matched in both versions, so I assume it would also be the same in the other localizations. The other factors don't seem essential unless we're really unlucky with TM pointers.