Submission #4770: pirohiko's NES Final Fantasy II in 07:32.37

(Link to video)
Nintendo Entertainment System
baseline
FCEUX 2.2.2
27187
60.0988138974405
570
Unknown
Final Fantasy II (J).nes
Submitted by pirohiko on 7/21/2015 9:53:10 PM
Submission Comments

Game objectives

  • Allow Left+Right / Up+Down
  • Emulator used: FCEUX 2.2.2 (Old PPU)
  • Major skip glitch
  • Executes arbitrary code
  • Corrupts memory
  • Genre: RPG
  • Uses a game restart sequence
  • Aims for fastest time
  • Heavily abuses programming errors
  • Manipulates Luck

Usable memory address

  • $00F5 = RNG index
  • $00F6 = RNG index direction, if it is more than 80, it is leftward.
  • $F900-$F9FF = RNG table
  • $F900+($00F5) = RNG
  • $00F7 = The encounter number of times
  • $00F8 = The encounter threshold in UW

Save and Restart

Even if a game is reset, the encounter table is held. 1. You save a game 2. You move it one pixel 3. You reset a game 4. The encounter is skipped When you overwrite a game, the confirmation message is very slow. Because a game is saved before confirmation, it is fast that a game is reset than it closes a menu. It is faster to touch a power supply, but 1/4 time is good at a good balance with the distance to walk.

To Paloom

The route going around the world to the west obtains a canoe and is faster than a route across the river by more than 50 seconds.

Chocobo Forest

Because the power supply was initialized, NPC RNG is not manipulated. On the way, I adjusted it to be able to encounter the Land Turtle.

Takeover of the shuttle ship

When you push the start button just before you enter the paid sailing ship, the autopilot is concluded with a menu screen and becomes able to steer it by yourself. But you can never get into a ship if you got it off in the island.

Deist Cavern

The monster of this place cannot escape. I pushed forward RNG for encounter evasion twice using Potion. Because the encounter number of times is 4, the land turtle appears.

45-floor bug

Outline

Please refer to the post of TaoTao.
This game has room movement of "goto" and "return". 5 bytes are pushed to stack domain by "goto" movement, and it is popped for "return" movement. "goto" movement is repeated between the rooms with complicated divergence of stairs. "goto" movement is restricted by 45 times, but that's insufficient, so when a battle was accomplished, a stack overflow occurs.

Top of the stack and NMI

When Non-Maskable Interrupts (NMI) occurs by this game, $0100 are run. $0100 are the top of the stack domain that is 256 bytes, and ReTurn from Interrupt (RTI) and JMP are written in dynamically here. When the stack is pushed up to $0101-$0102, unjust JMP is carried out at the time of NMI, the game almost freezes, and the save data often disappear, too.

Why were $6785 called?

When the second character attacked the Land Turtle, a stack domain was renewed to $0101 by a recursive Jump SubRoutine (JSR).
27364 frame
A:FF X:04 Y:08 S:02 P:NvUbdIzc                              $9B4A:20 B6 9B  JSR $9BB6
A:FF X:04 Y:08 S:00 P:NvUbdIzc                                $9BB6:A5 C4     LDA $00C4 = #$FF
NMI occurs in the middle of a calculation, and return address and P-Register are pushed to stack up as "$010F:27 A0 FC".
  • P:nvUbdIZC = 0b00100111 = 0x27
