Another improvement to Gen 2 save glitch.
The strategy for this run is to get out of bounds to map 0xFF00, similar to my previous
Crystal save glitch TAS. This is done by resetting right after the player's coordinates are written but before the visible map cache is saved, resulting in a desynchronized map state, allowing for the map to be exited in unintentional ways. Map 0xFF00's corruption gives us access to a highly corrupted inventory and thus a seemingly easy vector for ACE.
However, this run opts to do this very early, before even talking to Mom. This poses a grave problem: you can't use wrong pocket TMs/HMs without a Pokemon in the party (as the game prevents item effects for items needing a Pokemon. Granted this is strange for wrong pocket TMs/HMs since separate code handles the correct TMs/HMs pocket). There is also the minor problem of not being able to actually use Mail to setup an ACE payload.
So without a Pokemon, it seems like this route is impossible. However, I discovered a saving grace: registered items. Registered items are not subject to the Pokemon in a party limitation (as Game Freak didn't add such code to registered item handling). So we can freely use a wrong pocket TM/HM by "registering" a wrong pocket TM/HM. An extra saving grace is HM03, which runs the daycare withdraw code, thus allowing us to get a Pokemon!
Another change here is a different wrong pocket TM is now used. TM33 is used, which has its effect pointer at F418
. This ends up sliding down wReceiveCallDelay_StartTime
(which appears to just be a copy of the current time, and eventually our trainer ID. This gives us enough tools to jump to the temp Mail buffer.
Bytes | Instruction | Comment |
---|
3a | ld a,(hl-) | Current minute, a = 0 |
62 | ld h,d | High byte of TID, h = d0 |
f7 | rst $30 | Low byte of TID, acts as jp ha , jump to d000 (a little before temp mail buffer) |
The mail payload has also changed, it now is able to handle subframe inputs, allowing for a much faster final ACE section.
Bytes | Instruction | Comment |
---|
97 | sub a,a | a is variable at this point, so 0 it out |
f6 f0 | or a,$F0 | a = $F0, f = $00 |
f5 | push af | push $F000 (a little before temp mail buffer) |
d6 f6 | sub a,$F6 |
d6 f1 | sub a,$F1 | a = $09, f = $40 |
f5 | push af | push $0940 (middle of UpdateJoypad, the latest before it doesn't poll input correctly) |
f6 d0 | or a,$D0 | a = $D9 |
e0 a5 | ldh ($FFA5),a | write a reti to hJoypadSum |
d2 a4 ff | jp nc,$FFA4 | jump to hJoypadDown |
The general idea in this routine is it pushes af values to act as return addresses, first to UpdateJoypad (to update joypad variables), then back to the mail payload (effectively acting as a loop). hJoypadDown is jump to to execute what was pressed down, then the planted reti
lets the payload loop. UpdateJoypad trashes most registers, except HL, so HL is purely used for the input opcode payload.
The input opcode payload performs the following operations.
Address | Memory change |
---|
wPlayerLastMapY ($d4e9) | $0A -> $49 |
wPartyCount ($dcd7) | $01 -> $00 |
wSouthConnectionStripXOffset ($d1be) | $cf -> $06 |
wSouthConnectionStripYOffset ($d1bd) | $94 -> $09 |
wSouthConnectedMapNumber ($d1b6) | $10 -> $4c |
wSouthConnectedMapGroup ($d1b5) | $78 -> $03 |
Red event flag ($db5e) | $44 -> $43 |
wInputType ($e2c7) | $00 -> $ff |
Corrupted stack ($e0f0) | $ff -> $5e |
Corrupted stack ($e0ef) | $00 -> $76 |
The stack pointer is set to $e0df in the end, finishing the payload.
So with these in place, the plan is follows:
- Perform save corruption to misalign the visible map cache and the player's Y coord.
- Step down to get OOB.
- Create Mail.
- Create TM33.
- Fake "register" HM03.
- Use Select in the overworld to use "HM03" and thus get a Pokemon.
- Use Mail to write payload.
- Use TM33.
- Win!
DrD2k9: Obviously a well planned and executed run.
Since the method of performing the save glitch is different than it is in the Gold/Silver versions, Accepting as a kinda new branch.
NOTE TO PUBLISHER: Once this is published we need to update the obsoletion chains to separate the Gold and Crystal runs of the "save glitch" branch. I don't mind doing it if you don't want to.