Resetting the game while saving is bad, but in a TASers point of view it can be very useful. This TAS uses this to corrupt save data and complete the game.
Game objectives
- Emulator used: lsnes rr1-Δ17ε3
- Heavy glitch abuse
- Corrupts save data
- Manipulates luck
This run uses the same strategy as the
currently published run. It uses a more accurate emulator, which is the reason this run looks slower. However, if you take away the frames that are lost due to emulator differences, you can see that this run basically saves 2 frames from better luck manipulation (which also depends on the core used).
What is happening?
Resetting while saving
If you reset the game while saving it normally either doesn't let you CONTINUE at all, or it shows that The file data is destroyed, but if you reset just at the correct frame you can continue a save where every address starting from $D162 to $D2F5 is filled with 0xFF (dec 255) which will make the game think you have 255 Pokemon. Since the game normally thinks of you having only 6 Pokemon, it will overwrite other addresses when you switch Pokemon.
Important addresses
Trainer ID (2 bytes): $D358
Current map: $D35D
Map function (2 bytes): $D36D
In the game code the current map will load a bank and then it will jump to the address that is stored in the map function address. If you overwrite the map address with a value that loads bank 0x16 (which are 0x11, 0x13, 0x15, 0x16, 0x17, 0x1A, 0x1B, 0x1D, 0x5A, 0x71, 0x76, 0xCF, 0xD0 and 0xEA) and then you overwrite the map function address with a value that eventually reaches the rating routine, you can finish the game. These addresses can be manipulated by switching Pokemon and Items.
To make this faster, it is possible to manipulate the Trainer ID (TID) to get the values faster. The rating routine is at 16:6439 (bank 0x16, address $6439) but the TID can only manipulate 2 bytes, the bank (in this case 0xD0) and the higher byte of the address that will be jumped to (in this case 0x64). So we currently will jump to 16:64xx. The xx will be the byte before the TID which is 0x01. Jumping to 16:6401 executes some instructions and then happens to come across 16:6439, the rating routine! Now we need to place these values, we have to move the values from:
- $D357 to $D36D
- $D358 to $D36E
- $D359 to $D35D
The process
- Swap one of the first few Pokemon, in this case the 7th, with the 10th Pokemon. This will overwrite addresses like the item count with 0xFF. Now the game thinks that you have 255 items (there is also a side effect that the Pokedex data is filled with 0xFF, so we have seen and caught 152 Pokemon).
- Swap the 12th Pokemon with the 13th so that the 0x64 goes to $D384 and 0xD0 goes to $D385.
- Swap the 13th Pokemon with the 11th so that the 0x64 goes to $D32C and 0xD0 goes to $D32D. Here a 11 byte data overlaps and causes 0x64 to go to $D342.
- Swapping Pokemon always moves big chunks of bytes, swapping items makes finer steps. So move the 0xD0 from $D32D to $D331.
- Swap the 11th Pokemon with the 12th. This causes 0xD0 to go to $D35D (current map) and the 0x64 goes to $D36E, since there is a 0x01 before the TID it is now at $D36D.
Closing the menu will make the game see the 0xD0, load bank 0x16 and thus jumps to 16:6401 which executes some instructions until it executes the rating and the credits routine starting at 16:6439.
Manipulating the TID
The TID is changed by the internal gameboy timer which only allows waiting a frame to change it. It also isn't possible to predict that value so you can only brute force the best output. The TID is determined after you chose NEW GAME so you have to wait frames before that. There are 4 different places where you can wait:
- at the GAME FREAK scene
- at the little running Pikachu scene
- at the title screen
- at the "New Game" menu.
Since I already had a version where I waited 9 frames in total I just had to test every possible way where I waited 0, 1, 2... 7 or 8 frames. The formula for a given number n of total frames I have to wait is
1/6*(n+1)(n+2)(n+3)
so I just had to test 495 inputs and I didn't find any better solution. The brute force lua script for this (for Bizhawk) can be found
here.
The previous run waited a total of 11 frames where this run waits only 9 frames
Screenshots
[dead links removed]
Thanks to
p4wn3r and gia which did a great job exploring the game, optimizing the runs and finding new strategies to completely skip the game.
Noxxa: This submission has led to a lot of heated discussion and debate as to what should happen if a run is "resynced" on another, superior emulator, even though it does not actually improve upon the
previous run by p4wn3r. I do not consider this run a real improvement upon the previous run, because the two-frame improvement only exists because of the change in emulator core. It cannot be replicated on the same emulator as that of the previous run.
So, what to do with resyncs? I do not believe in obsoleting runs with new runs that do not contain an actual improvement - it is not fair to the original author to do so. So, I think the previous publication should remain, and thus this submission shall be rejected. There can be discussed about adding credit to Masterjun for his resync efforts in the current publication - it seems the majority of people wish for something like that to be done - but there is
another topic for this discussion. I agree in giving Masterjun credit for his work in resyncing this run to the Gambatte core, and putting a note in the current publication, but it does not warrant a new publication. Rejecting this submission.