A:00 X:10 Y:EE S:11 P:nvUbdIZC               $FC9E:85 04     STA $0004 = #$00
A:00 X:10 Y:EE S:0E P:nvUbdIZC                  $0100:4C 4C 9B  JMP $9B4C
A:00 X:10 Y:EE S:0E P:nvUbdIZC                  $9B4C:6A        ROR
NMI jumped to $9B4C, and a Stack-Pointer slipped off when the Program-Counter returned from many subroutines. RTI using 3 bytes at the end of NMI is usually appropriate, but the Program-Counter goes to $A028 because RTS, which in this case only 2 bytes uses, was run.
27374 frame
A:00 X:03 Y:00 S:0E P:nvUbdIZC                  $9B84:60        RTS -
A:00 X:03 Y:00 S:10 P:nvUbdIZC                $A028:04        NOP (illgal)
A:00 X:03 Y:00 S:10 P:nvUbdIZC                $A02A:66 A9     ROR $00A9 = #$76
A:00 X:03 Y:00 S:10 P:NvUbdIzc                $A02C:15 85     ORA $85,X @ $0088 = #$04
A:04 X:03 Y:00 S:10 P:nvUbdIzc                $A02E:67        RRA $20 (illgal)
A:40 X:03 Y:00 S:10 P:nvUbdIzc                $A030:2F        RLA $A997 (illgal)
A:40 X:03 Y:00 S:10 P:nvUbdIzc                $A033:05 85     ORA $0085 = #$0E
A:4E X:03 Y:00 S:10 P:nvUbdIzc                $A035:66 A9     ROR $00A9 = #$BB
A:4E X:03 Y:00 S:10 P:nvUbdIzC                $A037:69 85     ADC #$85
A:D4 X:03 Y:00 S:10 P:NvUbdIzc                $A039:67        RRA $20  (illgal)
A:F2 X:03 Y:00 S:10 P:NvUbdIzc                $A03B:2F        RLA $A997 (illgal)
A:40 X:03 Y:00 S:10 P:nvUbdIzc                $A03E:06 85     ASL $0085 = #$0E
A:40 X:03 Y:00 S:10 P:nvUbdIzc                $A040:66 A9     ROR $00A9 = #$5D
A:40 X:03 Y:00 S:10 P:nvUbdIzC                $A042:20 85 67  JSR $6785
  • $A041:"A9 20 85 67" is "LDA #$20" and "STA $0067"
  • $A042:"20 85 67" becomes "JSR $6785", because 1 byte slips off than a right program.
27374 frame
A:40 X:03 Y:00 S:0E P:nvUbdIzC                  $6785:4C 42 64  JMP $6442
A:40 X:03 Y:00 S:0E P:nvUbdIzC                  $6442:CE CF D0  DEC $D0CF = #$85
A:40 X:03 Y:00 S:0E P:NvUbdIzC                  $6445:4C 4D F3  JMP $F34D
It can arrive at the credits by "JMP $F34D", but MMC1, which became unstable because of "RLA $A997", will fail in bank changing. I initialize MMC1 with "DEC $D0CF" to evade it.

The details of the character

SRAM Addresses

Save Data 1
$64400100CECFD04C4DF31400140005000500
Save Data 2
$67000000FFFFFFFFFF951E001E0005000500
$67400100CECFD04C4DF31400140005000500
$67800200D0DAD14C42642800280005000500
$67C00800A2B6A2B6FFFF1E001E0005000500

Meaning of the character name

1st Five space that were skipped"Shi" is death
2nd "O KA KI" is DEC $D0CF "Bi Bu Re" is JMP $F34D
3rd "Ki Chi Ku" is without meaning"Bi Ji Pa" is JMP $6442
4th "No N No N" is without meaning

Nameable Text Table

8A8B8C8D8E 8F90919293
9495969798 999A9B9C9D
9E9FA0A1A2 A3A4A5A6A7
A8A9AAABAC B0B1B2B3B4
ADAEAFB5B6 3C3D3E3F40
4142434445 464748494A
6465666768 4B4C4D4E4F
7D7E7F7CFF 8081828384
CACBCCCDCE CFD0D1D2D3
D4D5D6D7D8 D9DADBDCDD
DEDFE0E1E2 E3E4E5E6E7
E8E9EAEBEC F0F1F2F3F4
EDEEEFF5F6 5051525354
5556575859 5A5B5C5D5E
696A6B6C6D 5F60616263
BDBEBFBCC2 8586878889

Special Thanks

  • cheap: Cheap showed that Deist Cavern was the shortest route.
  • FinalFighter: FinalFighter made the LuaScript which told that a PC passed a specific address.
  • naruko: Naruko taught me code where MMC1 did not freeze. And he also offered various documents.
  • TaoTao: TaoTao made a movie of the 45-floor bug. I was able to discover the jump to SRAM of $6785 by investigating the movie with LuaScript of FinalFighter.

ars4326: (Made some minor grammatical corrections for better readability).
ars4326: Judging underway!
ars4326: Hello, pirohiko. This run was an outstanding technical display of arbitrary code execution (ACE), which, despite a considerable trek through the overworld, provided an entertaining payoff. The included overlay in the encode made the process easier to understand and added to the viewing experience. Thread feedback, also, was mostly enthusiastic and appreciative of the amount of effort put in. Great work on another well-made TAS!
Accepting for publication to Moons!
Guga: Processing...
Last Edited by adelikat on 10/14/2023 1:56 PM
Page History Latest diff List referrers