User Files from OnehundredthCoin

Upload All User Files

#638479355124534524 - SMB1 Bad Apple

In 04:48.14 (17317 frames), 2 rerecords
Uploaded 19 days ago by OnehundredthCoin (see all 10)
My efforts to shrink the input log's file size ended up corrupting the input log for the previously uploaded .bk2 and apparently the .tasproj as well. This is the full unmodified tasproj, which I honestly thought I was uploading last time. I have checked this tasproj multiple times before uploading.
The rerecord count is incorrect, and should be 37512

#638398423526853571 - Super Mario Bros. ACE Total Control "Travelling Salesman" playaround

In 02:25.38 (100726 frames), 0 rerecords
1 comment, 127 downloads
Uploaded 1/3/2024 1:32 AM by OnehundredthCoin (see all 10)
Uses subneshawk in Bizhawk 2.9.1, this TAS begins with pre-set RAM. (would be obtained through a brief SMB3 TAS and then cartridge swapping)
This demonstration includes: Custom music, custom screens, bad jokes.
in an earlier Userfile, I demonstrated simply changing the game from world N-2 to 8-4, winning the game about a minute and 15 seconds after the console was turned on. This time I decided to play around with ACE as much as possible, utilizing the 2Kb on RAM to set up code which lets me write more code. I end up writing a nice loop allowing me to read the controller to determine what needs updated: APU registers, OAM, the Nametables, or perhaps nothing at all. With it I tell the story of what happens to Mario after saving the day, and according to myself it involves the Travelling Salesman Problem.
"Cool, so how does this work?"
Let's begin by explaining how this ACE Exploit works.
In Super Mario Bros., killing Bowser with fireballs will "Reveal his true form". In world one, he's really a goomba, in world 2, a buzzy beetle, and so on. When you parse this table out of bounds, some tomfoolery occurs. World 'N' is world 0x16, so we're replacing Bowser with the 23rd entry in a table 8 entries long. This results in Bowser becoming an object beyond the bounds on the object table! Regardless, the game loads that ID and jumps somewhere to determine how it should behave. It ends up jumping the PC to the end of the level loading routine, right at the part where existing sprites are all cleared out, and the "gameplay loop mode" is incremented. Normally, this would increment it from 2 (setting up a stage) to 3 (normal gameplay loop) but since it was already at 3, now it becomes 4 which, again, will parse a table out of bounds. When the game determines where to jump for "Gameplay loop mode 4" it ends up in open bus! (with 53 on the databus) This runs `SRE ($53),Y` and to make a long story short that ends up shifting address $000A to the right, and this new value is on the databus. Luckily for us, we can manipulate address $000A before killing bowser. If we set it to the value 0x80 (by simply holding the A button and *not* the B button) this will shift into 0x40, which will place an `RTI` instruction in open bus, jumping the PC to address $181.
Address $181 is not cleared when the game boots up, so if you were to write a payload there in another game, such as Super Mario Bros. 3, and swap cartridges without turning off the power, the code you write will still exist when killing Bowser in SMB1. Okay... so what code do I put there?
The code I write will begin by reading the controller twice and storing the values read at $c3 and $c2. This will be a pointer to where we write our own custom code. I read the controller once more, this time storing the value at $c1. This will be the payload length. I read the controller X times, where X is the payload length, storing the values read at where ($c2) points. Once all the bytes are written, I read the controller one more time to determine if we should restart the loop, change the pointer, and write something new. Otherwise, I read the controller 2 more times (forming a pointer) and jump there. This lets me execute the custom code I write.
Fun fact, I cannot use the NMI to wait for V-Blank. My solution is to use address $2002, which might've raised a few eyebrows. Reads from $2002 if on the wrong PPU cycle can cause a race-condition wherein the console returns a false-negative, stating the V-Blank has not occurred when in reality it has. My work around for this is to start each frame by reading the controller, and if in that input I press the right button, a function I wrote will waste precisely 1 CPU cycle, circumventing the race condition. I wrote a lua script to automate the process of pressing the right button, since it happens a lot.
I begin by writing code that let's me update the nametables. I clear them and draw a blue box. I spend a few frames writing a custom audio engine, but I decide to keep using SMB1's built in audio engine to finish playing the Bowser Defeated sound and the victory jingle. During this time I also update the nametable to add some humorous text. "Bowser is defeated" "Peace has returned to the kingdom" ... "Mario files for unemployment" "The kingdom assigns him the title of..." and now it's time for part 2.
Part 2: moving the screen and playing custom music.
The loop of code I wrote is essentially, "read controller to determine if we need to update audio. (if we do, read the controller to determine which channels need updating, then read the controller multiple times per channel) Read the controller to determine the horizontal scroll of the screen"
With my custom music player, I was able to extract data from famitracker, run it though a program I made (converting it into button presses) and play it in my TAS via pressing buttons! As the screen scrolls during this section (also done through pressing buttons)it reveals the title the kingdom has assigned Mario. he is now the Travelling Salesman! ("The NP-Hard game to TAS!")
Part 3: OAM
I modified the loop since I no longer need to scroll the screen. For here, I added some code to modify OAM data. This lets me make Mario run across the screen. The loop is now "Read the controller for the Race-Condition-Fix. Read the controller to determine audio channels that need changed. Read multiple times per changed audio channel. Read to determine graphical changes (the lower 3 bits are Nametable, OAM, and Scroll). Read for OAM changes if needed, 1 read to determine how many bytes, 1 read for the OAM offset, then x reads to fill in the data. If updating the nametable, this jumps to the main setup loop, where I write the payload at address $380, then set up some bytes for my 'Fast Nametable Writer', including the payload destination on the PPU Bus (2 bytes) the location of the payload to be copied (usually at $380) the length of the payload, then the value of the PPUAddress after the payload is written (affects the screen scroll)" Phew- that's a lot of controller reads for just one frame, you following along? Luckily if no graphical or audio changes are needed, every frame is only 3 inputs long. (Race-Condition-Prevention, no audio, no graphics)
With this set up, I can essentially make any audio and visual the NES is able to produce (except sample audio), with the huge caveat that the pattern data is restricted to whatever is contained inside the Super Mario Bros. cartridge. Speaking of...
Part 4: Drawing a character not present in SMB1's pattern table
I ask the question "Are you familiar with the travelling salesman problem?". Like most questions, this ends in a question mark. SMB1 does not have a question mark in the pattern data, so I had to get clever. It's actually a series of sprites using the '.' character, assembled in the shape of a question mark. I also used some sprites colored the same colored the background, overlapping others to allow for some thinner parts of the question mark, so it wasn't super blocky.
Part 5: The travelling salesman
The grand finale! (except for the fact that the TAS has a scene afterwards)
I made Mario run to 32 toad houses in a near-optimal path. I intentionally chose the 2nd best path I was able to generate for a joke in the next scene. This was just a combination of all the other tools I had programmed for myself. I have custom music, I update the OAM data to animate Mario running, and whenever he runs over a house I update it's color. The average frame here has 56 inputs.
Part 6: The end
A little card pops up reading "SUCCESS!" Then lists some stats. Mario ran to all 32 toad houses. He ran 1068 pixels, for 617 frames. Toad slides on screen, and says "Thank you mario! But your route was suboptimal!"
And the run ends.
Part 7: Where do I go from here?
Anyway, I'm going to continue to work on this. I don't know what I'll make happen next, other than Toad firing mario from his Travelling Salesman career, and Mario will likely be assigned another role.
I hope this explained it enough! Cheers!

