TASVideos

Tool-assisted game movies
When human skills are just not enough

Submission #5899: pirohiko's SNES Final Fantasy V "game end glitch" in 10:42.29

Console: Super NES
Game name: Final Fantasy V
Game version: JPN
ROM filename: Final Fantasy V (J).snes
Branch: game end glitch
Emulator: lsnes-rr2 beta23
Movie length: 10:42.29
FrameCount: 38601
Re-record count: 14132
Author's real name: K.N
Author's nickname: pirohiko
Submitter: pirohiko
Submitted at: 2018-04-01 11:18:01
Text last edited at: 2018-04-28 18:38:58
Text last edited by: fsvgm777
Download: Download (6361 bytes)
Status: published
Click to view the actual publication
Submission instructions
Discuss this submission (also rating / voting)
List all submissions by this submitter
List pages on this site that refer to this submission
View submission text history
Back to the submission list
Author's comments and explanations:

(Link to video)

Game objectives

  • Emulator used: lsnes rr2-beta23
  • Heavy glitch abuse
  • Uses sub-frame resets
  • Aims for fastest time
  • Uses game-breaking glitches
  • Corrups save data
  • Abuses programming errors
  • Manipulates luck
  • Arbitrary Code Execution

Subframe reset

If resetting is done while WRAM is being transferred to SRAM, a mixed SRAM is created. When reset between the X / Y address, it warps horizontally from the SRAM position, but it needs to pass a checksum. It is also possible to mix the state of various event flags.

Checksum

The checksum of FF6 adds the game data to the 16-bit register every 8 bits, but this game adds it to the 16-bit register every 16 bits. In this game, it is relatively easy to adjust checksum separately for even and odd bytes in config. Even number bytes have frame advance time, so even number bytes move more intensely.

Helmet of memory destruction.

This movie abuses subframe reset. Some untouched objects will destroy memory when checked. Memory after $1417 will be destroyed if some untouched objects are checked. This game's V-blank interrupt has a jump address set to $1F00, which is dynamically rewritten when changing game scenes. If this address is destroyed, the program of this game jumps to $000000 by the BRK opcode.

