Moldorm 2 Bumper Bounce

Have you ever hovered Moldorm 2? Or have you ever seen someone hover Moldorm 2? If so, did you think it would be absolutely hilarious to call them a "cheater"? If you have said that, please leave.

Something you may have noticed happens sometimes is a violent reaction from one bumper in the next room. Perhaps it's applauding you for saving 6 seconds. Or perhaps it's so delighted with itself for the cleverness of calling you a "cheater" that it can't stop laughing. Neither of these is the case. Unfortunately and fortunately, respectively.

Boing, as it were

There's a key thing that bumpers do that Moldorm doesn't: bounce other sprites. When bumpers can bounce a sprite is pretty straightforward, but I noticed something funny, and also I want this page to be longer, so let's take a deeper dive.

We'll go through these lines one-by-one, and it will all make sense in the end.

TYA
Sprite index to A
EOR $1A
Exclusive OR with frame counter
AND #$03
Mask for bits 0 and 1
ORA $0F70, Y
Add in flags
BNE failure
Fail if nonzero
LDA $0DD0, Y
Get sprite state
CMP #$09
9 is the active state
BCC failure
Above 9 are stunned/lifted
LDA $0E60, Y
Invulnerability
ORA $0F60, Y
Statis
AND #$40
Check the bit
BNE failure

Frame rules

Ahhh, frame rules. One of the most well-renowned concepts in the game. Bumper-to-sprite interactions are no exception, and they use the standard collision frame rule calculation. Take the sprite slot of the sprite in question and exclusive-OR it with the frame counter. Finally, look at the bottom 2 bits. If they're both 0, then the collision check proceeds. But this one has an efficient twist.

Altitude

Oh altitude, you've become as famous as frame rules ever since spooky. Bumpers only want to hit sprites flat on the ground. To do this, they take the previous frame rule value and OR in the bits of the sprite's altitude. If those together are nonzero, then the collision check is skipped. This is the same result as checking each separately, but it's more efficient, both space- and cycle-wise. I'm a little impressed.

State

The next check is the sprite's state. This value is compared to $09, the value indicating the sprite is active and running its full AI. The check uses the operation BCC, which, when used with the preceding CMP, behaves as "less than". So this check also allows for sprites in states $0A (being carried by player) and $0B (frozen or stunned). All other sprite states—dead, dying, falling, exploding—fail and will result in the collision check being skipped.

Invulnerability and Statis

Now we're at the stuff that actually matters. These 2 are lumped together in the code, and because invulnerability is straightforward, I've decided to lump them together here. How straightforward is invulnerability? If bit 6 of $0E60,Y is on, then the sprite can't be hurt.

Statis is pretty straightforward as well, but it was a given a funky name in the disassembly, so it's 100× more confusing. If bit 6 of $0F60,Y is on, then the sprite will not count towards kill rooms. Enemies like anti-faeries, and for some reason keese, and non-enemy sprites like bumpers and statues have this bit set. This will allow shutter doors to open or chests to appear when the condition is "kill everyone" but those guys are still on screen.

These two properties occupy the same bit of separate addresses, so they can be safely ORed together before the check instead of looking at them separately. Another surprising win for the vanilla devs!

Bumpers have the statis bit set, but not invulnerability. The latter doesn't matter because they don't even run routines that check for damage from the player, so that already hardcodes them to be invulnerable.

Something funny

What you may not have noticed but I definitely did, was that there's no mention of the layer any sprite is on. This would imply that bumpers can hit sprites on other layers. Sure enough, if I edit a bumper's memory to be on the lower layer, it still bounces sprites that land inside its hitbox.

Something important

Another oddity that will be important to remember is that all of these initial checks are executor-agnostic. Only the sprite to be bounced is looked at; who actually does the bouncing is irrelevant.

:Oooox

You now know everything there is to know about bumpers for this glitch. But it doesn't explain the bouncing. Clearly, something is off about Moldorm. There are a lot of things off about Moldorm, but we only need to look at one thing (with some rubbernecking along the way).

Hitboxes

Moldorm has 2 hitboxes. This should come as no surprise to anyone, but it is a little unorthodox. Moldorm consists of a single sprite, and each sprite is only assigned one hitbox. So how does the second hitbox work? Which one even is the second hitbox?

It's the tail. Duh. Moldorm's main hitbox is his head. The specific thing about Moldorm that we need to look at is his segmentation. Each segment needs to operate somewhat independently, but also dependently. Moldorm uses subroutines to operate each segment of his body, and this occurs in the draw routine. Sure, that makes sense. Most of his body does nothing except exist. They need to move with the head in a choo-choo train fashion, but that's it. The tail is different.

