don't click here

My first adventure with ASM code in Sonic 2

Discussion in 'Engineering & Reverse Engineering' started by Tets, Feb 2, 2008.

Thread Status:
Not open for further replies.
  1. Tets

    Tets

    one rude dude Oldbie
    905
    72
    28
    I'm not sure if this has got easier as of late or if I was just retarded two years ago, but I've finally figured out how to work with ASM code in the Sonic engine. I've been browsing the forums the last couple of days slowly building up knowledge and finally I'm here to present some of my work so others can use it or tell me how I can improve it.

    A lot of what I've done in Sonic 2 is fixing bugs in the game with random code snippets I've found here and there, but I've also done a bit of my own. The first thing I set about to do was change the Super Sonic transformation so it happens when you double-tap jump and add the ability to de-transform similarly. Anyone here would know that those plainly rip off Sonic 3 and Sonic 1 Megamix, respectively, but it was a good opportunity for me to learn how the Sonic engine works.

    I'm still very much a beginner, so my code is probably bad and inefficient. Suggestions to improve it are welcome. I'm working with Xenowhirl's 2007 Sonic 2 disassembly.

    I first commented out the last two lines in Sonic_JumpHeight before the rts, since I no longer needed the transformation check to be called at the height of the jump. I then added a line in Obj01_MdJump to branch to Sonic_DblJump (the name is inaccurate, I never really planned to code any kind of doublejump, I just couldn't think of a better name for it). I'm not sure if that's the ideal place to add it, but it works for now.
    Code (ASM):
    1. Obj01_MdJump:
    2.     bsr.w   Sonic_JumpHeight
    3.     bsr.w   Sonic_ChgJumpDir
    4.     bsr.w   Sonic_LevelBound
    5.     bsr.w   Sonic_DblJump
    6.     jsr ObjectMoveAndFall
    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
    I had some trouble in the beginning trying to get the doublejump function to work. Most of my attempts resulted in transformation immediately upon jumping. Eventually I realized I could fix it by using a "double jump" status flag. Earlier in the day I had disabled the Sonic_RollJump function, so I used the now free rolljump flag. This is what my newly coded Sonic_DblJump (which I began writing just below Sonic_Jump, but it could probably go almost anywhere else) looked like at that time.
    Code (ASM):
    1. Sonic_DblJump:
    2.     btst    #4,status(a0)   ; is doublejump flag set?
    3.     beq.s   +       ; if not, branch
    4.     rts
    5. +
    6.     move.b  (Ctrl_1_Press_Logical).w,d0
    7.     andi.b  #$70,d0         ; is jump button being pressed?
    8.     beq.w   return_1A330        ; if not, branch
    9.     bset    #4,status(a0)       ; set doublejump flag
    10.     tst.b   (Super_Sonic_flag).w    ; is Sonic already Super?
    11.     beq.s   +           ; if not, branch
    12.     bsr.l   Sonic_RevertToNormal    ; revert to normal Sonic
    13.     rts
    14. +
    15.     bsr.s   Sonic_CheckGoSuper  ; test for Super Sonic transformation
    16.     rts
    In the beginning of the above routine the rolljump flag, now referred to as the doublejump flag, is checked. If the flag is cleared it goes on to set the flag and then checks if Sonic is Super already, branching to either Sonic_CheckGoSuper or Sonic_RevertToNormal accordingly. Finally I added a line to the beginning of Obj01_MdNormal that clears the doublejump flag.
    Code (ASM):
    1. Obj01_MdNormal:
    2.     bclr    #4,status(a0)   ; clear doublejump flag
    3.     bsr.w   Sonic_CheckSpindash
    4.     bsr.w   Sonic_Jump
    5.     bsr.w   Sonic_SlopeResist
    6.     bsr.w   Sonic_Move
    7.     bsr.w   Sonic_Roll
    8.     bsr.w   Sonic_LevelBound
    9.     jsr ObjectMove
    10.     bsr.w   AnglePos
    11.     bsr.w   Sonic_SlopeRepel
    12.  
    13. return_1A2DE:
    14.     rts
    At this point it worked almost exactly as intended. However, while testing I found that the code doesn't differentiate between jumping and just rolling off a high place (or if it does, I couldn't find a way to test for it). This was mostly apparent in Casino Night while rolling through the tubes, I would often de-transform while trying to activate the springs in them. To fix this I coded my own check for jumping by using status flag 7, which to the best of my knowledge is not used at all for Sonic. It seems like a clunky workaround though, and I would appreciate suggestions for a better fix. Regardless, I'll now document how I did it.

    First I added a line near the bottom of Sonic_Jump to set my new jumping flag. I added it just after the line that plays the jumping sound effect. (You'll notice that two lines are commented out in this code box, those are the lines that branch to the rolljump function that I removed.)
    Code (ASM):
    1. Sonic_Jump:
    2.     move.b  (Ctrl_1_Press_Logical).w,d0
    3.     andi.b  #$70,d0     ; is A, B or C pressed?
    4.     beq.w   return_1AAE6    ; if not, return
    5.     moveq   #0,d0
    6.     move.b  angle(a0),d0
    7.     addi.b  #$80,d0
    8.     bsr.w   CalcRoomOverHead
    9.     cmpi.w  #6,d1           ; does Sonic have enough room to jump?
    10.     blt.w   return_1AAE6        ; if not, branch
    11.     move.w  #$680,d2
    12.     tst.b   (Super_Sonic_flag).w
    13.     beq.s   +
    14.     move.w  #$800,d2    ; set higher jump speed if super
    15. +
    16.     btst    #6,status(a0)   ; Test if underwater
    17.     beq.s   +
    18.     move.w  #$380,d2    ; set lower jump speed if under
    19. +
    20.     moveq   #0,d0
    21.     move.b  angle(a0),d0
    22.     subi.b  #$40,d0
    23.     jsr (CalcSine).l
    24.     muls.w  d2,d1
    25.     asr.l   #8,d1
    26.     add.w   d1,x_vel(a0)    ; make Sonic jump (in X... this adds nothing on level ground)
    27.     muls.w  d2,d0
    28.     asr.l   #8,d0
    29.     add.w   d0,y_vel(a0)    ; make Sonic jump (in Y)
    30.     bset    #1,status(a0)
    31.     bclr    #5,status(a0)
    32.     addq.l  #4,sp
    33.     move.b  #1,jumping(a0)
    34.     clr.b   stick_to_convex(a0)
    35.     move.w  #$A0,d0
    36.     jsr (PlaySound).l   ; play jumping sound
    37.     bset    #7,status(a0)   ; set jumping flag
    38.     move.b  #$13,y_radius(a0)
    39.     move.b  #9,x_radius(a0)
    40. ;   btst    #2,status(a0)
    41. ;   bne.s   Sonic_RollJump
    42.     move.b  #$E,y_radius(a0)
    43.     move.b  #7,x_radius(a0)
    44.     move.b  #2,anim(a0) ; use "jumping" animation
    45.     bset    #2,status(a0)
    46.     addq.w  #5,y_pos(a0)
    Next I added one more line to the beginning of Obj01_MdNormal to clear the jumping flag.
    Code (ASM):
    1. Obj01_MdNormal:
    2.     bclr    #7,status(a0)   ; clear jumping flag
    3.     bclr    #4,status(a0)   ; clear doublejump flag
    4.     bsr.w   Sonic_CheckSpindash
    5.     bsr.w   Sonic_Jump
    6.     bsr.w   Sonic_SlopeResist
    7.     bsr.w   Sonic_Move
    8.     bsr.w   Sonic_Roll
    9.     bsr.w   Sonic_LevelBound
    10.     jsr ObjectMove
    11.     bsr.w   AnglePos
    12.     bsr.w   Sonic_SlopeRepel
    13.  
    Finally I made the following changes to my Sonic_DblJump function to account for the jumping flag.
    Code (ASM):
    1. Sonic_DblJump:
    2. Sonic_DblJump:
    3.     btst    #7,status(a0)   ; is jumping flag set?
    4.     beq.s   +++ ; if not, branch
    5.     btst    #4,status(a0)   ; is doublejump flag set?
    6.     beq.s   +       ; if not, branch
    7.     rts
    8. +
    9.     move.b  (Ctrl_1_Press_Logical).w,d0
    10.     andi.b  #$70,d0         ; is jump button being pressed?
    11.     beq.w   return_1A330        ; if not, branch
    12.     bset    #4,status(a0)       ; set doublejump flag
    13.     tst.b   (Super_Sonic_flag).w    ; is Sonic already Super?
    14.     beq.s   +           ; if not, branch
    15.     bsr.l   Sonic_RevertToNormal    ; revert to normal Sonic
    16.     rts
    17. +
    18.     bsr.s   Sonic_CheckGoSuper  ; test for Super Sonic transformation
    19. +
    20.     rts
    21.  
    And that concludes my wall of text. Looking back through my code now I see a couple of areas where I could greatly optimize it. But for now it's pretty messy, so if anyone wants to use it, they do so at their own risk. For my next bit of code I've been thinking of trying to do three acts per zone, but I'm not sure if I have the expertise for that kind of procedure yet.
     
  2. Hitaxas

    Hitaxas

    Retro 80's themed Twitch streamer ( on hiatus) Member
    A code that reverts super sonic back to normal...cool. Nice work.
     
  3. Hayate

    Hayate

    Tech Member
    I believe that's because if you roll off a slope it counts it as a roll-jump. Since you removed roll-jump behavior, it would count it as a normal jump.
     
  4. Tets

    Tets

    one rude dude Oldbie
    905
    72
    28
    Oops, I just realized I made a glaring omission in my last code box, and unfortunately I'm well past the edit time limit now. I wouldn't suggest using most of it anyway, my main goal for posting this was to get critique on my coding style.

    And thanks, Hitaxas, though like I said it was really just something from Sonic 1 Megamix that I liked.
     
  5. Hitaxas

    Hitaxas

    Retro 80's themed Twitch streamer ( on hiatus) Member
    You can also make a button press in mid-air be required to transform by adding

    Code (Text):
    1. btst #7,status(a0); is jumping flag set?
    2.         beq.s return_1ABA4; if not, branch
    3.         btst #4,status(a0); is doublejump flag set?
    4.         beq.s return_1ABA4; if not, branch
    right under

    Code (Text):
    1. Sonic_CheckGoSuper:
    2.     tst.b   (Super_Sonic_flag).w; is Sonic already Super?
    3.     bne.s   return_1ABA4; if yes, branch
    :)


    Edit: There is only one problem with your code, besides the one with the slopes. You can go through the "Transform" animation over and over when you double jump in air. With that fixed, the code it pretty much perfect for what you tried to do here.


    Edit2: That problem can be removed by going to

    Code (ASM):
    1.  
    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  #$70,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
    and commenting out or removing these lines:

    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.  
     
  6. Varion Icaria

    Varion Icaria

    He's waiting.... Tech Member
    1,019
    11
    18
    S4: Cybernetic Outbreak
    Instead of using the Roll status, you can used the unused SST $21, In S3 $2F is the double jump flag.
     
  7. Tets

    Tets

    one rude dude Oldbie
    905
    72
    28
    Hitaxas, I mentioned that I already commented out those lines in the fourth paragraph of my first post. I probably should have made it clearer by adding a code box for that as well, but I didn't think to. Thanks all the same.

    I've been learning a lot more about the Sonic engine the last couple of days. I just now realized the existence of the already available jumping flag, thanks to Varion Icaria, and will make use of SST $21 for the double jump flag. I should be able to clean up my code a lot more now.
     
  8. Hitaxas

    Hitaxas

    Retro 80's themed Twitch streamer ( on hiatus) Member
    Ah, there goes my problem of not reading throughly... yeah, the SST $21 is a better way to make use of the jump flag both in S1 and S2.
     
  9. Tets

    Tets

    one rude dude Oldbie
    905
    72
    28
    Here's some more code I wrote today. This is a Super Sonic monitor (once again, from Sonic 3) that I made to replace the blank monitor. To begin I replaced the first entry in off_12924 with dc.w super_monitor-off_12924.
    Code (ASM):
    1. off_12924:
    2.     dc.w super_monitor-off_12924    ; 0 - Super
    For my super_monitor function I lifted two lines from the super rings monitor code and modified it to give the player 50 rings. Next I pasted in the Sonic_CheckGoSuper code without the emerald and ring checks in the beginning and changed each (a0) to (a1). Then I remembered Tails is in this game too, so I added a player mode check in the beginning to prevent the monitor from working for him. Below is the final code. I typed this all in just above robotnik_monitor:.
    Code (ASM):
    1. super_monitor:
    2.     addq.w  #1,(a2)
    3.     cmpi.w  #1,(Player_mode).w  ; is player Sonic?
    4.     bls.s   +           ; if not, branch
    5.     rts
    6. +
    7.     lea (Ring_count).w,a2
    8.     addi.w  #$32,(a2)
    9.  
    10.     move.b  #1,(Super_Sonic_palette).w
    11.     move.b  #$F,(Palette_frame_count).w
    12.     move.b  #1,(Super_Sonic_flag).w
    13.     move.b  #$81,obj_control(a1)
    14.     move.b  #$1F,anim(a1)           ; use transformation animation
    15.     move.b  #$7E,(Object_RAM+$2040).w   ; load Obj7E (super sonic stars object) at $FFFFD040
    16.     move.w  #$A00,(Sonic_top_speed).w
    17.     move.w  #$30,(Sonic_acceleration).w
    18.     move.w  #$100,(Sonic_deceleration).w
    19.     move.w  #0,invincibility_time(a1)
    20.     bset    #1,status_secondary(a1) ; make Sonic invincible
    21.     move.w  #$5F+$80,d0
    22.     jsr (PlaySound).l   ; Play transformation sound effect.
    23.     move.w  #$16+$80,d0
    24.     jmp (PlayMusic).l   ; load the Super Sonic song and return
    I was most of the way through copying the "S" tiles from the Sonic 3 monitor graphics when I remembered I have no idea how sprite mappings work or how to edit them, so they would have been useless. It still works great though, it just uses the static tiles. Now I just need to find out how to place this monitor in debug mode instead of the teleport monitor.
     
  10. Dracula

    Dracula

    Oldbie
    605
    0
    16
    I'm watching you!
    Converting NES Mappers to MMC5
    Very nice and it works just like S3.
     
  11. Hitaxas

    Hitaxas

    Retro 80's themed Twitch streamer ( on hiatus) Member
    Nice, you wrote it the same way I wrote it... Except for the check for sonic part. I enabled Super Tails as a test. =P
     
  12. Tets

    Tets

    one rude dude Oldbie
    905
    72
    28
    [​IMG]

    Didn't want to start a new thread just for this. I was bored yesterday so I challenged myself to "port" the super peel-out from Sonic CD. It's not so much a port as a best guess approximation, though. I borrowed some code from the spindash in the nick arcade disassembly since I didn't need the charging aspect of the final spindash. It was surprisingly easy to add the animation to Sonic's walk/run cycle, and I made some minor edits to the frames so they fit in better with the rest, so it looks pretty good in action.

    As I said though it's only an approximation. Through trial and error I settled on $B00 as a good speed at which to unleash the peel-out ($600 in water). Also it currently uses the spindash sounds, I'm sure it's no trivial matter to port sound effects between games. Some advice on this would be appreciated.

    Unfortunately I've just realized I have no place to upload this. I do have webspace I can use but I'm not entirely sure if it's within the terms of use that I can upload it, and I've been having trouble getting an FTP connection to it regardless. Sorry, guys.
     
  13. Hitaxas

    Hitaxas

    Retro 80's themed Twitch streamer ( on hiatus) Member
    Nice work on the PeelOut.
    Upload files to Sendspace or rapidshare. =P
     
  14. Tweaker

    Tweaker

    Banned
    12,387
    2
    0
    Eww, fuck rapidshare.

    I suggest FileDen.

    Nice work, by the way!
     
  15. Tets

    Tets

    one rude dude Oldbie
    905
    72
    28
    Right, I don't know why I didn't think of that before. I'm more familiar with Sendspace, here's a link: http://www.sendspace.com/file/h7zv16.

    This build also includes new level layouts for EHZ, the Super Sonic modifications I originally posted, and various small art edits (Sonic 3 monitor graphics, for example). I disabled the peel-out in Super Sonic mode since I'm not entirely sure what to do with the animations. Level select is also enabled by default and the emeralds check is commented out in the transformation code.
     
  16. Hitaxas

    Hitaxas

    Retro 80's themed Twitch streamer ( on hiatus) Member
    When ever I tried to add the peel-out to either S1 or S2, it would always end up in failure. I figured it was new animations, and a clone of the spindash code that checks for up rather than down...


    Cool little hack, it has some good features.
    For Super Sonic, make the animation his running animation, since it seems the most fitting. =P
     
  17. Spanner

    Spanner

    The Tool Member
    Well, adding it in Sonic 1 is a bugger, it gives you 2 errors:
    Which leads to this subroutine:
    Code (ASM):
    1.  
    2. Boundary_Bottom:
    3.         move.w  ($FFFFF726).w,d0
    4.         move.w  ($FFFFF72E).w,d1
    5.         cmp.w   d0,d1
    6.         blt.s   Boundary_Bottom_locret
    7.         cmpi.w  #$501,($FFFFFE10).w ; is level SBZ2 ?
    8.         bne.w   KillSonic   ; if not, kill Sonic
    9.         cmpi.w  #$2000,($FFFFD008).w
    10.         bcs.w   KillSonic
    11.         clr.b   ($FFFFFE30).w   ; clear lamppost counter
    12.         move.w  #1,($FFFFFE02).w ; restart the level
    13.         move.w  #$103,($FFFFFE10).w ; set level to SBZ3 (LZ4)
    14. Boundary_Bottom_locret:
    15.         rts
    Anyway, Tets. You're doing great work with this hack & the EHZ layouts are good, keep it up.
     
  18. Tets

    Tets

    one rude dude Oldbie
    905
    72
    28
    Looks like I've become a full member. To celebrate, here's a new build of my hack which still hasn't got a proper name. Here's the new link: http://www.sendspace.com/file/3w0u8c

    The super peel-out now "charges" for roughly half a second and I've raised the speed at which the peel-out run animation is triggered. It's a lot closer to Sonic CD behavior now.

    At the request of a local friend of mine, I replaced the normal run frames with the beta run frames. Naturally this broke the double-size Sonic on the SEGA screen, so to avoid having to fix the mappings I took the "easy" way out and ported the Sonic 1 SEGA screen. I'd like to properly fix it some time though.

    Finally there is a partially edited Chemical Plant Zone act 1. I think partially edited is as far as it's going to get for a while though, editing this zone gives me a headache with the excessive path swapping that's used, and I'd kill to be able to organize chunks so I can easily find the ones I need.

    I haven't got a lot of future plans for this hack other than level editing. One thing I'd like to do is port Knuckles. I'm not entirely sure if that's a realistic plan at my current skill level, but I'll try.
     
  19. Puto

    Puto

    Shin'ichi Kudō, detective. Tech Member
    2,013
    0
    16
    Portugal, Oeiras
    Part of Team Megamix, but haven't done any actual work in ages.
    This really needs a "charge" animation so we can see when the peelout is ready for release.
     
  20. amphobius

    amphobius

    doing more important things with my life Member
    2,120
    0
    16
    life
    Porting Knux to hacks is too common.

    Go for something else.
     
Thread Status:
Not open for further replies.