How do I get the invincibility song to resume after getting the powerup monitor with it unexpired?

Discussion in 'Discussion & Q&A' started by Miles Sebas Prower, Aug 25, 2023.

  1. Miles Sebas Prower

    Miles Sebas Prower Newcomer Member

    Joined:
    Aug 22, 2023
    Messages:
    21
    Location:
    Alvarenga, Charallave
    Hi, I would like to get the invincibility song to resume from where it is after you break a invincibility monitor while the powerup didn't expire before you break it. I'm specifically trying to add this to Sonic 1 using the 2005 Hivebrain disassembly, but the song doesn't play and instead the BGM just resumes, example, I break a invincibility monitor in Green Hill Zone and its BGM just resumes and doesn't play the invincibility theme. What I'm trying to do is get the invincibility song to resume after you break the powerup monitor while you still have it instead of restarting because I found it a bit off that in the Sonic games the theme restarts after you break a invincibility monitor, regardless of you having the powerup when you break it, so I'm trying to change this and get the song to not restart unless the powerup expired and you break a invincibility monitor, similar to the Mario games when you take a invincibility star while the powerup hasn't expired. Is there something I did wrong, like, does the bne just before the command to play the song have to do with it?
     
  2. Devon

    Devon I'm a loser, baby, so why don't you kill me? Member

    Joined:
    Aug 26, 2013
    Messages:
    1,377
    Location:
    your mom
    What you can do is for each of the PlaySound routines, you store the current song ID being played in a variable (you should also check if it really is a song ID first by checking if it is in $81-$9F, except $88, the 1UP theme, since that is more or less acting as a sound effect). When running the routine, first you would read the song ID stored in that variable, update it with the new song ID, and check if the old song ID and the new song ID are both the invincibility ID. If so, don't update the sound driver queue.

    Here's some sample code
    Code:
    ; ---------------------------------------------------------------------------
    ; Check if a sound ID should be played
    
    ; input:
    ;        d0 = track to play
    ; returns:
    ;        cc = play it
    ;        cs = don't play it
    ; ---------------------------------------------------------------------------
    
    CheckSoundID:
                    cmpi.b  #bgm__First,d0          ; Is this a song ID?
                    bcs.s   .play                   ; If not, branch
                    cmpi.b  #bgm__Last,d0
                    bhi.s   .play                   ; If not, branch
                    cmpi.b  #bgm_ExtraLife,d0       ; Is this the 1-UP jingle ID?
                    beq.s   .play                   ; If so, branch
    
                    cmpi.b  #bgm_Invincible,d0      ; Is this the invincibility song ID?
                    bne.s   .updatesongid           ; If not, branch
                    cmp.b   (v_current_song).w,d0   ; Is the invincibility song already playing?
                    beq.s   .dontplay               ; If so, branch
    
            .updatesongid:
                    move.b  d0,(v_current_song).w   ; Update current song ID
    
            .play:
                    andi    #~1,ccr                 ; Play the sound
                    rts
    
            .dontplay:
                    ori     #1,ccr                  ; Don't play the sound
                    rts
    
    ; ---------------------------------------------------------------------------
    ; Subroutine to play a music track
    
    ; input:
    ;        d0 = track to play
    ; ---------------------------------------------------------------------------
    
    ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
    
    
    PlaySound:
                    bsr.s   CheckSoundID            ; Should we play this sound?
                    bcs.s   .dontplay               ; If not, branch
                    move.b  d0,(v_snddriver_ram+v_soundqueue0).w
    
            .dontplay:
                    rts    
    ; End of function PlaySound
    
    ; ---------------------------------------------------------------------------
    ; Subroutine to play a sound effect
    ; ---------------------------------------------------------------------------
    
    ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
    
    
    PlaySound_Special:
                    bsr.s   CheckSoundID            ; Should we play this sound?
                    bcs.s   .dontplay               ; If not, branch
                    move.b  d0,(v_snddriver_ram+v_soundqueue1).w
    
            .dontplay:
                    rts    
    ; End of function PlaySound_Special
    
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Unused sound/music subroutine
    ; ---------------------------------------------------------------------------
    
    PlaySound_Unused:
                    bsr.s   CheckSoundID            ; Should we play this sound?
                    bcs.s   .dontplay               ; If not, branch
                    move.b  d0,(v_snddriver_ram+v_soundqueue2).w
    
            .dontplay:
                    rts    
    

    Of course, v_current_song will need to be defined. For the sake of optimization, it might be best to make a separate PlaySound routine specifically for music and only have the check be run on that, and then make every song play call use that routine instead, and just have all the sound effects/commands just use the regular versions. If you also want it to have a song not be restarted if a PlaySound to its ID is called while it's still playing, then you can just remove the invincibility song ID check.
     
    Last edited: Aug 25, 2023
  3. nineko

    nineko I am the Holy Cat Member

    Joined:
    Mar 24, 2008
    Messages:
    1,902
    Location:
    italy
    I actually added this feature in my hack back in the day, because I too didn't like how the invincibility song restarted if you broke a second monitor before the first one expired (most easily done in GHZ1). However, I took a much simpler approach, since there already is a handy variable that can be checked.

    Find this code in the Obj2E_ChkInvinc routine:
    Code:
    move.b #1,($FFFFFE2D).w ; make Sonic invincible
    move.w #$4B0,($FFFFD032).w ; time limit for the power-up
    Change it to this:
    Code:
    move.w	#$4B0,($FFFFD032).w ; time limit for the power-up
    
    cmpi.b	#$1,($FFFFFE2D).w	; am I already invincible?
    beq.s	Obj2E_NoMusic	; if so, branch
    
    move.b	#1,($FFFFFE2D).w ; make	Sonic invincible
    As a design choice, you might even make it add 20 more seconds of invincibility to the ones you have left instead of resetting the timer to 20, though I didn't do that, so that simple exercise is left to the reader (hint: the move.w should become something else).
     
    Last edited: Aug 26, 2023