#638263374139051838 - Gimmick! "Subframe Input" in 10 frames, Assuming RAM is initialized with all zeroes

In 00:00.18 (70 frames), 13 rerecords
Game: Gimmick! ( NES, see all files )
Uploaded 7/30/2023 6:10 PM by OnehundredthCoin (see all 10)
I've uploaded a 15 frame TAS of Gimmick! in the past, where I press the reset button twice. This TAS only presses the reset button once, though it only works if address $00F4 is initialized as a 00 instead of FF. Since the CPU power up state is inconsistent on actual hardware, I'm assuming this is (for some consoles) a valid power up state, and would run just fine.
As a brief recap of how this works, Gimmick! initializes every byte except addresses $F0 - $FF with zeroes. (then overwrites $FA - $FF) The NMI on frame 5 happens whether the PC is spinning or not, and I abuse this by stalling on frame 4 with 59 subframe inputs. The PC is at address $88E1 with PRG bank 0x7 when the NMI occurs, some banks are swapped out, and the RTI sends us to $88E1 with PRG bank 0x1B, which happens to be JSR $00A2. The controller data is stored at addresses $F5 - $F8.
The idea is to execute JSR $E0F0 which jumps to the credits, specifically for the good ending. This is done by pressing 0xC0 on controller 2 (A + B) and no buttons on controller 1, resetting the game, then pressing 0xE0 on controller 2 (A + B + Select) and 0xF0 on controller 1 (A + B + Select + Start) after the subframe stalling. That leaves addresses $F4 through $F8 as 00 F0 20 F0 E0, or BRK, JSR $E0F0. Again, this only works if address $F4 is initialized as 00, instead of Bizhawk's power up state of FF for that byte.