x

Moldorm's tail is the only part that can be damaged, and it accomplishes this in an inelegant way. The first thing to do after drawing is set the address $0D90,X to 1. Next, the addresses $0F60,X and $0CAA,X are set to 0. These are the addresses for hitbox and deflection properties, respectively. Clearing the deflection properties makes some sense, assuming we want them all 0. And hitbox 0 happens to be the one we want for the tail, but these addresses contain other properties… I guess they'll fix it later?

After that, Moldorm's coordinates (which represent his head) are pushed to the stack, and new values (of the tail) are written to his coordinate addresses. The standard damage from player check is run with those values. The 1 into $0D90,X from earlier is to tell that routine to not apply any knockback to Link. After the routine, it is set back to 0.

Oh, here's where they fixed those reckless zeros. $0F60,X is set to $09 and $0CAA,X to $04. And this is where I must point out a weird oversight. $04 is not the value Moldorm spawns with. He actually spawns with $81, which means he will stay active off-screen (bit 7) and won't be killed manually under certain conditions (bit 0). So why is it set to $04? All that bit does is make Moldorm immune to sword and hammer. Does this mean that without the tail, Moldorm is vulnerable to sword attacks? No. Even without that property, other aspects of the check leave Moldorm impervious. It does, however, mean that Moldorm is prevented from being active off screen.

As far as the ROM data is concerned, Moldorm should be active, even when off-screen, but the tail, as soon as it's allowed to run its code, decides to change that. You can sort of see this. If Link's coordinates are offset from where they should be (such as with the jingle glitch), you might notice that Moldorm's sound effect plays, with Moldorm nowhere in sight. The only problem I noticed when I changed the code to restore $81 was a very rare teleporting tail graphic. Perhaps this is the reason they changed that value? Who knows?

Transitions

This is the last piece of the puzzle to tie everything together. When you transition, sprites from both the new room and the old room are visible on screen. Transitions call a subroutine every frame to cache a bunch of data for every sprite and put old sprite data in there for a second run. 24 different properties are cached, but for some reason, $0F60,X isn't one of them. Neither is $0CAA,X, but that doesn't matter.

While all these other values end up being cached and restored, the one for statis and hitbox is not. By sheer coincidence, hitboxes $09 and $1A (the one bumpers should have) are exactly the same! Wait… What!? Every other hitbox is at least subtly different from all the others, and… Hold on… Bumpers are the only sprite with hitbox $1A. Why didn't you just reuse $09? What a waste.

Okay, so the hitbox effectively stays the same, but statis doesn't. Moldorm counts for kill rooms, and this property is forced onto the bumper, because the original value is never saved.

Stop hitting yourself

Literally. The bumper is just hitting itself. With statis off, every other check is passed. Obviously, the bumper's hitbox overlaps with itself. Thus, every 4 frames, the bumper just bounces itself. It stays in place, because, with its coordinates perfectly matching themselves, the recoil velocity on both axes is 0. Hilariously, the redundant invulnerability bit would have prevented the bouncing completely (that address is indeed cached), and no one would know of this glitch. It would be too subtle; everything else appears completely normal.

What if we go up?

This glitch isn't specific to bumpers. Those properties of Moldorm will transfer to any slot 0 sprite during the transition. So what happens in the room above? In that room, the north-west crystal switch happens to be in slot 0. And it's super easy to do this glitch. So easy that I'm surprised it's never been noticed here. During the transition into Moldorm 2, just hold up. Voila! The crystal switch is now weird. Let's treat it differently!

If you try to walk onto it, it seems normal, but compare it to the other crystal switch. Walking into that one will let you go a few pixels in, but this glitchy one stops you fairly early. It can even seem like you're stuck on nothing if you align yourself pefectly with the orange pegs and try to pass vertically.

Now try slashing it. You can't. The switch will clink but not change color, and you'll recoil a little. Other things can trigger the switch, but your hammer and sword will not be among those things.

Summary

In practice, a specific property called "statis" is the only thing preventing bumpers from hitting themselves. During transitions, most properties of sprites are cached so that old and new can share the same addresses for execution. Hitboxes and statis (on the same address) are not cached. Moldorm's tail's hitbox is executed as part of a subroutine that also handles drawing, so it is executed during these transitions. This subroutine ends up changing both the hitbox and statis of sprite 0 slots on transitions where Moldorm is visible. Moldorm and bumpers have different hitboxes that happen to be exactly the same size and position, but the statis property that prevented bumpers from interacting with themselves was cleared.

Shortest summary

The bumper is literally hitting itself.