don't click here

Transform at will in Sonic 2

Discussion in 'Engineering & Reverse Engineering' started by Machenstein, May 28, 2012.

  1. Machenstein

    Machenstein

    Member
    830
    0
    0
    With the help of vladikcomper, we figured out how to implement the Sonic 3 method of Super Sonic transformation into Sonic 2. In the original Sonic 2, you had no control over when Sonic transformed once you collected 50 or more rings. Your only recourse was to try not to jump which automatically triggered the Super Sonic transformation. With this tutorial, your Sonic 2 hack will give you more control over when Sonic transforms.

    The first thing you do is locate the label Sonic_JumpHeight. You should see something like this:

    Code (ASM):
    1. ; loc_1AAF0:
    2. Sonic_JumpHeight:
    3.     tst.b   jumping(a0) ; is Sonic jumping?
    4.     beq.s   Sonic_UpVelCap  ; if not, branch
    5.  
    6.     move.w  #-$400,d1
    7.     btst    #6,status(a0)   ; is Sonic underwater?
    8.     beq.s   +       ; if not, branch
    9.     move.w  #-$200,d1
    10. +
    11.     cmp.w   y_vel(a0),d1    ; is Sonic going up faster than d1?
    12.     ble.s   +       ; if not, branch
    13.     move.b  (Ctrl_1_Held_Logical).w,d0
    14.     andi.b  #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed?
    15.     bne.s   +       ; if yes, branch
    16.     move.w  d1,y_vel(a0)    ; immediately reduce Sonic's upward speed to d1
    17. +
    18.     tst.b   y_vel(a0)       ; is Sonic exactly at the height of his jump?
    19.     beq.s   Sonic_CheckGoSuper  ; if yes, test for turning into Super Sonic
    20.     rts
    Replace this:

    Code (ASM):
    1.     tst.b   y_vel(a0)       ; is Sonic exactly at the height of his jump?
    2.     beq.s   Sonic_CheckGoSuper  ; if yes, test for turning into Super Sonic
    3.     rts
    with this:

    Code (ASM):
    1.     move.b  (Ctrl_1_Press_Logical).w,d0
    2.     andi.b  #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed?
    3.     bne.s   Sonic_CheckGoSuper  ; if yes, test for turning into Super Sonic
    4.     rts
    That's it! Now you can make Sonic transform at will just like in Sonic 3. At those times when you are low on rings though, what if you want to cancel out Super Sonic? There is also a fix for that. First, find the label Obj01_MdJump. It should look like this:

    Code (ASM):
    1. Obj01_MdJump:
    2.     bsr.w   Sonic_JumpHeight
    3.     bsr.w   Sonic_ChgJumpDir
    4.     bsr.w   Sonic_LevelBound
    5.     jsr (ObjectMoveAndFall).l
    6.     btst    #6,status(a0)   ; is Sonic underwater?
    7.     beq.s   +       ; if not, branch
    8.     subi.w  #$28,y_vel(a0)  ; reduce gravity by $28 ($38-$28=$10)
    9. +
    10.     bsr.w   Sonic_JumpAngle
    11.     bsr.w   Sonic_DoLevelCollision
    12.     rts
    13. ; End of subroutine Obj01_MdJump
    Insert this under Obj01_MdJump:

    Code (ASM):
    1.     bsr.w   Sonic_CancelSuper
    It should now look like this:

    Code (ASM):
    1. Obj01_MdJump:
    2.     bsr.w   Sonic_CancelSuper
    3.     bsr.w   Sonic_JumpHeight
    4.     bsr.w   Sonic_ChgJumpDir
    5.     bsr.w   Sonic_LevelBound
    6.     jsr (ObjectMoveAndFall).l
    7.     btst    #6,status(a0)   ; is Sonic underwater?
    8.     beq.s   +       ; if not, branch
    9.     subi.w  #$28,y_vel(a0)  ; reduce gravity by $28 ($38-$28=$10)
    10. +
    11.     bsr.w   Sonic_JumpAngle
    12.     bsr.w   Sonic_DoLevelCollision
    13.     rts
    14. ; End of subroutine Obj01_MdJump
    Finally, create the subroutine. Right under "; End of subroutine Obj01_MdJump" insert this:

    Code (ASM):
    1. ; ---------------------------------------------------------------------------
    2. ; Subroutine to cancel Super Sonic
    3. ; ---------------------------------------------------------------------------
    4.  
    5. Sonic_CancelSuper:
    6.         tst.b   (Super_Sonic_Flag).w
    7.         beq.s   +
    8.         move.b  (Ctrl_1_Press_Logical).w,d0
    9.     andi.b  #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed?
    10.         beq.s   +
    11.         addq.l  #4,(sp)
    12.         jmp     Sonic_RevertToNormal
    13. +       rts
    Now you can cancel out Super Sonic at any time without having to wait for your rings to run out. You can also use just one button to make Sonic transform and cancel out by replacing this in each step:

    Code (ASM):
    1.     andi.b  #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed?
    With one of these:

    Code (ASM):
    1.     andi.b  #button_A_mask,d0
    2.     andi.b  #button_B_mask,d0
    3.     andi.b  #button_C_mask,d0
    Now you have complete control over when Sonic transforms in Sonic 2!
     
  2. Knucklez

    Knucklez

    I love 2B 'n' ass. Member
    683
    17
    18
    Wow, this is beyond useful. I'm glad you guys finally got this issue addressed. Could you also provide the ROM with this implementation? :v:
     
  3. Machenstein

    Machenstein

    Member
    830
    0
    0
    Yup.
     
  4. Aerosol

    Aerosol

    Not here. Moderator
    11,078
    479
    63
    Not where I want to be.
    Sonic (?): Coming summer of 2055...?
    Forgive me but...isn't this actually really basic? I pulled this off while I was trying to code my own homing attack for Sonic 2, and I'm pretty retarded when it comes to asm. Not trying to shit on your parade or anything. I'm just not sure a whole topic was necessary for this.
     
  5. Knucklez

    Knucklez

    I love 2B 'n' ass. Member
    683
    17
    18
    So much for me knowing anything about asm if this is basic. As far as I'm concerned, I haven't seen this in any hacks of Sonic 2.
     
  6. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,670
    231
    43
    SonLVL
    Just because you have not seen it does not mean it is complex.
     
  7. Aerosol

    Aerosol

    Not here. Moderator
    11,078
    479
    63
    Not where I want to be.
    Sonic (?): Coming summer of 2055...?
    This. And just to clarify, I'm only talking about checking for a button press to activate Super Sonic, not the deactivation code. This modification also fixes the "transform after signpost" glitch, I think. That's what happened to me.
     
  8. TheInvisibleSun

    TheInvisibleSun

    OVER THE TOP TECHNO-BLAST Member
    1,626
    193
    43
    Buffalo, NY, USA
    The Water
    Should this be put in the guide then?
     
  9. Tets

    Tets

    one rude dude Oldbie
    878
    46
    28
    This was one of the first things I did when I hacked Sonic 2. Depending on how you code it, it either completely or partially fixes the "transform after signpost" glitch. My implementation still allowed you to transform if you hit the button exactly as you pass the signpost, leaving you stuck walking in the air as in the original glitch. I was never quite able to pin down a fix for that before I lost interest.
     
  10. Knucklez

    Knucklez

    I love 2B 'n' ass. Member
    683
    17
    18
    Yes, but the glitch that still remains is when you jump past the signpost as regular Sonic and activate the Super transformation, which leaves you stuck walking/running in the air with the results screen not appearing.
     
  11. vladikcomper

    vladikcomper

    Tech Member
    203
    125
    43
    Sonic Warped
    Lol, I didn't expect that me helping you with that manual transformation thingie yesterday will do a guide.
    Anyways, this is quite helpful one, because the way transformation was done in the original Sonic 2 is really annoying. I hope in future we'll see more Sonic 2 hacks with better way of transformation.

    But frankly, solution this guide suggests is not perfect, I would say, 'hack-ish'. I mean that Sonic_CancelSuper subroutine I wrote for you. I knew this wasn't all good from the beginning, but hell, for some reason I couldn't think properly yesterday. Silly me. Because the good solution was so simple.

    Let me fix my stupid mistake and introduce this good solution as an alternative to your guide:

    * * *

    Go to Sonic_JumpHeight and replace this:

    Code (Text):
    1.         tst.b   y_vel(a0)               ; is Sonic exactly at the height of his jump?
    2.         beq.s   Sonic_CheckGoSuper      ; if yes, test for turning into Super Sonic
    3.         rts
    with this:

    Code (Text):
    1.         move.b  (Ctrl_1_Press_Logical).w,d0
    2.         andi.b  #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed?
    3.         bne.s   Sonic_CheckGoSuper      ; if yes, test for turning into Super Sonic
    4.         rts
    Goto Sonic_CheckGoSuper and replace:

    Code (Text):
    1.     bne.s   return_1ABA4
    at the very beginning with

    Code (Text):
    1.     bne.w   Sonic_RevertToNormal
    That's it.

    * * *

    Now, there are few bugs that original game has:
    1) Sonic's transformation palette bug
    2) Sonic freezing in air after revert to normal bug
    They are much easier to fix.

    * * *

    1) Sonic's transformation palette bug

    A palette bug occurs when you transform for the second time and on: Sonic colors look wrong during transformation animation. It happens due to program error in Super palette cycling code. The code resets palette position incorrectly when revert to normal cycle is over.

    For HG disassembly.
    Goto PalCycle_SuperSonic_revert and find these lines:

    Code (Text):
    1.     subq.w  #8,(Palette_frame).w    ; previous frame
    2.     bcc.s   +           ; branch, if it isn't the first frame
    3.     move.b  #0,(Palette_frame).w
    The last instruction uses 'byte' type, while the variable used as 'word' in the rest of the code (see SUBQ line for example). Therefore, the variable is not cleared properly, which causes wrong colors to load in the next transformation.
    Replace '.b' with '.w' and the bug is gone.

    For Xenowhirl's 2007 Disassembly.
    The label you're looking for is loc_2188 and those 3 lines look like this:

    Code (Text):
    1.     subq.w  #8,($FFFFF65C).w
    2.     bcc.s   loc_21B0
    3.     move.b  #0,($FFFFF65C).w
    * * *

    2) Sonic freezing in air after revert to normal bug

    It happens when Sonic has to revert from transformation instantly. The controls are looked when the transformation starts until a certain moment (controlled by PalCycle_SuperSonic routine), and routine that reverts Sonic to normal doesn't bother to unlock the controls.

    In the beginning of Sonic_RevertToNormal add:
    Code (Text):
    1.     move.b  #0,(MainCharacter+obj_control).w    ; restore Sonic's movement
    Applies to both disassemblies.
     
  12. Tets

    Tets

    one rude dude Oldbie
    878
    46
    28
    I totally forgot about the transformation palcycle bug, it's something the average player would never encounter in vanilla Sonic 2. I remember posting a quick fix for it years ago, it took me the longest time to track that one down due to its utter simplicity, but I don't know that it ever found its way into any guides.

    As for the "stuck in the air" bug, I had never even thought of simply restoring player control in the RevertToNormal routine. It seems like there should be a better way to do it, but I think that more or less cuts it.
     
  13. Machenstein

    Machenstein

    Member
    830
    0
    0
    That's much better. Thanks again, vladikcomper. There is one last thing I want to point out though.

    [​IMG]

    These garbled tiles appear on Sonic when he transforms. Is this a side effect of fixing the palette bug or could it be something else?
     
  14. vladikcomper

    vladikcomper

    Tech Member
    203
    125
    43
    Sonic Warped
    It's nothing to do with palettes. This is DMA transfer bug, it happens when transferred Sonic's art crosses 128 KB ROM bank.
    Check out this post for fixing it: http://forums.sonicretro.org/index.php?showtopic=10880&st=3915&p=626425&#entry626425
    This is for Sonic 1. In Sonic 2 it's exactly the same, except for the label you'll be looking for is 'ArtUnc_Sonic'.
     
  15. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    9
    18
    United Kingdom
    YouTuber
    I use to have that problem years ago, but "align $20000" takes up quite a bit of space. I use "align $10000" (any lower and the glitch still happens) and I haven't had any glitches since. So I've applied this for all my characters. Seeming as I've had no problems since, I guess this is fine?
     
  16. Sik

    Sik

    Sik is pronounced as "seek", not as "sick". Tech Member
    6,719
    0
    0
    being an asshole =P
    Align $10000 aligns to 64KB, the issue can still happen if the artwork crosses a 128KB boundary. Didn't check how big are Sonic's sprites though, if they're under 64KB then it's never going to cross a 128KB boundary anyways (since they won't cross a 64KB one, and 128KB boundaries are also 64KB boundaries - similar rules apply to other powers of two).

    The best way to avoid wasting space is moving stuff around though =P
     
  17. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    9
    18
    United Kingdom
    YouTuber
    Mine's at 81KB, but still no problems =P


    Anyway, that's useful to know, thanks for the tip.
     
  18. vladikcomper

    vladikcomper

    Tech Member
    203
    125
    43
    Sonic Warped
    Yes, sure. If your art is smaller than $10000 bytes (64 KB), you can align it like that without worrying that your art may cross 128 KB boundary.
    But notice, that bug only happens when transferred tiles cross the boundary, not the whole art. So you may even place one bunch of tiles in before the boundary, and another after it, for example. But such alignment would be a real pain in ass though =P

    But like Sik said, to avoid wasting space, it's good to organize your data order. Use listing file to see what offsets your data takes and how much 'align' directives take. If they take too much, you can always move some data from end of ROM to wasted space.
     
  19. Sik

    Sik

    Sik is pronounced as "seek", not as "sick". Tech Member
    6,719
    0
    0
    being an asshole =P
    I generally tend to do that, actually, but I can afford to do it because each sprite is its own file in the source code, so at worst alignment would affect only one sprite and nothing else.
     
  20. Machenstein

    Machenstein

    Member
    830
    0
    0
    I found a small quirk with vladikcomper's alternative to the guide. If you push the transform button when don't have all 7 Chaos Emeralds and 50 rings, Sonic simply flashes yellow for a second. I would suggest going with the subroutine in the first guide until this issue is fixed with the alternative one.