Adding Negative Rings to Sonic 1

Discussion in 'Tutorials' started by BL3H, Feb 8, 2025.

  1. BL3H

    BL3H idiot sandwich Member

    Joined:
    Jul 19, 2022
    Messages:
    62
    Location:
    Tails' Workshop, Angel Island
    I've decided to take a step back from all of the technical tutorials and instead move over to a preference tutorial. If you want to make a use out of the unused Sonic 1 monitors, then follow this guide as I show you how to implement Negative Rings into Sonic 1. Reminder that we're using Hivebrain 2005, but I'm sure you can figure out the labels for GitHub.

    There are two things before we start. First, we need to define negative rings, as in, how will they work? You can find negative ring boxes scattered across levels (once they're placed into the levels). Upon breaking them, one of two things could happen. Either, you lose 10 rings, or, if you have less than 10 rings, your ring counter is negated and is set into the negatives, where the ring text will constantly flash red until you collect enough rings or ring boxes to get out of the negatives. That's how we're going to make them work in our tutorial.

    The other thing to mention is that you need a free RAM address. I'm using $FFFFF5C1 for our tutorial, defined as NegativeRingsFlag. Ok, now we can begin!

    First, replace the entirety of Obj2E_ChkS with this:

    Code:
    Obj2E_ChkS:
            cmpi.b    #7,d0        ; does monitor contain 'S'
            bne.s    Obj2E_ChkNegaring
            nop
         
    Obj2E_ChkNegaring:
            cmpi.b    #8,d0
            bne.s    Obj2E_ChkEnd
            move.w    ($FFFFFE20).w, d0
            cmpi.b    #$A, d0
            blt.s    Obj2E_IntoNegs
         
    Obj2E_RmvRings:
            subi.w    #$A,($FFFFFE20).w ; subtract 10 rings from the number of rings you have
            ori.b    #1,($FFFFFE1D).w ; update the ring counter
            move.w    #$B5,d0
            jmp    (PlaySound).l    ; play ring sound
         
    Obj2E_IntoNegs:
            tst.b    NegativeRingFlag
            beq.s    @yes
            bra.w    Obj2E_RmvRings
         
    @yes:
            move.b    #$01,(NegativeRingFlag).w
            move.w    #$A1,d0
            jmp    (PlaySound).l    ; play ring sound
    
    This is the code to make our negative ring box function. It's probably recommended that you change the sounds for this, I was using the checkpoint sound to tell me if we went into Negative mode.

    Next, you're going to want to replace Obj2E_ChkRings with this:

    Code:
    Obj2E_ChkRings:
            cmpi.b    #6,d0        ; does monitor contain 10 rings?
            bne.s    Obj2E_ChkS
            tst.b    NegativeRingFlag
            bne.s    Obj2E_ExitDebt
            addi.w    #$A,($FFFFFE20).w ; add    10 rings to the    number of rings    you have
            ori.b    #1,($FFFFFE1D).w ; update the ring counter
            cmpi.w    #100,($FFFFFE20).w ; check if you have 100 rings
            bcs.s    Obj2E_RingSound
            bset    #1,($FFFFFE1B).w
            beq.w    ExtraLife
            cmpi.w    #200,($FFFFFE20).w ; check if you have 200 rings
            bcs.s    Obj2E_RingSound
            bset    #2,($FFFFFE1B).w
            beq.w    ExtraLife
    Obj2E_RingSound:
            move.w    #$B5,d0
            jmp    (PlaySound).l    ; play ring sound
        
    Obj2E_ExitDebt:
            move.w    ($FFFFFE20).w, d0
            cmpi.b    #$A, d0 ; do we have 10 negarings?
            blt.s    @yes
            subi.w    #$A,($FFFFFE20).w ; subtract 10 rings from the number of negarings you have
            move.b    #$80,($FFFFFE1D).w ; update ring counter
            move.w    #$B5,d0
            jmp    (PlaySound).l    ; play ring sound
        
    @yes:
            move.w    #0,($FFFFFE20).w ; reset number    of rings to zero
            move.b    #$80,($FFFFFE1D).w ; update ring counter
            move.b    #$00,(NegativeRingFlag).w
            move.w    #$B5,d0
            jmp    (PlaySound).l    ; play ring sound
    
    Now, whenever you collect a ring box whilst in Negative mode, you can get rid of 10 negative rings or get rid of all of them entirely. Now, we need to actually make the rings themselves remove a negative ring. Go to CollectRing and replace that with this:

    Code:
    CollectRing:                ; XREF: Obj25_Collect
            tst.b    NegativeRingFlag
            bne.w    CollectRingN
            addq.w    #1,($FFFFFE20).w ; add 1 to rings
            ori.b    #1,($FFFFFE1D).w ; update the rings counter
            move.w    #$B5,d0        ; play ring sound
            cmpi.w    #100,($FFFFFE20).w ; do    you have < 100 rings?
            bcs.s    Obj25_PlaySnd    ; if yes, branch
            bset    #1,($FFFFFE1B).w ; update lives    counter
            beq.s    loc_9CA4
            cmpi.w    #200,($FFFFFE20).w ; do    you have < 200 rings?
            bcs.s    Obj25_PlaySnd    ; if yes, branch
            bset    #2,($FFFFFE1B).w ; update lives    counter
            bne.s    Obj25_PlaySnd
    loc_9CA4:
            addq.b    #1,($FFFFFE12).w ; add 1 to the    number of lives    you have
            addq.b    #1,($FFFFFE1C).w ; add 1 to the    lives counter
            move.w    #$88,d0        ; play extra life music
    Obj25_PlaySnd:
            jmp    (PlaySound_Special).l
        
    ; End of function CollectRing
    CollectRingN:
            subi.w    #$1,($FFFFFE20).w ; subtract 1 ring from the number of negarings you have
            move.b    #$80,($FFFFFE1D).w ; update ring counter
            move.w    #$B5,d0
            jmp    (PlaySound).l    ; play ring sound
    
    Next, go to Level_MainLoop and insert this before cmpi.b #8,($FFFFF600).w:

    Code:
           tst.w    ($FFFFFE20).w
            beq.s    @yes
            bra.w    @skip
        
    @yes:
            move.b    #$00,(NegativeRingFlag).w
    @skip:
    
    This will disable the Negative Ring flag when our counter hits zero, so that way, we don't underflow to 255 and glitch out the counter. Next, go to HurtSonic and add this below beq.w Hurt_NoRings:

    Code:
            tst.w    NegativeRingFlag ; are we in the negatives?
            bne.w    Hurt_NoRings
    
    Next, go to Obj3A_RingBonus and add this below beq.s Obj3A_ChkBonus:

    Code:
           tst.w    NegativeRingFlag ; are we in the negatives?
            bne.s    Obj3A_ChkBonus ; if so, branch
    
    This will prevent the negative rings from being added to your score! Finally, go to Obj21_Flash and replace it with this:

    Code:
    Obj21_Flash:                ; XREF: Obj21_Main
            moveq    #0,d0
            btst    #3,($FFFFFE05).w
            bne.s    Obj21_Display
            tst.w    NegativeRingFlag ; are we in the negatives?
            bne.s    @flashred ; if so, branch
            tst.w    ($FFFFFE20).w    ; do you have any rings?
            bne.s    Obj21_Flash2    ; if not, branch
           
    @flashred:
            addq.w    #1,d0        ; make ring counter flash red
    
    You've finally implemented Negative Rings into Sonic 1, but, that Goggles monitor is sort of ugly. Lucky for you, I'm willing to give away the simple edit I did for the Monitor art. You can download it below. Happy hacking! :b

    Quick Edit: Forgot a step!
    Quick Edit: Forgot another step!
     

    Attached Files:

    Last edited: Feb 8, 2025
  2. Joao Gamer

    Joao Gamer Well-Known Member Member

    Joined:
    Nov 22, 2023
    Messages:
    95
    Location:
    Brazil
    Umm... i followed the tutorial but i got this error:
    [​IMG]
     
  3. Devon

    Devon Do not contact me. Member

    Joined:
    Aug 26, 2013
    Messages:
    1,480
    Read the post thoroughly.
     
    IAmAShad0 likes this.
  4. Joao Gamer

    Joao Gamer Well-Known Member Member

    Joined:
    Nov 22, 2023
    Messages:
    95
    Location:
    Brazil
    Ohhh, my attention deficit is attacking me:p
     
    IAmAShad0 likes this.
  5. IAmAShad0

    IAmAShad0 . Member

    Joined:
    Oct 11, 2024
    Messages:
    63
    Location:
    London
    I have no idea what I'm supposed to do with that info. Do I define it in Constants.asm?
     
  6. BL3H

    BL3H idiot sandwich Member

    Joined:
    Jul 19, 2022
    Messages:
    62
    Location:
    Tails' Workshop, Angel Island
    You can define it at the top of your sonic.asm file or in constants.asm. It really doesn't matter.
     
    IAmAShad0 likes this.
  7. IAmAShad0

    IAmAShad0 . Member

    Joined:
    Oct 11, 2024
    Messages:
    63
    Location:
    London
    Yeah, but HOW would I define it?
     
  8. BL3H

    BL3H idiot sandwich Member

    Joined:
    Jul 19, 2022
    Messages:
    62
    Location:
    Tails' Workshop, Angel Island
    Code:
    NegativeRingsFlag:    equ $FFFFF5C1
     
    Blue Gamer and IAmAShad0 like this.
  9. IAmAShad0

    IAmAShad0 . Member

    Joined:
    Oct 11, 2024
    Messages:
    63
    Location:
    London
    Thanks. I'll credit you.

    Also at the beginning or the end?
     
    Last edited: Feb 8, 2025
  10. BL3H

    BL3H idiot sandwich Member

    Joined:
    Jul 19, 2022
    Messages:
    62
    Location:
    Tails' Workshop, Angel Island
    Best if you do at the beginning.
     
    IAmAShad0 likes this.
  11. IAmAShad0

    IAmAShad0 . Member

    Joined:
    Oct 11, 2024
    Messages:
    63
    Location:
    London
    I can put it anywhere, right?
     
  12. Joao Gamer

    Joao Gamer Well-Known Member Member

    Joined:
    Nov 22, 2023
    Messages:
    95
    Location:
    Brazil
    Yeah.