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): ; loc_1AAF0: Sonic_JumpHeight: tst.b jumping(a0) ; is Sonic jumping? beq.s Sonic_UpVelCap ; if not, branch move.w #-$400,d1 btst #6,status(a0) ; is Sonic underwater? beq.s + ; if not, branch move.w #-$200,d1 + cmp.w y_vel(a0),d1 ; is Sonic going up faster than d1? ble.s + ; if not, branch move.b (Ctrl_1_Held_Logical).w,d0 andi.b #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed? bne.s + ; if yes, branch move.w d1,y_vel(a0) ; immediately reduce Sonic's upward speed to d1 + tst.b y_vel(a0) ; is Sonic exactly at the height of his jump? beq.s Sonic_CheckGoSuper ; if yes, test for turning into Super Sonic rts Replace this: Code (ASM): tst.b y_vel(a0) ; is Sonic exactly at the height of his jump? beq.s Sonic_CheckGoSuper ; if yes, test for turning into Super Sonic rts with this: Code (ASM): move.b (Ctrl_1_Press_Logical).w,d0 andi.b #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed? bne.s Sonic_CheckGoSuper ; if yes, test for turning into Super Sonic 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): Obj01_MdJump: bsr.w Sonic_JumpHeight bsr.w Sonic_ChgJumpDir bsr.w Sonic_LevelBound jsr (ObjectMoveAndFall).l btst #6,status(a0) ; is Sonic underwater? beq.s + ; if not, branch subi.w #$28,y_vel(a0) ; reduce gravity by $28 ($38-$28=$10) + bsr.w Sonic_JumpAngle bsr.w Sonic_DoLevelCollision rts ; End of subroutine Obj01_MdJump Insert this under Obj01_MdJump: Code (ASM): bsr.w Sonic_CancelSuper It should now look like this: Code (ASM): Obj01_MdJump: bsr.w Sonic_CancelSuper bsr.w Sonic_JumpHeight bsr.w Sonic_ChgJumpDir bsr.w Sonic_LevelBound jsr (ObjectMoveAndFall).l btst #6,status(a0) ; is Sonic underwater? beq.s + ; if not, branch subi.w #$28,y_vel(a0) ; reduce gravity by $28 ($38-$28=$10) + bsr.w Sonic_JumpAngle bsr.w Sonic_DoLevelCollision rts ; End of subroutine Obj01_MdJump Finally, create the subroutine. Right under "; End of subroutine Obj01_MdJump" insert this: Code (ASM): ; --------------------------------------------------------------------------- ; Subroutine to cancel Super Sonic ; --------------------------------------------------------------------------- Sonic_CancelSuper: tst.b (Super_Sonic_Flag).w beq.s + move.b (Ctrl_1_Press_Logical).w,d0 andi.b #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed? beq.s + addq.l #4,(sp) jmp Sonic_RevertToNormal + 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): andi.b #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed? With one of these: Code (ASM): andi.b #button_A_mask,d0 andi.b #button_B_mask,d0 andi.b #button_C_mask,d0 Now you have complete control over when Sonic transforms in Sonic 2!
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:
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.
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.
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.
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.
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.
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): tst.b y_vel(a0) ; is Sonic exactly at the height of his jump? beq.s Sonic_CheckGoSuper ; if yes, test for turning into Super Sonic rts with this: Code (Text): move.b (Ctrl_1_Press_Logical).w,d0 andi.b #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed? bne.s Sonic_CheckGoSuper ; if yes, test for turning into Super Sonic rts Goto Sonic_CheckGoSuper and replace: Code (Text): bne.s return_1ABA4 at the very beginning with Code (Text): 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): subq.w #8,(Palette_frame).w ; previous frame bcc.s + ; branch, if it isn't the first frame 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): subq.w #8,($FFFFF65C).w bcc.s loc_21B0 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): move.b #0,(MainCharacter+obj_control).w ; restore Sonic's movement Applies to both disassemblies.
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.
That's much better. Thanks again, vladikcomper. There is one last thing I want to point out though. 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?
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'.
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?
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
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.
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.
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.