don't click here

Some changes/fixes for Sonic 1

Discussion in 'Engineering & Reverse Engineering' started by RetroKoH, Sep 4, 2012.

  1. RetroKoH

    RetroKoH

    Member
    1,722
    101
    43
    S1Fixed: A successor to ReadySonic
    Since the thread is still alive and well, and I decided to dip my toe back into things... I wanna touch on something that always bugged me in Sonic 1, and I almost guarantee no one noticed. But I did 4 years ago when I last worked on a hack, and I do again now.

    Sonic 1 has a 64 color palette file of all white, just for the background on the sega screen... Which the game branches away to go set up, and then come back to load it into RAM... Nah, methinks that could be optimized. Now, if you want to replace the Sega BG palette to something more colorful, you might not opt to do this... hell you might not opt to anyway, but I think it's good to share anyway. Someone could learn something. Go to @loadpal: under GM_Sega: and replace this:

    Code (Text):
    1.     @loadpal:
    2.         ;moveq    #palid_SegaBG,d0
    3.         ;bsr.w    PalLoad2    ; load Sega logo palette
    NOTE: I tweaked it to fade into white, because I think it looks nicer... so keep that in mind if you decide to do this.

    Code (Text):
    1.     @loadpal:
    2.         ;moveq    #palid_SegaBG,d0
    3.         ;bsr.w    PalLoad1    ; load Sega logo palette - Tweaked to allow fade in
    4.  
    5. ; Nah, let's make that more efficient, shall we?
    6.         lea        (v_pal_dry_dup).l,a3
    7.         moveq    #$3F,d7
    8.  
    9.     @loop:
    10.         move.w    #cWhite,(a3)+    ; move data to RAM
    11.         dbf        d7,@loop
    12.         bsr.w     PaletteFadeIn ; added to allow fade in
    If you instead want to change it to a proper, more colorful palette to suit you, then disregard my changes but still change to PalLoad1 and add PaletteFadeIn to make it look a lot nicer.
     
  2. RetroKoH

    RetroKoH

    Member
    1,722
    101
    43
    S1Fixed: A successor to ReadySonic
    Question... has anyone ever accidentally made the Final Zone boss unhittable? My guess is that I either did something inadvertently to the SolidObject Routine or a shift to OSTs made something not work. I'll PM a ROM to someone willing to test but I just wonder if anyone's had this happen to them.

    In hindsight I could've put this in Basic Q/A but IDK how to Delete posts now. Forum's changed a bit.
     
  3. TheInvisibleSun

    TheInvisibleSun

    OVER THE TOP TECHNO-BLAST Member
    1,630
    194
    43
    Buffalo, NY, USA
    The Water
    I don't have an answer to the Final Zone question, but to 'delete' posts, just edit the post to request that it be deleted (this is how it always worked, right?)
     
  4. RetroKoH

    RetroKoH

    Member
    1,722
    101
    43
    S1Fixed: A successor to ReadySonic
    I thought so... but I hit Edit and didn't see a Delete button. Either I'm just blind or I'm not used to any changes that have been made since I was last here
     
  5. TheInvisibleSun

    TheInvisibleSun

    OVER THE TOP TECHNO-BLAST Member
    1,630
    194
    43
    Buffalo, NY, USA
    The Water
    When you edit, literally replace the text with something like "mods please delete this"
     
  6. RetroKoH

    RetroKoH

    Member
    1,722
    101
    43
    S1Fixed: A successor to ReadySonic
    I know I'm quoting a glitch Clownacy posted nearly 5 years ago, but it's to do with a question I currently have. I seem to recall an obscure glitch in Marble Zone Act 2 where if you perfectly ran through the start, hitting both Buzz Bombers and triggering the switch fast enough, you can somehow crash the game. I could've sworn I saw video of this once but oddly I can't find evidence of this anywhere so now I'm starting to think I'm experiencing the Mandela Effect or something.

    Has anyone ever experienced a bug like this... and could it be related to this issue that Clownacy fixed?
     
  7. Clownacy

    Clownacy

    Tech Member
    1,096
    676
    93
    If I remember right, that bug was listed on various wikis (Sonic Retro and TCRF included). Eventually a thread was created where people tried to recreate it, and it was determined that the bug did not actually exist, so it was removed.

    The bug that I fixed shouldn't cause any crashes anyway - it's simply a null-pointer dereference that's harmless in Sonic 1's case, because it only reads a byte. The bug only matters because it causes a crash when you port objects to Sonic 2. The reason it does is because Sonic 2 would read a word instead of a byte, and the address it would try to read from would be odd, causing a crash.
     
    • Informative Informative x 2
    • Like Like x 1
    • List
  8. Kilo

    Kilo

    Deathly afraid of the YM2612 Tech Member
    926
    932
    93
    Canada
    Sonic 1 Source Code Recreation + Source Code Wiki Page
    Small fix to a peculiar bug:
    If you get a game over by drowning, the title screen will stop scrolling. This is because $F744 is set when the player drowns, which is the scroll lock flag. However it doesn't get cleared at the title screen. Here's a hardware demonstration (Featuring anxiety filled Kilo's heavy breathing and tripping)

    The fix to this is a really simple one. At Title_LoadText, just before the branch to LevelSizeLoad, clear $F744.
     
  9. Cyber Axe

    Cyber Axe

    Oldbie
    I'm interested in the score reset back to last checkpoint, imo that's the way it should be.

    Though i do think monitor behaviour is fine the way it is.

    Just thought it would be handy to list some bugs I've found for people to look at if interested, i'm not yet skilled enough to figure them out at present

    Here are bug's I've found
    1. Starlight Zone Glitch: when the zone fades in on the bottom just right of centre there's a couple of vertical blue bars that appear for a few frames (not tested on revision 0, you can see it at the start of the demo)
    2. The next glitch happens when you roll into a rock from the right side (found it when testing spindash) there's a bridge in green hill act 2 i think it is where there's rocks either side if you roll into the right from the right you tend to go into the rock a few pixels then get pushed out (sometimes doesn't trigger)
    3. There is a small period of time where if you hit an invincibility monitor you can still die before the sparkles appear (I'm actually planning on looking into this one as i think it's an easy fix and if so will post it)
    4. When testing the Air Roll I found this (I don't think it's related to air roll though): if you press jump just as you hit a spring you don't get the spring sound but still get the spring bonus height and animation, I believe you have to hit jump the same frame as you hit the spring for this to occur
    And from my count there's still about 9 bugs on https://info.sonicretro.org/Sonic_the_Hedgehog_(16-bit)/Bugs#General_bugs yet to be fixed, that I've yet to come across bug fixes for.

    Edit:

    I have just tried to confirm 2 and 4

    2: defiantly happens, i just tested it with the rock left of the bridge on GHZ2 just before the end goal run towards the rock and go into a roll and you will roll into the rock

    4: I cannot get to trigger again so it must be if you have air roll on and you jump at the same time as the spring, i have implemented a variation of air roll where you can't curl into a ball if you are in the spring jump animation but will roll if in the air and not in the spring jump animation, will toggle my implementation to the original one from the guide confirm this is the cause.

    Edit 2:
    4: I have tested this a second time with the air roll feature and still cannot get it to activate when i originally found that bug i managed to get it to activate a few times so i'm wondering if this was related to having the OptimiseSound enabled at the time or something similar.

    Also I may have fixed 3 since, the toggle on invincibility was the first thing in the Pow_ChkInvinc: after the monitor type check (I thought that might happen later before i looked at that subroutine) what i ended up doing is making it so that Pow_ChkInvinc gets checked before all the other monitors and that "seems" to make the monitor activate faster, but it's a hard one to test because i don't know a good location to hit a monitor then immediately hit an enemy or trap, though I am aware i have done this which is how i discovered it in the first place.

    Edit 3:
    4: Tested this again after disabling the air roll from previous attempt, the only difference is this time i was facing left on the spring, I bounced continuously and hit jump at just the right time and the spring sound did not play (it's the first spring at the start of GHZ1 I tested with)

    Pretty sure I was facing left when I originally found this bug. (what is it with bugs when facing left in this game)
     
    Last edited by a moderator: Jun 28, 2020
  10. DeltaW

    DeltaW

    Originally a Wooloo Member
    I do apologise regarding the thread being bumped but I believe what I'm about to show is a no-brainer.

    In Sonic (3) and Knuckles, when you hit a monitor from below, you hit it rather than it bouncing to the floor like in Sonic 1, 2 and 3. I'll demostrate it for you:

    [​IMG]
    Sonic 3 and Knuckles allows you to hit the monitor from below.

    [​IMG]
    This is not the case for Sonic 1 (applies to its sequel)

    If you want to make the monitor behave like S3K in Sonic 1 and 2, it's pretty simple to do.

    In Sonic 1 (Hivebrain), locate Touch_Monitor and this is what you will get:

    Code (Text):
    1. Touch_Monitor:
    2.        tst.w    $12(a0)        ; is Sonic moving upwards?
    3.        bpl.s    loc_1AF1E    ; if not, branch
    4.        move.w    $C(a0),d0
    5.        subi.w    #$10,d0
    6.        cmp.w    $C(a1),d0
    7.        bcs.s    locret_1AF2E
    8.        neg.w    $12(a0)        ; reverse Sonic's y-motion
    9.        move.w    #-$180,$12(a1)
    10.        tst.b    $25(a1)
    11.        bne.s    locret_1AF2E
    12.        addq.b    #4,$25(a1)    ; advance the monitor's routine counter
    13.        rts  

    If you look in the last 6 lines of code, it makes sure it reverses Sonic's y-motion in order for the monitor to fall. In S3K, the code is removed in order for this behaviour to occur, so remove the last 6 lines of code.

    In Sonic 2 (GitHub), locate Touch_Monitor and you will see this:

    Code (Text):
    1. Touch_Monitor:
    2.    btst    #1,status(a0)
    3.    beq.s    loc_3F768
    4.    tst.w    y_vel(a0)    ; is Sonic moving upwards?
    5.    bpl.s    loc_3F768    ; if not, branch
    6.    move.w    y_pos(a0),d0
    7.    subi.w    #$10,d0
    8.    cmp.w    y_pos(a1),d0
    9.    blo.s    return_3F78A
    10.    neg.w    y_vel(a0)    ; reverse Sonic's y-motion
    11.    move.w    #-$180,y_vel(a1)
    12.    tst.b    routine_secondary(a1)
    13.    bne.s    return_3F78A
    14.    move.b    #4,routine_secondary(a1) ; set the monitor's routine counter
    15.    rts
    As I previously said, the last 6 lines reverses Sonic's y-motion in order for the monitor to fall. We don't want that so remove it.

    Now save, build and let's test it!

    [​IMG]

    And there we go, it behaves as intended! Enjoy! ;)
     
  11. Code (Text):
    1. ; ===========================================================================
    2. ; ---------------------------------------------------------------------------
    3. ; Object 19 - unused rolling ball (placeable in Debug Mode)
    4. ; ---------------------------------------------------------------------------
    5.  
    6. Obj19:                    ; XREF: Obj_Index
    7.         moveq    #0,d0
    8.         move.b    $24(a0),d0
    9.         move.w    Obj19_Index(pc,d0.w),d1
    10.         jmp    Obj19_Index(pc,d1.w)
    11. ; ---------------------------------------------------------------------------
    12. Obj19_Index:    dc.w Obj19_Main-Obj19_Index    ; 0
    13.         dc.w Obj19_Move-Obj19_Index    ; 2
    14.         dc.w Obj19_Move2-Obj19_Index    ; 4
    15.         dc.w Obj19_Delete-Obj19_Index    ; 6
    16.         dc.w Obj19_Solid-Obj19_Index    ; 8
    17. ; ---------------------------------------------------------------------------
    18. ; loc_5C98:
    19. Obj19_Main:
    20.         move.b    #$18,$16(a0)
    21.         move.b    #$C,$17(a0)
    22.         bsr.w    ObjectFall
    23.         jsr    (ObjHitFloor).l
    24.         tst.w    d1
    25.         bpl.s    locret_5CEC
    26.         add.w    d1,$C(a0)
    27.         move.w    #0,$12(a0)
    28.         move.b    #8,$24(a0)
    29.         move.l    #Map_obj48,4(a0)
    30.         move.w    #$43AA,2(a0)
    31.         move.b    #4,1(a0)
    32.         move.b    #3,$18(a0)
    33.         move.b    #$18,$19(a0)
    34.         move.b    #1,$1F(a0)
    35.         bsr.w    sub_5DC8
    36.  
    37. locret_5CEC:
    38.         rts
    39. ; ---------------------------------------------------------------------------
    40. ; loc_5CEE:
    41. Obj19_Solid:
    42.         move.w    #$23,d1
    43.         move.w    #$18,d2
    44.         move.w    #$18,d3
    45.         move.w    8(a0),d4
    46.         bsr.w    SolidObject
    47.         btst    #5,$22(a0)
    48.         bne.s    loc_5D14
    49.         move.w    ($FFFFD008).w,d0
    50.         sub.w    8(a0),d0
    51.         bcs.s    loc_5D20
    52.  
    53. loc_5D14:
    54.         move.b    #2,$24(a0)
    55.         move.w    #$80,$14(a0)
    56.  
    57. loc_5D20:
    58.         bsr.w    sub_5DC8
    59.         bsr.w    DisplaySprite
    60.         bra.w    loc_5E2A
    61. ; ---------------------------------------------------------------------------
    62. ; loc_5D2C:
    63. Obj19_Move:
    64.         btst    #1,$22(a0)
    65.         bne.w    Obj19_Move2
    66.         bsr.w    sub_5DC8
    67.         bsr.w    Obj19_Calc
    68.         bsr.w    SpeedToPos
    69.         move.w    #$23,d1
    70.         move.w    #$18,d2
    71.         move.w    #$18,d3
    72.         move.w    8(a0),d4
    73.         bsr.w    SolidObject
    74.         jsr    (Sonic_AnglePos).l
    75.         cmpi.w    #$20,8(a0)
    76.         bcc.s    loc_5D70
    77.         move.w    #$20,8(a0)
    78.         move.w    #$400,$14(a0)
    79.  
    80. loc_5D70:
    81.         btst    #1,$22(a0)
    82.         beq.s    loc_5D7E
    83.         move.w    #$FC00,$12(a0)
    84.  
    85. loc_5D7E:
    86.         bsr.w    DisplaySprite
    87.         bra.w    loc_5E2A
    88. ; ---------------------------------------------------------------------------
    89. ; loc_5D86:
    90. Obj19_Move2:
    91.         bsr.w    sub_5DC8
    92.         bsr.w    SpeedToPos
    93.         move.w    #$23,d1
    94.         move.w    #$18,d2
    95.         move.w    #$18,d3
    96.         move.w    8(a0),d4
    97.         bsr.w    SolidObject
    98.         jsr    (Sonic_Floor).l
    99.         btst    #1,$22(a0)
    100.         beq.s    loc_5DC0
    101.         move.w    $12(a0),d0
    102.         addi.w    #$28,d0
    103.         move.w    d0,$12(a0)
    104.  
    105. loc_5DC0:
    106.         bsr.w    DisplaySprite
    107.         bra.s    loc_5E2A
    108. ; ---------------------------------------------------------------------------
    109.  
    110. sub_5DC8:
    111.         tst.b    $1A(a0)
    112.         beq.s    Obj19_Animate
    113.         move.b    #0,$1A(a0)
    114.         rts
    115. ; ---------------------------------------------------------------------------
    116. ; loc_5DD6:
    117. Obj19_Animate:
    118.         move.b    $14(a0),d0
    119.         beq.s    loc_5E02
    120.         bmi.s    loc_5E0A
    121.         subq.b    #1,$1E(a0)
    122.         bpl.s    loc_5E02
    123.         neg.b    d0
    124.         addq.b    #8,d0
    125.         bcs.s    loc_5DEC
    126.         moveq    #0,d0
    127.  
    128. loc_5DEC:
    129.         move.b    d0,$1E(a0)
    130.         move.b    $1F(a0),d0
    131.         addq.b    #1,d0
    132.         cmpi.b    #4,d0
    133.         bne.s    loc_5DFE
    134.         moveq    #1,d0
    135.  
    136. loc_5DFE:
    137.         move.b    d0,$1F(a0)
    138.  
    139. loc_5E02:
    140.         move.b    $1F(a0),$1A(a0)
    141.         rts
    142. ; ---------------------------------------------------------------------------
    143.  
    144. loc_5E0A:
    145.         subq.b    #1,$1E(a0)
    146.         bpl.s    loc_5E02
    147.         addq.b    #8,d0
    148.         bcs.s    loc_5E16
    149.         moveq    #0,d0
    150.  
    151. loc_5E16:
    152.         move.b    d0,$1E(a0)
    153.         move.b    $1F(a0),d0
    154.         subq.b    #1,d0
    155.         bne.s    loc_5E24
    156.         moveq    #3,d0
    157.  
    158. loc_5E24:
    159.         move.b    d0,$1F(a0)
    160.         bra.s    loc_5E02
    161. ; ---------------------------------------------------------------------------
    162.  
    163. loc_5E2A:
    164.         move.w    8(a0),d0
    165.         andi.w    #$FF80,d0
    166.         move.w    ($FFFFF700).w,d1
    167.         subi.w    #$80,d1
    168.         andi.w    #$FF80,d1
    169.         sub.w    d1,d0
    170.         cmpi.w    #$280,d0
    171.         bhi.w    DeleteObject
    172.         rts
    173. ; ---------------------------------------------------------------------------
    174. ; loc_5E4A:
    175. Obj19_Delete:
    176.         bra.w    DeleteObject
    177. ; ---------------------------------------------------------------------------
    178. ; sub_5E50:
    179. Obj19_Calc:
    180.         move.b    $26(a0),d0
    181.         bsr.w    CalcSine
    182.         move.w    d0,d2
    183.         muls.w    #$38,d2
    184.         asr.l    #8,d2
    185.         add.w    d2,$14(a0)
    186.         muls.w    $14(a0),d1
    187.         asr.l    #8,d1
    188.         move.w    d1,$10(a0)
    189.         muls.w    $14(a0),d0
    190.         asr.l    #8,d0
    191.         move.w    d0,$12(a0)
    192.         rts
    The rolling ball code ported to Sonic 1 Final! Still not sure what causes it to float when stood on, unless someone decides to provide a explanation.
     
  12. Inferno

    Inferno

    Member
    36
    71
    18
    Sonic 1 Definitive
    I actually believe I can explain the floating.

    The status flag for Sonic standing on the object is the same as the one used by Sonic for if he isn't on the ground but shouldn't fall. Since this reuses routines from Sonic's collision, it sees that status bit 3 of the object is set, and then triggers that very behavior, causing the ball to float.

    The primary ways to avoid this is to either make the ball jump to labels in that code which avoids the checks for bit 3, OR make new variants of those routines which remove the checks which are only relevant to the player character.
     
    • Like Like x 5
    • Informative Informative x 2
    • List
  13. Kilo

    Kilo

    Deathly afraid of the YM2612 Tech Member
    926
    932
    93
    Canada
    Sonic 1 Source Code Recreation + Source Code Wiki Page
    The ClearScreen routine is broken. One of the functions is intended to clear the H-scroll buffer, from $CC00 to $CFFF. It does this by loading the H-scroll buffer into a1, and then moving longword 0 into it, and increment. However, the amount of times it was meant to loop was set too high and actually goes into the SST space. It ends up clearing up to $D004. This is unnoticeable mid game since ClearScreen is never ran mid-game (Logically)
    To fix this, go to loc_133A and change
    Code (Text):
    1. move.w    #$100,d1
    to
    Code (Text):
    1. move.w    #$FF,d1
    This probably happened because Naka forgot that dbf loops one more time than you actually set it.
     
  14. Rrose80149

    Rrose80149

    Member
    92
    19
    8
    I think you're wrong. it was in the DeformBgLayer label.
    You have to change the tst.b to clr.w to solve the drown bug problem.
     
  15. Inferno

    Inferno

    Member
    36
    71
    18
    Sonic 1 Definitive
    Uh.... that's not how this works! If you change that, you'll change the code flow at some point to be beyond what was intended! tst.b checks if the byte is 0, and uses that for a conditional branch! clr.w sets a WHOLE WORD to 0!

    Also, Iso's not incorrect here. The issue is with that RAM address not being cleared when entering the title screen. Their solution is the more logical one.
     
  16. Inferno

    Inferno

    Member
    36
    71
    18
    Sonic 1 Definitive
    Ok, I'll actually supply the code change to make.

    Change this:
    Code (Text):
    1. jsr    (Sonic_AnglePos).l
    Into this:
    Code (Text):
    1. jsr    (loc_14602).l
    Skips the check.
     
  17. Brainulator

    Brainulator

    Regular garden-variety member Member
    I'm curious: with respect to this post (content abridged and linked for clarity):
    What are these bugs? I've been meaning to fix the display-before-delete series of bugs, but have hesitated for many of them (mainly those involving modifying the stack pointer), not knowing which ones are safe and which ones are not.
     
  18. Clownacy

    Clownacy

    Tech Member
    1,096
    676
    93
    I can't say for sure, but I imagine I edited the post to fix those bugs when I found them.
     
  19. Brainulator

    Brainulator

    Regular garden-variety member Member
    Hmm... it seems one archive I found differs in how objects 2E and 4C/4D are fixed. Such edits are of course obscured thanks to the new forum software, but at least it seems like the current guide should be bug-free. Thanks for the heads up.