Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!

quote:

It's been almost two years since my last video. I've been working on this ever since, but didn't have any noteworthy progress to share until now. This video provides a blueprint for a solution to the biggest problem with the BitFS 0xA Pole Skip plan, which we've named the Final Speed Transfer (FST). This video does not solve the FST, but it reduces the problem to a much simpler (although computationally difficult) form.

 

The pole skip relies on getting PU speed for Mario, and then moving to the tilting pyramid platform in a PU. This causes the platform's rotation matrix to be applied to Mario at a very large distance, which magnifies the vertical displacement he gets by a factor of thousands. This is used in VCutM in 1 Key. Normally this displacement is always negative, but ds273 demonstrated that it can be positive at certain extreme platform tilt ranges (https://www.youtube.com/watch?v=bS_5UJLibKc). I believe this is because at some step in the calculations for the rotation matrix, the game assumes the rotation about the z axis for the platform is 0.

 

The problem with the FST is that tilting the platform into this range while also having PU speed is almost impossible. When Mario has PU speed and is pushing against a position that is out of bounds, he will stay in place, but he won't snap down to the floor of the platform as it tilts. The platform's rotation matrix is supposed to apply to Mario, so in theory he should stay at the surface, but as discussed the rotation matrix is incorrect, and he will drift away from the surface of the floor due to the error. The game only considers Mario to be on the platform if he is within 4 units vertically of the floor, so he quickly exits this range due to the accumulating rotation error, and the platform stops tilting.

 

This makes it very hard to tilt the platform after performing the final squish cancel speed transfer. Additionally, performing a speed transfer has required Mario to slide off the platform and fall for at least 6 frames. Each frame Mario is not on the platform, it tilts back to the resting position. These 6 frames pretty much eliminate any chance of being able to meet the extreme platform tilt requirements. Additionally, there are limitations to how far you can tilt the platform in the right direction and still meet the conditions for a squish cancel speed transfer.

 

Despite these obstacles, in this video I use 3 bullies with hacked speeds, angles and positions on 3 specific frames to pull off the FST. Nothing else is hacked. I use a number of tricks and optimizations to perform a squish cancel speed transfer to a sufficient PU speed for Mario while still meeting the requirements for the platform tilt. Additionally, I make use of some powerful automation software developed by bad_boot, myself, AnthonyC4, fifdspence and Krithalith to calculate a way to perform the platform displacement upwarp and navigate a quick return route through PUs.

 

Here's what happens.

 

Step 1: Mario activates the track platform at the beginning and waits by the 1 up so the platform can get into position. Then, Mario performs movement that causes him to land on the farther pyramid platform at a floating-point-precise X and Z position. pannenkoek2012 was kind enough to TAS this section, as he has a method to target FP precise positions. This was actually TASed after the next part, so the position was known beforehand. I hexed in the appropriate number of waiting frames based on where the track platform needed to be on a later frame.

 

Step 2: Mario lands on the platform, and simply waits for it to tilt a bit. Then at a specific time, he performs a punch cancel to get a little bit of speed. This is when the first bully collision happens. I hacked the bully to have 75 million speed in a direction parallel to Mario's speed, but I hacked the position to be fully perpendicular to both speed vectors. Because the bully-Mario collision is basically elastic, both objects preserve their speed in this case. If the angle was anything but perpendicular, the bully would transfer a small portion of its momentum to Mario, which would easily give him 32 speed (knockback speed is capped at 32). 32 speed is a problem because MArio moves way you far and slides off the platform. We need him to barely move at all so Mario must have only a little bit of speed, hence the requirement that the bully's speed be perfectly perpendicular to the angle of collision.

 

