don't click here

Some changes and fixes for Sonic 2

Discussion in 'Engineering & Reverse Engineering' started by Esrael, Jun 7, 2012.

  1. Alex Field

    Alex Field

    シュート! カオス・エメラルド・ザが消えようとしている! Member
    I've noticed that certain palette indexes are crashing the game; either I've discovered a new bug, or my ROM hack is trying to fight back against me; whatever the case, here's the index, in case someone figures out why the issue occurs.
    Code (Text):
    1. PalPointers:
    2. PalPtr_SEGA:    palptr Pal_SEGA,  0
    3. PalPtr_Title:    palptr Pal_Title, 1
    4. PalPtr_BGND:    palptr Pal_BGND,  0
    5. PalPtr_EHZ:    palptr Pal_EHZ,   1
    6. PalPtr_EHZ2:    palptr Pal_EHZ2,  1
    7. PalPtr_OWZ1:    palptr Pal_OWZ1,  1
    8. PalPtr_OWZ2:    palptr Pal_OWZ2,  1
    9. PalPtr_WZ:    palptr Pal_WZ,    1
    10. PalPtr_SSZ1:    palptr Pal_SSZ1,  1
    11. PalPtr_SSZ2:    palptr Pal_SSZ2,  1
    12. PalPtr_MTZ:    palptr Pal_MTZ,   1
    13. PalPtr_MTZ2:    palptr Pal_MTZ,   1
    14. PalPtr_WFZ:    palptr Pal_WFZ,   1
    15. PalPtr_HTZ:    palptr Pal_HTZ,   1
    16. PalPtr_HPZ:    palptr Pal_HPZ,   1
    17. PalPtr_RWZ:    palptr Pal_RWZ,   1
    18. PalPtr_OOZ:    palptr Pal_OOZ,   1
    19. PalPtr_MCZ:    palptr Pal_MCZ,   1
    20. PalPtr_CNZ:    palptr Pal_CNZ,   1
    21. PalPtr_CPZ:    palptr Pal_CPZ,   1
    22. PalPtr_CPZ2:    palptr Pal_CPZ2,   1
    23. PalPtr_DEZ:    palptr Pal_DEZ,   1
    24. PalPtr_ARZ:    palptr Pal_ARZ,   1
    25. PalPtr_ARZ2:    palptr Pal_ARZ2,   1
    26.         palptr Pal_EHZ,   1    ; for some reason, this specific entry crashes the game...
    27. PalPtr_SCZ:    palptr Pal_SCZ,   1
    28. PalPtr_OWZ1_U:    palptr Pal_OWZ1_U, 1
    29. PalPtr_HPZ_U:    palptr Pal_HPZ_U, 0
    30. PalPtr_CPZ_U:    palptr Pal_CPZ_U, 0
    31. PalPtr_SS:    palptr Pal_SS,    0
    32. PalPtr_ARZ_U:    palptr Pal_ARZ_U, 0
    33. PalPtr_ARZ2_U:    palptr Pal_ARZ2_U, 0
    34. PalPtr_MCZ_B:    palptr Pal_MCZ_B, 1
    35. PalPtr_CNZ_B:    palptr Pal_CNZ_B, 1
    36. PalPtr_SS1:    palptr Pal_SS1,   3
    37. PalPtr_SS2:    palptr Pal_SS2,   3
    38. PalPtr_SS3:    palptr Pal_SS3,   3
    39. PalPtr_SS4:    palptr Pal_SS4,   3
    40. PalPtr_SS5:    palptr Pal_SS5,   3
    41. PalPtr_SS6:    palptr Pal_SS6,   3
    42. PalPtr_SS7:    palptr Pal_SS7,   3
    43. PalPtr_SS1_2p:    palptr Pal_SS1_2p,3
    44. PalPtr_SS2_2p:    palptr Pal_SS2_2p,3
    45. PalPtr_SS3_2p:    palptr Pal_SS3_2p,3
    46. PalPtr_OOZ_B:    palptr Pal_OOZ_B, 1
    47. PalPtr_Result:    palptr Pal_Result,0
    48.         palptr Pal_EHZ,   1    ; this too!
    49.         palptr Pal_EHZ,   1    ; this too!
    50.         palptr Pal_EHZ,   1    ; this too!
    51. PalPtr_Knux:    palptr Pal_Knux,  0
    52. PalPtr_CPZ_K_U:    palptr Pal_CPZ_K_U, 0
    53. PalPtr_ARZ_K_U:    palptr Pal_ARZ_K_U, 0
    54. PalPtr_SS_K:    palptr Pal_SS_K, 0
    55. PalPtr_HPZ_K_U:    palptr Pal_HPZ_K_U, 0
    56. ; MENUS GO HERE
    57. PalPtr_SonicMenu:    palptr Pal_SonicMenu,  0
    58. PalPtr_TailsMenu:    palptr Pal_TailsMenu,  0
    59. PalPtr_KnuxMenu:    palptr Pal_KnuxMenu,  0
    60. PalPtr_EggmanMenu:    palptr Pal_EggmanMenu,  0
    61. PalPtr_RetroMenu:    palptr Pal_RetroMenu,  0
    62. PalPtr_Ending:    palptr    Pal_Ending, 0
     
  2. Devon

    Devon

    There's nothing left but faith Tech Member
    854
    572
    93
    I'm not sure what you exactly mean by "crashing the game". Are you trying to load those Pal_EHZ entries? The only issue that I came across was with "levartptrs" not being able to take into account any additional operators without surrounding it with parenthesis (i.e. you can't put in PalID_EHZ+1, because it gets assembled as "PalID_EHZ+1<<24", which is PalID_EHZ+$1000000). To fix that alongside any other potential issues, I changed:
    Code (Text):
    1.     dc.l (plc1<<24)|art
    2.     dc.l (plc2<<24)|map16x16
    3.     dc.l (palette<<24)|map128x128
    to
    Code (Text):
    1.     dc.l ((plc1)<<24)|(art)
    2.     dc.l ((plc2)<<24)|(map16x16)
    3.     dc.l ((palette)<<24)|(map128x128)
     
    Last edited: Oct 14, 2022
  3. I assume "crashing the game" refers to a 68K exception occurring when you try to use those palette indices, but without knowing what kind of exception (address error, illegal instruction, etc.) is occurring, I would not know where to start looking. Are you using an exception handler in your hack?
     
  4. Alex Field

    Alex Field

    シュート! カオス・エメラルド・ザが消えようとしている! Member
    No, as in it crashes if ANYTHING tries to load those entries.
    I wasn't, although that gave me the idea to import the Sonic 1 error exception to see what comes up; I got Line 1111 Emulator $00000001 as my result.
     
  5. Devon

    Devon

    There's nothing left but faith Tech Member
    854
    572
    93
    Well, how exactly are you loading those entries?
     
  6. Line 1111 Emulator exception at offset $00000001 (part of the initial stack pointer value in the vector table). Seems something is causing those pointers to jump to invalid code instead of their intended destination.
     
    Last edited: Oct 14, 2022
  7. Alex Field

    Alex Field

    シュート! カオス・エメラルド・ザが消えようとしている! Member
    Strange, as the broken entries are broken regardless of what's there, even with a generic EHZ entry.
    PalLoad function.
     
  8. Devon

    Devon

    There's nothing left but faith Tech Member
    854
    572
    93
    What's the exact ID that you are passing to the function?
     
  9. Alex Field

    Alex Field

    シュート! カオス・エメラルド・ザが消えようとしている! Member
    The entry right before Knuckles' palette entry.
     
  10. Devon

    Devon

    There's nothing left but faith Tech Member
    854
    572
    93
    Please post some code/be more specific, because otherwise, I'm lost. I wanna see how EXACTLY you are doing it. It's possible that there's something about it you are not catching. So far, you've only really told me what you are intending to do, but not what's actually being done.
     
    Last edited: Oct 15, 2022
  11. Alex Field

    Alex Field

    シュート! カオス・エメラルド・ザが消えようとしている! Member
    Code (Text):
    1.     moveq    #$36,d0    ; load Knuckles' palette index
    2. +    bsr.w    PalLoad_Now    ; load Sonic's palette line
    The code used to load the palette; and yes, I did also use move.b and even move.w to load it instead, but it still crashes.
     
  12. Devon

    Devon

    There's nothing left but faith Tech Member
    854
    572
    93
    Okay, so a couple of things:
    Code (Text):
    1. PalPtr_SEGA:    palptr Pal_SEGA,  0            ; 00
    2. PalPtr_Title:    palptr Pal_Title, 1            ; 01
    3. PalPtr_BGND:    palptr Pal_BGND,  0            ; 02
    4. PalPtr_EHZ:    palptr Pal_EHZ,   1            ; 03
    5. PalPtr_EHZ2:    palptr Pal_EHZ2,  1            ; 04
    6. PalPtr_OWZ1:    palptr Pal_OWZ1,  1            ; 05
    7. PalPtr_OWZ2:    palptr Pal_OWZ2,  1            ; 06
    8. PalPtr_WZ:    palptr Pal_WZ,    1            ; 07
    9. PalPtr_SSZ1:    palptr Pal_SSZ1,  1            ; 08
    10. PalPtr_SSZ2:    palptr Pal_SSZ2,  1            ; 09
    11. PalPtr_MTZ:    palptr Pal_MTZ,   1            ; 0A
    12. PalPtr_MTZ2:    palptr Pal_MTZ,   1            ; 0B
    13. PalPtr_WFZ:    palptr Pal_WFZ,   1            ; 0C
    14. PalPtr_HTZ:    palptr Pal_HTZ,   1            ; 0D
    15. PalPtr_HPZ:    palptr Pal_HPZ,   1            ; 0E
    16. PalPtr_RWZ:    palptr Pal_RWZ,   1            ; 0F
    17. PalPtr_OOZ:    palptr Pal_OOZ,   1            ; 10
    18. PalPtr_MCZ:    palptr Pal_MCZ,   1            ; 11
    19. PalPtr_CNZ:    palptr Pal_CNZ,   1            ; 12
    20. PalPtr_CPZ:    palptr Pal_CPZ,   1            ; 13
    21. PalPtr_CPZ2:    palptr Pal_CPZ2,   1            ; 14
    22. PalPtr_DEZ:    palptr Pal_DEZ,   1            ; 15
    23. PalPtr_ARZ:    palptr Pal_ARZ,   1            ; 16
    24. PalPtr_ARZ2:    palptr Pal_ARZ2,   1            ; 17
    25.         palptr Pal_EHZ,   1                ; 18
    26. PalPtr_SCZ:    palptr Pal_SCZ,   1            ; 19
    27. PalPtr_OWZ1_U:    palptr Pal_OWZ1_U, 1            ; 1A
    28. PalPtr_HPZ_U:    palptr Pal_HPZ_U, 0            ; 1B
    29. PalPtr_CPZ_U:    palptr Pal_CPZ_U, 0            ; 1C
    30. PalPtr_SS:    palptr Pal_SS,    0            ; 1D
    31. PalPtr_ARZ_U:    palptr Pal_ARZ_U, 0            ; 1E
    32. PalPtr_ARZ2_U:    palptr Pal_ARZ2_U, 0            ; 1F
    33. PalPtr_MCZ_B:    palptr Pal_MCZ_B, 1            ; 20
    34. PalPtr_CNZ_B:    palptr Pal_CNZ_B, 1            ; 21
    35. PalPtr_SS1:    palptr Pal_SS1,   3            ; 22
    36. PalPtr_SS2:    palptr Pal_SS2,   3            ; 23
    37. PalPtr_SS3:    palptr Pal_SS3,   3            ; 24
    38. PalPtr_SS4:    palptr Pal_SS4,   3            ; 25
    39. PalPtr_SS5:    palptr Pal_SS5,   3            ; 26
    40. PalPtr_SS6:    palptr Pal_SS6,   3            ; 27
    41. PalPtr_SS7:    palptr Pal_SS7,   3            ; 28
    42. PalPtr_SS1_2p:    palptr Pal_SS1_2p,3            ; 29
    43. PalPtr_SS2_2p:    palptr Pal_SS2_2p,3            ; 2A
    44. PalPtr_SS3_2p:    palptr Pal_SS3_2p,3            ; 2B
    45. PalPtr_OOZ_B:    palptr Pal_OOZ_B, 1            ; 2C
    46. PalPtr_Result:    palptr Pal_Result,0            ; 2D
    47.         palptr Pal_EHZ,   1                ; 2E
    48.         palptr Pal_EHZ,   1                ; 2F
    49.         palptr Pal_EHZ,   1                ; 30
    50. PalPtr_Knux:    palptr Pal_Knux,  0            ; 31
    51. PalPtr_CPZ_K_U:    palptr Pal_CPZ_K_U, 0        ; 32
    52. PalPtr_ARZ_K_U:    palptr Pal_ARZ_K_U, 0        ; 33
    53. PalPtr_SS_K:    palptr Pal_SS_K, 0            ; 34
    54. PalPtr_HPZ_K_U:    palptr Pal_HPZ_K_U, 0        ; 35
    55. PalPtr_SonicMenu:    palptr Pal_SonicMenu,  0        ; 36
    56. PalPtr_TailsMenu:    palptr Pal_TailsMenu,  0        ; 37
    57. PalPtr_KnuxMenu:    palptr Pal_KnuxMenu,  0        ; 38
    58. PalPtr_EggmanMenu:    palptr Pal_EggmanMenu,  0        ; 39
    59. PalPtr_RetroMenu:    palptr Pal_RetroMenu,  0        ; 3A
    60. PalPtr_Ending:    palptr    Pal_Ending, 0        ; 3B
    Looks like you miscounted, or you changed the palette table.

    One more question, from where is this being run at? Is it from an object?
     
  13. Alex Field

    Alex Field

    シュート! カオス・エメラルド・ザが消えようとしている! Member
    It's just the routine that loads Sonic's (or, in this case, Knuckles') palette when starting the level (Level_LoadPal).
     
  14. Devon

    Devon

    There's nothing left but faith Tech Member
    854
    572
    93
    Only thing I can think of is for you to go to where the stack pointer register points to in RAM, and follow the path of addresses that are pushed from calls/interrupts to determine where it's exactly crashing from, with the help of your listing output (note that interrupts/exceptions push the return address and the status register (which will look something like $23xx or $27xx in Sonic 2), so keep that in mind. Also if you are using vladikcomper's debugger, the stack trace starting from SP is already there at the bottom of the screen).

    Might be helpful to post the rest of what's under Level_LoadPal, maybe. It might be better to move this into Basic Q&A or a separate thread, to be honest. Kinda clogging up this thread.
     
  15. Fixing the Pitch of the Sega Sound

    This is one that I am absolutely amazed no one ANYWHERE has seemed to have noticed, much less discussed: the pitch of the SEGA Sound in Sonic 2 is just a tiny bit higher pitched than it should be. Whether it is intentional or not, I don't know, but I found it impossible to ignore. Thankfully, it is actually really easy to restore it to match Sonic 1 and 3K.

    In the sound driver, find this section under zPlaySegaSound:
    Code (Text):
    1.  
    2. .loop:
    3.    ld   a,(hl)           ; Get next PCM byte
    4.    ld   (zYM2612_D0),a       ; Send to DAC
    5.    inc   hl           ; Advance pointer
    6.    nop
    7.    ld   b,0Ch           ; Sega PCM pitch
    8.    djnz   $           ; Delay loop
    9.  
    10.    nop
    11.    ld   a,(zAbsVar.QueueToPlay)   ; Get next item to play
    12.    cp   c           ; Is it 80h?
    13.    jr   nz,.stop       ; If not, stop Sega PCM
    14.    ld   a,(hl)           ; Get next PCM byte
    15.    ld   (zYM2612_D0),a       ; Send to DAC
    16.    inc   hl           ; Advance pointer
    17.    nop
    18.    ld   b,0Ch           ; Sega PCM pitch
    19.    djnz   $           ; Delay loop
    20.  
    21.    nop
    22.    dec   de           ; 2 less bytes to play
    23.    ld   a,d           ; a = d
    24.    or   e           ; Is de zero?
    25.    jp   nz,.loop       ; If not, loop
    26.  
    Delete all four of the nops, and change both instances of '0Ch' to '0Dh'. That's it.
    (This does appear to be safe for real hardware; the 2612 in my Model 1 VA6 handles it without any problems.)



    Fix Erratic Behavior of Various Badniks in Debug Mode

    In debug mode, quite a few Badniks will still track Sonic while he is an object, while others will behave erratically, such as Grabbers moving up and down wildly. This is caused by Obj_GetOrientationToPlayer not checking for debug mode. This is also a simple fix:

    Code (Text):
    1. Obj_GetOrientationToPlayer:
    2.    moveq   #0,d0
    3.    moveq   #0,d1
    4.    lea   (MainCharacter).w,a1 ; a1=character
    5.    move.w   x_pos(a0),d2
    6.    sub.w   x_pos(a1),d2
    7.    mvabs.w   d2,d4   ; absolute horizontal distance to main character
    8.    lea   (Sidekick).w,a2 ; a2=character
    9.    move.w   x_pos(a0),d3
    10.    sub.w   x_pos(a2),d3
    11.    mvabs.w   d3,d5   ; absolute horizontal distance to sidekick
    12.    cmp.w   d5,d4   ; get shorter distance
    13.    bls.s   ++   ; branch, if main character is closer
    14.  
    Above the 'cmp.w d5,d4', insert these two lines:
    Code (Text):
    1.  
    2. tst.w   (Debug_placement_mode).w ; is debug mode active?
    3. bne.s    +       ; if so, treat sidekick as closer
    4.  
    There are quite a few other similar bugs in debug mode in both Sonic 1 and 2 that can be fixed by inserting those two lines in various locations.
     
    Last edited: Nov 13, 2022
  16. Alex Field

    Alex Field

    シュート! カオス・エメラルド・ザが消えようとしている! Member
    You know how in 2-player mode, whenever a teleport monitor is hit, the background color never changes? Well, turns out it's the result of a single line of code; in Vint_Level, you should see something similar to this:
    Code (Text):
    1. Vint_Level:
    2.     bsr.w    ReadJoypads
    3.     tst.b    (Teleport_timer).w
    4.     beq.s    loc_6F8
    5.     lea    (VDP_control_port).l,a5
    6.     tst.w    (Game_paused).w    ; is the game paused ?
    7.     bne.w    loc_748    ; if yes, branch
    8.     subq.b    #1,(Teleport_timer).w
    9.     bne.s    +
    10.     move.b    #0,(Teleport_flag).w
    11. +
    12.     cmpi.b    #$10,(Teleport_timer).w
    13.     blo.s    loc_6F8
    14.     lea    (VDP_data_port).l,a6
    15.     move.l    #vdpComm($0000,CRAM,WRITE),(VDP_control_port).l
    16.     move.w    #$EEE,d0
    17.  
    18.     move.w    #$1F,d1
    19. -    move.w    d0,(a6)
    20.     dbf    d1,-
    That $1F should be changed to $20, and now the color changes correctly.
     
  17. Clownacy

    Clownacy

    Tech Member
    929
    241
    43
    I don't think that's correct. Here's the complete code:

    Code (ASM):
    1.        lea    (VDP_data_port).l,a6
    2.        move.l    #vdpComm($0000,CRAM,WRITE),(VDP_control_port).l
    3.        move.w    #$EEE,d0 ; White.
    4.  
    5.        move.w    #32-1,d1
    6. -      move.w    d0,(a6)
    7.        dbf       d1,-
    8.  
    9.        ; Skip a colour.
    10.        move.l    #vdpComm($0042,CRAM,WRITE),(VDP_control_port).l
    11.  
    12.     if fixBugs
    13.        move.w    #31-1,d1
    14.     else
    15.        ; This does one more colour than necessary: it isn't accounting for
    16.        ; the colour that was skipped earlier!
    17.        move.w    #32-1,d1
    18.     endif
    19. -      move.w    d0,(a6)
    20.        dbf       d1,-
    What this does is fill the first two palette lines with white, skip the first colour of the third palette line, and then set the remaining colours to white. Skipping that one colour is deliberate. There is, however, a small bug where the first colour of the first palette line is set to white twice because of an incorrect loop counter.