Showing posts with label Flying Battery Zone. Show all posts
Showing posts with label Flying Battery Zone. Show all posts

Sunday, April 1, 2018

The many tendrils of a Sonic 3 level, part 3: hiding in plain sight

Have you ever been on an egg hunt, and ended up walking past the damn things multiple times without actually seeing them?

Shortly after the code for the animal object, at $2CA7C we run across the code for the title card object. The first thing it does in its init routine is check if the current zone is one of the Competition levels, and if so set byte $44 of its own SST.
Obj_TitleCardInit:
        cmpi.b  #$E,(Current_zone).w
        bcs.s   loc_2CA96
        cmpi.b  #$12,(Current_zone).w
        bhi.s   loc_2CA96
        st      $44(a0)
        jmp     (Delete_Current_Sprite).l
When this flag is set, various aspects of the object's behavior are changed in order to display a unique set of title cards in Competition mode. However, these are ultimately never shown, because the object calls the Delete_Current_Sprite function immediately after setting the flag.
loc_2CA96:
        ...
        lea     TitleCard_LevelGfx,a1
        moveq   #0,d0
        move.b  (Apparent_zone).w,d0
        lsl.w   #2,d0
        movea.l (a1,d0.w),a1
        move.w  #$A9A0,d2
        jsr     (Queue_Kos_Module).l
Shortly after, we find the code which loads the title card graphics. It uses the value of the apparent zone as an index to the TitleCard_LevelGfx array, which is a list of pointers to KosM-compressed archives containing the letters that spell out each zone's name:
TitleCard_LevelGfx:     dc.l ArtKosM_AIZTitleCard
                        dc.l ArtKosM_HCZTitleCard
                        dc.l ArtKosM_MGZTitleCard
                        dc.l ArtKosM_CNZTitleCard
                        dc.l ArtKosM_FBZTitleCard
                        dc.l ArtKosM_ICZTitleCard
                        dc.l ArtKosM_LBZTitleCard
                        dc.l ArtKosM_AIZTitleCard       ; MHZ
                        dc.l ArtKosM_AIZTitleCard       ; SOZ
                        dc.l ArtKosM_AIZTitleCard       ; LRZ
                        dc.l ArtKosM_AIZTitleCard       ; SSZ
                        dc.l ArtKosM_AIZTitleCard       ; DEZ
                        dc.l ArtKosM_AIZTitleCard       ; DDZ
                        dc.l ArtKosM_AIZTitleCard       ; HPZ
                        dc.l ArtKosM_ALZTitleCard
                        dc.l ArtKosM_BPZTitleCard
                        dc.l ArtKosM_DPZTitleCard
                        dc.l ArtKosM_CGZTitleCard
                        dc.l ArtKosM_EMZTitleCard
                        dc.l ArtKosM_BonusTitleCard
                        dc.l ArtKosM_BonusTitleCard
                        dc.l ArtKosM_BonusTitleCard
Then, at $2CC62, the apparent zone is used again, this time to inform the mapping frame used by the "name" portion of the title card:
Obj_TitleCardName:
        move.b  (Apparent_zone).w,d0
        add.b   d0,$22(a0)
The sprite mappings used by the title card object can be found at $2D90C. These mappings have the same layout as their Sonic & Knuckles counterparts, except the S&K stages all point at a blank mapping frame, and there's a mapping frame for the Competition mode title cards which was removed in Sonic & Knuckles.
Map_TitleCard:  dc.w Map_TitleCard_Blank-Map_TitleCard
                dc.w Map_TitleCard_Banner-Map_TitleCard
                dc.w Map_TitleCard_Act-Map_TitleCard
                dc.w Map_TitleCard_Zone-Map_TitleCard
                dc.w Map_TitleCard_AIZ-Map_TitleCard
                dc.w Map_TitleCard_HCZ-Map_TitleCard
                dc.w Map_TitleCard_MGZ-Map_TitleCard
                dc.w Map_TitleCard_CNZ-Map_TitleCard
                dc.w Map_TitleCard_FBZ-Map_TitleCard
                dc.w Map_TitleCard_ICZ-Map_TitleCard
                dc.w Map_TitleCard_LBZ-Map_TitleCard
                dc.w Map_TitleCard_Blank-Map_TitleCard  ; MHZ
                dc.w Map_TitleCard_Blank-Map_TitleCard  ; SOZ
                dc.w Map_TitleCard_Blank-Map_TitleCard  ; LRZ
                dc.w Map_TitleCard_Blank-Map_TitleCard  ; SSZ
                dc.w Map_TitleCard_Blank-Map_TitleCard  ; DEZ
                dc.w Map_TitleCard_Blank-Map_TitleCard  ; DDZ
                dc.w Map_TitleCard_Blank-Map_TitleCard  ; HPZ
                dc.w Map_TitleCard_2PMode-Map_TitleCard
                dc.w Map_TitleCard_Bonus-Map_TitleCard
                dc.w Map_TitleCard_Stage-Map_TitleCard
