User Files for The Legend of Zelda

Upload All User Files

#637971270692437190 - The Legend of Zelda "Subframe Inputs" in 44 seconds

Zelda_Subframe_Win.bk2
In 00:00.00 (0 frames), -1 rerecords
4 comments, 146 downloads
Uploaded 8/26/2022 4:11 PM by OnehundredthCoin (see all 12)
VBlank count is definitely not accurate. Apologies for uploading this 3 times, the website was giving me an error since the file was missing VBlankCount. I assumed it didn't go through.
This is far from optimal.
"What's with the 18 seconds of nothing on the file name screen?"
So, the way this TAS works is by sending in non-matching inputs over and over again with the SubNesHawk core (bizhawk version 2.8) to create precise amounts of lag. And it needs to be incredibly precise. At the end of any frame, there are the following instructions.
STA $2000
STA $FF
RTI
JMP $E45B
"STA $2000" Enables the Non Maskable Interrupt, so another frame can begin after that point. "STA $FF" stores a copy of the data in $2000 at $FF. "RTI" pulls 3 bytes off the stack, and returns to an infinite loop at address $E45B. "JMP $E45B" is the infinite loop. It just keeps jumping to itself. I need to create lag so precise, that it starts a new frame after "STA $2000" but before "RTI". I think this is around a 5 CPU cycle window.
Keep in mind, whenever I stall for additional inputs, it's not adding by a single CPU cycle, it adds 218 cycles. To time it just right, I need to stall for more than just one frame. If I time it just right, a new frame begins in that 5 cycle window, adding 3 more bytes to the stack. This sets it up so if I hit the "RTI" instruction on a later frame, it will immediately follow it up with a second RTI instruction. I can repeat this process as long as I want. What does this achieve?
Well, if I do it enough times I can make the stack overflow. The "Register Name" selection on the file name screen has an interesting property. Your inputs are pushed to the stack, and aren't overwritten before the end of the frame. On the frame you initially select this option, a value of $34 is pushed to the stack one byte higher than where your inputs will get stored. By overflowing the stack, writing these desired bytes, and letting the giant tower of RTI instructions all execute, you could return to address $xy34, where "xy" is whatever buttons you hold down on controller 1. The names of the save files are stored at $0638, so I could use this to begin executing from $0634 by holding down "06" which is a combination of Down and Left.
Slight issue, $0634 is set to a value of 00 if the middle file doesn't exist yet. So I need to set up that save file, return to the menu, and re-enter the file name screen. With a value of 00 it executes a BRK instruction, which jumps to the programmable interrupt. Zelda doesn't use such an interrupt, so it jumps to some code that leads to another BRK. an infinite loop. If $0634 has a value of "01", however, it's an ORA instruction, and I don't have to worry about it.
"What are you writing with the file names?"
The code I can write is extremely limited. the bytes I can write are 00 - 24, 28 - 2C, 63, and 64. Not the most useful bytes, but let's see what we can do with them. We have the ASL instructions, which let's us multiply a byte by 2. ("Arithmetic Shift Left" also tosses bit 7 into the carry flag. Also any number greater than 255 will get truncated to a single byte.) This can be used to change some of the bytes in the payload to more useful ones.
I write: ASL $06
ASL $06
ASL $06 (Address $06 starts at a value of 0x12. shifting it thrice gives it a value of 0x90, which is "BCC" or Branch on Carry Clear.)
ASL $07 (Address $07 starts at a value of 0xFF. shifting it gives it a value of 0xFE. combined with the branch instruction, if executed this causes an infinite loop, since 0xFE is -2. it branches back 2 bytes to the start of the branch instruction.)
ASL $0622,X (X = 0x25, this shifts address $0647)
ASL $0622,X (this also shifts address $0647)
ASL $60,X (The number 60 isn't a byte that I can write. It starts as 0x18, but the two previous instructions shift it to a value of 0x60. the offset of X makes it shift address $85, which is the vertical position of the cursor for selecting characters to name the file.)
CLC (Clear the Carry flag just in case)
JSR $0006 (Jump to that infinite loop branch I made)
In short, this creates an infinite loop, moves the cursor for selecting letters to name a file with, and then jumps to that loop.
With the cursor offset, I can now grab characters from outside the bounds of the table.
"Hold up. Why are you jumping to an infinite loop?"
Remember how the game jumps to an infinite loop after regularly executing "RTI"? I'm unable to jump back there with the bytes I have to work with, so I need to create my own loop. This is the game's way of "Spinning" while we wait for the next frame.
"What about the changes you make to the save file with the new characters?"
This time, I have more bytes to work with. However, I am unable to change the name of file 2, since that file already exists. I'll need to work around it. I write:
LDA #$13 (A = 0x13)
STA $12 (Store A in $12. this wins the game)
INX (X is now 0x26)
NOP
NOP
NOP
ASL $0622,X (X = 0x26, this shifts address $0648)
ASL $0622,X (this also shifts address $0648)
ASL $60,X (This is leftover from the previous payload. it has no use in the second payload)
JMP $0648 (I can't write "JMP" so I needed to shift something else into this value. it started as 0x13. With "JMP" set up, it creates an infinite loop.)
In short, this wins the game and then loops infinitely.
"Okay... why did you run payload 1 on the name register screen, but payload 2 in game?"
Unfortunately, the code for the credits isn't loaded on the name register screen, so I had to start the game. Also, due to underflowing the stack, the game will crash after registering the new names. It does however save them, so I can simply reset the game and start from there. After loading in, I press the start button to pause and begin subframe mashing again. Once the stack is about to overflow, I press UP+A on controller 2 to bring up a menu that has the same properties as the name register menu. That's right, it pushes my inputs to the stack and never overwrites it! Once again I can jump to $0634 and execute the new file names.
This wins the game from the pause screen.
"You mentioned this is far from optimal. What can be improved?"
One glaring issue with this TAS is the several seconds of subframe mashing. First off, I can begin mashing earlier. If I subframe mash while writing the file names, or while the level is loading for payload 2, I can execute the code earlier. Second, I'm still figuring out how to optimize the subframe mash.
Right now, I have a LUA script simply alternate inputs over and over until it lands a new frame inside the 5 cycle window. This is inconsistent. Some times it takes 4 frames, other times around 20. Sometimes I have chains of 4 frames multiple times in a row, other times 20 frames multiple times in a row. It's likely due to executing the "STA $FF" (the last instruction before the next frame) on a different cycle than other times it works. Either that, or due to how a frame can take 29780 or 29781 CPU cycles before the next one begins. I've got some research to do. I imagine I might be able to save time by stalling longer than 20 frames if it can end up in another large chain of 4 frame successes. I'd also like to cut out a payload entirely, but I've been unable to win the game without offsetting the cursor. One idea I had was using link's position to write a branch-loop, but I'm unable to jump to his position with the limited 24 bytes I have to work with. I'll keep looking for ideas though.
Anyway, the combination of what was written in the above paragraph and the obvious lack of entertainment during the periods of subframe mashing is why this is currently a user file and not being submitted for publishing yet.

#637956051181818139 - The Legend of Zelda Subframe Crash on title screen

Zelda_Subframe_Crash.bk2
In 00:00.00 (0 frames), 592 rerecords
2 comments, 115 downloads
Uploaded 8/9/2022 1:25 AM by OnehundredthCoin (see all 12)
If this works on console, Bizhawk is terrifyingly accurate.
Done in Bizhawk 2.8, SubNesHawk core.
So, TLoZ has the entire game loop inside an interrupt, with the exception of spinning. Of course, the Non Maskable Interrupt is disabled for this entire duration until the moment before spinning. However, there is a very brief 5 CPU cycle window where the NMI can happen before the RTI, so if timed correctly you can nest an interrupt inside the interrupt. This requires subframe button mashing for a ridiculous amount of time even just to line it up for a single nested interrupt, but should you nest too many, the stack overflows! We can then resolve 84 RTIs in a row, eventually pulling off some "garbage" as a return address. This leads to a BRK, which leads to a BRK, which leads to a BRK... and the infinite loop might as well be a game crash, since the NMI isn't going to run anymore.
You could probably make this happen somewhere other than the title screen to begin executing code somewhere else, but it needs more experimenting.
This was achieved through a crummy LUA script that just kept adding a new input, stalling for 7 frames, and seeing if another NMI happened before the RTI. It could probably be improved, since I was specifically checking for an exact address being pushed to the stack, when there are actually 2 different addresses that could be pushed between enabling the NMI and executing the RTI.
Hilariously, since the entire code is inside the NMI, when I need to perfectly time the NMI to happen before the RTI, the entire frame happens, so the game continues to play slowly whenever I can nest another NMI.

#68581123126351736 - Zelda NES lua script

zeldanes.lua
279 downloads
Uploaded 1/5/2021 1:16 PM by xy2_ (see all 139)
For Zelda NES bootleg

#30066700268521847 - keymashing intensifies

keymashing intensifies.bk2
In 03:21.90 (12134 frames), 0 rerecords
957 downloads
Uploaded 4/7/2016 1:04 AM by Pokota (see all 10)
this is just to test how my url checker script in mirc handles userfiles links.

#24931209484908147 - Gleeok ladder white sword drop glitch

white sword ladder glitch.fm2
In 00:57.96 (3483 frames), 2 rerecords
1 comment, 1175 downloads
Uploaded 8/19/2015 6:23 PM by drjasonkimball (see all 1)
This is a glitch was that first discovered by lobsang2 during a Randomizer race (Randomizer 2.0 seed 98003768930 mass hysteria), that resulted in a white sword being acquired.
The setup requires a 4 headed Gleeok to be in a room with water, and the ladder. Currently the exact mechanism of the glitch is not fully understood.
The general setup is to kill 2 of Gleeok's heads, then stand over the water and let 1 of the floating heads knock you away from the water so the ladder is removed. Then kill 1 of the remaining heads while not standing on water. This sets up a weird state and the next time the ladder is activated, an extra sprite appears under it. Killing the sprite while standing in the middle of the ladder will spawn the white sword for a very short time, but it can be collected.

#23194306587881454 - Zelda glitched

Zelda TAS glitched_v2-p.fm2
In 03:43.00 (13402 frames), 79032 rerecords
788 downloads
Uploaded 6/2/2015 1:03 PM by TASeditor (see all 188)

#22882074853975783 - Zelda game end glitch

Zelda TAS game end glitch.fm2
In 03:34.70 (12903 frames), 69731 rerecords
1191 downloads
Uploaded 5/19/2015 11:35 AM by TASeditor (see all 188)

#22820369846398997 - Zelda glitched

Zelda TAS glitched-compact_v3.fm3
In 03:55.93 (14179 frames), 43607 rerecords
1493 downloads
Uploaded 5/16/2015 4:53 PM by TASeditor (see all 188)
Branch 0 contains finished run.
Branch 2 and 3 prevent crashing after item glitch, but the cave to 9th level isn't opened.
The item glitch is achieved by executing 6C 9A B3 in Link's and Enemy 1 and 2's Y positions.

#22800189426508556 -

Zelda TAS glitched_9_1.fm2
In 03:18.57 (11934 frames), 34442 rerecords
699 downloads
Uploaded 5/15/2015 7:04 PM by TASeditor (see all 188)

#22707016956060914 -

Zelda TAS glitched_7_1.fm2
In 04:16.49 (15415 frames), 29828 rerecords
790 downloads
Uploaded 5/11/2015 2:22 PM by TASeditor (see all 188)

#22688295886187627 - Zelda glitched (up to graveyard) v2

Zelda TAS glitched-compact_v2.fm3
In 03:04.43 (11084 frames), 21474 rerecords
1427 downloads
Uploaded 5/10/2015 6:08 PM by TASeditor (see all 188)
Used 1st save slot to manipulate 0x16 to 0. Collecting a rupee to manipulate 0x0618 to 0x4C.

#22662980833139671 - Zelda glitched (lvl 9 warp glitching v2)

Zelda no Densetsu - The Hyrule Fantasy (Japan) (v1.1)wr2_warpglitch_lv9_v2.fm2
In 04:54.13 (17677 frames), 22806 rerecords
1224 downloads
Uploaded 5/9/2015 2:46 PM by TASeditor (see all 188)

#22661854390314577 - Zelda glitched (lvl 9 warp glitching)

Zelda no Densetsu - The Hyrule Fantasy (Japan) (v1.1)wr2_warpglitch_lv9.fm2
In 05:09.22 (18584 frames), 20069 rerecords
1224 downloads
Uploaded 5/9/2015 1:33 PM by TASeditor (see all 188)
This is based on RAT's movie. It shows that it is possible to warp glitch all throught level 9, using the sidewards wooden sword do a different scrolling than the red bombs.

#22658755306120550 - Zelda glitched (up to graveyard)

Zelda TAS glitched-compact.fm3
In 06:23.85 (23069 frames), 11835 rerecords
929 downloads
Uploaded 5/9/2015 10:12 AM by TASeditor (see all 188)
Here's an optimized run up to the graveyard.

#21090597415188330 - The Legend of Zelda 2nd quest "Swordless" Challenge

zelda.fm2
In 10:40.00 (38463 frames), 1612 rerecords
1 comment, 1225 downloads
Uploaded 2/27/2015 7:16 PM by jprofit22 (see all 1)
Through the beginning of level 4. Another bout of planning to ensue. Re-record count is probably suspect...

#2014772723216438 - The Legend of Zelda 100%

The Legend of Zelda 100% TAS.fm2
In 08:13.54 (29661 frames), 14047 rerecords
1389 downloads
Uploaded 10/21/2012 5:13 PM by TASeditor (see all 188)
I had to kill two more enemies in the first dungeon to make the boss dropping a fairy.
To avoid it I have to redo the 4th dungeon at the point where I killed those two bats at the beginning. Not killing them avoids that I have to kill two more enemies to get a fairy in the 1st dungeon. This is also needed to get 5 rupees in the first dungeon.