Detailed route

  • Saved to data 1 at the position of $0AD8 = {X=0x9C, Y=0x8A}.
    • In the initial state it is more difficult to reduce than adding an even number of checksums, so I first increased it with config ($0970-).
    • By setting to store the cursor position, cursor movement of the menu screen is shortened.
  • Saved to data 3 and 2 at position of $0AD8 = {X=0x9E, Y=0x7B}.
    • It walked downwards and rightwards.
  • Resetting while saving to data 1, at position of $0AD8 = {X=0xAD, Y=0x90}.
    • I adjusted the checksum by reducing the increased configuration value.
    • It is important to speed up the message of the battle, but if you speed up the battle speed faster you will only accelerate the enemy.
    • By subframe reset, the position of data 1 has become {X=0xAD, Y=0x8A}.
  • Loaded from data 1.
    • It walked eight steps to the right.
  • Resetting while saving to data 2, at position {X=0xB5, Y=0x8A}.
    • Because walking is short, I can adjust the checksum by waiting for some frames, but I changed the character position rather than wait long.
    • By subframe reset, the position of data 2 has become {X=0xB5, Y=0x7B}.
    • Data 2 was apparently lost as the checksum was exceeded.
  • Loaded from data 3.
    • It does not move.
  • Resetting while saving to data 2, at position {X=0x9E, Y=0x7B}.
    • By losing data 2, the overwrite question was omitted.
    • The unjoined Lenna whose position was changed in Data 2 was overwritten by the Bartz joined flag.
    • By overwriting the SRAM $0700-$0708, the checksum is corrected.
  • Loaded from data 2.
    • I waited one frame on the loading screen to manipulate luck.
    • This waiting time is absorbed by later waiting time.
    • It walked upwards.
  • Saved to data 4 at position {X=0xB6, Y=0x69}.
    • Normal reset.
  • Loaded from data 3.
    • It walked two steps to the right.
  • Resetting while saving to data 4, at position {X=0xA0, Y=0x7B}.
    • The checksum was adjusted by only waiting for 2 frames when saving the data without using the config screen.
    • By subframe reset, the position of data 4 has become {X=0xA0, Y=0x69}.
  • Loaded from data 4.
    • In this position of the ocean there is an event related to the ship, so I got it!
    • The double speed flag by the chocobo is kept even on the ship, so it is quadrupled.
    • The memory address of the position where the ship landed is $0AEF = {X=0xA6, Y=0x4B}.
  • Saved to data 1 and 3, and resetting while saving to data 4, at position {X=0xA6, Y=0x4B}.
    • I overlapped the ship and saved it.
    • By subframe reset, the position of data 4 has become {X=0xA6, Y=0x69}.
    • This position is adjacent to the middle entrance of the pirates cave.
    • Data 4 was apparently lost as the checksum was incorrect.
  • Loaded from data 3.
    • Landed in front of the Wind Shrine.
  • Resetting while saving to data 3, at the ship landed position {X=0xB5, Y=0x3D}.
    • By subframe reset, the ship landed position of data 3 has become {X=0xB5, Y=0x4B}.
    • Data 3 was apparently lost as the checksum was incorrect.
  • Loaded from data 1.
    • It does not move.
  • Resetting while saving to data 3, at position {X=0xA6, Y=0x4B}.
    • By subframe reset, the position of data 3 has become {X=0xA6, Y=0x4B}.
    • The checksum of data 3 was still inaccurate.
  • Loaded from data 2.
    • It does not move.
  • Resetting while saving to data 3, at position {X=0xB5, Y=0x7B}.
    • The checksum was adjusted mainly by the setting of the custom pad of config.
    • By subframe reset, the position of data 3 has become {X=0xB5, Y=0x4B}, same as the ship.
  • Loaded from data 3.
    • I visited Carwen to pick up the Ice Rod.
    • Disturbance by the residents was avoided with the previous luck manipulation.
  • North Mountain
    • When they get off the ship, their appearance is changed, but the no-encounter flag by Chocobo is kept.
  • Magissa
    • Luck manipulation can be done easily by input before battle.
    • Because the attack magic can not be avoided, the duplicated man was sacrificed.
    • By pressing LR a few lag frames have been reduced.
    • Ice Rod is strong.
    • Then they returned straight to the save point.
  • Saved to data 3, and resetting while saving to data 4.
    • Data 4 was overwritten until no-encounter flag $0A53.
    • They include the Magissa flag $0A18, and helmet flag $0A67 is not included.
    • The checksum was adjusted using several configuration settings and window colors.
  • Loaded from data 4.
    • I waited 17 frames on the loading screen to manipulate luck.
    • To avoid encounters with enemies, 14 steps were added.
    • The double speed flag was erased by the event of a slow moving ship.
    • The no-encounter flag was erased by the event getting off Chocobo.
  • Resetting while saving to data 3.
    • Data 3 was overwritten until $0A67.
    • Because the rear row can escape faster, I changed it.
    • The checksum was adjusted using several configuration settings.
  • Loaded from data 3.
    • Let's set arbitrary code.

Arbitrary code setup

A direct page is 256 bytes that SNES CPU frequently accesses, and it has a memory address set according to the scene of the game different. In this game, the jump address of the BRK opcode is set to $000000. The direct page is set to $0000 in the battle scene, and pad input is put in $0000-$0005. But after loading the save data the memory will be filled with 0. Therefore to execute arbitrary code it was necessary to fight before checking the helmet. However, because it is disturbed by the "no-encounter flag ($0A53:0x80)", you need to see the event getting off Chocobo.

Closed menu input

When walking, the direct page will be set to $0B00, And when you open the menu screen it will be set to $0100. If you input the pad in two frames at the moment the menu screen closes, it will be put into $0100-$0105 and it will not change until you open it again.

  37858|........A.......|
  37859|..sSudl.A.L.....|
address 00 01 02 03 04 05
$0100 20 3E A0 3E A0 3E

Battle end input

If you escape when the second character is in order, $000A will be "FC 00 01". Then $0000 was adjusted at the moment the battle screen closed.
  38444|....u...A.......|
address 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
$0000 80 08 80 08 80 08 FC 00 01

Checked helmet input

  38595|B.sSu..rA.L.....|
  38596|B.sSu.lrAXLR....|
address 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
$0100 20 3E A0 3E A0 3E F0 BB F0 BB 50 02 80 01 F0 BB
$0110 A0 B9 00 00

