Thursday, October 26, 2017

Non-standard Eggheads, part 2

On the subject of the unused FBZ2 boss head, reader Silver Sonic 1992 asked:
Was this the intended use for that frame?
I guess I should've went into more detail regarding the nature of the bug. When the boss object begins swinging around the platform, the code at loc_7078A sets bit 2 of the bitfield at offset $38 of its SST:
loc_7078A:
    move.b  #8,5(a0)
    bset    #2,$38(a0)
    move.l  #loc_707EC,$34(a0)
    ...
Meanwhile, the head object tries to keep tabs on this bit by loading the RAM address for the boss' SST into register a1, which it has stored away at offset $44 of its own SST, and then checking the contents of offset $38. However, due to an oversight, it ends up checking offset $38 of register a0, which is its own SST, rather than register a1:
loc_67BFC:
    clr.b   $22(a0)
    movea.w $44(a0),a1
    btst    #2,$38(a0)
    beq.s   loc_67C12
    move.b  #1,$22(a0)
Okay, now for today's bug. Lava Reef Zone's act 2 boss has a unique head object with only one idle frame, in which the art has been redrawn to give Eggman's whiskers extra lighting from the lava below.


However, due to an oversight, only two of the three frames are ever seen. When the boss is defeated, it simply displays the second frame, which is the regular damage frame. The oversight is hard to notice due to how quickly the boss sinks back into the lava.

The code that picks which mapping frame to display is at loc_79C1C:
loc_79C1C:
    jsr     (Refresh_ChildPositionAdjusted).l
    movea.w $46(a0),a1
    move.b  #$F,$22(a0)
    btst    #6,$2A(a1)
    beq.s   loc_79C3E
    move.b  #$10,$22(a0)
    bra.w   loc_79C4C
; ---------------------------------------------------------------------------

loc_79C3E:
    btst    #7,$2A(a1)
    beq.s   loc_79C4C
    move.b  #$11,$22(a0)

loc_79C4C:
    jmp     (Child_Draw_Sprite2).l
Much like before, the head object is keeping tabs on the boss object, except this time the boss object's RAM address is at offset $46, and the bitfield the head object checks is the status bitfield at offset $2A.

Here's how this code works: it defaults to mapping frame $F, switches to frame $10 if bit 6 is set, and switches to frame $11 if bit 7 is set. Bit 6 is set when the boss takes damage, and bit 7 is set when it is defeated. However, when the boss takes its final hit, both bits are set, and the bra.w loc_79C4C instruction skips over the bit 7 check if bit 6 is already set.

To fix the bug, simply remove the bra.w instruction.

1 comment:

  1. I noticed when beating this boss, the Endboss music continues to play, and not fade to the level's music.

    ReplyDelete