don't click here

Chaotix Hacking (formerly Chaotix Level Editing)

Discussion in 'Engineering & Reverse Engineering' started by Andlabs, Jan 29, 2010.

Thread Status:
Not open for further replies.
  1. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
  2. Thorn

    Thorn

    Tech Member
    335
    19
    18
    Home
    Sonic 2 Retro Remix
    Oh, I've certainly noticed. I've been checking Recent Changes on the Wiki every hour or so to see what you've done; I'm a bit of a Chaotix nut and the prospect of level design or getting a level rip for Sonic 2 (I know that the level palette uses up more colors, though, so it'd be hard) has my attention. I spent some time yesterday trying to get the data read by SonED2 by uncompressing it and recompressing it the way used in Sonic 2, but had no luck. Anyway, please have my babies, <3, etc.

    Actually, while there's a topic on it, lemme ask a question on Chaotix that maybe somebody knows the answer to... there's a bit of a lead-in to this one, but it's been bugging me for years, so I might as well ask. I remember looking around a few years ago and noticing the code "FFADC1:05 | Enable Grow (Leader) (Only works if Always Have Shield is enabled)" (now available on the <a href="http://info.sonicretro.org/Cheat_Codes:Knuckles'_Chaotix" target="_blank">Wiki</a>). Cut to a few years later, and I gain a greater understanding of the innards of classic Sonic. I understood that there's actually a word at $FFADC0 that says how many frames are left on either a Grow or Shrink item, and that the "Always Have Shield" requirement is a lie... rather, it only triggers on specific levels like World Entrance 2 (Final Boss). I then found that the code for other levels is always on some offset of $40 away from that code, e.g. $FFAE00 is that word's location in Botanic Base 1 Morning. I spent some time compiling a list of where that code moves to for different levels and times of day -- I think I found something like six codes, all multiples of $40 apart, that worked for every level and time of day. The list has been lost to time, unfortunately, but I could always recreate it.

    I'm sure that the effects of the values in RAM after this word move around between levels too, probably as a group of $40 bytes, so that list might have detailed the movements of a large chunk of RAM. Question is, why does it move in there first place, and is there some sort of logic behind where it moves to? Is this due to the game, or is it just a quirk with 32X hardware or 32X PAR codes? $40 was also the size of an SST in Sonic 2, which also held values for power-up time left: is this related? Or is this all nothing and I'm totally overthinking it?
     
  3. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    Ha, thanks. And this information proves useful. I keep coming across a function that handles up to $40 blocks of data $40 bytes in side, starting at $FFAD08. However, 8 allocated zones * 7 allocated acts * 4 allocated times of day == $E0 supported blocks, so I may be wrong.

    In any case, one could assume the real offset for enable grow is $39(aN). The following code looks relevant:

    Code (Text):
    1. ROM:0088418C; ---------------------------------------------------------------------------
    2. ROM:0088418C
    3. ROM:0088418C loc_88418C:                ; CODE XREF: sub_883B32+644j
    4. ROM:0088418C                 tst.w   $26(a6)
    5. ROM:00884190                 bne.w   loc_884074
    6. ROM:00884194                 moveq   #0,d0
    7. ROM:00884196                 subq.b  #1,$39(a6)
    8. ROM:0088419A                 bne.s   loc_8841C0
    9. ROM:0088419C                 move.b  $38(a6),d0
    10. ROM:008841A0                 addq.b  #4,d0
    11. ROM:008841A2                 cmpi.b  #$20,d0; ' '
    12. ROM:008841A6                 bcs.s   loc_8841AA
    13. ROM:008841A8                 moveq   #0,d0
    14. ROM:008841AA
    15. ROM:008841AA loc_8841AA:                ; CODE XREF: sub_883B32+674j
    16. ROM:008841AA                 move.b  d0,$38(a6)
    17. ROM:008841AE                 move.b  #3,$39(a6)
    18. ROM:008841B4                 move.w  word_8841E6(pc,d0.w),0(a4)
    19. ROM:008841BA                 move.w  word_8841E8(pc,d0.w),$C(a4)
    20. ROM:008841C0
    21. ROM:008841C0 loc_8841C0:                ; CODE XREF: sub_883B32+668j
    22. ROM:008841C0                 subq.b  #1,$3B(a6)
    23. ROM:008841C4                 bne.s   locret_8841E4
    24. ROM:008841C6                 move.b  $3A(a6),d0
    25. ROM:008841CA                 addq.b  #1,d0
    26. ROM:008841CC                 cmpi.b  #4,d0
    27. ROM:008841D0                 bcs.s   loc_8841D4
    28. ROM:008841D2                 moveq   #0,d0
    29. ROM:008841D4
    30. ROM:008841D4 loc_8841D4:                ; CODE XREF: sub_883B32+69Ej
    31. ROM:008841D4                 move.b  d0,$3A(a6)
    32. ROM:008841D8                 move.b  #8,$3B(a6)
    33. ROM:008841DE                 move.b  byte_884206(pc,d0.w),4(a4)
    34. ROM:008841E4
    35. ROM:008841E4 locret_8841E4:                ; CODE XREF: sub_883B32+692j
    36. ROM:008841E4                 rts
    37. ROM:008841E4; END OF FUNCTION CHUNK FOR sub_883B32
    In this case, a6 is the value of $FFFFE028, which is set to the value of the first entry in the above array. When a level is loaded, the entires are cycled away:

    Code (Text):
    1. ROM:00880D64; =============== S U B R O U T I N E =======================================
    2. ROM:00880D64
    3. ROM:00880D64
    4. ROM:00880D64 sub_880D64:                ; CODE XREF: DoGameMode+56Ep
    5. ROM:00880D64                            ; DoGameMode+1A28p ...
    6. ROM:00880D64                 moveq   #0,d0
    7. ROM:00880D66                 lea     ($FFFFE026).w,a0
    8. ROM:00880D6A                 move.w  d0,(a0)+
    9. ROM:00880D6C                 move.w  d0,(a0)+
    10. ROM:00880D6E                 move.w  d0,(a0)+
    11. ROM:00880D70                 move.w  d0,(a0)+
    12. ROM:00880D72                 move.w  d0,(a0)+
    13. ROM:00880D74                 move.w  #$7FFF,(a0)+
    14. ROM:00880D78                 lea     ($FFAD08).l,a0
    15. ROM:00880D7E                 moveq   #$3F,d7; '?'
    16. ROM:00880D80                 move.w  a0,($FFFFE026).w
    17. ROM:00880D84
    18. ROM:00880D84 loc_880D84:                ; CODE XREF: sub_880D64+28j
    19. ROM:00880D84                 lea     $40(a0),a1
    20. ROM:00880D88                 move.w  a1,(a0)
    21. ROM:00880D8A                 movea.w a1,a0
    22. ROM:00880D8C                 dbf     d7,loc_880D84
    23. ROM:00880D90                 move.w  d0,-$40(a0)
    24. ROM:00880D94                 move.l  d0,($FFFFCA9E).w
    25. ROM:00880D98                 move.l  d0,($FFFFCAA2).w
    26. ROM:00880D9C                 move.w  d0,($FFFFE1A2).w
    27. ROM:00880DA0                 move.w  #$D45E,($FFFFD01E).w
    28. ROM:00880DA6                 move.w  #5,($FFFFE01E).w
    29. ROM:00880DAC                 move.w  #$F,($FFFFE020).w
    30. ROM:00880DB2                 move.w  #$3F,($FFFFE022).w; '?'
    31. ROM:00880DB8                 move.w  #$3F,($FFFFE024).w; '?'
    32. ROM:00880DBE                 rts
    33. ROM:00880DBE; End of function sub_880D64
    This is called by more than just the level loader, so at this point I'm not entirely sure. And then there's this... thing:

    Code (Text):
    1. ROM:00880DC0; =============== S U B R O U T I N E =======================================
    2. ROM:00880DC0
    3. ROM:00880DC0
    4. ROM:00880DC0 sub_880DC0:                ; CODE XREF: sub_8AAB9C+2AEp
    5. ROM:00880DC0                 move.l  #$FF0000,d0
    6. ROM:00880DC6                 move.w  ($FFFFE032).w,d0
    7. ROM:00880DCA                 bmi.s   loc_880DE2
    8. ROM:00880DCC                 cmpi.l  #$FF0D08,d0
    9. ROM:00880DD2                 bcc.s   loc_880DDC
    10. ROM:00880DD4                 move.l  #$FFAD08,d0
    11. ROM:00880DDA                 bra.s   loc_880DE2
    12. ROM:00880DDC; ---------------------------------------------------------------------------
    13. ROM:00880DDC
    14. ROM:00880DDC loc_880DDC:                ; CODE XREF: sub_880DC0+12j
    15. ROM:00880DDC                 move.l  #$FF8000,d0
    16. ROM:00880DE2
    17. ROM:00880DE2 loc_880DE2:                ; CODE XREF: sub_880DC0+Aj
    18. ROM:00880DE2                            ; sub_880DC0+1Aj
    19. ROM:00880DE2                 movea.w d0,a0
    20. ROM:00880DE4                 subi.l  #$FFAD08,d0
    21. ROM:00880DEA                 neg.w   d0
    22. ROM:00880DEC                 andi.w  #$7FC0,d0
    23. ROM:00880DF0                 beq.s   loc_880E12
    24. ROM:00880DF2                 lsr.w   #6,d0
    25. ROM:00880DF4                 add.w   d0,($FFFFE024).w
    26. ROM:00880DF8                 move.w  ($FFFFE026).w,d1
    27. ROM:00880DFC                 move.w  a0,($FFFFE026).w
    28. ROM:00880E00                 subq.w  #1,d0
    29. ROM:00880E02
    30. ROM:00880E02 loc_880E02:                ; CODE XREF: sub_880DC0+4Aj
    31. ROM:00880E02                 lea     $40(a0),a1
    32. ROM:00880E06                 move.w  a1,(a0)
    33. ROM:00880E08                 movea.w a1,a0
    34. ROM:00880E0A                 dbf     d0,loc_880E02
    35. ROM:00880E0E                 move.w  d1,-$40(a0)
    36. ROM:00880E12
    37. ROM:00880E12 loc_880E12:                ; CODE XREF: sub_880DC0+30j
    38. ROM:00880E12                 clr.w   ($FFFFE032).w
    39. ROM:00880E16                 rts
    40. ROM:00880E16; End of function sub_880DC0
    But in any case there is just no single code to enable grow and shrink, nor a proper series, but rather a code based on the value of another memory address at any given point in time.

    ..................

    EDIT
    Apparently the value of $FFFFE028 depends on... the last address that level mappings are loaded to. Stay tuned.
     
  4. Thorn

    Thorn

    Tech Member
    335
    19
    18
    Home
    Sonic 2 Retro Remix
    Hm, cool that my crazy anecdote actually ties into something. Regarding the 8 *7 * 4 you're pointing out, I know that when I compiled that chart, I found the word that handles frames left on grow or shrink (and again, likely other data in a set of $40 bytes, but I didn't know that before I started Sonic hacking) was always in one of six different locations. While there's other RAM that "moves" too based on the level from some experimenting I did, I don't think you're looking at nearly 8 * 7 * 4 different possibilities, even if that many are plausible.

    Again, that word also seems to be dependent on another flag somewhere... if you activate a PAR code over it after hitting a shrink, even after the original item wears off, it'll stay tied to that item until another Grow box is hit. I never did find the flag. Of course, this isn't just about those two items, but those were the easiest to observe the "moving RAM" phenomenon if only because they were some of the only ones the GSHI had incorrectly listed as a code.

    Here's a bit from a text file I found on my computer, but the chart saying which level everything was tied to is long gone, and you probably have that info available right there in the disassembly. Some of what I found was useless, but I'll put it all in anyway.

    Beginning of game (Introduction 0): $FFAE00 plus...
    $00: Byte? - horizontal compress - unknown scale
    $01: Byte - horizontal scale (doesn't work properly via PAR code in Kega Fusion)
    * $80 - 2x horizontal
    * $40 - 4x hor
    * $20 - 8x hor
    * etc.
    $02: Byte? - vertical compress
    $03: Byte - vertical scale - see horizontal scale above
    These values remain consecutive in other levels, but are located elsewhere in RAM.

    Introduction - Evening Portion (3): $FFAE00 plus...
    $00: Word - remaining frames of a Grow/Shrink item. Grow item triggers by default if this is set before a Grow/Shrink item is opened, and if either item is opened over the course of the level, the last item used dictates the effects. There must be a flag elsewhere.
    $02: Word? - Unknown; defaults to 0500
    $04: Word? - Unknown; defaults to 0100
    $06: Word? - Unknown; defaults to 0100
    $08: Word - Defaults to AE48. At 0000, partner Espio is gold, and arm disappears, and body disappears in waiting animation. Further experimentation needed.
    These values remain consecutive in other levels, but are located elsewhere in RAM.


    Best of luck from here on out, because that's the end of the little experiments I did way back when and I don't even know what's useful and what's not. If there's any busy work I can help with, like re-charting how some of these values move around, let me know.~
     
  5. DigitalDuck

    DigitalDuck

    Arriving four years late. Member
    5,418
    492
    63
    Lincs, UK
    TurBoa, S1RL
    It does work properly (sort of). When you input a PAR code into KEGA Fusion in the format "xxxxxx:00yy", it automatically assumes that you only want to change byte xxxxxx to yy, rather than the expected xxxxxx to 00 and xxxxxx+1 to yy. Hope that makes sense.
     
  6. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    Wow, that's just dumb. Does it use sscanf() to parse these codes?!

    Anyway I'm still going at it, stay tuned.
     
  7. DigitalDuck

    DigitalDuck

    Arriving four years late. Member
    5,418
    492
    63
    Lincs, UK
    TurBoa, S1RL
    It's like that deliberately. It provides a useful way of changing only one byte instead of two, which (I believe) the original Pro Action Replay couldn't do. If you do need to change xxxxxx to 00 and xxxxxx+1 to yy, you can always use "xxxxxx:0000 + xxxxxx+1:00yy".
     
  8. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    Meh.

    Also turns out I was wrong:

    Code (Text):
    1. ROM:00883B16 sub_883B16:                        ; CODE XREF: DoGameMode+89Ap
    2. ROM:00883B16                                    ; ROM:0088651Cp
    3. ROM:00883B16                 lea     ($FFFFE272).w,a5
    4. ROM:00883B1A                 lea     ($FFFFE028).w,a6
    5. ROM:00883B1E
    6. ROM:00883B1E loc_883B1E:                        ; CODE XREF: sub_883B16+18j
    7. ROM:00883B1E                 move.w  (a6),d0
    8. ROM:00883B20                 beq.s   locret_883B30
    9. ROM:00883B22                 movea.w d0,a6
    10. ROM:00883B24                 moveq   #0,d0
    11. ROM:00883B26                 move.b  6(a6),d0
    12. ROM:00883B2A                 jsr     sub_883B32(pc,d0.w)
    13. ROM:00883B2E                 bra.s   loc_883B1E
    This looks like an event loop, though I'm not entirely sure. So $FFFFE028 must be the first in a list of pointers to handle events. The problem is that I can't find anything that writes to this address; only reads.

    I'm going to save this for later. But thanks Thorn for the information; it may prove useful soon enough.
     
  9. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    I just found code to handle monitors, meaning I now know where grow and shrink come into play. I'll provide details soon.
     
  10. Thorn

    Thorn

    Tech Member
    335
    19
    18
    Home
    Sonic 2 Retro Remix
    ^ Hah, I kept trying to stress that I wasn't trying to change the topic onto those items and that they just happened to show the relocated values in RAM well enough for you to see the phenomenon as a whole, but I think you've already gone into it so deeply that I'll just watch what you find. :P

    @DigitalDuck: You'd think that to just change a byte, you would simply type something like FFADC1:05 (see the PAR codes on the Wiki). The way Fusion does it is completely unintuitive, but at least now I know, thanks.
     
  11. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    Not really, no, this just happened to have happened. My real focus is the object status table format, which the grow and shrink monitors involve. If I can find where they're stored, I can finally interpret the bulk of this code.

    I can also provide this little tidbit: offset $30 is the flags for the player; bit 0 on indicates the player has a shield.
     
  12. DigitalDuck

    DigitalDuck

    Arriving four years late. Member
    5,418
    492
    63
    Lincs, UK
    TurBoa, S1RL
    You can; Fusion will automatically change FFADC1:05 to FFADC1:0005.
     
  13. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    Okay, I think I figured it out. There's a set of object status blocks that the game allocates to a series of slots. You have six slots to work with; to access them you multiply the slot # by 2 and call a function, which places the OST into that slot and returns the pointer to the OST. The slots are words starting at $FFFFE026. So for $FFFFE028, you would pass the number 2.

    I'm still slowly figuring this out, so don't worry :D
     
  14. Mercury

    Mercury

    His Name Is Sonic Tech Member
    1,740
    21
    18
    Location Location
    AeStHete
    Ironically, I was screwing around in gens Kmod the other day, looking at Chaotix's OST. I didn't get very far before life intervened, so I haven't gone back.

    I'm no brilliant hacker or anything, and this is very crude, but it's what I learned, if you can make any sense of it.

    And yes, I'm well aware that I am total bollocks at presenting information.
     
  15. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    Thanks, this information will be very useful. But this also makes the situation even more confusing than ever. I'm going to go turn the following funtion to C; this is the one that grabs an OST and puts it in a slot, but from what I can tell it will give you a different OST each time? :S

    Code (ASM):
    1. ROM:00881702 ; =============== S U B R O U T I N E =======================================
    2. ROM:00881702
    3. ROM:00881702
    4. ROM:00881702 GetOSTAtSlot:                           ; CODE XREF: DoGameMode+584p
    5. ROM:00881702                                         ; ROM:00884A98p ...
    6. ROM:00881702                 move.l  d7,-(sp)
    7. ROM:00881704                 lea     ($FFFFE01E).w,a0
    8. ROM:00881708                 move.w  -2(a0,d0.w),d7
    9. ROM:0088170C                 lea     ($FFFFE026).w,a0
    10. ROM:00881710                 adda.w  d0,a0
    11. ROM:00881712                 tst.w   ($FFFFE026).w
    12. ROM:00881716                 beq.s   loc_88172E
    13. ROM:00881718                 tst.l   d0
    14. ROM:0088171A                 bpl.s   loc_881724
    15. ROM:0088171C
    16. ROM:0088171C loc_88171C:                             ; CODE XREF: GetOSTAtSlot+20j
    17. ROM:0088171C                 move.w  (a0),d7
    18. ROM:0088171E                 beq.s   loc_881736
    19. ROM:00881720                 movea.w d7,a0
    20. ROM:00881722                 bra.s   loc_88171C
    21. ROM:00881724 ; ---------------------------------------------------------------------------
    22. ROM:00881724
    23. ROM:00881724 loc_881724:                             ; CODE XREF: GetOSTAtSlot+18j
    24. ROM:00881724                                         ; GetOSTAtSlot+28j
    25. ROM:00881724                 tst.w   (a0)
    26. ROM:00881726                 beq.s   loc_881736
    27. ROM:00881728                 movea.w (a0),a0
    28. ROM:0088172A                 dbf     d7,loc_881724
    29. ROM:0088172E
    30. ROM:0088172E loc_88172E:                             ; CODE XREF: GetOSTAtSlot+14j
    31. ROM:0088172E                 move.l  (sp)+,d7
    32. ROM:00881730                 ori     #8,ccr
    33. ROM:00881734                 rts
    34. ROM:00881736 ; ---------------------------------------------------------------------------
    35. ROM:00881736
    36. ROM:00881736 loc_881736:                             ; CODE XREF: GetOSTAtSlot+1Cj
    37. ROM:00881736                                         ; GetOSTAtSlot+24j
    38. ROM:00881736                 move.w  ($FFFFE026).w,(a0)
    39. ROM:0088173A                 move.w  a0,d7
    40. ROM:0088173C                 movea.w (a0),a0
    41. ROM:0088173E                 move.w  (a0),($FFFFE026).w
    42. ROM:00881742                 clr.w   (a0)
    43. ROM:00881744                 move.w  d7,2(a0)
    44. ROM:00881748                 moveq   #0,d7
    45. ROM:0088174A                 move.w  d7,4(a0)
    46. ROM:0088174E                 move.l  #unk_881768,$10(a0)
    47. ROM:00881756                 move.l  d7,$20(a0)
    48. ROM:0088175A                 move.l  d7,8(a0)
    49. ROM:0088175E                 move.l  d7,$C(a0)
    50. ROM:00881762                 movem.l (sp)+,d7
    51. ROM:00881766                 rts
    52. ROM:00881766 ; End of function GetOSTAtSlot
    53. ROM:00881766
    54. ROM:00881766 ; ---------------------------------------------------------------------------
    55. ROM:00881768 unk_881768:     dc.b   0                ; DATA XREF: GetOSTAtSlot+4Co
    56. ROM:00881769                 dc.b   0
    57. ROM:0088176A                 dc.b   0
    58. ROM:0088176B                 dc.b   0
    59. ROM:0088176C                 dc.b $80 ; Ç
    60. ROM:0088176D                 dc.b   0
    EDIT
    Code (Text):
    1. void *GetOSTAtSlot(int OSTnum)
    2. {
    3.     int d7;
    4.     int *a0;
    5.  
    6.     d7 = 0xE01C[OSTnum];
    7.     a0 = 0xE026 + OSTnum;
    8.     if (*0xE026 == 0) // no entries in the list
    9.         return a0;
    10.     if (OSTnum > 0) {
    11.         for (; d7 >= 0; d7--) {
    12.             if (*a0 == 0)
    13.                 break;
    14.             a0 = *a0;
    15.         }
    16.         if (d7 < 0) // not found
    17.             return a0;
    18.     } else
    19.         while ((d7 = *a0) != 0)
    20.             a0 = d7;
    21.     *a0 = *E026;
    22.     d7 = a0;
    23.     a0 = *a0;
    24.     *E026 = *a0;
    25.     *a0 = 0;
    26.     (*a0)[2] = d7;
    27.     (*a0)[4] = 0;
    28.     (*a0)[0x10] = unk_881768;
    29.     (*a0)[8] = (*a0)[0xC] = (*a0)[0x20] = 0;
    30.     return a0;
    31. }
    Now I'm thinking that these values at $FFFFE026..$FFFFE030 are really a queue or stack of some sort...
     
  16. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    Nailed it.

    Code (Text):
    1. void *GetOSTAtSlot(int OSTnum)
    2. {
    3.     int d7;
    4.     int *a0;
    5.  
    6.     d7 = 0xE01C[OSTnum];
    7.     a0 = 0xE026 + OSTnum;
    8.     if (*0xE026 == 0) // no entries in the list
    9.         return a0;
    10.     if (OSTnum > 0) {
    11.         for (; d7 >= 0; d7--) {
    12.             if (*a0 == 0)
    13.                 break;
    14.             a0 = *a0;
    15.         }
    16.         if (d7 < 0) // not found
    17.             return a0;
    18.     } else
    19.         while ((d7 = *a0) != 0)
    20.             a0 = d7;
    21.     *a0 = *E026;
    22.     d7 = a0;
    23.     a0 = *a0;
    24.     *E026 = *a0;
    25.     *a0 = 0;
    26.     (*a0)[2] = d7;
    27.     (*a0)[4] = 0;
    28.     (*a0)[0x10] = unk_881768;
    29.     (*a0)[8] = (*a0)[0xC] = (*a0)[0x20] = 0;
    30.     return a0;
    31. }
    32.  
    33. void InitOSTs(void)
    34. {
    35.     int *a0, *a1;
    36.     int d7;
    37.  
    38.     E026 = E028 = E02A = E02C = E02E = 0;
    39.     E030 = 0x7FFF;
    40.     E026 = a0 = AD08;
    41.     for (d7 = 0x3F; d7 >= 0; d7--) {
    42.         a1 = a0[40];
    43.         *a0 = a1;
    44.         a0 = a1;
    45.     }
    46.     a0[-40] = 0; // close up the last value
    47.     CA9E = CAA2 = E1A2 = 0;
    48.     D01E = 0xD45E;
    49.     E01E = 5;
    50.     E020 = 0xF;
    51.     E022 = E024 = 0x3F;
    52. }
    53.  
    54. CALLS FOR A LEVEL
    55.  
    56. InitOSTs()
    57.     E026 = AD08; all else 0
    58.     AD08 = AD48
    59.     AD48 = AD88
    60.     ...
    61. GetOSTAtSlot(6)
    62.     E026 = AD48; E02C = AD08; all else 0
    63.     AD08 = 0
    64. GetOSTAtSlot(6) (repeated)
    65.     E026 = AD88; E02C = AD08; all else 0
    66.     AD08 = AD48
    67.     AD48 = 0
    68. [some time later]
    69. GetOSTAtSlot(2)
    70.     E026 = ADC8; E028 = AD88; E02C = AD08; all else 0
    71.     AD08 = AD48
    72.     AD48 = AD88
    73.     AD88 = 0
    So the OSTs are a linked list. $FFE026 is the address of the first free entry. The proper name of GetOSTAtSlot is AllocOST, since that's what it's doing. The variables $FFE028..$FFE030 are set by AllocOST only when it is told to. So now the only thing left is to determine which of these variables point to player 1, player 2, etc. and we can finally dive deeper into Chaotix.
     
  17. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    All right. As far as I can tell:

    $FFFFE028 is initially given to the first player. Since that value needs to be overwritten, it gets copied to $FFFFE034; likewise for Player 2 and $FFFFE036.
     
  18. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    Well I give up so I'm asking the board. I think I found the routine to handle button pushes, since it uses the character traits. But I can't disassemble everything because at one point it calls a function loaded from RAM... based on addresses from a list of negative jumps — they jump BACKWARD. No matter what I do, IDA treats them as forward jumps. I've tried different addressing modes, different targets, changing the values to signed; all to no avail. Can someone help me?

    Code (Text):
    1. ROM:008F56A6 word_8F56A6:    dc.w $FCDA            ; DATA XREF: sub_8F565E+Eo
    2. ROM:008F56A6                                    ; TODO
    3. ROM:008F56A8                 dc.w $FCD8
    4. ROM:008F56AA                 dc.w $FCD6
    5. ROM:008F56AC                 dc.w $FCD4
    6. ROM:008F56AE                 dc.w $FCD2
    7. ROM:008F56B0                 dc.w $FCD0
    8. ROM:008F56B2                 dc.w $FCCE
    9. ROM:008F56B4                 dc.w $FCCC
    10. ROM:008F56B6                 dc.w $FCCA
    11. ROM:008F56B8                 dc.w $FCC8
    12. ROM:008F56BA                 dc.w $FCC6
    13. ROM:008F56BC                 dc.w $FCC4
    14. ROM:008F56BE                 dc.w $FCC2
    15. ROM:008F56C0                 dc.w $FCC0
    16. ROM:008F56C2                 dc.w $FCBE
    17. ROM:008F56C4                 dc.w $FCBC
    18. ROM:008F56C6                 dc.w $FCBA
    19. ROM:008F56C8                 dc.w $FCB8
    20. ROM:008F56CA                 dc.w $FCB6
    21. ROM:008F56CC                 dc.w $FCB4
    22. ROM:008F56CE                 dc.w $FCB2
    23. ROM:008F56D0                 dc.w $FCB0
    24. ROM:008F56D2                 dc.w $FCAE
    25. ROM:008F56D4                 dc.w $FCAC
    26. ROM:008F56D6                 dc.w $FCAA
    27. ROM:008F56D8                 dc.w $FCA8
    28. ROM:008F56DA                 dc.w $FCA6
    29. ROM:008F56DC                 dc.w $FCA4
    30. ROM:008F56DE                 dc.w $FCA2
    31. ROM:008F56E0                 dc.w $FCA0
    32. ROM:008F56E2                 dc.w $FC9E
    33. ROM:008F56E4                 dc.w $FC9C
    34. ROM:008F56E6                 dc.w $FC9A
    35. ROM:008F56E8                 dc.w $FC98
    36. ROM:008F56EA                 dc.w $FC96
    37. ROM:008F56EC                 dc.w $FC94
    38. ROM:008F56EE                 dc.w $FC92
    39. ROM:008F56F0                 dc.w $FC90
    40. ROM:008F56F2                 dc.w $FC8E
    41. ROM:008F56F4                 dc.w $FC8C
    42. ROM:008F56F6                 dc.w $FC8A
    43. ROM:008F56F8                 dc.w $FC88
    44. ROM:008F56FA                 dc.w $FC86
    45. ROM:008F56FC                 dc.w $FC84
    46. ROM:008F56FE                 dc.w $FC82
    47. ROM:008F5700                 dc.w $FC80
    48. ROM:008F5702                 dc.w $FC7E
    49. ROM:008F5704                 dc.w $FC7C
    50. ROM:008F5706                 dc.w $FC7A
    51. ROM:008F5708                 dc.w $FC78
    52. ROM:008F570A                 dc.w $FC76
    53. ROM:008F570C                 dc.w $FC74
    54. ROM:008F570E                 dc.w $FC72
    55. ROM:008F5710                 dc.w $FC70
    56. ROM:008F5712                 dc.w $FC6E
    57. ROM:008F5714                 dc.w $FC6C
    58. ROM:008F5716                 dc.w $FC6A
    59. ROM:008F5718                 dc.w $FC68
    60. ROM:008F571A                 dc.w $FC66
    61. ROM:008F571C                 dc.w $FC64
    62. ROM:008F571E                 dc.w $FC62
    63. ROM:008F5720                 dc.w $FC60
    64. ROM:008F5722                 dc.w $FC5E
    65. ROM:008F5724                 dc.w $FC5C
    66. ROM:008F5726                 dc.w $FC5A
    67. ROM:008F5728                 dc.w $FC58
    68. ROM:008F572A                 dc.w $FC56
    69. ROM:008F572C                 dc.w $FC54
    70. ROM:008F572E                 dc.w $FC52
    71. ROM:008F5730                 dc.w $FC50
    72. ROM:008F5732                 dc.w $FC4E
    73. ROM:008F5734                 dc.w $FC4C
    74. ROM:008F5736                 dc.w $FC4A
    75. ROM:008F5738                 dc.w $FC48
    76. ROM:008F573A                 dc.w $FC46
    77. ROM:008F573C                 dc.w $FC44
    78. ROM:008F573E                 dc.w $FC42
    79. ROM:008F5740                 dc.w $FC40
    80. ROM:008F5742                 dc.w $FC3E
    81. ROM:008F5744                 dc.w $FC3C
    I'm using IDA 5.5.
     
  19. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    All right, if my question can't be answered, could an IDC script do this, and how? I don't know IDC. Thanks.
     
  20. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    Code (Text):
    1. TABLE 1
    2. OFFSET        SIZE    DESCRIPTION
    3. $0-$1        word    Pointer to next OST in allocator chain
    4. $2-$39        ?    ?
    5. $3A        word    Pointer to table 2
    6. $3B-$3F        ?    ?
    7.  
    8. TABLE 2
    9. OFFSET        SIZE    DESCRIPTION
    10. $0-$1        word    Pointer to next OST in allocator chain
    11. $2-$2F        ?    ?
    12. $30        byte    Flags
    13.             BIT    DESCRIPTION
    14.             0    has sheild?
    15.             1    ?
    16.             2    ?
    17.             3    if 1 then shrunken, if 0 then grown
    18.                 only checked when $38 != 0
    19. $32        word    Invincibility timer (from $4B0 to $0; $0 == no invincibility; each new box adds $4B0)
    20. $33-$37        ?    ?
    21. $38        word    Grow/shrink timer (from $4B0 to $0; $0 == no size change; each new like box adds $4B0;
    22.             each unlike box sets $0 and returns to normal)
    23. $39-$3F        ?    ?
    It begins...
     
Thread Status:
Not open for further replies.