Last 7 frames input

When Joypad-Registers was read by unjust timing, bit position slipped, so I did the input by which that was considered.
               1-1              1-2              2-1              2-2
  38595|B.sSu..rA.L.....|................|................|................|
  38596|B.sSu.lrAXLR....|.YsS..lr.XLR.12.|.YsS.dlrAX.R.1..|.Ys..d.rA.L.0.23|
  38597|B..S............|................|B...............|B...............|
  38598|..s.udlr....012.|...S.d.r........|B..Sud.......1.3|BY..u.lrAX..0.23|
  38599|.Y..u...A..R01..|....ud.r..LR0.2.|B..Sud.....R01.3|BY..u.lrAX..0.23|
  38600|BY.Su..rA...012.|BY...d.r...R0.2.|BY.Sud.....R01.3|BY..u.lrAX..0.23|
  38601|.....dl.A....1.3|....u.lr.X.R01..|....u...AX...12.|........A.L...2.|
Actual Joypad binary
A9 EF EC 06 57 CB
0E 9F 05 8C 00 05 CB CB
9C 28 1D 9C 3A 1D CB CB
8E 48 1D 9C 1A 05 CB CB
85 D6 C6 D8 5C CB A2 C0

Executed codes

  00CEE0 5C 00 1F 00 JML $001F00  A:04fc X:1f52 Y:130e S:1ff5 D:0b00 DB:00 nvmxdIzC V:240 H:  98
  001F00 00          BRK
  000000 80 08       BRA $000A
  00000A FC 00 01    JSR (0100,x) -- $2052 return 0101
  000101 3E A0 3E    ROL
  000104 A0 3E F0    LDY #$F03E   -- Y = F03E
  000107 BB          TYX          -- X = Y
  000108 F0 BB       BEQ
  00010A 50 02       BVC $010E
  00010E F0 BB       BEQ
  000110 A0 B9       LDY #$00B9   -- Y = 00B9
  000113 00          BRK
  000000 80 08       BRA $000A
  00000A FC 00 01    JSR (0100,x) -- $F13E return 4218 yey!
  004218 C1 FE       CMP
  00421A A9 EF EC    LDA #$ECEF   -- A = ECEF
  00421C 06 57       INC $0B57    -- Event talk flag on
  00421F CB          WAI
  00CEE0 -> 001F00 -> 000000 -> 00000A -> 004218
  004218 0E 9F 05    ASL $059F    -- GALUF ID 42 -> KLIRE ID 84
  00421B 8C 00 05    STY $0500    -- BUTZ  ID 00 -> LENNA ID B9
  00421E CB          WAI
  004218 9C 28 1D    STZ $1D28    -- APU data fix $1D28 = 0000
  00421B 9C 38 1D    STZ $1D3A    -- APU data fix $1D3A = 0000
  00421E CB          WAI

  004218 8E 48 1D    STX $1D49    -- APU data fix $1D49 = F03E
  00421B 9C 1A 05    STZ $051A    -- LENNA Status = 0000
  00421E CB          WAI

  004218 85 D6       STA $0BD6
  00421A C6 D8       DEC $0BD8    -- Event Pointer = C8ECEF
  00421C 5C CB A2 C0 JML $C0A2C0  -- Event Script engine

likelihood

Dead zombie and chemist glitch could also do Arbitrary Code Execution likewise, but I thought the second world was far.

Special Thanks

  Yu-ki(hs), Sumurai Goroh, Yona2san

Masterjun: This looks interesting. Judging.

Masterjun: An important part to note for this run is the fact that it executes controller registers while they are being updated. This is known to not be emulated in a correct way on emulator. This gives this run a high chance of not working on console at all. However, leading the game code to the controller registers is done perfectly fine, so while these exact input sequences probably won't work on console, it's likely there are indeed some inputs which work. The run wouldn't look very different, so we can safely say that this isn't a problem.

Important to note is if there was a submission that is a bit longer, but with a more accurate way of beating the game in terms of emulator accuracy, then it can count as superior and obsolete this movie.

No other problems with this run and the viewer feedback has been quite good as well.

Accepting to Moons.

fsvgm777: Processing.


Similar submissions (by title and categories where applicable):