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): tst.w $30(a0) bne.s loc_1AFE6 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): move.w $30(a0),d0 beq.s Obj01_Display subq.w #1,$30(a0) lsr.w #3,d0 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): Sonic_Display: ; XREF: loc_12C7E move.b $30(a0),d0 beq.s Obj01_Display subq.b #1,$30(a0) lsr.w #3,d0 bcc.s Obj01_ChkInvin Obj01_Display: jsr DisplaySprite Obj01_ChkInvin: tst.b ($FFFFFE2D).w ; does Sonic have invincibility? beq.s Obj01_ChkShoes ; if not, branch tst.b $32(a0) ; check time remaining for invinciblity beq.s Obj01_ChkShoes ; if no time remains, branch move.b ($FFFFFE05).w,d0 andi.b #7,d0 bne.s Sonic_ChkShoes subq.b #1,$32(a0) ; subtract 1 from time bne.s Obj01_ChkShoes tst.b ($FFFFF7AA).w bne.s Obj01_RmvInvin cmpi.w #$C,($FFFFFE14).w bcs.s Obj01_RmvInvin moveq #0,d0 move.b ($FFFFFE10).w,d0 cmpi.w #$103,($FFFFFE10).w ; check if level is SBZ3 bne.s Obj01_PlayMusic moveq #5,d0 ; play SBZ music Obj01_PlayMusic: lea (MusicList2).l,a1 move.b (a1,d0.w),d0 jsr (PlaySound).l ; play normal music Obj01_RmvInvin: move.b #0,($FFFFFE2D).w ; cancel invincibility Obj01_ChkShoes: tst.b ($FFFFFE2E).w ; does Sonic have speed shoes? beq.s Obj01_ExitChk ; if not, branch tst.b $34(a0) ; check time remaining beq.s Obj01_ExitChk move.b ($FFFFFE05).w,d0 andi.b #7,d0 bne.s Sonic_ExitChk subq.b #1,$34(a0) ; subtract 1 from time bne.s Obj01_ExitChk move.w #$600,($FFFFF760).w ; restore Sonic's speed move.w #$C,($FFFFF762).w ; restore Sonic's acceleration move.w #$80,($FFFFF764).w ; restore Sonic's deceleration move.b #0,($FFFFFE2E).w ; cancel speed shoes move.w #$E3,d0 jmp (PlaySound).l ; run music at normal speed There, now $31, $33 and $35 are now free to use.
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.
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).