Note that both TitleCard_LevelGfx and Map_TitleCard contain valid entries for Flying Battery Zone, which is why we can get as far as displaying its title card in Sonic 3.

That's not why we're here, though. At $2CC08, right before being dismissed, the title card is responsible for loading the current level's KosM PLCs. It does this by calling the rather appropriately named LoadEnemyArt function:
LoadEnemyArt:
        lea     off_2DF60,a6
        move.w  (Apparent_zone_and_act).w,d0
        ror.b   #1,d0
        lsr.w   #6,d0
        adda.w  (a6,d0.w),a6
        move.w  (a6)+,d6
        bmi.s   locret_2DF5E

loc_2DF50:
        movea.l (a6)+,a1
        move.w  (a6)+,d2
        jsr     (Queue_Kos_Module).l
        dbf     d6,loc_2DF50

locret_2DF5E:
        rts
Once again, it uses the value of the apparent zone (and act) as an index to a pointer array, this time containing pointers to the KosM PLCs for each act in the game.

The thing is, much like TitleCard_LevelGfx and Map_TitleCard before it, this pointer array also contains valid entries for Flying Battery Zone:
off_2DF60:      dc.w PLCKosM_AIZ-off_2DF60
                dc.w PLCKosM_AIZ-off_2DF60
                dc.w PLCKosM_HCZ1-off_2DF60
                dc.w PLCKosM_HCZ2-off_2DF60
                dc.w PLCKosM_MGZ1-off_2DF60
                dc.w PLCKosM_MGZ2-off_2DF60
                dc.w PLCKosM_CNZ-off_2DF60
                dc.w PLCKosM_CNZ-off_2DF60
                dc.w PLCKosM_FBZ-off_2DF60
                dc.w PLCKosM_FBZ-off_2DF60
                dc.w PLCKosM_ICZ-off_2DF60
                dc.w PLCKosM_ICZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
                dc.w PLCKosM_LBZ-off_2DF60
Remember when I said the graphics for Flying Battery's enemies went out the door with the rest of the level load block?
PLCKosM_FBZ:    dc.w 1
                dc.l ArtKosM_Blaster
                dc.w $A000
                dc.l ArtKosM_Technosqueek
                dc.w $A500
Uh... April Fools!

The PAR code 02DF46:7010 will force every level to load Flying Battery Zone's KosM PLC. You can use this alongside the codes 05B58C:7010 and 05B5C2:7010 from my previous post in order to place the FBZ enemies in any level using debug mode. FBZ's palette is long gone (I checked), but luckily Carnival Night Zone's is a suitable replacement.

Friday, January 5, 2018

Flying Battery enemies in S3A, part 2

It's not just Flying Battery Zone 2 that has cool stuff lying around in its object layout. Act 1's layout has an object with ID $8F placed at coordinates $2EE0, $5E0:
FBZ1_Sprites:   dc.w   $80,   $80,     0, $2EE0, $85E0, $8F00, $FFFF,     0,     0
Now, what do you imagine we'll find if we look up object ID $8F, or 143 in the master object list?
    ...
    dc.l Obj_LBZ_EndBoss            ; 140
    dc.l Obj_CNZEndBoss             ; 141
    dc.l Obj_CNZMiniboss            ; 142
    dc.l Obj_AA_1_FBZ1_Boss         ; 143
    dc.l Delete_Current_Sprite      ; 144
    dc.l Delete_Current_Sprite      ; 145
    dc.l Delete_Current_Sprite      ; 146
    ...
Okay, that probably wasn't much of a surprise if you happened to watch the video I linked to in my previous post. That's right, it's the boss of Flying Battery Zone 1, Gapsule:


In my video, I mentioned how the only difference between the S3A version of Gapsule and the one in Sonic & Knuckles lies in its color: the S3A version uses a slightly different shade of black from every other capsule in the stage.

Unfortunately, I made a slight faux pas while talking about Gapsule's button: I mentioned how its colors are also slightly different, using a dark tan around its edges rather than the light tan that every other capsule in the game uses.

Check this out, though. Here is the palette used by every other capsule in the game: the player palette:


Now, here's the palette that Gapsule uses, which is loaded over the level's regular enemy palette:


Do you see it? If you force the button to use Gapsule's palette instead of the player palette, then its edges become dark tan instead of light tan. The button simply uses a different palette line between S3A and Sonic & Knuckles.

Reader Silver Sonic 1992 asks:
Also, why is there a copy of the FBZ Gapsule boss in the disassembly labelled as unused? Is there anything special about it?
Let me elaborate. Way down at the bottom the S&K disassembly, there's a duplicate of Gapsule's art directly before the remaining Flying Battery Zone bosses; all three of them Nemesis-compressed. As the label notes, this copy of the art is unused: there are no other references to it anywhere in the disassembly.
ArtNem_FBZMinibossUnused: binclude "Levels/FBZ/Nemesis Art/Miniboss Unused.bin"
    even
ArtNem_FBZ2Subboss:       binclude "Levels/FBZ/Nemesis Art/Act 2 Subboss.bin"
    even
ArtNem_FBZEndBoss:        binclude "Levels/FBZ/Nemesis Art/End Boss.bin"
    even
So what's the deal? Let's look at an excerpt of Gapsule's init code from S3A:
    move.l  #loc_4C9CA,$34(a0)
    moveq   #$5E,d0
    jsr     (Load_PLC).l
    lea     Pal_FBZMiniboss(pc),a1
    jsr     (PalLoad_Line1).l
In S3A, the Nemesis art is neither a duplicate nor is it unused. As part of its setup, the boss performs a PLC request for PLC $5E, which happens to fall right inbetween the PLCs for Carnival Night Zone and Icecap Zone's act 1 bosses, and contains a reference to the Nemesis-compressed Gapsule art.
PLC_5C_5D:
    dc.w 1
    dc.l ArtNem_CNZMiniboss
    dc.w $A5C0
    dc.l ArtNem_BossExplosion
    dc.w $A000
PLC_5E:
    dc.w 4
    dc.l ArtNem_FBZMiniboss
    dc.w $A5C0
    dc.l ArtNem_EggCapsule
    dc.w $89C0
    dc.l ArtNem_BossExplosion
    dc.w $A000
    dc.l ArtNem_Squirrel
    dc.w $85C0
    dc.l ArtNem_BlueFlicky
    dc.w $8800
PLC_5F:
    dc.w 1
    dc.l ArtNem_ICZMiniboss
    dc.w $9520
    dc.l ArtNem_BossExplosion
    dc.w $A000
In Sonic & Knuckles, this was changed so Gapsule's art is instead stored in KosM format, most likely because Nemesis decompression isn't fast enough to display the boss immediately as it scrolls into view.
    move.l  #loc_6EF14,$34(a0)
    lea     (PLC_83D64).l,a1
    jsr     (Load_PLC_Raw).l
    lea     (ArtKosM_FBZMiniboss).l,a1
    move.w  #-$5A40,d2
    jsr     (Queue_Kos_Module).l
    lea     Pal_FBZMiniboss(pc),a1
    jsr     (PalLoad_Line1).l
As a result, PLC $5E was neutered pretty hard, and the reference to the Nemesis-compressed Gapsule art removed...
PLC_5E:
    dc.w 0
    dc.l ArtNem_BossExplosion
    dc.w $A000
...except apparently, the developers forgot to remove the art itself from the build. Whoops.


Bonus chatter: Here are some PAR codes that allow you to place the unused Flying Battery Zone objects using debug mode. First, these two force every level to use FBZ's debug list:
05B58C:7010
05B5C2:7010
Then, these replace some of the objects in FBZ's debug list with the three unused bosses:

GapsuleLaser bossAct 2 boss
05BFC2:0004
05BFC4:C948
05BFC6:0016
05BFC8:0B48
05BFCA:A52E
05BFCC:0004
05BFCE:D558
05BFD0:0016
05BFD2:37FE
05BFD4:252E
05BFD6:0004
05BFD8:DBA0
05BFDA:0016
05BFDC:33F8
05BFDE:A3E0

Thursday, January 4, 2018

Flying Battery enemies in S3A

In my previous post, I pointed out how S3A's object layout for Flying Battery Zone 2 has a second object placed slightly to the left of the end capsule, at coordinates $3130, $6D8:
FBZ2_Sprites:   dc.w   $80,   $80,     0, $3130, $86D8, $B400, $3210, $8660, $C600
                dc.w $FFFF,     0,     0
There isn't really any easy way to make the game load the level properly, and even if it did, there aren't any level blocks to stand on. Instead, let's just look up object ID $B4, or 180 in the object list:
Sprite_Listing:
    ...
    dc.l Obj_ICZEndBoss             ; 178
    dc.l Obj_ICZMiniboss            ; 179
    dc.l Obj_FBZEndBoss             ; 180
    dc.l Obj_HCZEndBoss             ; 181
    dc.l Obj_AB_1_FBZ_Laser_Boss    ; 182
    dc.l Obj_C6_1                   ; 183
    dc.l Obj_ICZCrushingColumn      ; 184
    ...
That's right! Like I documented in this video a couple of years back, Flying Battery Zone's bosses are fully implemented in Sonic 3, apart from an overall lack of sound effects, anyway. This includes act 2's laser miniboss even though it's not actually placed in the object layout.

Incidentally, I based that video's presentation on GoldS' legendary Sonic 3 and Knuckles Glitches and Oversights video series, which I sure hope all of you have already watched by now.


That's not all, though. If we go a bit further up the list, what do you suppose we'll find sandwiched between the enemies for Marble Garden Zone and Icecap Zone? (Carnival Night Zone's enemies are even higher up for some reason.)
    ...
    dc.l Obj_Spiker                 ; 165
    dc.l Obj_Mantis                 ; 166
    dc.l Obj_Blaster                ; 167
    dc.l Obj_TechnoSqueek           ; 168
    dc.l Obj_AIZ_EndBoss            ; 169
    dc.l Obj_Penguinator            ; 170
    dc.l Obj_StarPointer            ; 171
    ...
Both of Flying Battery Zone's regular enemies are also implemented! However, since their graphics normally get loaded through a PLC at the start of the level, they went out the door with the rest of the level load block.


Much like the bosses, both enemies are fully functional, except that Blaster tends to get stuck in place after firing some of his bullets. Oh, and you can jump on his bullets and they blow up like enemies. Freaky.

Wednesday, January 3, 2018

His and hers act 2 capsules

One of S3A's little idiosyncrasies is that, unlike the ones in which it descends from the top of the screen, any levels that feature stationary act 2 end capsules have them placed directly into the object layout, instead of having the boss object spawn them at the end of the fight.

In S&K, this was changed so that stationary capsules are also spawned by the boss, which unfortunately led to this bug where the capsule in Hydrocity Zone 2 is not properly aligned with the screen lock:


Why the developers changed this is a mystery; perhaps they were trying to remove any possibility that the player might somehow miss the screen lock and proceed to the next stage without fighting the boss, as can be seen here.

Surprisingly, such a minor detail can actually give us insight on an unrelated aspect of the game's development. It turns out, the object layout for Flying Battery Zone 2 contains one such stationary capsule, at coordinates $3210, $660.
FBZ2_Sprites:   dc.w   $80,   $80,     0, $3130, $86D8, $B400, $3210, $8660, $C600
                dc.w $FFFF,     0,     0
The reason this is interesting is because the S3A placement of the capsule is a stone's throw away from its final resting place in Sonic & Knuckles. This suggests that by the time it was removed from S3A, the level layout for Flying Battery 2 was already quite similar to its final layout in Sonic & Knuckles.


Astute readers will notice the second object present in the layout placed slightly to the left of the capsule at coordinates $3130, $6D8. Foreshadowing: the sign of a quality blog.

Thursday, November 9, 2017

The limbo bug explained

A couple of days ago, I said I would look into the method speedrunners use to trigger the limbo bug. Now, I'm back with the results. Surprisingly, it all has to do with the camera.

First, I'll post the video again for your convenience. Here's Flying Battery Zone 1 in 0:55 by Zurggriff, on June 16, 2017:


Okay, at the very start of the level, there's a long vertical shaft. When Sonic enters this shaft,
he's forced into a spin by one of the two objects at either end, pictured to the right.

This object forces Sonic into a spin by doing two things. One, it sets Sonic's spin dash flag at byte $3D of his SST. Two, in case he wasn't already spinning, it changes his animation to the spinning animation, and plays the spin sound effect for good measure.

The spin dash flag induces two distinct behaviors, depending on Sonic's current animation. If Sonic is in his spinning animation, then it will give Sonic a small boost of speed when he's moving too slowly. If that sounds familiar, it's because this behavior was used extensively in Sonic 2's Casino Night Zone.

However, if Sonic isn't in his spinning animation, the flag indicates he is currently charging a spin dash, which is released as soon as the player stops holding the down button.

The intended behavior is that when Sonic passes through the bottom object, his spin dash flag is set, forcing him into a spin, and then when he passes through the top one, the flag is cleared again. At the start of the level, though, the top object is far enough from the camera that the object manager elects not to spawn it.

When looking up or down, the camera's max vertical speed is temporarily reduced so that it will gently slide over to its target position. By stepping on the booster pad during this period, Sonic is able to zoom past the object at the top of the shaft before the camera can scroll up enough for it to spawn. This causes Sonic's spin dash flag to remain set.

Another special behavior of the camera is that the game is constantly recording the last few player positions to a buffer. When a spin dash is released, the camera temporarily uses values from this buffer rather than the player's live position, so that the player will briefly outrun the camera.

All of these aspects collide once Sonic reaches the vertical cylinder object. The object sets Sonic's object_control and status bitfields, and bumps him out of his spinning animation. Sonic's spin dash flag is still set, but since he isn't in his spinning animation any more, a spin dash release is triggered, assuming of course the player isn't holding down.

The cylinder object sets player 1's ride flag in own its status bitfield but at the same time, the spin dash release causes the camera to start reading from the player position buffer. The camera quickly snaps to where it was a short while ago, which was quite a ways to the left. So far left, in fact, that the cylinder object scrolls far enough off screen to be deleted.

Of course, when the camera scrolls back to the right, the object is loaded from the object layout again. But the damage is done. The object respawns with a clean status bitfield, and once again has no idea that player 1 was riding it.

Do the limbo, baby.

Wednesday, October 25, 2017

Non-standard Eggheads, part 1

I've unwittingly shown this before, but in each act 2 boss, Eggman's head has four frames of animation: the first two are played in a loop while the boss is idle, whereas the third and fourth frames are shown when it takes damage, and when it's defeated, respectively. Unlike in Sonic 1 and 2, Eggman doesn't giggle when the player takes damage.


Flying Battery Zone's boss has a different set of art, and the way it works is also a bit different. The first frame is shown while the player's position is being tracked, and flips horizontally to show Eggman actively searching for the player. The third and fourth frames work the same as before. Due to an oversight, however, the second frame is never used.


To fix this, go over to the Obj_FBZRobotnikHead object and replace the code at loc_67BFC with this:
loc_67BFC:
    clr.b   $22(a0)
    movea.w $44(a0),a1
    btst    #2,$38(a1)
    beq.s   loc_67C12
    move.b  #1,$22(a0)
Rebuild the ROM, wait for the boss to begin swinging around the platform and...


Hey, it's our old pal from the Data Select screen!


Additionally, you can also go over to the Obj_FBZEndBoss object and replace the code at loc_706C2 with this:
loc_706C2:
    move.w  d0,$14(a0)
    move.b  #4,5(a0)
    move.b  #$84,$38(a0)
    move.w  #$5F,$2E(a0)
    move.l  #loc_707EC,$34(a0)
    rts
This will make the boss also use the missing frame during its initial swing.

Thursday, September 14, 2017

Can't catch me if I'm already gone

Like Hydrocity Zone, Carnival Night Zone too features a one-way obstacle you wouldn't expect to fall back through, but which the layout accounts for anyway. This time, it's the hover fans scattered throughout both acts of the level.


In the above scenario, when you take damage over a row of fans, they won't catch you, and you'll fall into an otherwise empty room. There's a red spring in the corner to make sure you can get back out, which is kind of overkill, considering you can get within range of the fans simply by jumping.

I don't know what they were so worried about, because if you do this close to the bottom of the stage, you'll fall straight into Knuckles' path, where you'll likely get stuck anyway due to all the Knuckles-only breakable walls.

As for why it happens: although the fans are part of the level's blocks much like the water slides in Hydrocity Zone, they actually have no collision and are instead controlled by invisible objects placed directly over them. In turn, these objects don't affect the player when their routine counter is set to 4 or above. Previously, we saw how routines 6 and above are used when the player has died; routine 4 occurs when the player is falling back from taking damage.
sub_31E96:
    ...
    cmpi.b  #4,5(a1)
    bhs.w   locret_31F2E
    tst.b   $2E(a1)
    bne.s   locret_31F2E
    ...
I'm not sure why the object behaves that way, but there you go.

Something similar happens in Flying Battery Zone, where none of the screen event code runs if the player is dead. This leads to some visual weirdness if you save yourself from death by entering debug mode: since the screen events aren't running, the foreground plane isn't redrawn as you move around the stage.


This one I can explain: the screen event code is responsible for checking whether you're inside or outside the ship, and triggering all the different effects, such as loading palettes, changing backgrounds and doing the necessary level layout modifications. It does this by loading player 1's X and Y coordinates into the d0 and d1 registers upfront and comparing them against a bunch of different ranges.
FBZ1_ScreenEvent:
    cmpi.b  #6,($FFFFB005).w
    blo.s   loc_5242E
    rts                                     ; Don't do any special events while Sonic is dying
; ---------------------------------------------------------------------------

loc_5242E:
    lea     FBZ1_LayoutModRange(pc),a1
    move.w  ($FFFFB010).w,d0
    move.w  ($FFFFB014).w,d1
    move.w  ($FFFFEED2).w,d2
    jmp     loc_52442(pc,d2.w)
; ---------------------------------------------------------------------------

loc_52442:
    bra.w   FBZ1SE_Normal
; ---------------------------------------------------------------------------
    bra.w   FBZ1SE_LayoutMod1
; ---------------------------------------------------------------------------
    bra.w   FBZ1SE_LayoutMod2
; ---------------------------------------------------------------------------
    ...
If this code ran while during the death animation, the player could potentially enter one of those ranges while falling off the screen, causing the background to change while the camera is stuck where the player originally died. The simplest solution is to check for routine 6 or above before doing anything, and although it fudges up debug mode a bit, it has no visible effect when the camera freezes normally.

Wednesday, September 13, 2017

Why is there an invisible solid object rising along with the floor beam?

Beats me. The best way to answer this kind of question is to go in the disassembly, dummy out the relevant bit of code and see what happens. First off, the solid background flag isn't set until the thing starts moving, so that sucks.


That would be easily fixable, though, so let's move on. If you let the beam carry you through the one-way platform, your character won't have any vertical momentum, so they'll get caught on the top-only block and fall behind the background scroll, eventually getting crushed by the sideways collision on the beam as it plows on ahead.


This could be fixed by removing the sideways collision on the beam chunks. Lastly though, and perhaps most damning, is the fact that the beam does not carry you horizontally as it moves diagonally up the screen.


This is likely why every other use of the solid background flag only has the background plane scroll vertically. Even the crushing wall at the start of Hydrocity Zone 2, which moves horizontally, does not let you stand on top of it.

Friday, June 9, 2017

The out-of-bounds layout copy area

If you go beyond the natural end of Launch Base Zone 1, you'll come across this area before you reach the loopback: a bunch of perfectly coherent buildings that are nonetheless glued together in a nonsensical manner.


These are actually the same buildings you go through during the course of the act, as they appear from the inside and from the outside. When you enter one, the game copies the appropriate indoor section from this area over to the main layout, revealing the building's interior. When you leave, it copies over the matching outdoor section to hide it again.

Act 2 also has an out-of-bounds building, but it's tricky to reach because halfway through the level, the Death Egg bit erases all the regular chunks from the layout. The simplest solution is to scroll all the way to the end of the level, place a Star Post, hit it and die. You'll respawn in the loopback, and the Death Egg is gone until you exit the level. Now you can just go back to the left until you find it:


Unlike the ones in act 1, this one only has the outside version. This is because once you exit the building, there's no way to go back inside, so the game doesn't need to remember what the inside looks like.

Flying Battery Zone uses the same trick for when you enter and exit the ship. The size for this stage is set properly, so you can't go beyond the end of the level, but as it happens, the first copy area is right underneath the starting point!


Inside... and outside. Neat!

Another one that's within bounds is Angel Island Zone 1. Right at the start of Sonic's intro sequence, if you go directly upward, you'll find the interior version of the hollowed-out tree from later in the stage. Unfortunately, the right graphics aren't loaded, making it pretty unrecognizable. But at least you can stand on it.


Once again, only the inside version is present because once the interior is revealed, it's never covered up again, so the game doesn't need to recall its outside appearance.

Tuesday, May 23, 2017

Flying Battery Zone was originally Zone 5

While developing, we went snowboarding a lot at a nearby resort. People kept getting injured, though... Originally, this stage was planned to begin after Zone 8 (Flying Battery Zone). Sonic was going to break down the door from the airship and make a snowboard out of it on the way down. The other characters can fly, so they wouldn't appear in that event.
We're going to have to take Naka's word about the snowboarding bit. However, one look at standalone Sonic 3's level select and Flying Battery Zone's original place in the level order becomes evident:


There it is, smack dab between Carnival Night Zone and Icecap Zone. If you go and check the sound test, FBZ's music occupies slots $09 and $0A, right between CNZ and ICZ's music. In fact, Flying Battery Zone is the only level which appears out of turn in the game's internal level order. This suggests it was a relatively late change, a notion supported by the presence of fully-functional bosses in standalone Sonic 3.


If you have a Pro Action Replay or PAR-compatible emulator or flash cart, you can use the code FFE6CF:0004 to set the first Data Select slot to Zone 5. No, not Icecap Zone, the real Zone 5. It even comes with its own, otherwise unused preview icon, which is different to the one in Sonic & Knuckles.

The stage itself has been completely removed though, so if you try to play it, the game just freezes.


Shoot, so close!

Wednesday, May 17, 2017

When sprites use background art

This is something I came across while messing around with Flying Battery Zone's palette. There's this flat-colored tile which appears in the foreground with palette line 1, but also appears in the background with palette line 3. I guess the color index just happened to line up.


When I messed with the layout of palette line 1, suddenly the colors didn't line up anymore, requiring said tile to be split in two, one for the foreground and another for the background. Undeterred, I went looking for another tile I could usurp.


Well, that didn't take long. I replaced the second of the seemingly redundant tiles, and everything seemed fine until I ran into this monstrosity:


Long story short, since those collapsing platforms look a lot like the rest of the level, their tiles are stored along with the main level art. That way, they can be reused by the background planes without wasting extra VRAM. Apparently this is common practice; Hydrocity Zone has collapsing platform graphics at the start of the main level art in a similar manner.

The presence of duplicate tiles gives it away: sprites need all of their tiles to come in sequence, so the art file caters to them. Background planes aren't bound to such restrictions, so they end up using only the first tile, and as such survive my hamfisted experiments.