don't click here

Some changes and fixes for Sonic 2

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

  1. jasonchrist

    jasonchrist

    Give Us A Wank Banned
    1,893
    0
    0
    Sonic Classic Hybrid Project
    Know what Sonic 2 needs? A bad ending.
     
  2. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber

    This is probably the best/funniest bug in the whole game. It always made me laugh when Tails would just move left and right in his "waiting" animation, just yawning =P


    Either way, nice fix. I will apply this one!
     
  3. Esrael

    Esrael

    Neto Tech Member
    304
    257
    63
    Brazil, São Paulo, Guarulhos
    Neto Assembler Editor / Sonic 2 Delta / Neto MD-DOS
    Browsing in to How-tos I have found one which need be some fixes:
    SCHG How-to:Retain Rings when returning at a Star Post
    If you use this feature and had 100 or 200 rings which already gives 2 lifes and enter to Special Stage after returning you will be awarded with 2 lifes again.

    If you want this does not occur you will need comment or remove the next line after

    Code (ASM):
    1.  
    2. ; continue from a starpost / load checkpoint
    3. ; loc_1F35E:
    4. Obj79_LoadData:
    5.         ......
    6.     clr.w   (Ring_count).w       ; <---- This lines was commented or deleted by guide.
    7.     clr.b   (Extra_life_flags).w ; <---- Comment or Delete this line too if don't want rewarded after returning from Special Stage.
    8.  



    If you want something like Retain rings only when entering on Special Stage and not after death.
    First create a new variable -> $FFFFF100 to $FFFFF5FF is safe since is not used in Sonic 2.
    Ex:
    Bonus_Stage_Flag equ $FFFFF48E ; Sonic 2 Delta Bonus Flag as Example
    You can use other variable name and other free Ram Address.

    Setting the new variable when entering on Special Stage from Star Post:
    Insert "move.b #01, (Bonus_Stage_Flag).w in the following routine:
    Code (ASM):
    1.  
    2. ; loc_1F536:
    3. Obj79_Star:
    4.     move.b  collision_property(a0),d0
    5.     beq.w   loc_1F554
    6.     andi.b  #1,d0
    7.     beq.s   +
    8.     move.b  #1,($FFFFF7CD).w
    9.     move.b  #$10,(Game_Mode).w ; => SpecialStage
    10.         move.b  #01, (Bonus_Stage_Flag).w   ; <----- Insert this line to initialize our new variable
    11. +
    12.     clr.b   collision_property(a0)
    13.  
    and make the following chages into:

    Code (ASM):
    1.  
    2. Obj79_LoadData:
    3.     move.b  (Saved_Last_star_pole_hit).w,(Last_star_pole_hit).w
    4.     move.w  (Saved_x_pos).w,(MainCharacter+x_pos).w
    5.     move.w  (Saved_y_pos).w,(MainCharacter+y_pos).w                  
    6.     move.w  (Saved_Ring_count).w,(Ring_count).w
    7.     move.b  (Saved_Extra_life_flags).w,(Extra_life_flags).w
    8.  
    9.         tst.b   (Bonus_Stage_Flag).w   ; <----- Insert this line                
    10.         bne.s   Exit_Bonus_Stage     ; <----- Insert this line  
    11.  
    12.     clr.w   (Ring_count).w
    13.     clr.b   (Extra_life_flags).w
    14.  
    15. Exit_Bonus_Stage:                    ; <----- Insert this line  
    16.         clr.b   (Bonus_Stage_Flag).w   ; <----- Insert this line  
    17.  
    18.     move.l  (Saved_Timer).w,(Timer).w
    19.     move.b  #59,(Timer_centisecond).w
    20.  
    Done, now your rings will be retained if you are returning from Special Stage.
    Is recommended to clear the variable before loading new level.
     
  4. Machenstein

    Machenstein

    Member
    830
    0
    0
    It's about time the bugs in Sonic 2 got squashed. While you guys are updating the wiki, how about adding this to the guide. Just credit vladikcomper since he was the one who wrote the instructions I posted.

    Is there a way to fix how Super Sonic falls through the floor in Metropolis Zone after using a transporter while holding left or right?
     
  5. MoDule

    MoDule

    Tech Member
    327
    24
    18
    Procrastinating from writing bug-fix guides
    Like I said earlier, it probably wouldn't be good performance-wise to check every object each frame, but there's another way to get around this problem:

    Fix collisions with the lava collision maker object

    The Bug:
    The way object collisions work, it's impossible to collide with two objects at once unless the object itself does the collision checks. That's what we're going to do here.

    The Fix:
    We're going to be editing object 31, the lava collision maker. First locate the label Obj31_Init (loc_20E02):
    Code (ASM):
    1. ; byte_20DFE:
    2. Obj31_CollisionFlagsBySubtype:
    3.     dc.b $96    ; 0
    4.     dc.b $94    ; 1
    5.     dc.b $95    ; 2
    6.     dc.b   0    ; 3
    7. ; ===========================================================================
    8. ; loc_20E02:
    9. Obj31_Init:
    10.     addq.b  #2,routine(a0) ; => Obj31_Main
    11.     moveq   #0,d0
    12.     move.b  subtype(a0),d0
    13.     move.b  Obj31_CollisionFlagsBySubtype(pc,d0.w),collision_flags(a0)  ; <-------
    14.     move.l  #Obj31_MapUnc_20E6C,mappings(a0)
    15.     tst.w   (Debug_placement_mode).w
    16.     beq.s   +
    17.     move.l  #Obj31_MapUnc_20E74,mappings(a0)
    18. +
    19.     move.w  #make_art_tile(ArtTile_ArtNem_Powerups,0,1),art_tile(a0)
    20.     move.b  #$84,render_flags(a0)
    21.     move.b  #$80,width_pixels(a0)
    22.     move.b  #4,priority(a0)
    23.     move.b  subtype(a0),mapping_frame(a0)
    Now, we replace the data table Obj31_CollisionFlagsBySubtype and the line that uses it with the following:
    Code (ASM):
    1. Obj31_Widths:
    2.     dc.b $20    ; 0
    3.     dc.b $40    ; 1
    4.     dc.b $80    ; 2
    5.     dc.b   4    ; 3
    6. ; ===========================================================================
    7.  
    8.     (...)
    9.     move.b  Obj31_Widths(pc,d0.w),x_radius(a0)
    Next, we need to add our own collision check. Here's the routine, place it anywhere close to the object's code. I put it between Obj31_Main and the object's mappings.
    Code (ASM):
    1. Obj31_TestCollisions:
    2.     lea (MainCharacter).w,a1
    3.     bsr.s   +
    4.     lea (Sidekick).w,a1
    5. +
    6.     ; test horizontal
    7.     moveq   #0,d1
    8.     move.b  x_radius(a0),d1
    9.     ; left edge
    10.     move.w  x_pos(a1),d0
    11.     sub.w   x_pos(a0),d0
    12.     add.w   d1,d0
    13.     bmi.s   Obj31_NoCollision
    14.     ; right edge
    15.     add.w   d1,d1
    16.     cmp.w   d1,d0
    17.     bcc.s   Obj31_NoCollision
    18.     ; test vertical
    19.     moveq   #$20,d1 ; we assume a constant y_radius of 32 pixels
    20.     add.b   y_radius(a1),d1
    21.     ; top edge
    22.     move.w  y_pos(a1),d0
    23.     sub.w   y_pos(a0),d0
    24.     add.w   d1,d0
    25.     bmi.s   Obj31_NoCollision
    26.     ; bottom edge
    27.     add.w   d1,d1
    28.     cmp.w   d1,d0
    29.     bcc.s   Obj31_NoCollision
    30.     ; hurt player
    31.     move.l  a0,-(sp)    ; save object address
    32.     exg a0,a1       ; switch object and player addresses
    33.     jsr Touch_ChkHurt
    34.     movea.l (sp)+,a0 ; load 0bj address
    35.  
    36. Obj31_NoCollision:
    37.     rts
    38. ; ===========================================================================
    Now we need the object to call this routine. Right after the label Obj31_Main, add this:
    Code (ASM):
    1.     tst.w   (Debug_placement_mode).w
    2.     bne.s   +       ; skip collision checks if in object placement mode mode
    3.     bsr.s   Obj31_TestCollisions
    4. +
    Done.

    Now, I'm no expert on coding bounding box checks, so if someone can come up with a better collision checking routine that uses less cycles, post away. This does have the potential to slow the game down a little, so every little bit helps.
    What really helps is s3k's collision checking routine. Instead of going through the entire object list, it only checks objects that add themselves to a specific list. This means objects that have no collisions or ones that do the checks themselves will be skipped.
    The fix for the ARZ leaf makers should work the same way, but I'd need to check first to be sure.
     
  6. RetroKoH

    RetroKoH

    Member
    1,662
    22
    18
    Project Sonic 8x16
    I've used your Super Sonic fix, and will place this in Design Choices: http://info.sonicret...vior_in_Sonic_2
    I only put in what I used for adding this, and have added the fix for the WFZ glitch by RHS.

    Secondly, ask flamewing about your Super Sonic fix. I recall him mentioning this bug in particular at some point. I know he knows how to do it.
     
  7. RetroKoH

    RetroKoH

    Member
    1,662
    22
    18
    Project Sonic 8x16
    Could this also be applied to the CNZ blue blocks? Or is that a different bug? (I question because in S2K I climbed onto a wall and let a blue block move into me sideways, and it did nothing.)
    That is a fix I'd like to see, as would anyone with custom CNZ layouts.
     
  8. MoDule

    MoDule

    Tech Member
    327
    24
    18
    Procrastinating from writing bug-fix guides
    That would be object solidity, which is something different altogether. There's a whole bunch of problems with this that I'd like to see fixed, too.
     
  9. RetroKoH

    RetroKoH

    Member
    1,662
    22
    18
    Project Sonic 8x16
    http://info.sonicret...fect_in_Sonic_2 - Porting the LZ water ripple effect into Sonic 2.
    http://info.sonicretro.org/SCHG_How-to:Port_S3K_Object_Manager_into_Sonic_2 - Porting S3K Object Manager

    Hey MoDule! I did a little digging, after putting together the rhs SST guide, and found these two gems... I am adding them to the SCHG, as they are quite worthy... and its a crime that they never got put up.

    I simply copy and pasted these... I don't have much time to really look too much into them at the moment, so unless anyone else can edit wiki pages, what you see is what you get until I return.

    These guides are old though, and need to be fixed up. I possess no such skills to do so, but perhaps if anyone (I'm looking at you Esrael, RHS or MoDule) could fix them up, we can revive these guides and make them more serviceable for use.

    I might not be back for a little while... maybe later today or tomorrow, but after that I'm taking the weekend off. When I return, I would like to start some ground work on that Sonic 3 section of the SCHG I was crowing about a couple weeks back.
     
  10. RetroKoH

    RetroKoH

    Member
    1,662
    22
    18
    Project Sonic 8x16
    Watch this video walkthrough.
    Check out this YouTube video. Skip EVERYTHING up until 7:55, and watch Tails closely. You will notice a bug. When Tails flies past the cylinder, he goes into that animation. Has this been fixed in any revision/hack?

    Esrael, RHS, this sounds like a job for you two.
     
  11. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Mine will, on its next revision :v:/>

    To fix it, you need to add two checks: first go to Obj06_Spiral (loc_21512 for those who refuse to use a better disassembly). You will find this, or something like it:
    Code (ASM):
    1.     lea (MainCharacter).w,a1 ; a1=character
    2.     moveq   #p1_standing_bit,d6
    3.     bsr.s   +
    4.     lea (Sidekick).w,a1 ; a1=character
    5.     addq.b  #1,d6
    6. +
    Change it to this:
    Code (ASM):
    1.     lea (MainCharacter).w,a1 ; a1=character
    2.     moveq   #p1_standing_bit,d6
    3.     bsr.s   +
    4.     lea (Sidekick).w,a1 ; a1=character
    5.     addq.b  #1,d6
    6.     cmpi.w  #4,(Tails_CPU_routine).w
    7.     bgt.s   +
    8.     rts
    9. +
    Then scan down to Obj06_Cylinder (loc_21808). There will be similar code (except for two extra lines loading addresses to a2), do the same changes.

    The first case deals with EHZ spiral pathways; the second case deals with the cylinder in MTZ.

    Edit: added quote due to page break.
     
  12. RetroKoH

    RetroKoH

    Member
    1,662
    22
    18
    Project Sonic 8x16
    On this note, how about the Tails CNZ sliding glitch? I'm assuming this is a related bug (Somethig to do with the "pinball mode" object, I suspect?
     
  13. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber

    Module has already explained how to fix this glitch in this very topic. The post is here.
     
  14. RetroKoH

    RetroKoH

    Member
    1,662
    22
    18
    Project Sonic 8x16
    Ahh... oops. I guess I can wiki this one later today then. :D I'll include the other two above mentioned bugs with it since they sorta involve the same thing happening.
     
  15. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    I made a seperate topic at first for these bugs because it includes Sonic 1. But as this topic is all about Sonic 2 bugs, I thought I'd might as well post a snip-it from it to here.










     
  16. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber

    KingofHarts wanted to know the answer to this question. I actually always wanted this to be fixed, but never bothered looking. But as someone else wants to know the answer, I thought I'll investigate. And I've come up with a fix! For Sonic 2 and Sonic 3K. If you want the fix for S3K, click here. Sonic 2 fixes and explanation, continue reading.






    Sonic 2 fix - XenoWhirl's Disassembly


    Go to "sub_D77A:" and change this:

    Code (ASM):
    1. sub_D77A:
    2.     moveq   #0,d1
    3.     move.w  y_pos(a0),d0
    4.     sub.w   (a1),d0
    5.     cmpi.w  #-$100,(Camera_Min_Y_pos).w
    6.     bne.s   loc_D78E
    7.     andi.w  #$7FF,d0

    to this:

    Code (ASM):
    1. sub_D77A:
    2.     moveq   #0,d1
    3.     move.w  y_pos(a0),d0
    4.     sub.w   (a1),d0
    5.     tst.w   (Camera_Min_Y_pos).w        ; Does this level y-wrap?
    6.     bpl.s   loc_D78E            ; If not, branch and skip looping
    7.     cmpi.w  #$60,(Camera_Y_pos_bias).w  ; Is screen in its default position?
    8.     beq.s   +               ; If so, branch, and loop
    9.     ; It's not at its default position; Sonic must be looking up or down
    10.     tst.w   (Sonic_Look_delay_counter).w    ; Is Sonic still looking up or down?
    11.     bne.s   +               ; If so, branch, and keep looping, Sonic ain't moving anywhere!
    12.     ; So, Sonic was looking up or down, but now he isn't
    13.     move.w  #$60,(Camera_Y_pos_bias).w  ; move the screen to its default position quickly
    14. +  
    15.     andi.w  #$7FF,d0            ; Forever loop
    Done, explanation further below after the SVN disassembly fixes.






    Sonic 2 fix - SVN disassembly


    Go to "ScrollVerti:" and change this:

    Code (ASM):
    1. ScrollVerti:
    2.     moveq   #0,d1
    3.     move.w  y_pos(a0),d0
    4.     sub.w   (a1),d0     ; subtract camera Y pos
    5.     cmpi.w  #-$100,(Camera_Min_Y_pos).w ; does the level wrap vertically?
    6.     bne.s   +       ; if not, branch
    7.     andi.w  #$7FF,d0

    to this:

    Code (ASM):
    1. ScrollVerti:
    2.     moveq   #0,d1
    3.     move.w  y_pos(a0),d0
    4.     sub.w   (a1),d0     ; subtract camera Y pos
    5.     tst.w   (Camera_Min_Y_pos).w        ; Does this level y-wrap?
    6.     bpl.s   ++              ; If not, branch and skip looping
    7.     cmpi.w  #$60,(Camera_Y_pos_bias).w  ; Is screen in its default position?
    8.     beq.s   +               ; If so, branch, and loop
    9.     ; It's not at its default position; Sonic must be looking up or down
    10.     tst.w   (Sonic_Look_delay_counter).w    ; Is Sonic still looking up or down?
    11.     bne.s   +               ; If so, branch, and keep looping, Sonic ain't moving anywhere!
    12.     ; So, Sonic was looking up or down, but now he isn't
    13.     move.w  #$60,(Camera_Y_pos_bias).w  ; move the screen to its default position quickly
    14. +
    15.     andi.w  #$7FF,d0            ; Forever loop
    Done.






    Explanation, using Xenowhirls as a guide



    What originally happened is that when the camera scrolled down, then Sonic immediately jumps, He jumps "above" the camera. Because the game is forever-ing and'ing Sonic's y_pos, the camera then thinks that Sonic is all the way at the bottom! So it scrolls down for ages until it sees Sonic. The level has to let Sonic always "and" his y_pos otherwise when Sonic reaches the y-wrap, he will die and not cross it.


    Code (ASM):
    1.     tst.w   (Camera_Min_Y_pos).w        ; Does this level y-wrap?
    2.     bpl.s   loc_D78E            ; If not, branch and skip looping
    All this has done has replaced the "cmpi.w #-$100,(Camera_Min_Y_pos).w". The reason why is because tst'ing it is slightly quicker. You do not have to change it, but it's recommended.

    Anyway, it's asking if the level y-wraps. If not, skip all this code. Sonic doesn't need to cross the y-wrap because there isn't one, so we can leave his position alone.

    If it is a y-wrap level, it will NOT branch, and continue with the coding. Originally, it would just "and" Sonic's y_pos so he can cross the y-wrap, but we have a bug to fix!


    Code (ASM):
    1.     cmpi.w  #$60,(Camera_Y_pos_bias).w  ; Is screen in its default position?
    2.     beq.s   +               ; If so, branch, and loop

    When Sonic is not looking up or down, the "Camera_Y_pos_bias" is always at 60. So, is it at 60? If so, branch and loop Sonic's y_pos. So he can still cross the y-wrap. If NOT 60, then do NOT branch, and continue on to the next command.


    Code (ASM):
    1.     tst.w   (Sonic_Look_delay_counter).w    ; Is Sonic still looking up or down?
    2.     bne.s   +               ; If so, branch, and keep looping, Sonic ain't moving anywhere!

    This is needed. Elsewhere (in Sonic's code specifically) when Sonic is looking up or down, this has its RAM address added by 1. When it equals 78, the camera will stop moving. As soon as you let go of the up or down button, the RAM address gets cleared.


    Anyway, the reason why we need it here is because if Sonic is close to the y-wrap, the looking can go wrong. If you hold down, the camera will scroll up, if you hold up, the camera will still scroll up. Why? The camera thinks Sonic is miles away again. This only happens when the camera is at $7A0 or more.

    The reason why, is because Sonic has crossed the y-wrap, but the camera itself hasn't. Say, Sonic fell and crossed the y-wrap, and got to y_pos $C, the camera will be at $7AC. So, the camera thinks its miles below! So, hold up or down, it will scroll.

    The only way to get round this is to make Sonic's y_pos "and" itself again. So, when you hold up or down and make the camera scroll, "Sonic_Look_delay_counter" will not be 0, so it will branch and "and" Sonic's y_pos. As soon as you let go, "Sonic_Look_delay_counter" will be cleared, so it will no longer branch to "and" Sonic's y_pos! So, it only leaves us with one more command.

    Code (ASM):
    1. move.w  #$60,(Camera_Y_pos_bias).w  ; move the screen to its default position quickly
    This will move the camera back to normal extremely quickly. So quickly, that Sonic has NO chance of pulling that glitch off again.



    So what we have here now, is if you're on a level that does NOT y-wrap, nothing will be changed. Everything will still be normal. And you cannot pull this glitch off in non-y-wrap levels (to my knowledge). After looking up or down, the camera will still scroll back to normal at normal speeds.

    If you're on a y-wrap level, the camera will now scroll back so quickly, you cannot pull the glitch off. I got so close to the y-wrap, Sonic was actually at y_pos $0. 1 pixel away from crossing the y-wrap. I then tried pulling this glitch off then, and it didn't happen. Camera is too fast. It's definitely impossible to do this glitch now.


    Ta-dah!
     
  17. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Reposting what I posted over at the Q&A thread:

    For S2 at least, there is a better way to fix that bug: in ScrollVerti, find this:
    Code (Text):
    1. ScrollVerti:
    2.     moveq    #0,d1
    3.     move.w  y_pos(a0),d0
    4.     sub.w   (a1),d0     ; subtract camera Y pos
    5.     cmpi.w  #-$100,(Camera_Min_Y_pos).w ; does the level wrap vertically?
    6.     bne.s   +       ; if not, branch
    7.     andi.w  #$7FF,d0
    8. +
    and change it to this:
    Code (Text):
    1. ScrollVerti:
    2.     moveq    #0,d1
    3.     move.w  y_pos(a0),d0
    4.     sub.w   (a1),d0     ; subtract camera Y pos
    5.     cmpi.w  #-$100,(Camera_Min_Y_pos).w ; does the level wrap vertically?
    6.     bne.s   +       ; if not, branch
    7.     andi.w  #$7FF,d0
    8.     move.w  #$FC00,d1
    9.     add.w   d1,d0
    10.     eor.w   d1,d0
    11. +
    What this does is to convert the distance from the top of the screen from non-wrapping to wrapping; how it does that, I will let you guys figure out :v:

    (and yes, I know why; if someone figures out, I will confirm it)
     
  18. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    Smart-ass =P


    EDIT: Okay, I have an answer.


    Anyway, let's work this out. For this example, let's say Sonic is at y_pos $05EC.



    Code (ASM):
    1.     sub.w   (a1),d0             ; Minus Camera_Y_pos from d0

    When Sonic is at #$5EC, the camera is at #$58C.

    #$5EC - #$58C = #$60

    So d0 is now #$60.



    Code (ASM):
    1.     tst.w   (Camera_Min_Y_pos).w        ; Does this level y-wrap?
    2.     bpl.s   loc_D78E            ; If not, branch and skip looping

    Already explained. In y-wrap levels, the Camera_Min_Y_pos is always #-$100. In non-y-wrap levels, it's always #0 or more. So, is Camera_Min_Y_pos at #0 or more? If so, branch, it's not a y-wrap level. Otherwise, it must be less than #0, so it's obviously a y-wrap level.



    Code (ASM):
    1.     andi.w  #$7FF,d0            ; Loop Sonic's y_pos

    This is to make sure that d0 never goes past #$800. Otherwise, the camera will think Sonic will be miles high or below when Sonic crosses the y-wrap. So, let's take this into account. Let's change Sonic's current y_pos (#$0567) and #$7FF in question, into bits:

    Code (Text):
    1. #$07FF = 0000 0111 1111 1111
    2.  
    3. #$0060 = 0000 0000 0110 0000

    Because $7FF is a word, we will treat it as $07FF. Now, we put each of these bits on top of another, if the top is 0, then the bottom will be changed to a 0. If the top is 1, then the bottom will not change. And the result?

    Code (Text):
    1. #$07FF = 0000 0111 1111 1111
    2. #$0060 = 0000 0000 0110 0000
    3.          equals
    4. #$0060 = 0000 0000 0110 0000

    So, nothing changes. Basically, in #$07FF, the 0 will keep Sonic's y_pos first bit always at 0, and the 7 will always keep it as 7 or less (not letting it be 8 or more). Anything that is 8 or more will go to 0 or more instead. The F and the other F will never change anything.



    Code (ASM):
    1.     move.w  #$FC00,d1           ; Move #-$400 to d1

    d1 is now set at #-$400.



    Code (ASM):
    1.     add.w   d1,d0               ; Add d1 (#-$400) to d0

    Seeming as d0 is still #$60, with #-$400 added, d0 is now #$FC60.



    Code (ASM):
    1.     eor.w   d1,d0               ; Exclusive OR d0 with #-$400

    Let's change them into bits again.

    Code (Text):
    1. #$FC00 (#-$400) = 1111 1100 0000 0000
    2.  
    3. #$FC60 = 1111 1100 0110 0000

    Now, we put each of these bits on top of another, If the top is 0, then the bottom will not change. If the top is 1, then the bottom bit will reverse (0 becomes 1 and 1 becomes 0). And the result?

    Code (Text):
    1. #$FC00 = 1111 1100 0000 0000
    2. #$FC60 = 1111 1100 0110 0000
    3.          equals
    4. #$0060 = 0000 0000 0110 0000




    So basically, the EOR instruction is keeping the first byte at 00. If Sonic looks down fully, then immediately jumps, above the camera, his new y_pos will be in the FFXX's instead of 07XX's. That way, Sonic can never make it go to 07 like he used to. Because it's now at FF, he technically hasn't crossed the y-wrap, and the camera still thinks Sonic is close by, so everything is normal.


    Am I right?



    May I suggest though, wouldn't

    Code (ASM):
    1. eori.w  d1,d0

    be quicker than just "eor"?
     
  19. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Since the data is in a register, using eori won't make a difference -- the assembler will still convert it into an eor in the end.

    You are close, but you are wrong about the operation sequence keeping the top byte zero; what the sequence of operations does is this:
    Code (Text):
    1.     andi.w  #$7FF,d0        ; Discard bits above bit 10, including sign bit
    2.     move.w  #$FC00,d1   ; Move into register for speed
    3.     add.w   d1,d0       ; If bit 10 is set, bits 10-15 will be clear; if bit 10 was clear, bits 10-15 will be set
    4.     eor.w   d1,d0       ; Flip bits 10-15, so that they are set or clear according to what bit 10 was before the add
    So basically, it copies bit 10 to bits 11-15. So if bit 10 was set, the number becomes negative, while if bit 10 was clear, the number becomes positive; so bit 10 effectively becomes the sign bit. This means: a sign extension from bit 10.

    If you make the computation, the largest positive 10-bit number (bits 0-9 set, all else clear) is $3FF, while the largest negative 10-bit number is $FC00 = -$400. Both of these are half of the height of a wrapping level ($7FF) rounded down to -infinity.

    There is still the issue of why does this sign extension works. Simply put, it adds back the sign that the andi stripped. A distance higher than $3FF right after the andi represents a smaller distance on the other direction (a negative distance). Given the way numbers are stored (two's complement), the sign extension will do the work.
     
  20. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    That's what I meant by when he jumps above the camera, his new y_pos will be in the FFXX's instead of 07XX's. You just explained it in a lot more technical way =P


    Although, your way definitely works better. Ending result, it works the same way as mine except the camera can still move at it's original speed. And that's better, obviously.



    As for the eor thing, I learn something new everyday. I didn't know that, thanks for the tip.