#638179553100801346 - SMB1 ACE With Entertainment, by Mizumaririn and SeraphmIII

In 01:23.80 (5036 frames), 2110 rerecords
Uploaded 4/24/2023 5:48 PM by OnehundredthCoin (see all 10)

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

In 00:00.00 (0 frames), -1 rerecords
4 comments, 102 downloads
Uploaded 8/26/2022 4:11 PM by OnehundredthCoin (see all 10)
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 $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)
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

In 00:00.00 (0 frames), 592 rerecords
2 comments, 80 downloads
Uploaded 8/9/2022 1:25 AM by OnehundredthCoin (see all 10)
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.

#637864080729078524 - Gimmick! "Subframe Inputs" in 00:00.25

In 00:00.25 (15 frames), 360 rerecords
Game: Gimmick! ( NES, see all files )
5 comments, 100 downloads
Uploaded 4/24/2022 2:41 PM by OnehundredthCoin (see all 10)
Use the Bizhawk SubNesHawk Core to watch. (Or the youtube link)
This has not been console verified yet, so if anybody wants to give it a go, it would be very appreciated. But you should know this run involves executing uninitialized RAM as code, (using bizhawk's 00 00 00 00 FF FF FF FF pattern) so keep that in mind. I'm hesitant to submit a Subframe Input TAS without console verification.
In this TAS, I complete the Game "Gimmick" by utilizing subframe inputs, not unlike my TAS of Super Mario Bros. 3. More info on the technical details if verified, but I'll explain a general idea of how the "route" works.
At the moment I execute RAM as code, the game has uninitialized RAM from address $F1 through $F4. This is a bit problematic for verification, but it's also the key idea of how this run works. Controller data is stored at $F5 through $F8, in pretty much the same manner as SMB3.
Circling back to the uninitialized RAM, bizhawk's "00 00 00 00 FF FF FF FF" pattern for RAM on console boot leaves address $F2 with "00" and $F4 with "FF". Both of those bytes get executed, and "FF" is a 3 byte instruction. That limits the number of "controller bytes" from 4 to 2. (Those are also the only uninitialized bytes that get executed. Gimmick! Clears the first 240 bytes of the zero page, leaving $F0 - $FF uninitialized, but by the time I execute code, the only uninitialized bytes are $F1 through $F4)
On the first frame with inputs, I 'stall' for 58 inputs, then using both controllers, I write STY $00F4. This replaces the "FF" at address $F4 with "08", as that's what was held in the Y register. This creates a PHP instruction, but what's more useful is that it's only 1 byte long. Now I have the full 4 "controller bytes"
I reset the console, and recall that address $F4 is uninitialized. That means when resetting, Gimmick doesn't clear the 08. I might go back and try to improve this TAS, but the subframe mashing to execute code seems to only work on the first frame with inputs. I need to strategically write JSR $E0F0, or 20 F0 E0 written as bytes. I need to hold down E0 (A + B + Select) on controller 1, while the new inputs are 20 (Select) so I use the first possible frame after resetting to hold down A + B. Then I reset again.
On the third and final loop, I repeat the same subframe mashing as before, and hold down the buttons that write JSR $E0F0, which wins the game when executed.
If I could find a way to offset the code so I can execute 3 controller bytes while also lining up the 20 F0 E0 for loop 2, I could save 5 frames. Likewise, if I can execute RAM after the first frame with inputs, it's likely I could cut out the second reset, saving time.

#637810967022224841 - Kirby's Adventure DPCM (Failed Console Verification, Works in Emulator)

In 00:04.00 (240 frames), 294 rerecords
5 comments, 93 downloads
Uploaded 2/22/2022 3:18 AM by OnehundredthCoin (see all 10)
This is an unbelievably sloppy TAS that I made back in December to test if the DPCM audio bug exploit could be done in Kirby's Adventure. Unfortunately, after many tests for Console Verification, there has been no luck. I imagine the culprit is the DPCM audio bug, as unlike Super Mario Bros. 3, the title screen has DPCM audio.
I honestly don't know all the details of the DPCM audio bug or how emulating it works, but my hypothesis is that the bug is inconsistent on console, and so emulating here isn't "inaccurate", but the results may vary.
Anyway, the trick that made this TAS work happened by mistake, and reproducing it on purpose has been exceedingly difficult. I manipulated the stack in such a perfect manner to pop a value of the stack, store it in X, and use X as an offset that ends up storing a NOP at the JMP instruction that rests inside the programmable interrupt. From there, the programmable interrupt happens, and I use the bytes that appear after where the JMP was to write code, as that's where the controller data is stored.
Again, this TAS is crude and sloppy, but until I can get it working on console (or figure out why it doesn't work), I have no desire to attempt improving it.
Rerecord count is inaccurate. VBlankCount is also probably inaccurate. I don't know why, but the .bk2 file didn't include VBlankCount.

#75436230045449211 - Super Mario Bros. 3 "Game End Glitch" in 00:00:00.316

In 00:00.32 (19 frames), 0 rerecords
4 comments, 224 downloads
Uploaded 11/10/2021 6:36 AM by OnehundredthCoin (see all 10)
Run created in Bizhawk 2.6.3 (with some odd export issue, so I just pasted the inputs in version 2.3.2 and exported it there?) Before I submit this run, I'm going to be taking the time to write up a huge explanation, and probably make a video explaining how this run works.
The credits work perfectly fine without any visual bugs.
Uploaded as a user file so it can be console verified before submission.
Huge thanks to Bigbass for verifying the run.
The final run had 3183 rerecords, I'll fix the metadata before the submission.

#75291642453080158 - Super Mario Bros. 3 "Game End Glitch" in 0:00:00.399

In 00:00.25 (15 frames), 13882 rerecords
10 comments, 140 downloads
Uploaded 11/3/2021 6:19 PM by OnehundredthCoin (see all 10)
I'm going to make a much better writeup of this, but for now I'm just uploading the .bk2
This should beat the current TAS by 23 frames.
Keep in mind this run was made in version 2.3.2 with the SubNesHawk core. I believe this version has a bug with IRQ timing? I don't know all the details, but it might not work on later versions of the emulator. This should not affect the run on console, so I've been told.