don't click here

Exploring Soleil / Crusader of Centy

Discussion in 'General Sega Discussion' started by Hodgy, Apr 25, 2010.

  1. Hodgy

    Hodgy

    Member
    797
    0
    16
    UK
    Games programming :)
    In case you haven't noticed, Soleil is one of my favourite games on the Megadrive so I have decided to see what I can get out of the ROM :P

    The version of the ROM I'm using can be found here http://www.box.net/shared/gn2v7t7xjm

    Now I have done a little prodding around with lots of help from Jorge who suggested that I use Gens so I can use the debug tools to see what was going on, he pointed me in the direction of the bank register for the Z80 to find the music, this register displays 0x001F0000 and 0x001D8000 both of these memory locations have a lot of what seems to be ROM padding before them.

    But changing the bits at these locations doesn't seem to do anything.

    I will be mainly using this thread to log my findings but please post suggestions if you want to :)

    looks like this topic is going to help me :) : http://forums.sonicretro.org/index.php?showtopic=9785

    Thanks Andlabs for pointing me in the right direction :)
     
  2. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    Crusader of Centy/Soleil uses the Cube sound driver, just like Dr. Robotnik's Mean Bean Machine, and it appears to use the same revision of the drive (from what I could tell by the DAC table). Bank $1D8000 is for DAC samples. I could look into it further.
     
  3. Andlabs

    Andlabs

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

    All values little endian.

    First long is offset from beginning of data that marks the beginning of invalid (extra) tiles... because the way this compression method works will mean the last few pieces will be extra. When decompressing to VRAM, this isn't really a problem the end user will see...
    Second long (unk in the code below) is the number of bytes decompressed.

    DATA
    Each bit in each byte starting a chunk is scanned right to left.
    Bit==1 -> output next byte raw; copy to buffer
    Bit==0 -> copy from buffer to output and buffer, next word: nibbles abcd — acd (?) is pointer into buffer, b is count - 3 — look at the code, meh
    The buffer is $1000 bytes and is pre-filled with data (see the code below).

    Since both Ranger-X/Ex-Ranza and Crusader of Centy/Soleil use this compression, an appropriate name might be Toyota compression after Toshio Toyota, the only programmer who worked on both games — I'm not sure if YuYu Hakusho Gaiden (a different YuYu game for the Mega Drive from that fighter everyone knows about) uses it because I can't tell where/how it loads art yet :( (and yes, Nextech made Crusader of Centy, not Atlus; Gau Entertainment is Nextech)

    Most of the art in both games is stored in banks. For the US Crusader of Centy ROM, here are some, if not all, bank addresses:
    $59000
    $F0000
    $100000
    $111400
    $115B00
    $116E00
    $120000
    At each of these locations is a list of longwords — add the base address to the longword to get the address of the art.

    Some of these might be plane mappings too, bleh. I rushed this post out, so just reply if ysomething confuses/doesn't work/more questions/etc.

    Code (Text):
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <stdint.h>
    4. #include <string.h>
    5.  
    6. /* pietro gagliardi 27 february-17 march 2011 */
    7.  
    8. typedef uint8_t byte;
    9. typedef uint16_t word;
    10.  
    11. FILE *fin, *fout;
    12.  
    13. byte readbyte(void)
    14. {
    15. &nbsp;&nbsp;&nbsp;&nbsp;byte b;
    16.  
    17. &nbsp;&nbsp;&nbsp;&nbsp;fread(&b, 1, 1, fin);
    18. &nbsp;&nbsp;&nbsp;&nbsp;return b;
    19. }
    20.  
    21. word readleword(void)
    22. {
    23. &nbsp;&nbsp;&nbsp;&nbsp;word w;
    24.  
    25. &nbsp;&nbsp;&nbsp;&nbsp;w = readbyte();
    26. &nbsp;&nbsp;&nbsp;&nbsp;return w | (((word) readbyte()) << 8);
    27. }
    28.  
    29. uint32_t readlelong(void)
    30. {
    31. &nbsp;&nbsp;&nbsp;&nbsp;uint32_t w;
    32.  
    33. &nbsp;&nbsp;&nbsp;&nbsp;w = readbyte();
    34. &nbsp;&nbsp;&nbsp;&nbsp;w |= ((uint32_t) readbyte()) << 8;
    35. &nbsp;&nbsp;&nbsp;&nbsp;w |= ((uint32_t) readbyte()) << 16;
    36. &nbsp;&nbsp;&nbsp;&nbsp;return w | (((uint32_t) readbyte()) << 24);
    37. }
    38.  
    39. void writebyte(byte b)
    40. {
    41. &nbsp;&nbsp;&nbsp;&nbsp;fwrite(&b, 1, 1, fout);
    42. }
    43.  
    44. uint32_t size, end, unk;
    45.  
    46. void init_buf(byte *a0)
    47. {
    48. &nbsp;&nbsp;&nbsp;&nbsp;byte d0;
    49. &nbsp;&nbsp;&nbsp;&nbsp;word d1;
    50. &nbsp;&nbsp;&nbsp;&nbsp;
    51. &nbsp;&nbsp;&nbsp;&nbsp;d0 = 0;
    52. &nbsp;&nbsp;&nbsp;&nbsp;do {
    53. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d1 = 0xC + 1;
    54. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do {
    55. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*a0++ = d0;
    56. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d1--;
    57. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} while (d1 != 0);
    58. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d0++;
    59. &nbsp;&nbsp;&nbsp;&nbsp;} while (d0 != 0);
    60.  
    61. &nbsp;&nbsp;&nbsp;&nbsp;do {
    62. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*a0++ = d0;
    63. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d0++;
    64. &nbsp;&nbsp;&nbsp;&nbsp;} while (d0 != 0);
    65.  
    66. &nbsp;&nbsp;&nbsp;&nbsp;do {
    67. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d0--;
    68. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*a0++ = d0;
    69. &nbsp;&nbsp;&nbsp;&nbsp;} while (d0 != 0);
    70. &nbsp;&nbsp;&nbsp;&nbsp;
    71. &nbsp;&nbsp;&nbsp;&nbsp;d1 = 0x7F + 1;
    72. &nbsp;&nbsp;&nbsp;&nbsp;do {
    73. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*a0++ = d0;
    74. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d1--;
    75. &nbsp;&nbsp;&nbsp;&nbsp;} while (d1 != 0);
    76. &nbsp;&nbsp;&nbsp;&nbsp;
    77. &nbsp;&nbsp;&nbsp;&nbsp;d0 = 0x20;
    78. &nbsp;&nbsp;&nbsp;&nbsp;d1 = 0x6D + 1;
    79. &nbsp;&nbsp;&nbsp;&nbsp;do {
    80. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*a0++ = d0;
    81. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d1--;
    82. &nbsp;&nbsp;&nbsp;&nbsp;} while (d1 != 0);
    83. }
    84.  
    85. uint32_t decompress(void)
    86. {
    87. &nbsp;&nbsp;&nbsp;&nbsp;uint32_t n = 0, at;
    88. &nbsp;&nbsp;&nbsp;&nbsp;byte kbuf[0x1000];
    89. &nbsp;&nbsp;&nbsp;&nbsp;word kloc = 0xFEE;
    90. &nbsp;&nbsp;&nbsp;&nbsp;int I, j;
    91. &nbsp;&nbsp;&nbsp;&nbsp;
    92. &nbsp;&nbsp;&nbsp;&nbsp;printf("%X ", kbuf);
    93. &nbsp;&nbsp;&nbsp;&nbsp;init_buf(kbuf);
    94. &nbsp;&nbsp;&nbsp;&nbsp;size = readlelong();
    95. &nbsp;&nbsp;&nbsp;&nbsp;end += size + 8; /* +8 to count the two longs */
    96. &nbsp;&nbsp;&nbsp;&nbsp;printf("end: %X\n", end);
    97. &nbsp;&nbsp;&nbsp;&nbsp;unk = readlelong();
    98. &nbsp;&nbsp;&nbsp;&nbsp;printf("unk: %X\n", unk);
    99. &nbsp;&nbsp;&nbsp;&nbsp;printf("%X\n", ftell(fin));
    100. &nbsp;&nbsp;&nbsp;&nbsp;do {
    101. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte bits, b;
    102. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int I;
    103. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    104. #define w() writebyte(b); kbuf[kloc++] = b; kloc &= 0xFFF; n++
    105. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bits = readbyte();
    106. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (I = 0; I < 8; I++) {
    107. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (bits & 1) { /* 1 bit == just copy next */
    108. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b = readbyte();
    109. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;w();
    110. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else { /* 0 bit == reread */
    111. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;word loc;
    112. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte ni;
    113. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    114. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;&nbsp;&nbsp;&nbsp;loc = readleword();
    115. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ni = (loc & 0xF) + 2;
    116. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loc >>= 4;
    117. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loc &= 0xFFF;*/
    118. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
    119. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte q;
    120. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    121. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;q = readbyte();
    122. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ni = readbyte();
    123. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loc = (ni & 0xF0) << 4;
    124. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loc |= q;
    125. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loc &= 0xFFF;
    126. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ni &= 0xF;
    127. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ni += 2;
    128. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
    129. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (ni++; ni; ni--) { // start by adding 1 because the original uses dbf
    130. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b = kbuf[loc++];
    131. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;w();
    132. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loc &= 0xFFF;
    133. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
    134. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
    135. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bits >>= 1;
    136. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at = ftell(fin);
    137. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (at >= end) {
    138. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("\n\nEARLY END: %X %X\n", end, at);
    139. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return n;
    140. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
    141. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
    142. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at = ftell(fin);
    143. &nbsp;&nbsp;&nbsp;&nbsp;} while (at < end);
    144. &nbsp;&nbsp;&nbsp;&nbsp;return n;
    145. }
    146.  
    147. int main(int argc, char *argv[])
    148. {
    149. &nbsp;&nbsp;&nbsp;&nbsp;uint32_t outsize;
    150. &nbsp;&nbsp;&nbsp;&nbsp;
    151. &nbsp;&nbsp;&nbsp;&nbsp;fin = fopen(argv[1], "rb");
    152. &nbsp;&nbsp;&nbsp;&nbsp;fout = fopen(argv[2], "wb");
    153. &nbsp;&nbsp;&nbsp;&nbsp;end = strtoul(argv[3], NULL, 16);
    154. &nbsp;&nbsp;&nbsp;&nbsp;fseek(fin, end, SEEK_SET);
    155. &nbsp;&nbsp;&nbsp;&nbsp;outsize = decompress();
    156. &nbsp;&nbsp;&nbsp;&nbsp;printf("size of output: %X (%d)\n", outsize, outsize % 32);
    157. &nbsp;&nbsp;&nbsp;&nbsp;return 0;
    158. }
    (this code still has some debug stuff in it — I rushed this post)
     
  4. Vangar

    Vangar

    Member
    3,654
    62
    28
    Have you had a look at the BETA ROM? I remember there being some crazy stuff in there.
     
  5. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    Yeah that's what I was intending on doing later for The Cutting Room Floor =P I'll also post Ranger-X bank locations and a few other random pointers later.
     
  6. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    1
    0
    Writing my own MD/Genesis sound driver :D
    So did Toshio Toyota come to Gau after leaving Wolf Team? He programmed Granada... it uses the same compression, but not the art banking (raw pointers everywhere!). So I guess this is the best name for the format...
     
  7. Hodgy

    Hodgy

    Member
    797
    0
    16
    UK
    Games programming :)
    wow lots of progress being made, im very sorry for not persuing with this but real life has prevented me from putting any large ammounts of time into it :(