As the hero of this game, Link just doesn't understand why his name isn't in the title of the game. Who is this mysterious Zelda person? Even after beating the game, he is as clueless as ever...

Game objectives

  • Emulator used: FCEUX 2.2.2
  • Arbitrary Code Execution
  • Heavy glitch abuse
  • Luck Manipulation
  • Uses damage to save time
  • Uses game restart sequence

Comments

Shortly after the previous movie was submitted, sockfolder found a way to use the names of the 3 game files to acquire ACE. The 8-byte long filenames are conveniently stored right after each other starting at $0638, $0640 and $0648 (which was also pointed out by pirohiko). Even though the values of the characters only range from 0x00 to 0x64 (meaning we can only use less than half of the opcodes available), sockfolder found a way to poll values from the input data and slowly, bit by bit, writing (shifting) code into arbitrary locations (chosen by input). You can read his full post here.

The glitch that triggers it all

When the game tries to spawn a new sprite, it will check for a free slot (0x00) and puts the new value (the value of the sprite) in the free slot. In the FDS version of this game, if you fill up all slots and play the whistle to spawn a new sprite (for example when the whistle reveals a new exit), the game tries to find free slot but it overflows (it actually counts backwards and underflows) and puts the value in a dangerous location.
This dangerous location can be the state of a sprite, making the code for that sprite use the wrong value for indexing and the game jumps to $0602. This location is where the game stores a lot of the music data. The code manages to get through that (additionally pressing A at the same frame you activate the whistle with B makes it a bit safer) and eventually gets to the filenames at $0638... which hold the values for ZELDA, because we had to start the 2nd quest. Fortunately, we can use the remaining 3 characters directly after ZELDA for our code while still starting the 2nd quest. And we're also in luck that the code ZELDA does nothing dangerous when being executed.

Filenames

 23 0E 15 0D 0A 0E 4B 06
 20 4B 06 0A 10 02 33 02
 4C 40 06 36 2F 64 24 24
The first 5 bytes are ZELDA and the last 2 are left blank (0x24), which means that the important code starts at:
 $063D: 0E 4B 06  ASL $064B
which effectively changes the 4th letter in the 3rd filename from 0x36 to 0x6C (which is necessary, because the characters only ranged from 0x00 to 0x64). Then, the main loop starts:
 $0640: 20 4B 06  JSR $064B
 $0643: 0A        ASL
 $0644: 10 02     BPL $0648
 $0646: 33 02     RLA ($02),Y
 $0648: 4C 40 06  JMP $0640
 -
 $064B: 6C 2F 64  JMP ($642F)
$0640: So the main loop starts by making a subroutine call to $064B.
$064B: This jumps to whatever is inside $642F, which is $EA1F and happens to be the routine that deals with the input. After returning, A holds only the newly pressed buttons and Y holds all the buttons.
$0643: An Arithmetic Shift Left is done so that the Carry is 1 if A was just pressed, else the Carry is 0.
$0644: This will branch forward if B was not just pressed (since B is now the MSB), but if B was indeed just pressed this frame then we go to:
$0646: Opcode 0x33 is actually an illegal opcode but the microprocessor still does something according to the bits in the opcode. The important part is, that this instruction shifts a byte in memory one bit to the left. Which byte is shifted is given by whatever address is in $0002, which is $0602 because that is where the address was stored when the glitch started (remember how the glitch started by jumping to $0602?). Y is being added to the $0602 to give the final address that is being shifted. It will shift the Carry into the LSB, which was previously set at $0643.
$0648: Jump to the start of the main loop.

The code itself

Writing the code

