don't click here

Basic Questions & Answers thread

Discussion in 'Engineering & Reverse Engineering' started by Tweaker, May 29, 2008.

  1. WBilgini


    What Member
    Edited the page!'s_Sound_Driver_to_Sonic_2 Is this good or not? I don't know if this is the right place to post this but... yeah.

    Anyways, here is a question I have: how can I make Tails fly like Sonic 3 in Sonic 2? By that I mean, in Tails Alone, if you double-tap a jump button, Tails will fly in Sonic 3. Also, in Sonic & Tails, if you hold up and double-tap the jump button as Sonic, Tails CPU will carry you. How can I implement that? I don't want to switch to Sonic 3.
    Last edited by a moderator: Apr 5, 2022
  2. Overlord


    Now playable in Smash Bros Ultimate Moderator
    Long-term happiness
    Don't double-post, please.
  3. WBilgini


    What Member
    Asking questions again, can I remove the 2P mode from my hack? I don't really need it and it's just taking space for me.
  4. Cokie


    C. Okie Member
    In Sonic 3 and Knuckles, is Dynamic_object_RAM_end the start address of the last slot in dynamic or the first byte AFTER all of
    dynamic object ram?
    I ask for several reasons. Create_New_Sprite looks for an available slot as the counter goes from 89 to 0.

    It looks through 90 slots starting at the SECOND SLOT (lea next_object(a1),a1 ). If it couldnt find any the counter will

    decrement to -1 and rts.... Because it starts at the second slot, it will try to find the slot at Dynamic_object_RAM_end

    if the preceeding 89 slots are being used. Does this mean that this is the last slot and NOT
    right after the end of dynamic object ram? Why does Create_New_Sprite start searching at the second slot?



    lea (Dynamic_object_RAM).w,a1

    moveq #((Dynamic_object_RAM_end-Dynamic_object_RAM)/object_size)-1,d0

    bra.s loc_1BB0A


    lea next_object(a1),a1

    tst.l (a1)

    dbeq d0,loc_1BB0A



    Now the skdisasm equates state dynamic object ram has 90 slots, each 0x4A byte. By that, definiton, the first slot starts at Dynamic_object_RAM

    and last slot is the 0x4A bytes before Dynamic_object_RAM_end. Which is contrst to the above. Also, Level_object_RAM starts at Dynamic_object_RAM_end.

    Why is this seem different. By this, it appears Dynamic_object_RAM_end is after dynamic object ram and is some unknown 0X4a bytes for Level.

    FFFFB0DE : Dynamic_object_RAM ds.b object_size*90 ; $1A04 bytes ; 90 objects

    FFFFCAE2 : =$FFFFFFFFFFFFCAE2 Dynamic_object_RAM_end = *

    FFFFCAE2 : =$FFFFFFFFFFFFCAE2 Level_object_RAM = Dynamic_object_RAM_end ; $4EA bytes ; various fixed in-level objects

    FFFFCAE2 : ds.b object_size ; unknown
  5. resolved.
    Last edited: Jun 2, 2022
  6. Hitaxas


    Retro 80's themed Twitch streamer ( on hiatus) Member
    Question. What is the purpose of this specific invisible solid object in EHZ 1? I made some changes to a subroutine of SlopeObject in an effort to get character abillities to function on bridges and platforms, but in doing so, coming into contact with this specific subtype of Obj74 seems to crash the game. Removing it does some funky stuff to the level collision...

  7. MainMemory


    Kate the Wolf Tech Member
    Looks like it's just a regular invisible wall to me? It only exists in KiS2, so maybe it's there to stop you from climbing up into the spring? No idea why removing it would affect the collision otherwise though, it's a solid wall/floor anyways.
  8. Hitaxas


    Retro 80's themed Twitch streamer ( on hiatus) Member
    Strange. Removing it causes an issue at the next loop on the top path, causing characters to fall through the floor, as if a plane swapper was interacted with. But I didn't change the original object layout aside from that one solid object. Basically, somehow collision path is being changed to 2.

    Edit: I fully restored the original object layout (I.E without any new objects), and now it the problem seems to have disappeared. Unsure what caused it.
    Last edited: May 20, 2022
  9. Cokie


    C. Okie Member
    036A0C1A-1637-4019-B97E-52A013A47B22.png I wanted to confirm I understand correctly how the Camera catches up vertically, as sonic jumps. Below is Sonic 2's ScrollVerti
    code section that does such

    ; If Sonic's in the air, he has $20 pixels above and below him to move without disturbing the camera.
    ; The camera movement is also only capped at $10 pixels.
    addi.w #$20,d0
    sub.w d3,d0
    bcs.s .doScroll_fast ; If Sonic is above the boundary, scroll to catch up to him
    subi.w #$40,d0
    bcc.s .doScroll_fast ; If Sonic is below the boundary, scroll to catch up to him
    tst.b (Camera_Max_Y_Pos_Changing).w ; is the max Y pos changing?
    bne.s .scrollUpOrDown_maxYPosChanging ; if it is, branch
    bra.s .doNotScroll

    I made a diagram illustrating hopefully correctly what it does. Here is a reference to what each color line represents:

    green playery - cameray ( - 5 if sonic is rolling )
    black = plus 0x20
    blue = Camera_Y_pos_bias
    magenta = minus 0x40

    the red boxes represent sonic . I messed up making his origin at top left it should be his middle ^.^

    If sonic's Y is in the yellow rectangle region, Sonic is above the boundary ie:
    bcs.s .doScroll_fast ; If Sonic is above the boundary, scroll to catch up to him

    If sinc's Y is in the cyan rectangle region, Sonic is below the boundary ie:
    bcc.s .doScroll_fast ; If Sonic is below the boundary, scroll to catch up to him

    the green and blue rectangles represent that If Sonic's in the air, he has $20 pixels above and below him to move without disturbing the camera.

    Am I understanding this code correctly. Thank you and look forward to feedback
  10. Xiao Hayes

    Xiao Hayes

    Classic Eggman art Member
    The Sonic physics guide on this site explains it quite well now thanks to lapper's & co. recent hard work, I checked it out the other day and it was quite comprehensive.
  11. XPointZPoint


    That's no good! Member
    I'm working on a ROM hack and I ported Sonic's S1 pallet to Sonic 2. But every time I load up a level, the title card's pallet is all messed up!

    What's even weirder is when the level finishes up loading, the normal pallet loads in!

    What did I do wrong? (i used SonMapEd to port the pallet.)
  12. Cokie


    C. Okie Member
    Thank you I checked physics guide and either I am incorrect in my understanding of how the camera y catches up or I misunderstand that guide confirms it . I’ll clarify in a little while.
    Last edited: May 29, 2022
  13. I am trying to apply this guide to the current version of the Sonic 2 GitHub disassembly, but I've run into a bit of a problem. The tutorial is for an older version that had the size of bytes to transfer hard-coded:

    Code (Text):
    1. moveq   #$15,d0 ; Corrected to #$E in the tutorial
    The current disassembly uses a macro that I assume automatically calculates the size of the transfer based on the size of the PLC_Buffer as set in the constants include:

    Code (Text):
    1. moveq   #bytesToLcnt(Plc_Buffer_Only_End-Plc_Buffer-6),d0
    I tried simply swapping the macro call in place of the tutorial's hardcoded $E like this:
    Code (Text):
    2. ProcessDPLC_Pop:
    3.     lea (Plc_Buffer).w,a0
    4.     lea 6(a0),a1
    5.     moveq   #bytesToLcnt(Plc_Buffer_Only_End-Plc_Buffer-6),d0
    6. -   move.l  (a1)+,(a0)+
    7.     move.w  (a1)+,(a0)+
    8.     dbf d0,-
    9.     moveq   #0,d0
    10.     move.l  d0,(a0)+    ; clear the last cue to avoid overcopying it
    11.     move.w  d0,(a0)+    ;
    12.     rts
    However, it resulted in the game crashing with an illegal instruction exception about two seconds into a level (screenshot of the crash report is attached). Is there something else I need to change here to make it work? (I do suspect the "lea 6(a0),a1" may be a hardcoded value that needs to change, but I am not certain.)

    Attached Files:

  14. Brainulator


    Regular garden-variety member Member
    bytesToLcnt is equal to the value divided by 4, then subtracted by 1. What you should do is either set that moveq directly to $E or, preferably, do this:
    Code (Text):
    1. moveq   #(Plc_Buffer_Only_End-Plc_Buffer-6)/6-1,d0
    The 6 value only needs to change if you change the PLC format in the game itself.
  15. Thank you. I'm very new to programming in general, so I was unable to determine exactly what operation that macro performed. I did indeed set it manually to $E as a workaround, but I knew there had to be a way to retain the dynamic value. :>
  16. Brainulator


    Regular garden-variety member Member
    It should be noted that many of these values and macros can be found in s2.constants.asm and s2.macros.asm in the current disassembly.
  17. Dulappy


    koronesuki Member
    I have a question about the sprite rotation differences between the Genesis titles and Sonic Mania.

    I've noticed that there's a big difference in how the rotation "timing" is handled. Let me show you what I mean:

    Here's an obvious one.

    In Mania, Sonic does not rotate at all when going up this slope in Green Hill Act 1:

    However, he rotates in both vanilla Sonic 1:

    and Sonic 1 Smooth Edition (where he rotates all over the place anyway, due to how the Classic rotating system works):

    This is a weird one.

    In Sonic Mania, going up this loop does not rotate Sonic as soon as his angle changes. Instead, he suddenly turns 45 degrees at some point, after which he almost instantly falls off:

    For comparison, here's Sonic 1 Smooth Edition:

    And here's vanilla Sonic 1, where he seems to turn 45 degrees somewhat lower than he does in Mania:

    I have also noticed the same behavior occurs on Chemical Plant Zone's pipes.

    Then we have this, which is by far the weirdest one.

    On this part of the loop in Mania, Sonic seemingly turns at the same time he does in Sonic 1:


    Also, here's a funny bug that I assume is caused by odd collision:

    Overall, the differences are quite baffling to me, so if anyone knows how the rotation system works in Mania, I'd love it if they could explain it here.
  18. Having an issue with another tutorial that I'm trying to apply. I'm attempting to apply this optimization to Sonic 1, which requires a new variable (which I've equated to $FFFFFED0) that must be cleared every time the ring counter is reset.

    Code (Text):
    2.     moveq   #0,d0
    3.     move.w  d0,(v_rings).w   ; clear rings
    4.     move.w  #100,(ring_1up_limit).w ; <------- reset ring 1-up limit to 100
    5.     move.l   d0,(v_time).w   ; clear time
    6.     move.l   d0,(v_score).w   ; clear score
    Unfortunately, the instances of this that are required in Lev_Sel_LevelSS and PlayLevel routines result in an "illegal value" build error in the former:

    Code (Text):
    2. LevSel_Level_SS:
    3.        add.w   d0,d0
    4.        move.w   LevSel_Ptrs(pc,d0.w),d0 ; Inserting either of the indicated lines below results in an "Illegal Value" build error at this location
    5.        bmi.w   LevelSelect
    6.        cmpi.w   #id_SS*$100,d0   ; check   if level is 0700 (Special Stage)
    7.        bne.s   LevSel_Level   ; if not, branch
    8.        move.b   #id_Special,(v_gamemode).w ; set screen mode to $10 (Special Stage)
    9.        clr.w   (v_zone).w   ; clear   level
    10.        move.b   #3,(v_lives).w   ; set lives to 3
    11.        moveq   #0,d0
    12.        move.w   d0,(v_rings).w   ; clear rings
    13.        move.w  #100,(ring_1up_limit).w ; <-------
    14.        move.l   d0,(v_time).w   ; clear time
    15.        move.l   d0,(v_score).w   ; clear score
    16. ...
    18. PlayLevel:
    19.        move.b   #id_Level,(v_gamemode).w ; set screen mode to $0C (level)
    20.        move.b   #3,(v_lives).w   ; set lives to 3
    21.        moveq   #0,d0
    22.        move.w   d0,(v_rings).w   ; clear rings
    23.        move.w  #100,(ring_1up_limit).w ; <-------
    24.        move.l   d0,(v_time).w   ; clear time
    25.        move.l   d0,(v_score).w   ; clear score
    26. ...
    I unfortunately have no clue what could be going on. Any ideas?
  19. Dulappy


    koronesuki Member
    From my understanding, what's happening here is:

    By inserting any of those lines between
    Code (Text):
    1. move.w   LevSel_Ptrs(pc,d0.w),d0
    and the table it's referencing, you're barely placing LevSel_Ptrs outside of the program counter (pc)'s reach, which is 128 bytes.

    To fix this, all you have to do is load LevSel_Ptrs into an unused address register. I'll use a0 in this example.

    Replace this:
    Code (Text):
    1.        move.w   LevSel_Ptrs(pc,d0.w),d0
    With this:
    Code (Text):
    1.         lea (LevSel_Ptrs).l,a0
    2.         move.w    (a0,d0.w),d0
    It should work now.
  20. (removed)

    Attached Files:

    Last edited: Jun 4, 2022