don't click here

Desert Demolition Metatile Viewer

Discussion in 'Technical Discussion' started by Techokami, Mar 24, 2009.

  1. Techokami

    Techokami

    For use only on NTSC Genesis systems Researcher
    1,375
    86
    28
    HoleNet!
    Sonic Worlds Next
    So, there's this obscure licensed game for the Genesis that has a tileset I really wanted: Desert Demolition. It's a Wile E. Cyote VS Road Runner game, and lets you play through the game either as the Road Runner (Sonic-like gameplay, lots of fast running and loopdeloops) or Wile E. (lots of platforming and a little bit of puzzle solving). I thought it was fun when I was young...

    So being the nature of obscure games, there's little knoledge in the way of hacking or understanding how things work. But that doesn't stop me from being a stubborn fucker and doing everything myself!

    Levels are built from 32x32 pixel blocks, made out of 16 8x8 tiles. The format is like a bigger version of Sonic 1/2/3K's 16x16 mappings, in that each tile is represented in the standard Genesis VDP format: a bitmask of PCCY XAAA AAAA AAAA. 24 bytes make up a Map32 entry and looks like-a this:
    AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH IIII JJJJ KKKK LLLL MMMM NNNN OOOO PPPP
    Assembled as:
    ABCD
    EFGH
    IJKL
    MNOP


    I have written a PHP script to create a dump of the Map32 entries in a Gens KMod savestate. I don't quite know the level format yet, so I can't build level maps. Also, I can't seem to make it flip tiles when generating the Map32 dump, which is bad. If someone knows how to go about doing this, please give me a hand! It's the only thing I can't make this script do. Lightning pointed me to something useful, now it makes perfect rips! Thanks Lifning :3

    Also, pardon the mess.

    Code (PHP):
    1. <?php
    2. //Desert Demolition Level Ripper!
    3. //Code by Techokami
    4. //The format is straightforward - 16 8x8 tiles in the standard VDP format.
    5. // 0 1 2 3
    6. // 4 5 6 7
    7. // 8 9 A B
    8. // C D E F
    9. //Each 8x8 tile is represented by one word, which like all SEGA Genesis VDP pattern indices,
    10. //is a bitmask of the form PCCY XAAA AAAA AAAA. P is the priority flag, CC is the palette line to use,
    11. //X and Y indicate that the sprite should be flipped horizontally and vertically respectively,
    12. //and AAA AAAA AAAA is the actual tile index, I.e. the VRAM offset of the pattern divided by $20.  
    13. //2048 possible tiles.
    14. // [url="http://php.net/manual/en/language.operators.bitwise.php"]http://php.net/manual/en/language.operators.bitwise.php[/url]
    15. // Split a byte into nybbles
    16. // $leftnybble = floor($byte / 16);
    17. // $rightnybble = ($byte % 16);
    18. function getByte( &$source )
    19. {
    20.     return ord( fread( $source,1 ) );
    21. }
    22.  
    23. function getWord( &$source )
    24. {
    25.     return (getByte( $source ) * 0x100) + getByte( $source );
    26. }
    27.  
    28. function makePallete( $source, $gd )
    29. {
    30.     $result = array();
    31.     $I = 0;
    32.     for($I= 0; $I < 16; $I++)
    33.     {
    34.         $color = getByte($source);
    35.         $color2 = getByte($source);
    36.         // Genesis pallete entries are words - 0B GR
    37.         $red = 16 * ($color2 % 16);
    38.         $green = 16 * floor($color2 / 16);
    39.         $blue = 16 * ($color % 16);
    40.         if ($I == 0) $result[$I] = imagecolorallocate( $gd, 255, 0, 255 );
    41.         else $result[$I] = imagecolorallocate( $gd, $red, $green, $blue );
    42.     }
    43.     return $result;
    44. }
    45. //Make image with the tiles in VRAM
    46. $tilesone = imagecreate(256, 384);
    47. $tilestwo = imagecreate(256, 384);
    48. $tilesthree = imagecreate(256, 384);
    49. $tilesfour = imagecreate(256, 384);
    50. $ram = fopen("dd.gs0", "r");
    51. fseek($ram, 0xA50C);
    52. $palone = makePallete($ram, $tilesone);
    53. $paltwo = makePallete($ram, $tilestwo);
    54. $palthree = makePallete($ram, $tilesthree);
    55. $palfour = makePallete($ram, $tilesfour);
    56. //Now that we have the images and palletes ready, jump to the tiles!
    57. fseek($ram, 0x17D98);
    58. $I = 0;
    59. for($I= 0; $I < 48; $I++)
    60. {
    61.     $j = 0;
    62.     for($j= 0; $j < 32; $j++)
    63.     {
    64.         $y = 0;
    65.         for($y= 0; $y < 8; $y++)
    66.         {
    67.             $x = 0;
    68.             for($x= 0; $x < 8; $x = $x + 2)
    69.             {
    70.                 $byte = getByte($ram);
    71.                 // Split a byte into nybbles
    72.                 $leftpixel = floor($byte / 16);
    73.                 $rightpixel = ($byte % 16);
    74.                 //Paint the two pixels
    75.                 imagesetpixel($tilesone, $x + ($j * 8), $y + ($I * 8), $palone[$leftpixel]);
    76.                 imagesetpixel($tilesone, $x + 1 + ($j * 8), $y + ($I * 8), $palone[$rightpixel]);
    77.             }
    78.         }
    79.     }
    80. }
    81. fseek($ram, 0x17D98);
    82. $I = 0;
    83. for($I= 0; $I < 48; $I++)
    84. {
    85.     $j = 0;
    86.     for($j= 0; $j < 32; $j++)
    87.     {
    88.         $y = 0;
    89.         for($y= 0; $y < 8; $y++)
    90.         {
    91.             $x = 0;
    92.             for($x= 0; $x < 8; $x = $x + 2)
    93.             {
    94.                 $byte = getByte($ram);
    95.                 // Split a byte into nybbles
    96.                 $leftpixel = floor($byte / 16);
    97.                 $rightpixel = ($byte % 16);
    98.                 //Paint the two pixels
    99.                 imagesetpixel($tilestwo, $x + ($j * 8), $y + ($I * 8), $paltwo[$leftpixel]);
    100.                 imagesetpixel($tilestwo, $x + 1 + ($j * 8), $y + ($I * 8), $paltwo[$rightpixel]);
    101.             }
    102.         }
    103.     }
    104. }
    105. fseek($ram, 0x17D98);
    106. $I = 0;
    107. for($I= 0; $I < 48; $I++)
    108. {
    109.     $j = 0;
    110.     for($j= 0; $j < 32; $j++)
    111.     {
    112.         $y = 0;
    113.         for($y= 0; $y < 8; $y++)
    114.         {
    115.             $x = 0;
    116.             for($x= 0; $x < 8; $x = $x + 2)
    117.             {
    118.                 $byte = getByte($ram);
    119.                 // Split a byte into nybbles
    120.                 $leftpixel = floor($byte / 16);
    121.                 $rightpixel = ($byte % 16);
    122.                 //Paint the two pixels
    123.                 imagesetpixel($tilesthree, $x + ($j * 8), $y + ($I * 8), $palthree[$leftpixel]);
    124.                 imagesetpixel($tilesthree, $x + 1 + ($j * 8), $y + ($I * 8), $palthree[$rightpixel]);
    125.             }
    126.         }
    127.     }
    128. }
    129. fseek($ram, 0x17D98);
    130. $I = 0;
    131. for($I= 0; $I < 48; $I++)
    132. {
    133.     $j = 0;
    134.     for($j= 0; $j < 32; $j++)
    135.     {
    136.         $y = 0;
    137.         for($y= 0; $y < 8; $y++)
    138.         {
    139.             $x = 0;
    140.             for($x= 0; $x < 8; $x = $x + 2)
    141.             {
    142.                 $byte = getByte($ram);
    143.                 // Split a byte into nybbles
    144.                 $leftpixel = floor($byte / 16);
    145.                 $rightpixel = ($byte % 16);
    146.                 //Paint the two pixels
    147.                 imagesetpixel($tilesfour, $x + ($j * 8), $y + ($I * 8), $palfour[$leftpixel]);
    148.                 imagesetpixel($tilesfour, $x + 1 + ($j * 8), $y + ($I * 8), $palfour[$rightpixel]);
    149.             }
    150.         }
    151.     }
    152. }
    153. //Okay we got the tiles!  Let's start building the Map32.
    154. $map32 = imagecreatetruecolor(512, 768);
    155. fseek($ram, 0x26C0);
    156. $I = 0;
    157. for($I= 0; $I < 24; $I++)
    158. {
    159.     $j = 0;
    160.     for($j= 0; $j < 16; $j++)
    161.     {
    162.         $y = 0;
    163.         for($y= 0; $y < 4; $y++)
    164.         {
    165.             $x = 0;
    166.             for($x= 0; $x < 4; $x++)
    167.             {
    168.                 $tile = getWord($ram);
    169.                 // PCCY XAAA AAAA AAAA
    170.                 //0110 0000 0000 0000 - 0x6000 - determine pallete
    171.                 //0 = Pallete 0,  8192 = Pallete 1, 16384 = Pallete 2, 24576 = Pallete 3
    172.                 $tilepallete = $tile & 0x6000;
    173.                 switch($tilepallete) {
    174.                     case 0: $tilepallete = 0; break;
    175.                     case 8192: $tilepallete = 1; break;
    176.                     case 16384: $tilepallete = 2; break;
    177.                     case 24576: $tilepallete = 3; break;
    178.                     default: $tilepallete = 0; break;
    179.                 }
    180.                 //0001 0000 0000 0000 - 0x1000 - determine Y flip
    181.                 //0 = No, 4096 = Yes
    182.                 $tileyflip = $tile & 0x1000;
    183.                 //0000 1000 0000 0000 - 0x0800 - determine X flip
    184.                 //0 = No, 2048 = Yes
    185.                 $tilexflip = $tile & 0x800;
    186.                 //0000 0111 1111 1111 - 0x07FF - get tile ID
    187.                 $tileID = $tile & 0x07FF;
    188.                 //imagecopyresampled($map32, $tilesone, ($x * 8) + ($j * 32), ($y * 8) + ($I * 32), ($tileID % 32) * 8, (floor($tileID / 32)) * 8, 8, 8, 8, 8); break;
    189.                 $tempimg = imagecreatetruecolor(8,8);
    190.                 switch($tilepallete) {
    191.                     case 0: imagecopyresampled($tempimg, $tilesone, 0, 0, ($tileID % 32) * 8, (floor($tileID / 32)) * 8, 8, 8, 8, 8); break;
    192.                     case 1: imagecopyresampled($tempimg, $tilestwo, 0, 0, ($tileID % 32) * 8, (floor($tileID / 32)) * 8, 8, 8, 8, 8); break;
    193.                     case 2: imagecopyresampled($tempimg, $tilesthree, 0, 0, ($tileID % 32) * 8, (floor($tileID / 32)) * 8, 8, 8, 8, 8); break;
    194.                     case 3: imagecopyresampled($tempimg, $tilesfour, 0, 0, ($tileID % 32) * 8, (floor($tileID / 32)) * 8, 8, 8, 8, 8); break;
    195.                     default: imagecopyresampled($tempimg, $tilesone, 0, 0, ($tileID % 32) * 8, (floor($tileID / 32)) * 8, 8, 8, 8, 8); break;
    196.                 }
    197.                 $flipflag = $tileyflip + $tilexflip;
    198.                 $tempimg = image_flip($tempimg, $flipflag);
    199.                 imagecopyresampled($map32, $tempimg, ($x * 8) + ($j * 32), ($y * 8) + ($I * 32), 0, 0, 8, 8, 8, 8);
    200.                 imagedestroy($tempimg);
    201.             }
    202.         }
    203.     }
    204. }
    205. header('Content-Type: image/png');
    206. imagepng($map32);
    207.  
    208. //Borrowed from something open source Lightning linked me to.
    209. function image_flip($img, $type){
    210.     $width  = imagesx($img);
    211.     $height = imagesy($img);
    212.     $dest   = imagecreatetruecolor($width, $height);
    213.     switch($type){
    214.         case 0:
    215.             return $img;
    216.         break;
    217.         case 4096:
    218.             for($I=0;$I<$height;$I++){
    219.                 imagecopy($dest, $img, 0, ($height - $I - 1), 0, $I, $width, 1);
    220.             }
    221.         break;
    222.         case 2048:
    223.             for($I=0;$I<$width;$I++){
    224.                 imagecopy($dest, $img, ($width - $I - 1), 0, $I, 0, 1, $height);
    225.             }
    226.         break;
    227.         case 6144:
    228.             for($I=0;$I<$width;$I++){
    229.                 imagecopy($dest, $img, ($width - $I - 1), 0, $I, 0, 1, $height);
    230.            
    231.             }
    232.             $buffer = imagecreatetruecolor($width, 1);
    233.             for($I=0;$I<($height/2);$I++){
    234.                 imagecopy($buffer, $dest, 0, 0, 0, ($height - $I -1), $width, 1);
    235.                 imagecopy($dest, $dest, 0, ($height - $I - 1), 0, $I, $width, 1);
    236.                 imagecopy($dest, $buffer, 0, $I, 0, 0, $width, 1);
    237.             }
    238.             imagedestroy($buffer);
    239.         break;
    240.         default:
    241.             return $img;
    242.         break;
    243.     }
    244.     return $dest;
    245. }
    246. ?>
    247.  
     
  2. Nice Job!

    I have that Rom...wondered how to make a Sonic character hack using Road Runner as Sonic and Wild E. as Robotnick.

    But I have no experience/know-how to make a hack..
     
  3. SonikkuForever

    SonikkuForever

    Be cool, be wild, and be groovy! Member
    576
    0
    16
    Gathering information on Sega World Sydney and collecting Sonic merchandise.
    That's genius! Maybe it could be AOSTH styled, with Sonic as roadrunner and Scratch/Grounder as the Coyote. The game itself is very cartoony, lots of anvils.
     
  4. Glisp

    Glisp

    That one weird guy that does stuff. Member
    1,278
    2
    16
    Bloomington, IN
    None at the moment I'm afraid.
    I loved Desert Demolition. If fact I still have it. I haven't played it recently though due to the fact I've been playing other things for the Genesis.

    If I recall there were a few prototype builds of this in drx's February 23, 2008 release. This game is made by Blue Sky Software, which makes really awesome games. Their Specialty was licensed Genesis games. Probably their biggest liscensed titles were Sega Genesis Jurassic Park and its sequel Jurassic Park Rampage Edition. They are also the group who made the classic title Vectorman and its sequel Vectorman 2. (Both games interestingly use some sound effects from Jurassic Park Rampage Edition.)

    Desert Demolition is still one of my favorite Genesis titles. Too bad it doesn't really have music but instead has sound effects that create music when you move or do another action of sorts.
     
  5. Polygon Jim

    Polygon Jim

    Eternal Tech Member
    0
    3
    0
    across town from Hinchy
    All the bitches.
    I remember that game, from when I was younger :)

    I still have the cartridge for it actually.


    But now that I think of it, that could make an awesome Sonic based hack. Sonic as roadrunner, Robotnik as Wile E. Coyote. Running around trying to catch Sonic, as Robotnik would be awesome.