Step 3: It would be nice to just have Mario knockback with 0 speed so we can target the next position easily, but the tilted platform causes Mario to accelerate downhill. Knockback lasts for 25 frames and we need it to run out completely in order to perform the next part. In order for Mario to not move too far despite 25f of downhill acceleration, we want him to have around 10 speed or so, so he finishes with about the same speed in the negative direction. The combination of his low and changing speed and the rotation from the platform causes Mario to move in a small, roughly parabolic arc. I arranged for this arc to finish right at the edge of the lava, at an equilibrium point where the platform is tilted as far as it can go in that direction without Mario falling into the lava. THis is very important, because the platform tilt is represented by a normal vector (normal means perpendicular to it's surface), and due to the platform tilting logic, the X and Z components of the normal vector are conserved as we move across the platform towards the squish cancel spot. This means that our maximum platform tilt is limited by how far we can tilt the platform to start with. Ideally, the platform would be tilted at a 45° angle, as this provides the highest XZ normal sum, but I have to tilt it farther in the X direction for reasons I will explain below.

 

Step 4: Exactly 25 frames after the first bully collision, the bully collides with Mario again, this time at a non perpendicular angle so Mario gets 32 speed. The frame difference is important because it allows Mario to perform the 1 frame knockback glitch. This is a little-known glitch where if Mario enters a soft knockback action immediately after exiting it, he will exit it again in 1 frame. This conserves speed and puts Mario in idle, which is great for what we do next. Note that the glitch only works if you go from soft forward knockback to the same action, or soft backward knockback to the same action. Soft forward to soft backward or vice versa does not work, nor does this work with any other kind of knockback action.

 

Step 5: I also position the bully very close to Mario's position so the second collision displaces Mario close to the maximum distance (110 units or so). The combination of this clip distance along with the 32 speed conserved from the 1FKB glitch allows Mario to get across the platform much faster. Furthermore, 1FKB puts Mario in idle, which allows him to immediately dive in any direction since he has more than 29 speed. This means I can immediately perform a pause buffered dive recover as I can dive straight uphill. This is part of the reason for tilting the platform further in the X direction to start. If it was tilting at a 45° angle, uphill would be towards the center, which is not the direction we want to go. The DR is barely possible even diving straight uphill. so the tilt in the X direction is necessary. Not that when the game is paused, the platform appears to revert back to its resting position, but this is just a rendering glitch in the game.

 

Step 6: The dive+DR gives us +15 speed, but it also puts us in the air. It is possible to land immediately, but this leads to a bad quarterframe landing, and we need to traverse the platform as quickly as possible. Instead, I take advantage of the fact that Mario can be within 4 units of the platform floor and still be considered as on the platform (I mentioned this earlier). This applies even if Mario is in the air, so I am able to DR for several frames while continuing to tilt the platform. This avoids a bad qf landing, defacto speed loss, and ground deceleration, and I think all told it saves about a frame getting across the platform.

 

Step 7: Mario lands and runs for a couple frames to the edge of the platform. At this point, we have way too much speed. If Mario slides off the platform he will just fly off into the lava. We need him to decelerate rapidly. Fortunately, because we tilted the platform so far in the X direction and we were able to get the speed boost from the DR, we can do a second PBDR, this time to decelerate. IF you don't have any joystick input on the first frame after landing from a DR, Mario's speed will immediately drop to 0. Doing this saves at least 2 in-game frames over any other deceleration option (not actual frames because of the pause), and we need every frame we can get.

 

Step 8: I believe this is a new tech. Mario does a low joystick magnitude walk for 1 frame, which is uphill, so it gives him less than 1 speed. This puts him into a precise subpixel region on the edge of the platform known as a NUT spot (backronym: Nonstatic Unit Truncation). If Mario finishes a frame in such a spot in an action that can cancel to freefall, the error in the rotational displacement from the platform will move Mario off the edge of the platform, and he will enter freefall. Now, slow walking does not cancel to freefall, but if you don't input anything it will cancel to deceleration. Deceleration doesn't cancel to freefall either, but it does cause Mario to lose 1 speed. If after this, Mario has 0 speed, deceleration will cancel to idle, and that DOES cancel to freefall. However, the point of all this is to enter freefall without sliding off the platform so we can keep tilting it. If we have to avoid joystick input in order to enter the deceleration action, we won't be able to strain back onto the platform. So instead, I press C^ on the slow walking frame. This forces Mario into deceleration even if there is joystick input, so the chain of action cancels can proceed, and the input will be applied to freefall and cause Mario to move back onto the platform on the same frame that he enters freefall. I arrange for Mario to again be within 4 units of the platform so it continues to tilt in the right direction.

 

Step 9: On the next frame, Mario's Y speed (falling speed) is still low enough for him to hover over the platform in that 4 unit range by straining downhill. After that, he has too much falling speed, so I once again look to take advantage of the NUT spots. Because freefall landing cancels into freefall, I can chain 5 NUT spots together in a row with precise straining down the edge of the platform. Gravity is being applied this entire time, so I can build up -20 falling speed without ever leaving the platform. Mario needs to fall roughly 78 units to go below the floor and get squished by the platform, and gravity is four units per frame. This means in 3 frames, Mario will fall 20 + 24 + 28 = 72 units. By straining uphill in those 3 frames, I can make up the other 6 units, which means I successfully reduced the falling time from 7 (6 + a slideoff frame) to 3. This is crucial for meeting the platform tilt requirements.

 

Step 10: The third bully collision happens, which is a squish cancel speed transfer. This is done without the assistance of the track platform, which means the bully pushes Mario a considerable distance downhill. In order for this to work, The platform needs to be high enough for Mario to slideoff into the air from the squish push (more than 100 units above the lava). This is the other reason I started with the platform tilted so far in the X direction. It gives Mario barely enough time to get in position. If he takes even one more in-game frame to get there, the slideoff spot will be too low. On the other hand, tilting the platform significantly further in the X direction reduces the XZ normal sum, which causes us to fail to meet the platform tilt requirements at the end. It's all very tight.

 

Step 11: We now have PU speed and a great XZ normal sum, but our bias in the X direction means that the platform normal is still tilted too much in that direction. We need to convert the X tilt to Z tilt. However, as I explained before it is very difficult to tilt the platform after Mario has PU speed. After the speed transfer occurs, the platform tilts back underneath Mario. However, due to an idiosyncrasy in the code that displaces Mario rotationally, the displacement is not applied the first frame after Mario steps on the platform. This causes the platform to tilt downward without taking Mario with it, and Mario is now more than 4 units above the floor and can no longer tilt it. This is where the track platform comes in. I arrange for the slideoff spot to be near the edge of the track platform's wall hitbox, and I also arranged for the track platform wall to move into Mario on this exact frame. This nudges Mario about 7 units uphill, which puts him back within 4 units of the platform floor, so he can continue tilting it.

 

Step 12: Mario has now been on the platform for 2f so he will displace with it. Additionally, the error in the vertical displacement causes Mario to displace too far down each frame. I arranged for the track platform wall push to put Mario close to 4 units above the platform floor to maximize the number of tilt frames before Mario displaces more than 4 units BELOW the platform floor. This happens after 5 frames. At this point, the platform is still not tilted enough in th Z direction to pull off an upwarp. You might be wondering why we can't just perform a longer NUT spot chain to tilt the platform more in the Z direction and completely eliminate the need for the track platform push and subsequent tilt frames. Unfortunately, the NUT spots disappear as the platform tilts more in the Z direction, due to the displacement error favoring the center of the platform as the Z tilt increases. This is another reason why we must start with a higher X tilt.

 

Step 13: Mario has displaced below the platform and can no longer tilt it. However, in the first frame after it tilts back to the center, it puts Mario back within 4 units of the floor. This time, he's underneath it, so even though he does not rotate with it on the first frame, he is still within 4 units of it on the next frame, this time on the upper side. At this point step 12 basically repeats and Mario gets 5 more frames of tilt. This FINALLY meet the platform tilt requirements. For a small range of angles, Mario will get positive vertical displacement if he moves to a PU.

 

Step 14: But it's not that simple. Angles are not continuous, and the angles that Mario can turn to only will hit the platform in a PU at very specific distances. Furthermore, Mario also displaces a large distance horizontally. If this puts Mario out of bounds (only 1/16 positions are inbounds), the displacement won't happen at all. This all means that there are only a couple dozen of speed/angle combinations that will actually be valid for an upwarp, and most of these put him too far up, in a VPU. With all these filters, there are maybe 2 good speed/angle pairings for a given platform normal vector. Finding these would be totally unrealistic without automation software, and one of the tools I made does just that. I arranged for the third bully collision to give Mario the correct speed for this.

 

Step 15. Mario has performed the upwarp, but to complete the pole skip he must return to the main universe from his current position in a PU. I do this by manipulating Mario's speed using 1 frame crouchslides. Crouchslides cut a small percent of Mario's speed that depends on joystick input. They also cap his speed at 100, but if Mario moves into the air on the first frame this cap won't be applied. This gives us considerable control of Mario's speed in theory, but in practice most inputs don't move anywhere useful and cause Mario to bonk or fall into the lava in a different PU. So, I collaborated with AnthonyC4 to create a PU return route automation tool that iterates over all angles and inputs, with several filters for improving performance. The tool works quite well and you can see that I navigate back to the main universe very quickly. This route is actually the worst case scenario, because the upwarp puts me at a height just below the third level, which causes Mario to have to fall through PUs for quite a while in order to reach a platform on the second level. If we upwarp to a height where there is a floor, we can make it back in about a second. Also, it should be possible to target the Bowser 2 warp directly.

 

NOTE: This TAS is "console verified" to the extent that can be done with hacks (using an EverDrive and a ROM with the bully hacks). During the console verification process, which was done by M13, we discovered that the high speed bully collisions can produce an audio crash in some cases. There seem to be multiple workarounds, one of which is switching the game's sound output mode in the file select menu from Stereo to Mono. This TAS will crash in Stereo mode, but verifies successfully in Mono mode. Other than that, this TAS also avoids the other PU crashes that can happen, by using fixed camera during PU movement and avoiding certain actions and movements that can crash.

 

Also, the hacked bullies aren't actually visible on the frames where they collide with Mario, but they hover at that spot afterwards so you can still see where they were.

 

Thanks for reading! I hope you understand why this took two years :)