The small problem with this way of writing code is that it is really slow. You write the code by shifting bits, and you have to repress the buttons. In FCEUX this means you effectively write with a speed of 1 bit per 2 frames, which is 3.75 bytes per second (REALLY SLOW)... (well it's not really 3.75 bytes per second because of clever ways of writing code, which I explain later)
I say in FCEUX because this emulator only lets you input once per frame, even when it is polled multiple times. This also had the effect that sometimes some buttons were lost (because of unfortunate timing) and I had to wait a frame.
The whole memory where we want to write stuff is filled with 0x00's. This, and the fact that we are shifting from the right means that the lower the bytes are, the faster we can write them. For example a 0x00 takes no time at all, because we can just skip it. A 0x01 just takes 1 bit, 0x02 and 0x03 take 2 bits and so on. All bytes from 0x80 to 0xFF take all 8 bits and so I tried to avoid them as much as possible.
To shift in 1 bits, the Carry has to be set, so we have to newly press A for that frame (see $0643), and remember that we had to also newly press B (see $0644) to actually make the shift. Holding both A and B means that Y is at least 0xC0. Since Y is added to the address (which is $0602), we can write code starting at $06C2.
A way to actually execute the code is to corrupt the filename code. By shifting a 0 to $064B, changing it from 0x6C to 0xD8, we can escape from the loop. It will fail at the 0x22 at $0654, so we change that to a 0x44. Then the code will execute to our code, only that $06C2 is part of the BRK (the 0x00 instruction) at $06C1, so we don't start our code at $06C2, but $06C3.

Requirements

So, the credits are loaded with Level 9, which means we have to actually load it. This can be done by setting $0010 to 0x09 (level 9), $0011 to 0x00 (do something) and $0012 to 0x02 (load the bank).
After the level is loaded, we have to finish the game somehow. This is done by setting $0011 to 0x00 (do something) and $0012 to 0x13 (credits routine).

Let's go

Starting at $06C3:
 29 02 20 4C 84 09 09 85 10 6E 00 20 A5 3C D0 FC 09 13 20 4C 84 20 7B 63
Cool, huh? Let's see...
 $06C3: 29 02     AND #$02
 $06C5: 20 4C 84  JSR $844C
We are in luck and A is 0xCA which means we can change it to 0x02 by ANDing, which is faster than LDA #$02, because that would be A9 02 and remember that writing A9 is slower than writing 29. Jumping to $844C does quite a bit setup for us. It sets $0012 to whatever is in A (which is 0x02), it sets $0011 to 0x00 and it returns with A being 0x00.
 $06C8: 09 09     ORA #$09
 $06CA: 85 10     STA $0010
Because A returned as 0x00, we can use ORA to set A to 0x09, which again, is faster than using the slow LDA. Then we set $0010 to 0x09 and we finished our first requirement. Only the problem now is that where do we return to? How do we continue the game? How do we continue the code after Level 9 loaded?
 $06CC: 6E 00 20  ROR $2000
 $06CF: A5 3C     LDA $003C
 $06D1: D0 FC     BNE $06CF
NMI is disabled by the game to avoid interrupts (updating the screen) before the game is done calculating the frame. We manually activate it by shifting the Carry (which is thankfully set) into the NMI enable bit in $2000. Then we start our own "infinite loop" which continues until $003C holds 0x00. $003C is basically a timer that counts down until we can move in the dungeon. So the code continues when the level is loaded and we can basically move.
 $06D3: 09 13     ORA #$13
 $06D5: 20 4C 84  JSR $844C
Since $003C should be 0x00 by now, A is also 0x00 (because of the LDA $003C), which means we can, again, change it to 0x13 by using the fast ORA. Then we, again, call $844C which does the same thing as before, only with a different A. $0012 is set to 0x13 and $0011 is set to 0x00. At this point we could write a quick infinite loop to show the credits and so on, but that would result in a crash as soon as you press something after the credits. To avoid that, the last piece of code is this:
 $06D8: 20 7B 63  JSR $637B
$637B is the infinite loop the game uses, so the game is back to normal now and starts the credits routine.

Special Thanks to

  • RAT926 for finding the item glitch and finding slight improvements in the route.
  • pirohiko for pointing out errors in the submission text. :D
(Seriously though, who is Zelda?)

Nach: I don't know what's going on. I can't make any sense of this. Consider yourself as glitching out the judge☺ابوSنصرO محمدT بEنV محEمد فا Россия²راYبی‎(T)נ"ך. Accepting as new run for this game.
Spikestuff: Publishing!


EgixBacon
He/Him
Player (184)
Joined: 4/15/2013
Posts: 331
Location: In the attic
Samsara wrote:
Finally, a TAS that plays out like one of my nightmares
Oh my God. The screen even says Yes Vote. Put on your tinfoil helmet, Samsara. The day has finally come, when TASers are trying not just to manipulate luck... but to manipulate our minds with their subliminal messaging! sdfsgfkjhasdlgkjhasdflgjasdlhj MUST... OBEY. MUST. VOTE. YES. VOTE... VOTE... VOTE...
FanFiction|Youtube Still on Win7! Take that, Microsoft!
Joined: 3/9/2009
Posts: 530
EgxHB wrote:
Samsara wrote:
Finally, a TAS that plays out like one of my nightmares
Oh my God. The screen even says Yes Vote.
Post subject: Screen Wrap Explanation
Joined: 11/17/2005
Posts: 278
Location: Massachusetts, USA
scrimpeh wrote:
Nice improvement. Yes vote, natch. Edit: One thing I'd like to know in general is what happens in the screen wrap-around glitch. Why does it work and how is it done? If anyone could tell me, that'd be much appreciated.
Due to some odd grid-snapping code Link can only turn on every 4th pixel. For example, if you're at x=125, facing right, and you hold up, then Link will walk east to x=128 before turning north, and then start walking north. Movement on the same axis is unaffected. If Link is at x=125, facing right, and you press left, then Link will walk left immediately. There's no need to snap Link to the grid in this case so the game doesn't. Tapping one frame in a perpendicular direction will cause Link to do an instant 180 turn without moving. This is a bug in the grid-based code. (Who checked for 1-frame inputs in the 80s?) The check for screen transitions assumes that if Link was facing left then the player must be holding left. (Bad!) 1) Stand at x=5, facing left. 2) Tap up or down for exactly 1 frame. 3) Link is now at x=5, facing right. The grid-based code normally prevents this! 4) Walk left. Since Link is facing right, the map transition check for the right side of the screen is checked, oops. 5) Link's x-coordinate underflows and he appears on the right side of the screen. 6) And now that your x=255, and you're facing left, the left screen transition is checked, and that fails too. The y-coordinate is the same except that you need to adjust for y=0 being up in the status area. While walking around in the status area the map data is usually a copy of the top 3 rows of map data, shifted left a half tile. Except for when it isn't. :x
Post subject: Re: Screen Wrap Explanation
Editor, Skilled player (1441)
Joined: 3/31/2010
Posts: 2113
Catastrophe wrote:
scrimpeh wrote:
Nice improvement. Yes vote, natch. Edit: One thing I'd like to know in general is what happens in the screen wrap-around glitch. Why does it work and how is it done? If anyone could tell me, that'd be much appreciated.
Due to some odd grid-snapping code Link can only turn on every 4th pixel. For example, if you're at x=125, facing right, and you hold up, then Link will walk east to x=128 before turning north, and then start walking north. Movement on the same axis is unaffected. If Link is at x=125, facing right, and you press left, then Link will walk left immediately. There's no need to snap Link to the grid in this case so the game doesn't. Tapping one frame in a perpendicular direction will cause Link to do an instant 180 turn without moving. This is a bug in the grid-based code. (Who checked for 1-frame inputs in the 80s?) The check for screen transitions assumes that if Link was facing left then the player must be holding left. (Bad!) 1) Stand at x=5, facing left. 2) Tap up or down for exactly 1 frame. 3) Link is now at x=5, facing right. The grid-based code normally prevents this! 4) Walk left. Since Link is facing right, the map transition check for the right side of the screen is checked, oops. 5) Link's x-coordinate underflows and he appears on the right side of the screen. 6) And now that your x=255, and you're facing left, the left screen transition is checked, and that fails too. The y-coordinate is the same except that you need to adjust for y=0 being up in the status area. While walking around in the status area the map data is usually a copy of the top 3 rows of map data, shifted left a half tile. Except for when it isn't. :x
Ah, I see. Thanks a lot for the explanation.
Joined: 3/11/2008
Posts: 583
Location: USA
Samsara wrote:
Finally, a TAS that plays out like one of my nightmares
You're pulling my leg, what frame? I can't find it. (YES VOTEd for amazing wisdom and power performing ACE at 30 baud.) So...did you [try] writing a faster intermediate code-loading routine after you achieved the first, like the Pokémon ACE TASes did?
illegal opcode
Please, they're undocumented instructions.
Joined: 6/4/2009
Posts: 893
Samsara wrote:
i don't know why, but yes vote....
Samsara
She/They
Senior Judge, Site Admin, Expert player (2241)
Joined: 11/13/2006
Posts: 2822
Location: Northern California
eternaljwh wrote:
You're pulling my leg, what frame? I can't find it.
Accidental flattery is the best kind of flattery! (I edited that in.)
TASvideos Admin and acting Senior Judge 💙 Currently unable to dedicate a lot of time to the site, taking care of family. Now infrequently posting on Bluesky
warmCabin wrote:
You shouldn't need a degree in computer science to get into this hobby.
Joined: 3/11/2008
Posts: 583
Location: USA
Capping at native resolution rather than from encode would have been a bit less obvious (there are a few missed pixel-wide borders)...but poking values into the nametables at some likely frame would be even more easy to keep standards-compliant than image-editing (so as not to accidentally wrong-palette an inserted character). Pity it doesn't actually do that...what IS it doing during the extended wipe transition, anyway? Why does it do that rather than just start the ending sequence? (Must one bankswitch to L9's bank to access the ending routine, and level-transition is the easiest way to provoke that and still include "go to end"?)
Masterjun
He/Him
Site Developer, Expert player (2047)
Joined: 10/12/2010
Posts: 1185
Location: Germany
eternaljwh wrote:
So...did you [try] writing a faster intermediate code-loading routine after you achieved the first, like the Pokémon ACE TASes did?
Nope, I wrote the whole code in the same way.
eternaljwh wrote:
illegal opcode
Please, they're undocumented instructions.
Wikipedia mentions illegal opcodes first so I win. An instruction consists of an opcode and an address mode. I use the term illegal opcode because I want to focus on the actual opcode, not the whole instruction. Yes, alright, I worded it bad in the submission text...
eternaljwh wrote:
what IS it doing during the extended wipe transition, anyway? Why does it do that rather than just start the ending sequence? (Must one bankswitch to L9's bank to access the ending routine, and level-transition is the easiest way to provoke that and still include "go to end"?)
It actually is the ending sequence, only the timer for the fading isn't set correctly. It starts decreasing at 0x00 so it wraps over to 0xFF, which is a bit longer than intended. The reason for the crazy graphics is probably because other values weren't set correctly. And yeah, the credits are loaded with Level 9, so I had to switch to that first.
Warning: Might glitch to credits I will finish this ACE soon as possible (or will I?)
Masterjun
He/Him
Site Developer, Expert player (2047)
Joined: 10/12/2010
Posts: 1185
Location: Germany
I also updated the submission text, which now explains the code I wrote.
Warning: Might glitch to credits I will finish this ACE soon as possible (or will I?)
Rikus
He/Him
Joined: 6/5/2015
Posts: 12
Location: Finland, Pihtipudas
Are that kind of 'starts of glitching' usually random finds when messing around or intentional things that are planned for hours?
Custom sig
Joined: 1/13/2007
Posts: 343
I am disappoint that the TAS didnt't actually say YES VOTE. :) Seriously though. that was hilarious. Okay, next mission is to actually insert the text "YES VOTE" into an otherwise optimal TAS without using any in game text entry screens. Ideally it would still be optimal, but i think that's asking too much. (well gradius TAS could do it with option lettering, but that's cheating. :) )
Joined: 1/26/2014
Posts: 14
Location: JPN
Masterjun TASEditor Zelda glitch, it is complex, it will give a lot of impressive.
RADAR
Skilled player (1792)
Joined: 5/7/2008
Posts: 187
Location: Japan
Masterjun wrote:
I also updated the submission text, which now explains the code I wrote.
Thank you Masterjun. Excuse me, did I ask a wrong question? http://tasvideos.org/forum/viewtopic.php?p=409160#409160
Masterjun
He/Him
Site Developer, Expert player (2047)
Joined: 10/12/2010
Posts: 1185
Location: Germany
pirohiko wrote:
Excuse me, did I ask a wrong question? http://tasvideos.org/forum/viewtopic.php?p=409160#409160
Oops, I'm sorry. For some reason I missed that.
pirohiko wrote:
TASVideoAgent wrote:
$0643: An Arithmetic Shift Left is done so that the Carry is 1 if B was held, else the Carry is 0. $0644: This will branch forward if A was not held (since A is now the MSB), but if A was held then we go to:
Because the order of the key is "RLDUTSBA", I suppose that the explanation of $ 0643 and $ 0644 became alternate. When A=0x80 was pushed, ASL turns on a carry flag. When B=0x40 was pushed, ASL turns on a negative flag.
Indeed, thank you. I mixed up SNES and NES, because in SNES the first bit is B. I mapped A of the NES to the same key on my keyboard as B on the SNES, so I thought it was the same. Silly me! Fixed in the submission text.
Warning: Might glitch to credits I will finish this ACE soon as possible (or will I?)
ALAKTORN
He/Him
Former player
Joined: 10/19/2009
Posts: 2527
Location: Italy
ALAKTORN wrote:
Spikestuff wrote:
ALAKTORN wrote:
I thought BizHawk did NES? Am I wrong or is that also not up to par?
http://tasvideos.org/EmulatorResources/NESAccuracyTests.html
Thanks. Bizhawk 26 52 13 33 5 3 132 83.5% The 3 should be bolded if I’m understanding it right.
So is anyone gonna fix that?
Joined: 3/11/2008
Posts: 583
Location: USA
Masterjun wrote:
Indeed, thank you. I mixed up SNES and NES, because in SNES the first bit is B. I mapped A of the NES to the same key on my keyboard as B on the SNES, so I thought it was the same. Silly me!
The SNES controller reports the same as the NES controller, except with B/Y in the place of A/B, and AXLR 0000 afterward. It just has a different plug shape. (This is reflected in most (non-Square) SNES games using B for confirm and Y for cancel.) So the mess-up is very understandable.
Post subject: Movie published
TASVideoAgent
They/Them
Moderator
Joined: 8/3/2004
Posts: 15628
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. ---- [2868] FDS The Legend of Zelda "2nd quest, game end glitch" by TASeditor, Masterjun & sockfolder in 03:06.46
Experienced player (691)
Joined: 11/23/2013
Posts: 2239
Location: Guatemala
Hey guys, it's the major skip glitch, final boss skip glitch and corrupts memory tags are missing?
Here, my YouTube channel: http://www.youtube.com/user/dekutony