don't click here

Mercury pwns Yuji Naka

Discussion in 'Engineering & Reverse Engineering' started by Mercury, Aug 14, 2010.

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


    His Name Is Sonic Tech Member
    Location Location
    A lot of people hate the Sonic 1 Special Stages. Watching YouTube playthroughs, you'll hear them profaned quite often.

    I'm pretty good at beating them, myself, but I still hate them. Because I'm scientifically minded, I tried to figure out just why this is so.

    Then it hit me - Sonic doesn't have a variable jump height. Unlike when he's in the normal zones, you can't just let go of the jump button to mitigate his upward velocity.

    Having noticed this, it struck me that it was most likely the largest contributor to the hate for the Special Stages. Because you don't have as much control over Sonic as you've become accustomed to from playing the normal zones, it's frustrating and unfair. Trying to navigate through cramped paths winds up being an exercise in hitting every bumper and and reverse block through no fault of you own - Sonic just makes a full jump no matter what you do.

    Well, it was clear - I had to remedy this. I looked in the disassembly, and lo! - there was an unused routine for reducing Sonic's jump height in the Special Stages. Of course, merely reactivating the routine would be far too simple a fix - there had to be more than that. After all, if it worked, why would it be deprecated in the first place?

    It turns out the unused routine is the same as the one from Sonic's normal code. It's deprecated because, in the Special Stages, Sonic's in a rotating maze, where up isn't always up. The routine is simply impotent at any angle other than 0.

    Well, Yuji Naka might be lazy, but I'm not - so I wrote a new routine that actually does work, at any angle.

    This is what I did, and if you follow the steps, you can, too. This is for the SVN disassembly:

    First, open "_incObj\09 Sonic in Special Stage.asm" and find the label "Obj09_InAir". Replace this line:

    Code (ASM):
    2. bsr.w   nullsub_2
    with this one:

    Code (ASM):
    2. bsr.w   Obj09_JumpHeight
    Now, find the "nullsub_2" label. This is the deprecated routine, and we need to replace it with the new one I wrote, "Obj09_JumpHeight". So replace these lines:

    Code (ASM):
    2. nullsub_2:              ; XREF: Obj09_InAir
    3.         rts
    4. ; End of function nullsub_2
    6. ; ===========================================================================
    7. ; ---------------------------------------------------------------------------
    8. ; unused subroutine to limit Sonic's upward vertical speed
    9. ; ---------------------------------------------------------------------------
    10.         move.w  #-$400,d1
    11.         cmp.w   obVelY(a0),d1
    12.         ble.s   locret_1BBB4
    13.         move.b  (v_jpadhold2).w,d0
    14.         andi.b  #btnABC,d0
    15.         bne.s   locret_1BBB4
    16.         move.w  d1,obVelY(a0)
    18. locret_1BBB4:
    19.         rts
    with these:

    Code (ASM):
    2. ; ---------------------------------------------------------------------------
    3. ; Subroutine to limit Sonic's upward vertical speed
    4. ; ---------------------------------------------------------------------------
    6. ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
    9. Obj09_JumpHeight:               ; XREF: Obj09_InAir
    10.         move.b  (v_jpadhold2).w,d0  ; is the jump button up?
    11.         andi.b  #btnABC,d0
    12.         bne.s   locret_1BBB4        ; if not, branch to return
    13.         btst    #7,obStatus(a0)     ; did Sonic jump or is he just falling or hit by a bumper?
    14.         beq.s   locret_1BBB4        ; if not, branch to return
    15.         move.b  (v_ssangle).w,d0    ; get SS angle
    16.         andi.b  #$FC,d0
    17.         neg.b   d0
    18.         subi.b  #$40,d0
    19.         jsr (CalcSine).l           
    20.         move.w  obVelY(a0),d2       ; get Y speed
    21.         muls.w  d2,d0               ; multiply Y speed by sin
    22.         asr.l   #8,d0               ; find the new Y speed
    23.         move.w  obVelX(a0),d2       ; get X speed
    24.         muls.w  d2,d1               ; multiply X speed by cos
    25.         asr.l   #8,d1               ; find the new X speed
    26.         add.w   d0,d1               ; combine the two speeds
    27.         cmpi.w  #$400,d1            ; compare the combined speed with the jump release speed
    28.         ble.s   locret_1BBB4        ; if it's less, branch to return
    29.         move.b  (v_ssangle).w,d0
    30.         andi.b  #$FC,d0
    31.         neg.b   d0
    32.         subi.b  #$40,d0
    33.         jsr (CalcSine).l
    34.         muls.w  #$400,d1
    35.         asr.l   #8,d1
    36.         move.w  d1,obVelX(a0)
    37.         muls.w  #$400,d0
    38.         asr.l   #8,d0
    39.         move.w  d0,obVelY(a0)       ; set the speed to the jump release speed
    40.         bclr    #7,obStatus(a0)     ; clear "Sonic has jumped" flag
    42. locret_1BBB4:
    43.         rts
    Next, go to the "Obj09_OnWall" label, and add this line directly after it:

    Code (ASM):
    2. bclr    #7,obStatus(a0) ; clear "Sonic has jumped" flag
    Now, go to the "Obj09_Jump" label, and after this line:

    Code (ASM):
    2. bset    #1,obStatus(a0)
    add this one:

    Code (ASM):
    2. bset    #7,obStatus(a0) ; set "Sonic has jumped" flag
    Finally, go to the "Obj09_ChkBumper" label, and after this line:

    Code (ASM):
    2. bset    #1,obStatus(a0)
    add this one:

    Code (ASM):
    2. bclr    #7,obStatus(a0) ; clear "Sonic has jumped" flag
    Et voilà! Basically, what it does is it combines the X and Y speed using cos and sin to find how fast he's moving upward at the current angle. It compares this combined speed with the jump release speed ($400) and if it's greater, then it uses similar code to the normal jump to make Sonic move at $400 in the current angle. Simple.

    When my friend (who's always been bad at the Sonic 1 Special Stages by her own admission, and hasn't played them in years) tested it out, she got the Chaos Emerald on her first try!

    Yuji Naka has had to put up with a lot of shit in his time (not least of which the schoolyard bullies who taunted him in his youth for having a name that sounds for all the world like "huge knocker"), and now it's my turn to rub it in his face:

    PWN, Yuji Naka!

    + - The false bravado in this post is for humorous purposes only. I actually admire Yuji Naka a lot, and I'm sure he could improve my code greatly after but a brief glance at it.  

    So, let me know what you think of this, or if you find any bugs.

    Here's the built rom with the fix applied.
  2. theocas


    Tech Member
    Wow, this is pretty nice! I tried it on 3 special stages and I got them all on my first try. Since I used the Hivebrain disasm, I just copied over the required Constants and Variables from the SVN disasm. I'm lazy.
    And my special stages rotated way faster and the Up buttons are pure mayhem. Usually Sonic would just get stuck in mid-air, but this fixed it. Thanks for the fix!
  3. amphobius


    doing more important things with my life Member
    Mercury for Super Tech Member, pl0x

    This has made a stitch in my side no-more—I'm pretty sure some of the S1 special stage flack might dissapear now, if this was a commercial ROM. =P
  4. Namo


    take a screenshot of your heart Member
    Not bad work here. This certainly makes them more bearable. :)
  5. Dark Sonic

    Dark Sonic

    Working on my art!
    Not too shabby sir. Unfortunately I still hate the Sonic 1 special stages, but you at least made them easier... except that god damn 3rd stage D:
  6. Tweaker


    Interesting! I was always under the impression that the original behavior was intentional; it's pretty neat to know that there was code left over suggesting that it was supposed to work this way. Excellent find!
  7. FeliciaVal


    ooh thank you very much for this :) too bad I'm still using the Hivebrain dissassembly and I'm not sure how to make it work there
  8. FraGag


    Tech Member
    I just noticed it when trying to get all rings in the special stages in S1@SAGE 2010 (which I did :P) and it just amplified my frustration. Now I just have to remember to actually hold the jump button down to do a full-height jump. :P Nicely done!
  9. Mad Echidna

    Mad Echidna

    Gone Oldbie
    I propose this become a standard addition to all sonic hacks, as the 8 bit style egg prison has been :P
  10. MarkeyJester


    Nothing's Impossible Resident Jester
    A very interesting find, nice research!

    Of course, one thing I am still wondering is why Sonic moves directly up when jumping from slanted walls, not to say I want it more difficult, I just figured that Sonic's physics being very close to reality, that it would be considered or expected the jumping on a slant, will fource the character in the directional face of that slant.
  11. theocas


    Tech Member
    I used the Hivebrain disasm too, so I just copied these equates over from the SVN disasm (Some of them might not be used at all, I know that, but I couldn't sort it all out atm because I used more of them. I just got rid of the obvious ones.):
    Code (ASM):
    2. obRender:   equ 1   ; bitfield for x/y flip, display mode
    3. obGfx:      equ 2   ; palette line & VRAM setting (2 bytes)
    4. obMap:      equ 4   ; mappings address (4 bytes)
    5. obX:        equ 8   ; x-axis position (2-4 bytes)
    6. obScreenY:  equ $A  ; y-axis position for screen-fixed items (2 bytes)
    7. obY:        equ $C  ; y-axis position (2-4 bytes)
    8. obVelX:     equ $10 ; x-axis velocity (2 bytes)
    9. obVelY:     equ $12 ; y-axis velocity (2 bytes)
    10. obInertia:  equ $14 ; potential speed (2 bytes)
    11. obHeight:   equ $16 ; height/2
    12. obWidth:    equ $17 ; width/2
    13. obPriority: equ $18 ; sprite stack priority -- 0 is front
    14. obActWid:   equ $19 ; action width
    15. obFrame:    equ $1A ; current frame displayed
    16. obAniFrame: equ $1B ; current frame in animation script
    17. obAnim:     equ $1C ; current animation
    18. obNextAni:  equ $1D ; next animation
    19. obTimeFrame:    equ $1E ; time to next frame
    20. obDelayAni: equ $1F ; time to delay animation
    21. obColType:  equ $20 ; collision response type
    22. obColProp:  equ $21 ; collision extra property
    23. obStatus:   equ $22 ; orientation or mode
    24. obRespawnNo:    equ $23 ; respawn list index number
    25. obRoutine:  equ $24 ; routine number
    26. ob2ndRout:  equ $25 ; secondary routine number
    28. btnB:       equ %00010000 ; B       ($10)
    29. btnR:       equ %00001000 ; Right       ($08)
    30. btnL:       equ %00000100 ; Left        ($04)
    31. btnDn:      equ %00000010 ; Down        ($02)
    32. btnUp:      equ %00000001 ; Up      ($01)
    33. btnDir:     equ %00001111 ; Any direction   ($0F)
    34. btnABC:     equ %01110000 ; A, B or C   ($70)
    35. bitStart:   equ 7
    36. bitA:       equ 6
    37. bitC:       equ 5
    38. bitB:       equ 4
    39. bitR:       equ 3
    40. bitL:       equ 2
    41. bitDn:      equ 1
    42. bitUp:      equ 0
    44. v_jpadhold2:    = $FFFFF602 ; joypad input - held, duplicate
    45. v_jpadpress2:   = $FFFFF603 ; joypad input - pressed, duplicate
    46. v_jpadhold1:    = $FFFFF604 ; joypad input - held
    47. v_jpadpress1:   = $FFFFF605 ; joypad input - pressed
    48. v_ssangle:  = $FFFFF780 ; Special Stage angle (2 bytes)
    49. v_ssrotate: = $FFFFF782 ; Special Stage rotation speed (2 bytes)
  12. Aquaslash


    <The Has-been Legend> Moderator
    Except the ones that cut out that special stage system altogether :v:
  13. Mercury


    His Name Is Sonic Tech Member
    Location Location
    What do you mean by the "8 bit style egg prison"? Forgive my ignorance.
  14. Black Squirrel

    Black Squirrel

    no reverse gear Wiki Sysop
    Northumberland, UK
    steamboat wiki
    For the record the behaviour is the same in Sonic & Knuckles's bonus stage as it is in regular Sonic 1.

    So this was never "fixed" officially.
  15. Azu


    I must be stupid. Member
    See, why couldn't S1@SAGE2010 hack have this.
  16. Wow, does this make a difference when I play the game! The special stages are less of a pain in the ass now. Thanks for sharing this!
  17. Briraka


    Bloody Robot
    Yes, thank you Mercury, for making the special stages less of a pain to get through. :)
  18. Namagem


    2010: Mercury calls Yuji Naka out.
    2011: Yuji Naka joins Sonic Retro
    2012: Yuji Naka pwns the entire forum by making a sonic hack so awesome it is never topped. The community crumbles in shame.

    That being said, this is an awesome tweak. I must be too used to the old controls, because I keep failing hard.
  19. Phos


    Going for the high score on whatever that little b Member
    I always thought it was because Sonic is always jumping from a roll.

    I just thought of the jump as shooting Sonic forwards. Thinking of it like a platforming jump makes you think you have more control than you really do.
  20. Frozen Nitrogen

    Frozen Nitrogen

    Wouldn't the door have been easier? Wiki Sysop
    ...welcome to 1994?
Thread Status:
Not open for further replies.