Adbot
ADBOT LOVES YOU

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!
https://www.youtube.com/watch?v=9Q7Jko5yoFY

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!
https://www.youtube.com/watch?v=wR9YSmbq2Vs

quote:

In this video I reach the ledge after the cogs in 0 A presses. This was already possible using a SDC (https://www.youtube.com/watch?v=6KX1V...), but as there's only one 100c star this was non-renewable. This method frees up the SDC to be used elsewhere in the level, namely to get onto the elevator platform. This is just one part of a complicated theorized strategy to get past the pole 0xA, saving up to 3 A presses.


This technique relies on a glitch called the squish cancel (https://www.youtube.com/watch?v=SQhH8...) which uses weird geometry of the pendulum to let mario cancel his action to freefall in midair. Since a groundpound raises mario up slightly at first, by repeatedly groundpounding and squish cancelling we can gain lots of height! Unfortunately if we go too high the pendulum becomes intangible and this stops working. We can't go high enough to ledgegrab normally, but fortunately two parts of the wall have very slightly different normal vectors due to floating point rounding, allowing for a glg to get just enough height (https://www.youtube.com/watch?v=C9Nn4...). While gp chaining was proven with hacked pendulum movement (https://www.youtube.com/watch?v=mLlqJ...) this demonstrates it's possible with the real pendulum

This is much harder than it looks. The probability decreases exponentially with the number of squishes required. And the available sc spots are different for each angle. So I wrote a bruteforcer to check for possible pendulum movements that would work

There's lots to consider for this:
After every sc the number of frames until the next sc changes the height gained. On top of that, the total height across the chain must be within a very specific range. Too low and you can't glg. Too high and you leave the pendulum tangibility radius

The sc spots are also constrained by distance, as the maximum distance mario can fall before losing more height than a gp would gain isn't long enough to strain from any sc spot to any other. So a sc spot is only valid if it's close enough to a previous valid sc spot. As well, falling for a fixed number of frames would constrain the solutions too much, so it has to be dynamic. sc spots that are closer together can be strained to in less frames, gaining more height. Again, all of this height must also add to a specific range

Also, mario can't enter a sc spot willingly, the pendulum must move it under him, which means mario has to be in the right position before the squish. Which means if that pendulum has an exposed ceiling at that position on that frame, the sc spot is inaccesible

Also also the starting height of mario is below the max height of the pendulum, so for the first few groundpounds some sc spots are inaccessible because mario would just bump into the pendulum.

Also also also as mario goes higher up, further away sc spots leave the tangibility radius and become inaccessible

This means the available sc spots aren't just a function of the pendulum's angle, but also the pendulum's speed, acceleration, all previous angles, mario's position and height, and position and height at all previous steps

In addition to this the first 2 sc spots are special cases:
Squish cancelling doesn't cancel mario's momentum, so after the first sc, mario still has the speed from the dive. This means if the first sc spot is too far back he will unavoidably bonk against the back wall. This also constrains the 2nd sc spot to be in a specific region to be reachable from the 1st

The sc spots themselves are very precise. While floors and ceilings take up unit squares, the effect of the de-facto speed on the squish push meant the actual sc spots were sometimes as small as 0.01 units (tenth of a milimetre). The final ledge grab is float perfect - ~0.0001 units (1 micrometre)

That would be far too tedious to deal with manually, so on top of writing the simulator for the pendulum's movement, and the floor/ceiling simulator and the pendulum vertex calculator to get the sc spots, I wrote a sim for mario's air movement (and the camera movement) and automatically generated the entire sequence of inputs for the chain. Since the final grab is floating point precise, the simulator had to be float-perfect, including taking into account the squish push at every step. Unexpectedly the hardest part wasn't actually the final ledgegrab, but the first 2 sc spots. Since mario keeps his speed, the movement between the 2 can't be treated individually. And with the angles and movement so precise, I had to find a very narrow path through a vast search space. My dimensional iterator bruteforcer couldn't do it, so I wrote a Particle Swarm Optimization bruteforcer, which did the trick

I searched many angles, and this was the quickest solution I found taking 90 minutes of RNG manipulation. Faster solutions probably exist. Since the final A press save strat would contain like an hour of coin cloning anyway, it needn't be faster than that as it could be done simultaneously


https://www.youtube.com/watch?v=5gvMJs6Ts48

quote:

I demonstrate a delayed bob-omb snap in TTC without using a preset HOLP. ds273 (https://www.youtube.com/channel/UCKu5...) came up with this strat and asked me to verify that it's possible, which I've now done.

You see, for a while, ds273 has been trying to save more A presses in TTC. He has a complicated plan to do so, but it's not all there yet. The plan involves having a bob-omb snap to Mario after Mario ascends part of the level by chaining together ground pounds above a pendulum. Thus, this video demonstrates that the bob-omb snap is possible. Also, note that the ground pound chaining piece of the plan has also had a recent breakthrough (https://youtu.be/wR9YSmbq2Vs). So piece by piece, we're making progress towards completing the plan.

Here's a breakdown of what I do in the video. First, I use a wall overlap to clip past the outer wall of the level, and set the HOLP out of bounds using a bob-omb. I need both bob-ombs for the next step, so I climb the spinners to respawn the bob-omb that just died. From there, I grab one of the bob-ombs as it explodes, but also as the other bob-omb explodes as well. The result of this is that I end up holding a clone of the other bob-omb's spawner. Since the spawner is invisible, it doesn't update the HOLP when I hold it. Then I climb the spinners again. Once I'm up top, I switch from holding the bob-omb spawner to a sound effect object, which allows me to load the 5 yellow coins without cloning them. I didn't want to load these coins, but it was unavoidable given my path. Note that my goal at this point is to move 4000+ units away from the HOLP so that I can remotely drop a bob-omb at the HOLP without the bob-omb snapping to Mario instantly, but with the added constraint that I have to remain inside the yet-to-respawn bob-omb's spawner radius. That's why I ride the hand over to the rotating blocks and then drop down, which achieves that goal. Finally, I use the behind camera anywhere technique to position Mario behind the camera, then clone the respawning bob-omb and release it. The result of this is that the bob-omb gets released at the HOLP laterally, but at Mario's current height. And since the HOLP was out of bounds, this means the failsafe will trigger as soon as Mario goes within 4000 units of the bob-omb, causing the bob-omb to instantly snap to Mario. And just to confirm that everything worked, I then show the snapping.

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!
"dimensional iterator" and "Particle Swarm Optimization" are starting to sound like stellaris techs

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!
lots of clock videos

https://www.youtube.com/watch?v=HQo50BmkKGA

but where's the light speed bully squish PU to skip the pole solution?

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!
I can't wait for Part 4 of Bismuth's ABC series.

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!
This Super Mario Bros 3 Video Blew My Mind

https://www.youtube.com/watch?v=DK0PgI5dt2A

quote:

Goals

Complete the game as fast as possible.
Load the credits without any visual bugs.

Additional Comments
This run is 28 frames faster than the previous run of 47 frames, and has been console verified by Bigbass.

The huge time save was achieved by setting up the various requirements without jumping to address $8FE3, which took up the majority of the previous TAS.

I created this run with the SubNesHawk core of Bizhawk 2.6.3, using the Trace Logger to know exactly where the program counter was at the end of each frame.
The DPCM Bug
The NES had a hardware issue called the DPCM Bug. You can read more about the bug here, but in summary, a hardware error existed that could drop a single bit when reading the button inputs.

To work around this bug, the game reads button inputs in a loop until two consecutive inputs are the same. Normally inputs are read twice in a frame, but should the DPCM Bug happen, the inputs would be read 3 times.

To exploit the workaround, we could press different buttons every time the inputs are polled. This would cause the input loop to happen as many times as we want! But “what good does that do us?” you might ask. Let's take a look at how my run exploits this, and the technical details behind it that allow for such a run to exist.
How the run works
(Heads up, there’s a decent amount of jargon in the rest of the author’s comments. This assumes you’re already familiar with a decent amount of 6502 Assembly)

The Non Maskable Interrupt (NMI) happens at the start of V-Blank, and the programmable interrupt (IRQ) is set to fire just a few scanlines above that. If we’re still executing code inside the NMI when the IRQ fires, the wrong PRG banks are currently loaded for the IRQ code. Address $101 is used as an “IRQ Mode” to determine which branches to take inside the IRQ code. In this case, the IRQ Mode is 0x20, which expects Bank 0x18 to be loaded in, but the NMI was using bank 0x1A to make some various graphical updates so the IRQ jumps us to the wrong place! This leads to an RTS instruction, except we jumped here using an interrupt, which should use RTI to properly return. Because of this, the wrong bytes are pulled off the stack as a return address, which leads the program counter to address $0001.

This part of RAM is filled with BRK instructions, which jumps to the programmable interrupt code. Every time this happens, since the IRQ Mode is still 0x20, the same problems occur. We enter the code as an interrupt, but exit the code with RTS, sending us back to $0001. This might sound like it’s an infinite loop, but luckily for us, the IRQ Mode is at address $101, which happens to be inside the stack! With each BRK leading to an RTS, the stack pointer is moving downwards 6 bytes. This will eventually reach the IRQ Mode, overwriting it with 0xB4. Now when the programmable interrupt is executed, it properly reaches an RTI instruction, so the stack pointer stops shifting around with every BRK, and we can continue to execute bytes after address $0001.

The NMI continues to happen every frame, and the buttons we press during the NMI are stored at addresses $17, $18, $F5, $F6, $F7, and $F8. Through careful planning, these bytes are all we need to win the game.
The limitations
Every frame we can choose what buttons to hold down on both controllers, and these fill in the bytes listed above in a specific manner. Let's look at addresses $17 and $18 first.

$17 is the total held buttons on controller 1
$18 is the newly pressed buttons on controller 1 for this frame.

For instance, suppose I wish to use these addresses to write A9 20. Let’s understand how button presses are used to write these hexadecimal numbers. Each button corresponds to a single binary bit of this number: (Button names have been shortened to a single character. Start is represented by a capital S; Select with a lowercase s)


A: 0x80
B: 0x40
s: 0x20
S: 0x10
U: 0x08
D: 0x04
L: 0x02
R: 0x01

So if I wish to hold down 0xA9, I need 0x80 + 0x20 + 0x08 + 0x01. (A + Select + Up + Right)

To write A9 20, I need to take two frames. For the first frame, I’ll push all the buttons except the ones required for address $18. That will allow me to press the new buttons on the next frame, and write out the full desired operation. So for the first frame, I would only press 0x80 + 0x08 + 0x01. That makes the following:

$17: 89 (Total held)
$18: 89 (New buttons)

And by continuing to hold down all of those previous buttons, and pressing 0x20 on the next frame, I can write:

$17: A9 (Total Held)
$18: 20 (New buttons)

You might see the problem already. Suppose I want to write A9 10. It’s not possible to hold down 0xA9 when the newly pressed buttons write 0x10, as that would make the total buttons 0x80 + 0x20 + 0x10 + 0x08 + 0x01 which adds up to 0xB9. The bits that compose address $18 are required to fit within the bits composing address $17.

Now let’s say I want to write BD BD 00. Since the third byte is 00 I don’t need to change that byte, so this could be written with just the two addresses, right? Well, let’s see. To write this, I need to press A, Select, Start, Up, Down, and Right. Super Mario Bros. 3 masks away Up + Down, as well as Left + Right, so the result would actually be 0xB1, as the Up and Down presses get removed. This limits what bytes we can create, as any bytes ending in 3, 7, B, C, D, E, or F are impossible to write with button presses.

Moving on to addresses $F5 through $F8

$F5: New buttons pressed for controller 1
$F6: New buttons pressed for controller 2
$F7: Total held buttons for controller 1
$F8: Total held buttons for controller 2

Just like the previous addresses, the bits that compose $F5 need to be contained within the bits composing $F7. The same applies for $F6 and $F8. This allows us to write much more than what can be written with addresses $17 and $18, though it too has its restrictions. Suppose I want to write 0A 20 5A B8. Like before, this takes two frames.

Frame 1:
$F5: 50 (New 1)
$F6: 98 (New 2)
$F7: 50 (Total 1)
$F8: 98 (Total 2)

Frame 2:
$F5: 0A (New 1)
$F6: 20 (New 2)
$F7: 5A (Total 1)
$F8: B8 (Total 2)

However, suppose I want to write A2 20 86 F9. This cannot be done, as A2 contains bits that 86 does not, when both need to be written with controller 1.
The win condition
The goal is to reach the princess cutscene and then the credits. Jumping to the princess cutscene is surprisingly easy, though the credits are where the issues come in. Like the IRQ, the NMI has a byte that determines which branches the code should take. If the NMI Mode isn’t set to 0x20, the credits fail to load properly, resulting in a black screen. This has been demonstrated by Masterjun, who was able to load the princess cutscene in 13 frames. That run doesn’t meet the win condition unfortunately, as the credits fail to load.

In order to win the game with the proper credits sequence, we need to meet 6 requirements.

The $C000 bank needs to be 0x19
The $A000 bank needs to be 0x18
The PPU Control Register Copy (Address 0xFF) must be 0xA8
The Stack Pointer must be greater than 0x30
The NMI Mode (Address $100) must be 0x20
Jump to $B85A

It’s worth mentioning that by the first frame we gain control, the first 3 requirements are met and will remain that way so long as we don’t change the PRG banks or affect the PPU Control Register. Let’s focus on the other 3 requirements. After the first frame with inputs, the stack pointer is at 0x03, and the NMI mode is 0xB4. As Masterjun and ais523 pointed out in their submission, there exists a location in ROM that sets requirements 5 and 6 for us! Address $8FE3, which is where the game prepares the princess cutscene under normal gameplay.

This leaves us with two options:

Correct the stack pointer and jump to $8FE3
Correct the stack pointer and set up requirements 5 and 6 manually.

While it may be trivial to jump to $B85A, jumping to $8FE3 is complicated. Let’s take a look at why we can’t simply jump to $8FE3.

Recall from the limitations, the game will mask away conflicting left + right, or up + down inputs. To write JSR $8FE3, we need to be holding down 0x8F on one controller, and 0xE3 on another. 0x8F requires holding down all direction buttons, and 0xE3 requires left + right. We could substitute 0xE3 for 0xE1, as $8FE1 would read the same code (only if the zero flag is not set), which fulfills requirement 5 and 6, but that still leaves us with the problem of 0x8F. On top of that, we need to consider the opcode, JSR, which if written using the new inputs would conflict with 0x8F, as holding down 0x20 would change the value to 0xAF. Comparing that with the much easier $B85A, with no conflicting inputs, it might take more time setting up a jump to $8FE3 than it would to meet the requirements ourselves.
The problems

We need to be able to run through the button inputs in RAM more than once, so we’re going to need to write a jump to $0000. That would take up one of the bytes we could use from $F5 through $F8.
Address $16 holds a value of 0x1E, which is a 3 byte opcode. Executing that address will skip right over $17 and $18, so our button presses won't be usable.
Most of the space here is filled with 0x00, which writes BRK, a 2 byte long opcode. That makes us execute on either even or odd addresses. When executing around $16, we need to make sure we’re executing odd addresses to avoid skipping our button presses. This also assumes $15 is a 2 byte opcode. We don’t need to worry about that for our button presses at $F5, as the 0xFF opcode sitting at address $F0 will always align us with odd bytes.
Addresses $10 and $15 are both used as timers, and change every frame. $10 counts down, while $15 counts up. Different values create opcodes of varying lengths, which could offset our code. On top of that, some opcodes crash the NES, so we need to avoid executing these addresses when they hold a problematic value.
We’re unable to control the A register. Multiple bytes that execute between our stored button inputs can change A in unhelpful ways, or simply in a manner we can’t manipulate.
We’re unable to control the Y register. Addresses $8D and $8E both hold 0xA0, which corresponds to LDY Immediate. This will guarantee that between the bytes we can control at address $18 and $F5, the Y register will get reset to either 0xA0 or 0x00.
We still have to work with the limitations, which prevents us from writing any 3 byte long opcodes with our button presses.
Any instructions that work on the zero page with offsets, such as STA $FF,X, are truncated to always remain within the zero page, so we can’t simply store our desired value into $100 by offsetting it past address $FF.

The solutions
We may not be able to use the A or Y registers, but we have full control over X. We could load 0x20 into X and store it to create a jump to $0000, so we no longer need to worry about the jump every time we reach $F5.

If we’re about to execute $15 when it’s going to crash the NES, we could simply stall inside the input loop for so long that we don’t execute address $15 until the following frame, where it will hold a different value.

Problem 2 wasn’t relevant due to the short length of the run, as address $15 only ever created 2 byte long instructions when I needed to use the button presses on $17 and $18.

I can utilize the stack to push 0x20 into $100 instead of writing there directly.
The execution
Instead of jumping to $8FE3 to fix the NMI mode, I simply push the number 0x20 on the stack when the stack pointer is in the right place. I can also adjust the stack pointer by executing JSR, or PHA, so I can easily manipulate the stack pointer to line this up right.

Bytes Instruction Description
A2 20 LDX #20 X now holds a value of 0x20, which is used to write JSR
(06 10) 86 F9 (ASL $10) STX $F9 This stores 0x20 right after the button presses at address $F9. When executed, this will bring the program counter back to $0000, while also pushing two bytes on the stack. The stack pointer is now 0x01.
(0A) 48 8A 48 (ASL A) PHA TXA PHA This pushes 2 bytes to the stack. First it pushes 0x00 at $101, transfers X (0x20) to A, and then pushes 0x20 at $100, which completes requirements 4 and 5, as the stack pointer is now 0xFF. The JSR back to $0000 happens again, pushing the stack pointer to 0xFD.
20 5A B8 JSR $B85A This jumps to the credits, completing requirement 6 and winning the game.

To reiterate, when I’m “stalling” inside the input loop, I’m switching between pressing the A button and no inputs between every instance where the controllers are polled.

The first frame of input is spent stalling inside the NMI, and can’t be used to set controller 1’s button presses.

A frame by frame explanation is as follows:

The game takes 10 frames to set up the title screen.

Stall inside the NMI until the IRQ fires
Stall to write the first half of LDX 0x20
Stall to avoid a game crash at address $15
LDX 0x20
STX $F9
Stall to write the first half of the next frame.
PHA TXA PHA
Stall to write the first half of the next frame.
JSR $B85A to win the game.

Boat Stuck fucked around with this message at 03:01 on Dec 6, 2021

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!

I can't believe we're on part 4 of this and we still haven't gotten to integer modulo wraparound parallel universes yet.

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!

dirby posted:

As "Daro" on Bismuth's Discord said:

https://www.youtube.com/watch?v=TSCzC-WECw8

Wow, the anti-Pannen

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!
How did I miss this from 3 years ago?

https://www.youtube.com/watch?v=goad2ijHBE8

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!
new pannen just dropped

https://www.youtube.com/watch?v=lUBrwHyDMWc

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!
:siren:

"ABC Team TAS Console Verification - 3 A-Press Save in TTC"

https://twitch.tv/rcombs


edit:

highlights-

https://clips.twitch.tv/SpikyDreamyCrabOSsloth-iN4rXqbMrGSDIZEe

https://clips.twitch.tv/InventiveImportantTurnipCharlieBitMe-qNs5emuOMqqxQuGg

Boat Stuck fucked around with this message at 22:41 on Jul 5, 2022

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!

I see he gave up trying to explain all this Mario magic through subtitles.

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!



Beautiful

Adbot
ADBOT LOVES YOU

Boat Stuck
Apr 20, 2021

I tried to sneak through the canal, man! Can't make it, can't make it, the ship's stuck! Outta my way son! BOAT STUCK! BOAT STUCK!
Hum this part of this video showing the vertical columns rising from the empty misaligned boxes was strangely disturbing to watch.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply