don't click here

Why is the S&K miniboss music in Sonic 3? (Hydrocity miniboss)

Discussion in 'General Sonic Discussion' started by Jonny Axehandle, Apr 16, 2025.

  1. Jonny Axehandle

    Jonny Axehandle

    The one. The only. Oldbie
    88
    18
    8
    https://info.sonicretro.org/Big_Shaker

    This is something I keep scratching my head over. So this glitch causes the S&K miniboss music to play in S3. But what's that track doing on the S3 cart in the first place?
     
  2. Jayextee

    Jayextee

    Unpopular Opinions™ Member
    3,286
    82
    28
    Atro City
    I DONE MAKED GAMES.
    If you enter the sound test (within the level select) you'll find almost all of S3K's music is on the Sonic 3 cartridge; exceptions being title and 1-up jingles, music associated with endings, probably some others.

    But also, since this little music quirk can happen in Hydrocity act 2's boss as well, I'd presume it's some kind of an error baked into the game not being told the correct music to play when stopping the drowning theme as the player got air.
     
  3. jbr

    jbr

    Member
    95
    44
    18
    Yeah, since they were originally planned as one game I would imagine they did all the music in one go. Hence why it's already in the Sonic 3 cart.
     
  4. McAleeCh

    McAleeCh

    Oldbie
    1,573
    596
    93
    It's a strange case, though - all of the other Sonic & Knuckles exclusive tracks replace existing Sonic 3 themes outright to make it feel more like a 'new' game, but both versions of the miniboss music exist side-by-side in Sonic 3. Also, the Sonic 3 prototype we have access to shows that the Sonic & Knuckles miniboss music was originally used as the miniboss music in Sonic 3 too, so it makes me wonder if the final Sonic 3's miniboss music could have originally been composed for another purpose. Since it shares identical drums to Knuckles' theme, I do wonder if it may have been composed with the idea that it'd accompany the boss fight where the player faces off against Knuckles in Hidden Palace Zone? Of course, there's no way of knowing for sure, but it is interesting that those two themes are so closely linked compositionally.
     
  5. My random guess is that they simply forgot to change it to 3’s miniboss track in the code for what music plays after the drowning one plays, since S&K’s is very likely the original miniboss music they would’ve had to manually go back and edit those flags to use 3’s track instead.
     
  6. jbr

    jbr

    Member
    95
    44
    18
    Interesting question, we don't know why there are two boss themes. I guess they had plans for them which didn't quite come to fruition. Like you say, perhaps the Knuckles fight. Or maybe it was intended only for playing as Knuckles, since he encounters the egg robo rather than Robotnik? Although they could have done that in S3&K, and didn't. We'll probably never know.
     
  7. Mastered Realm

    Mastered Realm

    Member
    3,876
    586
    93
    -
    It's only speculation but also very plausible.
     
  8. Blue Spikeball

    Blue Spikeball

    Member
    2,721
    1,128
    93
    Would explain why they composed a new Knuckles theme for the final Sonic 3 alone to replace the proto track. To have it better tie in with his planned boss music.
     
  9. jbr

    jbr

    Member
    95
    44
    18
    That's also thought to be an MJ track, which may or may not be a factor. I really wish they'd just open up about that whole thing.
     
  10. McAleeCh

    McAleeCh

    Oldbie
    1,573
    596
    93
    Yes, that was kind of what I was trying to get at in a way, though I didn't really articulate it well. All the other MJ tracks outright replaced their SEGA Sound Team prototype equivalents in the final Sonic 3, except for the miniboss theme where both versions exist in the final game. That's what made me ponder whether the "MJ" miniboss theme was actually supposed to have a different purpose (since the SEGA Sound Team miniboss theme still exists in the track listing), and why I was wondering if maybe it was originally intended for another purpose, which might explain it existing alongside the other miniboss theme as a separate track rather than just replacing it wholesale.
     
    Last edited: Apr 16, 2025
  11. Sonic Hachelle-Bee

    Sonic Hachelle-Bee

    Taking a Sand Shower Tech Member
    837
    227
    43
    Lyon, France
    Sonic 2 Long Version
    Interesting topic.

    Something else to note, the only Knuckles only boss (the MGZ2 boss) also plays the S&K miniboss music instead of the regular boss music. Is this on purpose?
     
  12. Brainulator

    Brainulator

    Regular garden-variety member Member
    Even worse, it doesn't do this in Sonic 3 alone.

    The drowning music code is recycled from Sonic 1 and 2, and does not account for both bosses potentially having different themes. Another relevant post.
     
  13. expansivelovestories

    expansivelovestories

    reality is profoundly synergistic Member
    62
    35
    18
    It is crazy to consider that Sonic 3 is the only game soundtrack project work by Buxer!! ( i didn't know that for certain until now when checking on wikipedia. ) He is natural at it, and hopefully he has done some additional work some year at home. It's way ahead of its time in many ways. The weirder miniboss theme helps introduce and differentiate a concept which would have been all new, and possibly not as exciting whatsoever, at the time to Sonic fans.
     
  14. Battons

    Battons

    Shining Force Fan Member
    I’m also fairly sure that when & Knuckles is connected that it replaces the Sonic 3 boss theme in the sound test with the & Knuckles boss theme, so two different codes for the same track. Perhaps to fix this specific bug?
     
  15. Crimson Neo

    Crimson Neo

    Loopin' around. Member
    Was about to mention that about Knuckles technically having 3 different themes, which is a bizarre thing.

    But the bigg
    Well, in Sonic 3 (& Knuckles) they also use (S&K / original Sonic 3 proto's theme) for the first Flying Battery Act 2 boss, os I wonder if Marble Garden Act 2 was also probably meant to have two bosses? But like it were mentioned, in Sonic 3 alone it just used the major boss theme so... it's really hard to be sure.
     
  16. Black Squirrel

    Black Squirrel

    let's hurl a bwiki mart Wiki Sysop
    9,417
    3,218
    93
    Northumberland, UK
    the kwiki mart is real d'oh
    When I was a youngling I thought this was a conscious choice - that the sillier looking bosses would get the Sonic 3 theme, and the more dangerous ones would get the Sonic & Knuckles one (or the main boss music... or whatever I thought at the time).

    The Angel Island Act 1 boss slowly floats around and is very easy to beat, while the Hydrocity Act 1 boss has you spinning around in confined space with water, and you will die if you don't pay attention.


    The theory doesn't really hold up as you progress through the game, but to be fair, I spent more time with S3&K than regular Sonic 3.
     
  17. For whatever reason the Sonic 3 miniboss theme replaced the unused theme instead of replacing the miniboss theme. They did not account for this in the code that resumes boss music when drowning.
     
  18. XCubed

    XCubed

    Will Someday Own a Rent-A-Center Oldbie
    I’ve always thought this until we learned about the rest of the replaced prototype tracks. But hey, they could have thrown in the S3 Mini boss theme in so either it didn’t go to waste or it was per the contract with Brad Buxer.

    Either way, I’m glad we have it! They used the backup (or original) for S&K/S3&K.
     
  19. sayonararobocop

    sayonararobocop

    Member
    361
    127
    43
    The most concise answer is that two different functions are called here, and each returns a different sound ID (drowning returns $18 and the general boss music routine returns $2E). But why do two different functions call different sound IDs? And why is this piece of unused music in S3 but not in S3K? Due to countless hours of effort to document these games, we have a substantial amount of information about this topic.

    Helpful links:
    The Wiki
    Sonic 3 Unlocked

    Sonic Retro's very own S1 Disassembly at Github
    • sonic.asm
    • Constants.asm
    • s1.sounddriver.asm
    Sonic Retro's very own S2 Disassembly at Github
    • s2.asm
    • s2.constants.asm
    • s2.sounddriver.asm
    Sonic Retro's very own S3K Disassembly at Github
    • S3.asm
    • S3.constant.asm
    • sonic3k.constants.asm
    • sonic3k.asm
    Sonic 3 1103 Disassembly (the original by Esrael)
    • S303111993.asm
    • obj_0xAD.asm
    Why do two different functions call different sound IDs?

    First, let's look at the function that handles the music after the drowning countdown. I'll assume we all know how Drowning works in S1-3 from a practical perspective, just know that the function is triggered by canceling the drowning music (either through collecting an air bubble, exiting the water, popping an invincibility monitor or triggering Hyper form in S3K. Since I'm going into detail I'll wrap each game's implementation in Spoiler tags.

    In Sonic 1, this function has been identified as ResumeMusic. Sonic 1 features water in only Labyrinth Zone and the 3rd Act of Scrap Brain (which actually functions as a 4th act of LZ in the backend.)

    The implementation is a little crude and not really scalable because as you can see in the ASM code, the function output defaults to LBZ before testing a series of conditions that will load alternate music cues instead.

    Code (ASM):
    1. ResumeMusic:
    2.         cmpi.w    #12,(v_air).w    ; more than 12 seconds of air left?
    3.         bhi.s    .over12        ; if yes, branch
    4.         move.w    #bgm_LZ,d0    ; play LZ music
    First we test the level ID to see if it's actually supposed to be SBZ3 playing instead:

    Code (ASM):
    1. cmpi.w    #(id_LZ<<8)+3,(v_zone).w ; check if level is 0103 (SBZ3)
    2.         bne.s    .notsbz
    3.         move.w    #bgm_SBZ,d0    ; play SBZ music
    Next, we need to check if Sonic has actually popped an Invincibility monitor since that would supercede the regular level music. However, it looks like this was actually a bugfix added to Rev 01:

    Code (ASM):
    1. .notsbz:
    2.         if Revision<>0
    3.             tst.b    (v_invinc).w ; is Sonic invincible?
    4.             beq.s    .notinvinc ; if not, branch
    5.             move.w    #bgm_Invincible,d0
    And finally, we test to see if the screen has been locked, which S1's programmers used to identify a boss battle.

    Code (ASM):
    1. .notinvinc:
    2.             tst.b    (f_lockscreen).w ; is Sonic at a boss?
    3.             beq.s    .playselected ; if not, branch
    4.             move.w    #bgm_Boss,d0
    5. .playselected:
    6.         endif
    7.  
    8.         jsr    (PlaySound).l
    As for the sound cues, they're referenced throughout the code base. In Constants.asm we can find their pointer values beginning at line 174. Like most data in S1, the original zone order is reflected in the internal data structure. ResumeMusic nests the PlaySound function within, which loads the ASM of the audio from its internal sound driver.

    Code (ASM):
    1. ; Background music
    2. bgm__First:   equ $81
    3. bgm_GHZ:   equ ((ptr_mus81-MusicIndex)/4)+bgm__First
    4. bgm_LZ:       equ ((ptr_mus82-MusicIndex)/4)+bgm__First
    5. ...
    6. bgm_Boss:   equ ((ptr_mus8C-MusicIndex)/4)+bgm__First
    So for our bgm_Boss, the pointers can be seen in action in s1.sounddriver.asm, ultimately selecting the audio file for PlaySound

    Code (ASM):
    1. Music8C:    include "sound/music/Mus8C - Boss.asm"
    As implemented, the S1 function prioritizes sound cues and overloads the cue accordingly: Stage Music -> Invincibility -> Boss Music. In fact, it doesn't even consider the possibility that any other zones could trigger this behavior, and this rigid programming could be seen hitting its breaking point in the S2 Nick Arcade protos which were built off the top of S1's engine.

    For Sonic 2, ResumeMusic returns, with some bugfixes but also simplified from the Sonic 1 implementation (due presumably to the player encountering water on more levels).

    Code (ASM):
    1. loc_1D81E:
    2. ResumeMusic:
    3.     cmpi.b    #12,air_left(a1)
    4.     bhi.s    ResumeMusic_Done    ; branch if countdown hasn't started yet
    5.  
    6.     cmpa.w    #MainCharacter,a1
    7.     bne.s    ResumeMusic_Done    ; branch if it isn't player 1
    8.  
    9.     move.w    (Level_Music).w,d0    ; prepare to play current level's music
    10.  
    11.     btst    #status_sec_isInvincible,status_secondary(a1)
    12.     beq.s    +        ; branch if Sonic is not invincible
    13.     move.w    #MusID_Invincible,d0    ; prepare to play invincibility music
    14. +
    15.     tst.b    (Super_Sonic_flag).w
    16.     beq.w    +        ; branch if it isn't Super Sonic
    17.     move.w    #MusID_SuperSonic,d0    ; prepare to play Super Sonic music
    18. +
    19.     tst.b    (Current_Boss_ID).w
    20.     beq.s    +        ; branch if not in a boss fight
    21.     move.w    #MusID_Boss,d0    ; prepare to play boss music
    22. +
    23.     jsr    (PlayMusic).l
    24. ; return_1D858:
    25. ResumeMusic_Done:
    26.     move.b    #30,air_left(a1)    ; reset air to full
    27.     rts
    Here instruction move.w #MusID_Boss,d0 is called under the correct conditions which returns the boss music cue. Some structural changes, but ultimately the ptr zMusIDPtr_Boss is called which gets handled by the sound driver from there.
    S3 uses a new function, Player_ResetAirTimer that largely is the same

    Code (ASM):
    1. Player_ResetAirTimer:
    2.         cmpi.b    #12,air_left(a1)
    3.         bhi.s    loc_1744C        ; branch if countdown hasn't started yet
    4.         cmpa.w    #Player_1,a1
    5.         bne.s    loc_1744C        ; branch if it isn't player 1
    6.         move.w    (Current_music).w,d0    ; prepare to play current level's music
    7.         btst    #Status_Invincible,status_secondary(a1)
    8.         beq.s    loc_17430        ; branch if Sonic is not invincible
    9.         move.w    #mus_Invincibility,d0    ; prepare to play invincibility music
    10.  
    11. loc_17430:
    12.         tst.b    (Super_Sonic_Knux_flag).w
    13.         beq.w    loc_1743C        ; branch if it isn't Super
    14.         move.w    #mus_Invincibility,d0    ; prepare to play Super Sonic music (same as invincibility in this game)
    15.  
    16. loc_1743C:
    17.         tst.b    (Boss_flag).w
    18.         beq.s    loc_17446        ; branch if not in a boss fight
    19.         move.w    #mus_MinibossK,d0    ; prepare to play boss music
    20.  
    21. loc_17446:
    22.         jsr    (Play_Music).l
    23.  
    24. loc_1744C:
    25.         move.b    #30,air_left(a1)    ; reset air to full
    26.         rts
    27. ; End of function Player_ResetAirTimer
    28.  
    In this case, where we once returned Boss we now return a new track, mus_MinibossK!

    s3.constants.asm is actually not useful here, but sonic3K.constants.asm is!

    Here we can see for ourselves that the value is for MinibossK is $18

    Code (ASM):
    1. mus_MinibossK            ds.b 1        ; $18
    Lower in the same constants, we can see Miniboss assigned to $2E

    Code (ASM):
    1. mus_Miniboss            ds.b 1        ; $2E
    This code was never updated as evidenced by sonic3K.asm which has the same commands but updated the locations. Interestingly this is the only function that calls sound cue mus_MinibossK/$18 which might lend credence to the theory that it was never meant to be $18 in this function at all but $2E but it was missed for some reason. (whoever mapped the old constants to new ones, maybe).

    As for mus_Miniboss ($2E) we can find it being invoked many times. Every other miniboss object loads mus_Miniboss except for HCZ, which instead calls mus_EndBoss which is called in Act 2 Boss objects.

    Code (ASM):
    1. loc_47DBA:
    2.         move.l    #Obj_HCZ_MinibossLoop,(a0)
    3.         moveq    #signextendB(mus_EndBoss),d0
    4.         jsr    (Play_Music).l
    This code is updated in Sonic3K adding a MOV instruction

    Code (ASM):
    1.  
    2. loc_69F64:
    3.         move.l    #Obj_HCZ_MinibossLoop,(a0)
    4.         moveq    #signextendB(mus_Miniboss),d0
    5.         jsr    (Play_Music).l
    6. [B]        move.b    #mus_Miniboss,(Current_music+1).w[/B]
    So in the end, the code evidences that Sonic 3's programmers really wrote it that way. For HCZ Act 1's boss only, mus_EndBoss ($19) is played. The drowning music is possibly an oversight in the value assigned, but it also lacks any programming to account for S3's expanded music cues.

    1103 Proto Differences

    Of course, it's well known that the 1103 Prototype features an unused proto theme, the purpose for which has been debated throughout the years since the release of Sonic & Knuckles Collection.

    1103's unearthing showed that the level music in S&KC once occupied the sound cue IDs where the final MJ/Buxer team compositions rest. But, remember that our code snippet from s3.asm specifically sets the value for the to $2E for HCZ's miniboss. What does the 1103 Proto do? $18 is the miniboss music that plays during most encounters, so did the team simply change a couple of variables?

    An 1103 Disassembly goes a way towards solving this. This and the original by Esrael is disassembled in a slightly different format, but we can still identify the same ASM code by digging in.

    From S303111993.asm we can identify the pointers for the music queues and their relevant sound IDs (note that the disassembler had to identify $2E somehow, and the common thought at the time was it was a Super Sonic theme)

    Code (Text):
    1. Music_18_Ptr equ (Mini_Boss_Snd_Data&$FFFF)|$8000
    2. Music_19_Ptr equ (Boss_Snd_Data&$FFFF)|$8000
    3. ...
    4. Music_2E_Ptr equ (Super_Sonic_Theme_Snd_Data&$FFFF)|$8000
    5.  
    Some digging in the Disassembly later, I was able to find the Big Shaker Boss object in obj_0xAD.asm and can observe that like the later builds, it's specifically calling Boss_Snd ($19).

    Code (ASM):
    1.  
    2. Offset_0x037EEC:
    3.                 move.l  #Offset_0x037EFC, (A0)
    4.                 moveq   #Boss_Snd, D0                                      ; $19
    5.                 jsr     (Play_Music)                           ; Offset_0x001176

    What exactly is going on with that unused Miniboss theme?

    In conclusion

    In S3 1103, $2E

    Therefore it's reasonable to arrive at these potential explanations:
    • Player_ResetAirTimer incorrectly references mus_MinibossK ($18)
    • loc_47DBA incorrectly references mus_Endboss ($19) (which is attempted to be fixed in S3K but is functionally irrelevant as $18 and $2E are the same track in S3K)
    • Both are incorrectly referenced
     
    Last edited: Apr 29, 2025
    • Informative Informative x 3
    • Like Like x 1
    • List
  20. Battons

    Battons

    Shining Force Fan Member
    Glad to know I’m not crazy and there was in fact two IDs. Hadn’t checked since I posted that. Thanks for breaking it down and explaining it. I highly doubt theory 3 is correct considering team MJ was mostly team Buxer and he doesn’t really seem to care about that stuff. For theory two you’d need someone more familiar with the sound engineer to answer that. So I’m gonna hedge my bets on theory 1. That it was either an oversight or a bug, and was corrected with the & Knuckles rom connected to the game.