Pokemon Gen 1, 2, and 3 had save corruption, so why not Gen 4? :)

Game objectives

  • Emulator used: BizHawk 2.11.1
  • Beat the game as fast as possible
  • Use save corruption!

Save Corruption

The Save Medium

Like Gen 3, Gen 4 uses Flash for save data. Flash can only be written to using "commands" against the flash chip.
The main command used is simply the "page write" command. On this Flash chip, a page is 256 bytes. This command allows for writing a stream of bytes within an arbitrary location within a page of Flash. The command itself is combined with the bytes written, so all bytes are sent to the Flash chip in a buffer before the command executes.
Internally, this command is actually two commands in a trenchcoat: it first erases the selected bytes within the page to 0xFFs (as erasing is the only way to set bits), then proceeds to "program" them ("progamming" bytes can only clear bits, not set them).
On hardware, these commands take some time to complete on the Flash chip's side (requiring waiting for completion of the command). However, emulators do not emulate this timing, instead having all commands performed instantly once sent.
These commands are handled by the DS's SDK, so all games have the same internal behavior when it comes to command handling. An interesting quirk within the SDK's handling is that it waits 25ms after executing a command before checking if the command has finished. These commands typically finish much, much sooner than 25ms, resulting in effectively 25ms taken for each page write. This also means emulators having "instant" commands does not matter, as the SDK is going to wait at least 25ms regardless.

Gen 4's Save Format

Gen 4 has a fairly simple save format, as far as save corruption is concerned. There are two blocks of save data: "normal" save data, and "box" save data. Each block has a footer attached, containing counters, a CRC16, and a "magic number."
There is also a backup save system, where the game has a second pair of save blocks. This effectively creates two save sides, which the game alternates between for each save. The counters in the footer tell the game which side is newer.
This format ends up nearly defeating save corruption itself. Footers are only written at the end, and saving is only going to write to the "older" save, not the "newer" save. The game also will not allow a newer "normal" save to be loaded if its counter does not match the "newer" box save (as a way to prevent cloning box data).

Clearing Save Data

In Gen 3, you could simply abuse clearing save data in order to corrupt the "newer" save and thus force the game to load the "older" save and overwrite the "newer" save, thus allowing for reset as long as it occurred after the point deleting save data corrupted the save.
However, it seems Game Freak realized this, and thus patched this entrypoint. They did this by erasing all save footers before touching the save data. The older save's footer is always erased first here (preventing the older save be force loaded by abusing clearing save data).
However, Game Freak failed to account for one possibility: a save footer might not be entirely contained within a single Flash page, due to crossing a Flash page boundary. In Platinum, by chance, this possibility occurred for the box save footer. Due to this, the box save footer can be partially corrupted by simply resetting while the first page is erased, but before the second page is erased, creating a pseudo permanent corrupt state.
As a note, it appears Game Freak realized this, and thus patched this issue in HGSS by forcing the save footer to start on a new Flash page.

0xFFFFFFFF Counter

In Platinum, the save footer for the box save contains the first 4 bytes in the first Flash page, then the second Flash page contains the rest of the footer. These 4 bytes contain the "global count" and are interpreted as an unsigned integer. As such, an 0xFFFFFFFF count results in the game effectively always considering that box save as the "newer" save. As far as the game can tell, the box isn't actually corrupted per se, but since the "global count" does not match the newest normal save, the game assumes you reset after the normal save but before the box save, thus forcing you to load the older normal save. However, this assumption is broken with this corrupt count, this mismatch occur even after a complete save. This allows for partially saving over the "older" save, which if the checksum is still valid, will end up being loaded by the game.

CRC16 and RTC

The game uses a CRC16 to determine if a save is corrupt or not. In order to force the game to load this partially saved save, the CRC16 needs to still be correct. Unfortunately, there is very little data that can be easily manipulated, except one: the RTC. The game stores the current RTC within the save, so by changing RTC between saves, it is possible to manipulate a checksum collision.

Player Position Desync

