Monday, July 24, 2017

Special wall-breaking powers

The bit of code responsible for deciding whether or not a player should be able to destroy a breakable wall has quite a few peculiarities which make its behavior less than obvious, so I thought we could have a look at it and learn a couple of things along the way, along with help from our friend, the Sonic Retro wiki.

Here's the code:
    tst.b   (Super_Sonic_Knux_flag).w
    bne.s   loc_215F4
    cmpi.b  #2,$38(a1)
    beq.s   loc_215F4
    btst    #4,$2B(a1)
    bne.s   loc_215E0
    btst    #5,$2A(a0)
    beq.s   loc_2162A

loc_215E0:
    cmpi.b  #2,$20(a1)
    bne.s   loc_2162A
    move.w  d1,d0
    bpl.s   loc_215EE
    neg.w   d0

loc_215EE:
    cmpi.w  #$480,d0
    blo.s   loc_2162A

loc_215F4:
    bclr    #5,$2A(a0)
    bsr.s   sub_2165A
    ...
Alright, let's start from the top.
    tst.b   (Super_Sonic_Knux_flag).w
    bne.s   loc_215F4
Pretty straightforward. If you're Super Sonic or Super Knuckles (or the Hyper version of either character), then you can break the wall. Note that this leaves out Super Tails, as if he wasn't screwed over enough already.
    cmpi.b  #2,$38(a1)
    beq.s   loc_215F4
$38 is the character ID: Sonic is 0, Tails is 1, Knuckles is 2. So if you're playing as Knuckles, then you can break the wall. This effectively means the previous check is only relevant when playing as Sonic.
    btst    #4,$2B(a1)
    bne.s   loc_215E0
$2B is the secondary status bitfield, exclusive to the player objects. Sonic Retro helpfully chimes in:

BitHexDescription
4$10Fire shield flag.

So if you have a flame barrier, we skip over the next check. Which happens to be...
    btst    #5,$2A(a0)
    beq.s   loc_2162A
$2A is the primary status bitfield, universal to all objects. Note that we're checking the flags of the breakable wall in a0, not the player object loaded in a1. Retro says:

BitHexDescription
5$20Set if Sonic is pushing on this object.

This is a bit inaccurate. Bit 5 is only set if player 1 is pushing on the object while standing on something. Combined with the previous check, this means if you have a flame barrier, then you can break the wall even if in mid-air.
    cmpi.b  #2,$20(a1)
    bne.s   loc_2162A
$20 is the current animation ID, for objects that use the global animation system. In the case of the player objects, #2 corresponds to the spinning animation, used while either rolling or jumping. So if you aren't in the spinning animation, then you can't break the wall.
    move.w  d1,d0
    bpl.s   loc_215EE
    neg.w   d0

loc_215EE:
    cmpi.w  #$480,d0
    blo.s   loc_2162A
Finally, the player's horizontal velocity, which was previously stored in d1, is copied over to d0 and transformed into its absolute value. That value is then compared to $480, and if you're moving at a horizontal speed of less than 4.5 pixels, then you can't break the wall. This also applies to the flame barrier check, which is what allows Sonic to break through walls using his fireball dash move.

Notice anything fishy, though? Nowhere do we check whether the player has performed a double jump move or not, so if you have a flame barrier, just jumping at the wall with the requisite speed will work. In fact, there's no check for Sonic either, which means Tails can break down walls in the exact same way. This surely annoys players who try to avoid the first special ring in Angel Island 2 by jumping -- only to go through the wall due to their speed coming out of the tube.

5 comments:

  1. So there /aren't/ any specific "Knuckles-only" walls, they just put them in midair and restrict your access to fire shields? And Super Sonic can bust through them anyway? That's... not the conclusion I expected.

    ReplyDelete
    Replies
    1. Where did I say there aren't any Knuckles-only walls? Strap yourself in, we're just getting started.

      Delete
  2. I don't get why they wouldn't add a double jump move check. Do you think there's some logic to that, or it's most likely just an oversight?

    ReplyDelete
    Replies
    1. I dunno. I checked Sonic 1/2 and everything up to loc_215E0 is missing, so it was added specifically for Sonic 3. Smells like lousy programming to me.

      Delete
    2. Actually, the game does have a way to know whether the player is using a double jump move: the double jump flag, which is also used to track Tails and Knuckles' flying/gliding state. Among other things, it prevents you from using your double jump move more than once per jump.

      Delete