Three Up Three of Sonic's SSTs in Sonic 1

Discussion in 'Engineering & Reverse Engineering' started by Alex Field, Jul 12, 2020.

  1. Alex Field

    Alex Field

    シュート! カオス・エメラルド・ザが消えようとしている! Member
    Downunda, Mobius
    Sonic the Hedgehog 2+, Sonic the Hedgehog 3+
    In Sonic 1, invulnerability frames and invincibility/speed shoes time are controlled by an SST variable. Sonic 3 and Knuckles also does this, but uses them as a byte instead of a word, freeing 3 SSTs, so we might as well implement it here too.

    At "Touch_Hurt:", you'll see this:
    Code (Text):
    1.         tst.w    $30(a0)
    2.         bne.s    loc_1AFE6
    3.         movea.l    a1,a2
    Change that "tst.w" to a "tst.b"; then at "Hurt_ChkSpikes:", you'll see a "move.w #$78,$30(a0)". Change that to "move.b #$78,$30(a0)", and do the same thing at "Sonic_HurtStop:".

    At "Touch_ChkValue" change the "cmpi.w #$5A,$30(a0)" to "cmpi.b #$5A,$30(a0)"/

    Finally at "Sonic_Display:", you'll see this:
    Code (Text):
    1.         move.w    $30(a0),d0
    2.         beq.s    Obj01_Display
    3.         subq.w    #1,$30(a0)
    4.         lsr.w    #3,d0
    5.         bcc.s    Obj01_ChkInvin
    Now let's do the speed shoes and invincibility; at "Obj2E_ChkShoes:" and "Obj2E_ChkInvinc:", change the "move.w #$4B0" to "move.b #$96"; finally, replaced "Sonic_Display:" with this:
    Code (Text):
    1. Sonic_Display:                ; XREF: loc_12C7E
    2.         move.b    $30(a0),d0
    3.         beq.s    Obj01_Display
    4.         subq.b    #1,$30(a0)
    5.         lsr.w    #3,d0
    6.         bcc.s    Obj01_ChkInvin
    8. Obj01_Display:
    9.         jsr    DisplaySprite
    11. Obj01_ChkInvin:
    12.         tst.b    ($FFFFFE2D).w    ; does Sonic have invincibility?
    13.         beq.s    Obj01_ChkShoes    ; if not, branch
    14.         tst.b    $32(a0)        ; check    time remaining for invinciblity
    15.         beq.s    Obj01_ChkShoes    ; if no    time remains, branch
    16.         move.b    ($FFFFFE05).w,d0
    17.         andi.b    #7,d0
    18.         bne.s    Sonic_ChkShoes
    19.         subq.b    #1,$32(a0)    ; subtract 1 from time
    20.         bne.s    Obj01_ChkShoes
    21.         tst.b    ($FFFFF7AA).w
    22.         bne.s    Obj01_RmvInvin
    23.         cmpi.w    #$C,($FFFFFE14).w
    24.         bcs.s    Obj01_RmvInvin
    25.         moveq    #0,d0
    26.         move.b    ($FFFFFE10).w,d0
    27.         cmpi.w    #$103,($FFFFFE10).w ; check if level is    SBZ3
    28.         bne.s    Obj01_PlayMusic
    29.         moveq    #5,d0        ; play SBZ music
    31. Obj01_PlayMusic:
    32.         lea    (MusicList2).l,a1
    33.         move.b    (a1,d0.w),d0
    34.         jsr    (PlaySound).l    ; play normal music
    36. Obj01_RmvInvin:
    37.         move.b    #0,($FFFFFE2D).w ; cancel invincibility
    39. Obj01_ChkShoes:
    40.         tst.b    ($FFFFFE2E).w    ; does Sonic have speed    shoes?
    41.         beq.s    Obj01_ExitChk    ; if not, branch
    42.         tst.b    $34(a0)        ; check    time remaining
    43.         beq.s    Obj01_ExitChk
    44.         move.b    ($FFFFFE05).w,d0
    45.         andi.b    #7,d0
    46.         bne.s    Sonic_ExitChk
    47.         subq.b    #1,$34(a0)    ; subtract 1 from time
    48.         bne.s    Obj01_ExitChk
    49.         move.w    #$600,($FFFFF760).w ; restore Sonic's speed
    50.         move.w    #$C,($FFFFF762).w ; restore Sonic's acceleration
    51.         move.w    #$80,($FFFFF764).w ; restore Sonic's deceleration
    52.         move.b    #0,($FFFFFE2E).w ; cancel speed    shoes
    53.         move.w    #$E3,d0
    54.         jmp    (PlaySound).l    ; run music at normal speed
    There, now $31, $33 and $35 are now free to use.
    Last edited: Jul 12, 2020
  2. MarkeyJester


    Vague Memories Resident Jester
    Nice work~

    As a recommendation, I'd like to suggest moving the invincible timer from 32 to 31, that way, you can access 32 and 33 together as a word if need be.

    Another recommendation might be to change the invincible timer from $96 to $4B instead, and have the AND value be F instead of 7. The reason being, you could use the same "hurt timer" byte slot, and have it set to +78 when you're hurt, or -4B when you're invincible, and have them count up/down towards 0, and whether the timer represents hurt or invincible will be determined by the polarity (positive or negative).

    Since you're not going to be hurt while invincible, the two will never clash except for one minor visual where if you've recently gotten hurt, the flashing will stop as soon as you get invincibility, but it's an acceptable change that I don't think anyone would notice unless it were pointed out. You can test the timer, and if above 0, you're invulnerable/hurt, if below 0, you're invincible, if non-0, you cannot be hurt as you're either invulnerable or invincible.

    So byte 30 would be hurt/invincible timer, you can then shove speed shoes to 31, this will free up 32, 33, 34 and 35 together, and they can be accessed as words too.
  3. Alex Field

    Alex Field

    シュート! カオス・エメラルド・ザが消えようとしている! Member
    Downunda, Mobius
    Sonic the Hedgehog 2+, Sonic the Hedgehog 3+
    Step 2: Equate That Crap
    Go to all the locations you went to previous and replace $30 with invulnerable_time, $32 with invincibility_time and $34 with speedshoes_time; that way you can shift it easily and also move invincibility_time to $31 and speedshoes_time to $32, that way $33-$35 are free.

    Note: At Obj2E, you'll see ($FFFFD032) and ($FFFFD034), replace them with ($FFFFD000+invincibility_time) and ($FFFFD000+speedshoes_time).
    Last edited: Jul 13, 2020