(Sonic 1) Optimize Earning 1-Ups Through Rings

Discussion in 'Tutorials' started by Iso Kilo, Mar 1, 2020.

  1. Iso Kilo

    Iso Kilo Sonic 1 Beta Researcher Member

    Joined:
    Oct 9, 2017
    Messages:
    208
    Location:
    Small Town in BC, Canada
    So this tutorial is partially inspired by MGHack's tutorial on earning lives through points. It is also Hivebrain based, but it should be easy enough to port over to other disassemblies or games.
    In the Sonic games, whenever you collect 100 rings, you'll earn a life. However in Sonic 1 (And if I recall, Sonic 2), you can only collect 2 lives this way. This is because it was assumed that the player would never be able to achieve 300 rings naturally. If you were to say spam rings in a level editor you would learn this.
    So if you want to be able to always get lives for every 100 rings you get, simply follow these steps.

    Initializing
    First you'll want to select an unused RAM address to represent the ring limit to earn an extra life.
    You can pick out an unused RAM address here. To make it easier to understand, we'll make it an equate. Place this where ever you feel is appropriate, like the start of the file.
    Code:
    Ring_1Up_Limit = $FFFFXXXX ; <- The RAM address you chose
    Now we need to make it so when ever you start a new game, or level, this is set to 100.
    When ever the rings are cleared, place this below it.

    Code:
            move.w    #100,(Ring_1Up_Limit).w ; reset ring 1-up limit to 100
    Optimizing Earning Lives
    The first instance of earning lives via rings we'll tackle is in the CollectRing routine. We'll focus on this bit.
    Code:
            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
    First, scrap the part for detecting 200 rings. Everything from beq.s loc_9CA4 to bne.s Obj25_PlaySnd.
    Next, you'll need to check if the rings you've collected are the same as the limit. Replace this.
    Code:
            cmpi.w    #100,($FFFFFE20).w ; do    you have < 100 rings?
    With this.
    Code:
            move.w    ($FFFFFE20).w,d1    ; Move ring count into d1 for valid operation with cmp
            cmp.w    (Ring_1Up_Limit).w,d1 ; check if you have the ring limit
    And after the 1-up counter update, insert this.
    Code:
            add.w    #100,(Ring_1Up_Limit).w ; Increase ring limit to earn a 1-up
    Here's what it should look like if done properly:
    Code:
            move.w    ($FFFFFE20).w,d1    ; Move ring count into d1 for valid operation with cmp
            cmp.w    (Ring_1Up_Limit).w,d1 ; check if you have the ring limit
            bcs.s    Obj25_PlaySnd    ; if yes, branch
            bset    #1,($FFFFFE1B).w ; update lives    counter
            add.w    #100,(Ring_1Up_Limit).w ; Increase ring limit to earn a 1-up
    That should do it for collecting actual rings. But the 10-ring monitor still uses the old method.
    The 10-ring monitor handles this in nearly the same way as CollectRing. So you should be able to do it on your own. However, if you can't, here you go, I suppose.
    Code:
    Obj2E_ChkRings:
            cmpi.b    #6,d0        ; does monitor contain 10 rings?
            bne.s    Obj2E_ChkS
            addi.w    #$A,($FFFFFE20).w ; add    10 rings to the    number of rings    you have
            ori.b    #1,($FFFFFE1D).w ; update the ring counter
            move.w    ($FFFFFE20).w,d1    ; Move ring count into d0 for valid operation with cmp
            cmp.w    (Ring_1Up_Limit).w,d1 ; check if you have the ring limit
            bcs.s    Obj2E_RingSound
            add.w    #100,(Ring_1Up_Limit).w    ; Increase ring limit
            bset    #1,($FFFFFE1B).w    ; Update life counter
            beq.w    ExtraLife
    Enjoy the ability to spam rings and continue to get lives, I guess? :p
    Edit - Fixed a bit that was moving the ring count into d0 instead of d1, which would've canceled the ring sound effect.
     
    Last edited: Mar 2, 2020
    MGHACKS likes this.
  2. MGHACKS

    MGHACKS Uh.... meow? Member

    Joined:
    Aug 7, 2019
    Messages:
    126
    Location:
    Somewhere far from Sonic fanboys
    Great job mate for giving my tutorial a little twist. Just informing that you spelt my username as MGHack rather than MGHacks in your first sentence.