(Sonic 1) Optimize Earning 1-Ups Through Rings

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

  1. Kilo

    Kilo Foxy Fren Member

    Joined:
    Oct 9, 2017
    Messages:
    394
    Location:
    A warm and lovely place~
    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
  2. Unavailable

    Unavailable Imagine not spelling "unavaliable" correctly. Member

    Joined:
    Aug 7, 2019
    Messages:
    289
    Location:
    England
    EDIT: Never mind, please trash this if you can
     
    Last edited: Aug 12, 2020