Gen 4 makes the genius decision of effectively having 2 places where the player's location is saved. The first location is intended solely for the player's location, containing the map the player is on, along with the player's coordinates. However, while the map is taken from here upon loading the save, the player's coordinates here are not actually used. Instead, they are taken from the second location: the first map object saved. The game saves various map objects, mainly NPCs. The player itself counts as a map object, and the coordinates of this map object are what's actually used when loading the save.
This creates an obvious application for save corruption, allowing for the player to get out of bounds easily. This also allows for NPCs to be transferred between different maps, or even effectively removing NPCs from the new map.

Ledge Cancelling and Voiding

Normally, voids in Platinum contain tons of impassable tiles to prevent void exploration. However, ledge cancelling can allow for some void exploration. Ledge cancelling involves simply pressing X to open the menu while jumping a ledge, possible in the void where a ledge jump can occur after stopping (you can open the menu as long as you have "stopped"). Ledge cancelling effectively allows opening up a crack into the void, opening up a path in the top left of the map to explore upwards.
Ledge cancelling requires specific ASLR to manipulate a ledge within the void. Manipulating ASLR is actually very similar to Gen 5 initial seeding, and ends up being very easy for a TAS to manipulate as there are only 65 possible ASLR options and 8192 button input combos can be used to manipulate ASLR.

The Actual Run

Initial Seed Manip

RNG is seeded using the following formula:
0xAABBCCCC
AA = Day * Month + Minute + Second
BB = Hour
CCCC = 2 last digits of the year + vblanks since reset
This run uses July 31, 2035 at 11:19:22 AM, with 4435 vblanks since reset. This results in initial seed 0x020B1176.

Starter and Rival

The starter chosen is Chimchar. It's fastest to lose the rival fight, avoiding doing any damage to the rival (as such trigger dialogue in the battle). Chimchar has Leer, which doesn't reduce the effectiveness of the opponent's attacks, as opposed to Growl (Piplup) or Withdraw (Turtwig).
Battle RNG operates like Gen 5, in that it is seeded on battle start (using the same formula above) and only advances when needed instead of every frame. As such, the initial seed at the start of the battle effectively determines the entire battle. The battle RNG seed is manipulated to have Piplup use Pound 4 times in a row.
Chimchar is manipulated to have low defense IVs and a negative defense nature, allowing for Piplup to 4HKO Chimchar without 1/16 rolls (too difficult to manipulate, due to the above).

Void Route

The void route is fairly simple. Sandgem Mart can go to Pastoria Gym. Pastoria Gym can be exited, allowing for a run over from Pastoria City over to Veilstone City. Route 214 has 1 non-optional trainer, so save corruption is used to bypass this trainer. Veilstone Mart 5F can go to the 2nd Pokemon League room, which can then go to Hall of Fame room.

Tegron: Claiming for judging.

Tegron: Replacing movie file with this improvement posted by the author.
This is another amazing TAS for Pokémon using a save glitch, this time on the DS. There are many optimizations within the game itself, as well as setting the system date to finish the game faster. There are so many glitches when using save files that they can break the game even further, saving hours of gameplay and making it over 2 hours and 20 minutes faster than an RTA on emulator. This TAS is incredible.
Accepting to Standard

r3gamerz: Processing...


TASVideoAgent
They/Them
Moderator
Location: 127.0.0.1
Joined: 8/3/2004
Posts: 17998
Location: 127.0.0.1
Emulator Coder, Judge, Skilled player (1691)
Location: California
Joined: 2/26/2020
Posts: 933
Location: California
Missed a slight optimization with the final ledge cancel, costing a few frames, fixed movie: https://tasvideos.org/UserFiles/Info/639208106694793202
Emulator Coder, Judge, Skilled player (1691)
Location: California
Joined: 2/26/2020
Posts: 933
Location: California
And now 36 second improvement from integrating NPC ASE: https://tasvideos.org/UserFiles/Info/639212195718641005
Post subject: Movie published
TASVideoAgent
They/Them
Moderator
Location: 127.0.0.1
Joined: 8/3/2004
Posts: 17998
Location: 127.0.0.1
This movie has been published. The posts before this message apply to the submission, and posts after this message apply to the published movie. ---- [7376] DS Pokémon: Platinum Version "save glitch" by CasualPokePlayer in 20:08.954

1788991062