Submission #9457: CasualPokePlayer's GB Pocket Monsters: Green Version "game end glitch" in 04:18.68

Game Boy
Pocket Monsters: Green Version
game end glitch
BizHawk 2.9.1
15488 (cycle count 542494694)
59.87282555062188
42019
PowerOn
Pocket Monsters - Midori (Japan) (SGB Enhanced).gb
JPN v1.0
82c0eef40a5e2423699d9fd8ba15dfaa8b51d196
Submitted by CasualPokePlayer on 1/6/2025 8:23 PM
Submission Comments
Improvement over [1639] SGB Pocket Monsters: Green "warp glitch" by p4wn3r in 04:24.37 and #9444: Fortranm's GB Pocket Monsters: Green "warp glitch" in 04:22.88. This submission is intended to have Japanese non-save corruption runs be a separate branch.

Game objectives

  • Completes the game as fast as possible without save data corruption

ACE setup

Instead of using the select glitch and Dokokashira door glitch to simply perform a series of warps to get to the Hall Of Fame room, run opts to ultimately trigger ACE to trigger the Hall Of Fame sequence.
The select glitch ultimately sets up a case where the game will look for "Pokemon" outside of the actual party to decrease HP for "poisoned" ""Pokemon"". In some cases, this decreases the map ID in some of the warp entries, leading to the Dokokashira door glitch. However, it can possibly decrease another particularly useful value, the current map ID. This map ID is used by the game to determine which bank the current map script should be ran under. With a different bank being used than expected, the game will most likely "crash" in some way.
This "crash" could be an invalid opcode or stop, which ends execution immediately. It can however be one of the rst opcodes, which will eventually trigger rst $38. In Japanese Gen 1 games (along with some other unrelated games), rst $38 contains jp 0xF080. This was changed to be another rst $38 in Japanese Yellow 1.1, and subsequently all later versions of Gen 1 have rst $38 in rst $38. It's presumed that this jump was intended as some sort of leftover debug code, but in the case of the actual released game, it just gives easy access to ACE.
0xF080 contains data about the last sprite decompressed. A lot of it is junk, but it happens the beginning of this data is the sprite width and height. These have some variation, but they ultimately end up being some form of one of the jr opcodes, which allow for jumping forward, past most of this data. After that data, however, is a buffer of move strings. These move strings will end up having invalid opcodes in them, completely stopping execution. This buffer can be cleared by save and quitting, so a save and quit is required.
Eventually, more controllable bytes are reached. wIgnoreInputCounter, wStepCounter, wPlayerName, wPartyMon2OTID, wPartyMon2DVs. All of these are used to ultimately redirect execution to the Hall Of Fame sequence.
wIgnoreInputCounter is just a counter that just ticks down every frame. For the payload, the run ensures it is 0xF8. wStepCounter is made to be 0xFC (note that the step counter ticks downwards, not upwards, and resets upon a save and quit). The player is named "ギホゴ". The trainer ID is manipulated to be 0x0616. Multiple other TIDs could have been used, but this was the fastest one to manipulate. The starter DVs are manipulated to be 0xC4AA (0xC2AA also would work, but 0xC4AA is what I ended up getting). This results in the following payload:
; wIgnoreInputCounter + wStepCounter
ld hl,sp-4 ; hl = 0xDFF1
; player name
ld b,0x9C ; bc = 0x9C00
add hl,bc ; hl = 0x7BF1
; starter pokemon
; catch rate
dec l ; hl = 0x7BF0
; growl
dec l ; hl = 0x7BEF
; tid
ld b,0x16
; dvs and pp
call nz,0x23AA
The end of the payload does a jump to 0x23AA. This is a ROM address, within a far jump into some map code. This ends up calling the Bankswitch function in the game, which switches the ROM bank over to whatever b has and jumps to whatever hl has. This means the game bankswitches to bank 0x16 (keep in mind the game only has 0x20 ROM banks, so any b value higher than 0x1F effectively gets moduloed by 0x20, so 0x16, 0x36, 0x56, etc all work), and jumps to 0x7BEF. 0x7BEF in bank 0x16 is the middle of the Hall of Fame script.

Route

  • The trainer ID is manipulated to be 0x0616. 0x0636, 0x0656, 0x0676, 0x0696, 0x06B6, 0x06D6, and 0x06F6 also work, but 0x0616 ended up being the fastest to manipulate.
  • The player is named "ギホゴ" and the Rival is set to the first preset option.
  • Charmander is picked as the starter, with 0xC4AA DVs. 0xC2AA would also work for this TAS. In theory, a ton of other DVs would work for the ACE payload, but 0xC2AA and 0xC4AA are the best in this case, as they are the only ones which give Charmander 0 HP DVs, and thus gives Charmander 18 HP (even 1 HP DV would bump Charmander's HP to 19). It is not nicknamed, as the name is not shown enough to save time nicknaming. Squirtle and Bulbasaur cannot be used, as they have Tackle, which ruins the payload used.
  • The Rival fight is purposefully lost, as it does not need to be won and it is fastest to lose. This is done in 3 turns, each comprising of a 1/256 miss with Growl, and a 1/39 crit with Tackle. A 1/39 Tackle crit does 6 damage to Charmander, so having 18 HP allows for a 3 turn fight. Who doesn't love a 1/1178114537369 Rival fight.
  • Options are not set for the Rival fight. Keeping animations on during the Rival fight saves a bit of time due to Tackle being faster with animations on rather than off. It also saves time as it avoids ever going into the options menu, which is completely unneeded for this run.
  • A Pidgey is encountered at the end of Route 1. This has the shortest cry of the Pokemon in Route 1. Its encounter location is also manipulated to allow for the earliest poison tick to occur on entering Pallet Town.
  • A warp is done near the southern entrance to Fuschia City.
  • A save+quit is done once two poison ticks are done, as to ensure the next one after the save+quit triggers the ACE payload.
  • The Hall of Fame still needs input to clear some textboxes to advance to the credits, so input doesn't end until those textboxes are cleared.

DrD2k9: Claiming for judging.
Last Edited by CasualPokePlayer 1 day ago
Page History Latest diff List referrers