don't click here

Basic Questions & Answers thread

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

  1. Super Egg

    Super Egg

    Master of MS Paint. Member
    313
    0
    16
    Tomball, TEXAS
    Sonic 2 beta 3 hoax
    Hey there, it's THE SuperEgg here. Ok kiddos, let's talk a bit about Sonic 2 proto compressions.

    S2NA and S2B use the same layout compression and format, which is no compression, and a layout format the same as Sonic 1's. The background and foregrounds are separate files.

    As far as S2B is concerned, the level art files are compressed as such:

    Tiles - Nemesis
    Blocks - uncompressed
    Chunks - Kosinski

    I don't remember S2NA off the top of my head, as I haven't touched S2NA in about 2 years, but I assume it's the same.

    Collisions in S2B is uncompressed.

    SonLVL does support S2B by extension, but I never released a public LVl file, as I've abandoned the disasm to make a custom engine with it, so I haven't bothered to advance anywhere with it. I suppose I could release a disasm will the the LVL files for it later if there is a big enough call for it.

    Last note to make, the "improved" disasm doesn't change file type compression for the sake of "byte perfection." It's "improved" because I either reorganized the file names, locations, split more data from the disasm, ect.
     
  2. AsuharaMoon

    AsuharaMoon

    kakyoin did you lay this egg Member
    30
    23
    8
    Buenos Aires, Argentina
    Sonic Rocket, & others
    How do I port Knuckles' top boundary block (while gliding and climbing) to Sonic 1 correctly? Just asking cuz' I give it several unsuccessful tries as far my knowledge can (being the main reason why I deactivated it in my Rouge in S1 hack).

    While its functionality works quite fine, it suddenly activates itself on random places:

    [​IMG]

    And it also rarely happened with Tails' S3 flight codes (needs beta-testing since I recently modified it), so I would be grateful if someone could check them.

    Here's the codes:
    Knuckles' boundary block while...

    ...gliding:
    [68k]
    kloc_315D68: ; blocks Knuckles at the upper part of the boundary while gliding
    cmpi.w #$102,($FFFFFE10).w ; is level LZ3 ?
    beq.w kreturn_315D9A ; if yes, return
    cmpi.w #$501,($FFFFFE10).w ; is level SBZ2 ?
    beq.w kreturn_315D9A ; if yes, return

    move.w (Camera_Min_Y_pos).w,d0 ; $FFFFF73C
    cmp.w #$FF00,d0
    beq.w kloc_315D88
    add.w #$10,d0
    cmp.w y_pos(a0),d0
    ble.w kloc_315D88
    asr x_vel(a0)
    asr inertia(a0)

    kloc_315D88: ; Camera_Y_pos_bias = $FFFFF73E
    cmpi.w #$60,(Camera_Y_pos_bias).w ; is screen in its default position?
    beq.s kreturn_315D9A ; if yes, branch
    bcc.s kloc_315D96
    addq.w #4,(Camera_Y_pos_bias).w ; move screen back to default

    kloc_315D96:
    subq.w #2,(Camera_Y_pos_bias).w ; move screen back to default

    kreturn_315D9A: ; ...
    rts
    [/68k]
    ...and climbing:
    [68k]
    kloc_315A54: ; blocks Knuckles at the upper part of the boundary while climbing
    moveq #1,d1
    cmpi.w #$102,($FFFFFE10).w ; is level LZ3 ?
    beq.w kloc_315A76 ; if yes, branch
    cmpi.w #$501,($FFFFFE10).w ; is level SBZ2 ?
    beq.w kloc_315A76 ; if yes, branch

    move.w (Camera_Min_Y_pos).w,d0 ; $FFFFF73C
    cmp.w #-$100,d0
    beq.w kloc_315B04
    add.w #$10,d0
    cmp.w y_pos(a0),d0
    ble.w kloc_315B04
    move.w d0,y_pos(a0)

    bra.w kloc_315B04
    [/68k]
    Tails' boundary block while flying:
    [68k]
    loc_14892: ; blocks Tails at the upper part of the boundary while flying
    cmpi.w #$102,($FFFFFE10).w ; is level LZ3 ?
    beq.w Tails_Set_Flying_Animation ; if yes, branch
    cmpi.w #$501,($FFFFFE10).w ; is level SBZ2 ?
    beq.w Tails_Set_Flying_Animation ; if yes, branch

    move.w (Camera_Min_Y_pos).w,d0
    addi.w #$10,d0
    cmp.w y_pos(a0),d0
    blt.s Tails_Set_Flying_Animation
    tst.w y_vel(a0)
    bpl.s Tails_Set_Flying_Animation
    move.w #0,y_vel(a0)
    [/68k]
     
  3. Nintorch

    Nintorch

    Just another programmer. Member
    44
    33
    18
    There are a lot actually..
    AsuharaMoon, check S1 ram editing page and you'll notice your Camera_Min_Y_pos isn't correct:
    So it should be:
     
  4. AsuharaMoon

    AsuharaMoon

    kakyoin did you lay this egg Member
    30
    23
    8
    Buenos Aires, Argentina
    Sonic Rocket, & others
    Huh, how did I overlook that one? I was just checking the same list!

    Thanks!
     
  5. Nintorch

    Nintorch

    Just another programmer. Member
    44
    33
    18
    There are a lot actually..
    No problem :)
     
  6. Nintorch

    Nintorch

    Just another programmer. Member
    44
    33
    18
    There are a lot actually..
    EDIT: Now I can solve my problem
     
  7. Zycor

    Zycor

    Unlike Sonic, I don't chuckle. Member
    195
    11
    18
    Beats me.
    I'm watching a lets play of Sonic 2 8-bit and I also tried playing it myself, has anyone looked into why sometimes you can go over 10 lives and sometimes you can't? Someone commented saying it depended on whether you picked up your 100th ring through a 10 ring TV or from a normal ring, I'm curious about this behavior. I didn't see anything mentioned on the Wiki. I've encountered some strange bugs playing Sonic 2 8 Bit and this one is curious because in Sonic 1 8-bit your life counter would go over 9 no problem and reflected it on the results screen, but in levels it would just show 9.
     
  8. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,200
    430
    63
    Japan
    I thought I'd have a look into this, so I disassembled the SEGA Master System version of Sonic 2.

    Now, for the record, I'm not 100% familiar with the Master System games, I've played them mind, but not enough to be familiar. But judging by the code I'm seeing, it looks to me like there is no cap for the lives counter at all, only for the display to remain at 9 if it's beyond 9. The lives counter itself may go beyond 9. Observe:

    Code (Text):
    1. ROM:25C3 IncreaseRings:                          ; CODE XREF: ROM:026Cj
    2. ROM:25C3                                         ; sub_7378+8Cj
    3. ROM:25C3                 ld      a, (RingsCounter) ; load rings counter
    4. ROM:25C6                 add     a, 1            ; increase by 1
    5. ROM:25C8                 daa                     ; adjust for decimal addition (this should wrap to 0 once it surpasses 99 decimal)
    6. ROM:25C9                 ld      (RingsCounter), a ; update rings counter
    7. ROM:25CC                 or      a               ; check the number of rings now
    8. ROM:25CD                 jr      nz, DisplayRings ; if it has NOT wrapped back to 0, branch (no lives updating)
    9. ROM:25CF                 ld      hl, 0D298h      ; Load lives counter address
    10. ROM:25D2                 inc     (hl)            ; Increase lives counter
    11. ROM:25D3                 call    DisplayLives    ; Cap it for display only and update
    12. ROM:25D6                 ld      a, 0A6h ; 'ª'
    13. ROM:25D8                 ld      (byte_DD04), a
    14. ROM:25D8 ; END OF FUNCTION CHUNK FOR sub_7378
    15. ROM:25DB
    16. ROM:25DB ; =============== S U B R O U T I N E =======================================
    17. ROM:25DB
    18. ROM:25DB
    19. ROM:25DB DisplayRings:                           ; CODE XREF: j_DisplayRingsj
    20. ROM:25DB                                         ; sub_30+96Ap ...
    21. ROM:25DB                 ld      a, (DemoFlag)   ; is the demo running?  (I "think" this is demo, the hud doesn't display during demo)
    22. ROM:25DE                 or      a
    23. ROM:25DF                 ret     nz              ; if demo is on, branch
    24. ROM:25E0                 ld      a, (byte_D295)
    25. ROM:25E3                 cp      6
    26. ROM:25E5                 jr      nz, loc_25ED
    27. ROM:25E7                 ld      a, (byte_D296)
    28. ROM:25EA                 cp      2
    29. ROM:25EC                 ret     z
    30. ROM:25ED
    31. ROM:25ED loc_25ED:                               ; CODE XREF: DisplayRings+Aj
    32. ROM:25ED                 ld      a, (RingsCounter)
    33. ROM:25F0                 rrca                    ; Get upper digit but multiplied by 2
    34. ROM:25F1                 rrca
    35. ROM:25F2                 rrca
    36. ROM:25F3                 and     1Eh             ; get only upper digit
    37. ROM:25F5                 add     a, 10h
    38. ROM:25F7                 ld      (RingDigitUpper), a ; Upper digit of rings counter
    39. ROM:25FA                 ld      a, (RingsCounter)
    40. ROM:25FD                 rlca                    ; get lower digit by multiplied by 2
    41. ROM:25FE                 and     1Eh             ; get only lower digit
    42. ROM:2600                 add     a, 10h
    43. ROM:2602                 ld      (RingDigitLower), a ; Lower digit of rings counter
    44. ROM:2605                 ret
    And the lives counter updating:

    Code (Text):
    1. ROM:25AC DisplayLives:                           ; CODE XREF: j_DisplayLivesj
    2. ROM:25AC                                         ; sub_30+901p ...
    3. ROM:25AC                 ld      a, (DemoFlag)
    4. ROM:25AF                 or      a
    5. ROM:25B0                 ret     nz
    6. ROM:25B1                 ld      a, (LivesCounter) ; load lives counter
    7. ROM:25B4                 cp      9               ; has it reached 9 or above?
    8. ROM:25B6                 jr      c, loc_25BA     ; if not, branch
    9. ROM:25B8                 ld      a, 9            ; keep it at 9
    10. ROM:25BA
    11. ROM:25BA loc_25BA:                               ; CODE XREF: DisplayLives+Aj
    12. ROM:25BA                 rlca                    ; multiply by 2
    13. ROM:25BB                 and     1Eh             ; get only the digit
    14. ROM:25BD                 add     a, 10h
    15. ROM:25BF                 ld      (LivesDigitLower), a             ; update lives display counter
    16. ROM:25C2                 ret
    Note, this is just for ring collection it appears, but the claim is there is no cap for collecting a 10 ring monitor, but that would mean that a single ring collection in the routine above would have the cap, which it does not. I'll keep looking though, but either I've misunderstood your post, or I've yet to discover the capping within the routines of the game.

    --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

    EDIT: OK, I think I understand what you're talking about now.

    I've found the routine for collecting 10 rings from a monitor:

    Code (Text):
    1. ROM:4817 Monitor_Rings:                          ; CODE XREF: sub_2FA8+1854j
    2. ROM:4817                 res     0, (hl)
    3. ROM:4819                 ld      a, (RingsCounter)
    4. ROM:481C                 add     a, 10h          ; Add 10 to rings
    5. ROM:481E                 daa                     ; Adjust for decimal
    6. ROM:481F                 ld      (RingsCounter), a
    7. ROM:4822                 ld      a, 0B3h ; '¦'
    8. ROM:4824                 ld      (byte_DD04), a
    9. ROM:4827                 jp      DisplayRings
    This increases the ring counter by 10, and that's it. If the result ends up surpassing 100 rings or not doesn't matter, there is no change to the lives counter. It could quite easily be added in though.
     
  9. Ravenfreak

    Ravenfreak

    2 Edgy 4 U Tech Member
    3,087
    181
    43
    O'Fallon Mo
    Sonic 1 Game Gear Disassembly
    I've ported over the code from Sonic Chaos that removes the lives counter cap. I think I wrote a guide and put it on the wiki too. I'm not really sure why the programmed the lives counter to be capped.
     
  10. Zycor

    Zycor

    Unlike Sonic, I don't chuckle. Member
    195
    11
    18
    Beats me.
    Thanks for the reply MarkeyJester!

    I wrote the post when it was pretty late, so that may have lead to some clarity issues.
     
  11. Not really a coding question, but since I'm making a whole new set of sprites for Sonic 2 I've been wondering if this frame is used anywhere:

    [​IMG]

    I thought it was unused but it isn't listed as such on Sonic Retro or TCRF, but this may just be an oversight. Is there some specific situation it shows up in I don't know about or have forgotten?
     
  12. Fred

    Fred

    Taking a break Oldbie
    1,563
    117
    43
    Portugal
    Sonic 3 Unlocked
    That is a tweening frame for the "almost falling off" teetering animation.

    To expand on this: in Sonic 2, the teetering animation is split into two variants, "far" and "near", depending on how close you are to the ledge. Furthermore, the "far" animation is further split into two directions, depending on whether you're facing towards or away from the ledge.

    In order for the single "near" animation to look right, however, Sonic needs to be facing towards the ledge. If you happen to already be facing the ledge, then the animation simply plays normally, but if you happen to be facing away from the ledge, then the game displays that frame for a couple of moments as it flips the Sonic object towards the ledge.
     
  13. ItsM3Creeper

    ItsM3Creeper

    Pending Member
    1
    0
    1
    Hey, does anybody know how to fix the problem with the invincibility stars remaining intact after hitting an invincibility monitor and turning super in sonic 2? If anybody knows it would be much appreciated!
     
  14. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,742
    338
    63
    SonLVL
    When you turn super, delete the invincibility stars object.
     
  15. Aerosol

    Aerosol

    Not here. Moderator
    11,163
    573
    93
    Not where I want to be.
    Sonic (?): Coming summer of 2055...?
    C++ questions are allowed right?

    typedef struct {
    void (*logic)(void);
    void (*draw)(void);
    } Delegate;

    What kind of declaration is this? I'm confused about the contents of the struct specifically.
     
  16. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,200
    430
    63
    Japan
    Basically it's declaring a routine/function named "logic", with void return and with (void) parameters (and the same for "draw").

    So imagine you make a structure of the above, and we'll name it Example:
    Code (Text):
    1.    Delegate Example;
    Now example will have an entry named "logic", this will be a pointer to a routine to run, so we'll pretend we have a routine/function which has the same return and parameters:
    Code (Text):
    1. void Routine (void)
    2.  
    3. {
    4.    printf ("Do something sexy\n");
    5. }
    We can then pass the address of this routine to the structure's "logic" like so:
    Code (Text):
    1.     Example.logic = Routine;
    Then we can run that routine from the structure, basically calling it as if it were a function/routine to be called:
    Code (Text):
    1.     Example.logic ( );
    You can get this pointer to point to any other function/routine at any time so long as the return and the parameters are the same.

    Here is an example with a return and a few parameters:
    Code (Text):
    1. typedef struct {
    2.    bool (*Routine)(const char *String);
    3. } Delegate;
    Code (Text):
    1. bool Name (const char *String)
    2.  
    3. {
    4.    printf ("String is %s\n", String);
    5.    return (TRUE);
    6. }
    Then finally:
    Code (Text):
    1.        Delegate Example;
    2.        Example.Routine = Name;
    3.        bool Return = Example.Routine ("La la la...");
    4.        if (Return == TRUE)
    5.        {
    6.            // I donno... just an example...
    7.        }
     
  17. Aerosol

    Aerosol

    Not here. Moderator
    11,163
    573
    93
    Not where I want to be.
    Sonic (?): Coming summer of 2055...?
    I see. It'll take some practice and reading to really grasp the benefits of that, but I at least understand the mechanics. Thanks a lot!
     
  18. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,200
    430
    63
    Japan
    Well... the benefits only come into play when you're doing something extremely complicated which involves calling different functions but within a main loop of some sort. I suspect this structure will have different entries, each one may require their own unique routine for "logic" and "drawing", but rather than doing conditional checks to determine which one needs to run which routine, you simply have the pointer point directly to the routine it needs, and just call the pointer and it'll do the rest without any checking needed. It'll save on CPU time and instructions.

    Unfortunately, the above is circumstantial and it's difficult to give you a really good example.

    I used a similar method above when I was writing an assembler, I had a structural system and create an "item" for every instruction/directive possible for the CPU, then pointing each one to a specific routine responsible for assembling the binary for the instruction. Thus, I don't need several comparisons or switch tables, I just call the structure's routine which is pointing to the correct routine before hand, and it does all the rest, including reporting back syntax errors and such. I could then allow macros to add themselves to this list, or switch this structural list out for a different CPU architecture without having to have several main assembly loops for every single CPU/macro known to man...

    Like I said though, this is very circumstantial and it's usefulness is highly dependent on what you need it for. Do have a play around with it though, you might find a use for it yourself at some point.

    A code example perhaps, with an array of structures together:
    Code (Text):
    1.  
    2.    int Size = 4;
    3.    Delegate Example [Size];
    4.    Example [0].logic = RoutineA;
    5.    Example [1].logic = RoutineB;
    6.    Example [2].logic = RoutineA;
    7.    Example [3].logic = RoutineC;
    8.    for (Count = 0; Count < Size; Count++)
    9.    {
    10.        Example [Count].logic ( );
    11.    }
    12.  

    Each one can have a different routine pointer inside "logic" and run different code in this crude loop example.
     
    Last edited: Jul 20, 2019
  19. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,742
    338
    63
    SonLVL
    The Sonic Adventure games use structures with function pointers like that to handle all the objects in the game, and not just rings and springs, even background tasks and menus. If you're familiar with S3K, it's like the code pointer at the start of each object there. This kind of programming style I'd think is more common in plain C, since C++ has classes where you can use inheritance and overrides to provide a similar functionality.
     
  20. Aerosol

    Aerosol

    Not here. Moderator
    11,163
    573
    93
    Not where I want to be.
    Sonic (?): Coming summer of 2055...?
    Yea these examples make sense, because that code was part of an example game project. Thanks again fellas.