";
$objects = array();
for( $z=0; $z < 10; $z++ )
for( $a=0; $a < 3; $a++ )
{
echoObjects( $objects, $object_layout_index, $object_bank, $z, $a );
}
foreach($objects as $index=>$object )
{
echo binhex(chr($index)).' ';
}
return;
}
$colors = array();
$blockcolors = array();
$map = array();
$tiles = array();
$tilelocs = array();
$blocks = array();
// Getting level data
fseek( $rom, $map_index + 2*$zone );
$map_zone_index = getWord($rom);
fseek( $rom, $map_zone_index + 2*$act );
$level_address = getWord($rom);
fseek( $rom, $level_address);
$block_bank = getByte($rom);
$block_address = getWord($rom) + $block_bank * 0x4000 - 0x8000;
$map_bank = getByte($rom);
$map_address = getWord($rom) + $map_bank * 0x4000 - 0x8000;
$level_width = getWord($rom);
$level_height = getByte($rom)/4;
if( $level_width == 0 )
{
echo "Level garbled - width $level_width
";
return;
}
fseek( $rom, $object_layout_index + 2*$zone );
$object_layout_zone_index = getWord($rom) + $object_bank - 0x8000;
fseek( $rom, $object_layout_zone_index + 2*$act );
$object_layout_address = getWord($rom) + $object_bank - 0x8000;
if( $game == 'chaos' )
{
loadSCMap($map_address);
}
elseif( $game == 's2gg' )
{
loadS2Map($map_address);
}
else
{
loadSTTMap($map_address);
}
$auto_level_height = sizeof($map) / $level_width;
if( $level_height == 0 || ($auto_level_height < $level_height) || $game == 's2gg' )
{
$level_height = floor($auto_level_height/4) * 4;
// chaos ss1/intro have 0 height. why? who knows.
}
fseek( $rom, $tile_index + $zone*21 + $act*7 );
if( $game == 'stt' && $zone == 0x0A )
{
// Yes, it's ugly, but the game does this itself,
// by checking for game mode 0x11 (time attack).
fseek( $rom, 0x6B743 );
// All it does is move the offset to the previous level...
// why didn't they just change the offsets for that level?
// Who knows.
}
$tile_bank = getByte($rom);
$unknown = getWord($rom);
$tile_address = getWord($rom) + $tile_bank * 0x4000 - 0x8000;
fseek( $rom, $tile_address );
$unknown = getWord($rom);
$tile_num = getWord($rom);
$guideloc = getWord($rom) + $tile_address;
$tileloc = $tile_address + 6;
$image = imagecreatetruecolor( $level_width*32, $level_height*32 );
$blockimage = imagecreatetruecolor( 32*256, 32 );
// Creating the palette
fseek( $rom, $palette_id_address + $zone*6 + $act*2 ); // No hax this time, the game actually does this.
$palette_id_bg = getByte($rom);
$palette_id_obj = getByte($rom);
fseek( $rom, $palette_address + $palette_id_bg * 0x20 );
for( $c=0; $c<32; $c++ )
{
if( $c == 16 )
fseek( $rom, $palette_address + $palette_id_obj * 0x20 );
$color = ord(fread( $rom, 1 ));
$color2 = ord(fread( $rom, 1 ));
$red = 16 * ($color % 16);
$green = 16 * floor($color / 16);
$blue = 16 * ($color2 % 16);
if( $_GET['gray'] == 1 )
{
$red = 16*($c%16);
$green = 16*($c%16);
$blue = 16*($c%16);
}
$colors[$c] = imagecolorallocate( $image, $red, $green, $blue );
$blockcolors[$c] = imagecolorallocate( $blockimage, $red, $green, $blue );
}
// Loading tiles
$p = 3;
$guidebyte = 0;
for( $t=$tileloadat; $t<$tileloadat+0x100; $t++ )
{
$data = array();
$strings = array();
$p++;
if( $p == 4 )
{
fseek( $rom, $guideloc++ );
$guidebyte = getByte( $rom );
$p = 0;
}
$guide = bittest( $guidebyte, 2*$p ) + 2* bittest( $guidebyte, 2*$p+1 );
$tilelocs[$t] = dechex($tileloc).':'.$guide;
if( $guide == 0 )
{
$tiles[$t] = '';
}
if( $guide == 1 )
{
fseek( $rom, $tileloc );
$tiles[$t] = fread( $rom, 32 );
$tileloc += 32;
}
if( $guide == 2 )
{
$tiles[$t] = decodeTile( $tileloc );
}
if( $guide == 3 )
{
$tiles[$t] = decodeTile( $tileloc );
$ix = 0;
for( $b=7; $b>0; $b-- )
{
$tiles[$t][$ix+2] = $tiles[$t][$ix+0] ^ $tiles[$t][$ix+2];
$tiles[$t][$ix+3] = $tiles[$t][$ix+1] ^ $tiles[$t][$ix+3];
$tiles[$t][$ix+18] = $tiles[$t][$ix+16] ^ $tiles[$t][$ix+18];
$tiles[$t][$ix+19] = $tiles[$t][$ix+17] ^ $tiles[$t][$ix+19];
$ix += 2;
}
}
}
// Loading tile blocks
for( $b = 0; $b < 256; $b++)
{
$blocks[$b] = array();
fseek( $rom, $block_address + 2*$b );
$loc = ord(fread($rom,1)) + ord(fread($rom,1))*256;
fseek( $rom, $block_bank * 0x4000 - 0x8000 + $loc );
for( $i = 0; $i < 16; $i++)
{
$t = ord( fread( $rom, 1 ) );
$d = ord( fread( $rom, 1 ) );
$blocks[$b][$i] = $d * 256 + $t;
}
}
// Caching the blocks in a second image
for( $b = 0; $b < 256; $b++ )
{
createBlock( $blockimage, $b, $b*32,0);
}
if( $_GET['blocks'] == 1 )
{
// Show blocks
for( $t=$tileloadat; $t<$tileloadat + 0x100; $t++ )
{
displayTile( $image, $tiles[$t], 0, (($t-$tileloadat) % 128)*8, floor(($t-$tileloadat) / 128) * 8 );
}
$b = 0;
for( $c = 0; $c < 16; $c++ )
for( $r = 0; $r < 16; $r++ )
{
displayBlock( $image, $b, $c*64,$r*32+32);
imagestring( $image, 1, $c*64+36, $r*32+14+32, dechex($b), $colors[15] );
$b++;
}
}
elseif( isset( $_GET['tiles'] ) )
{
// Show tiles
$t = 192;
for( $i=0; $i<8; $i++ )
for( $j=0; $j<8; $j++ )
{
imagestring( $image, 1, $j*100 + 20, $i*24, ($tilelocs[$t]), $colors[15] );
imagestring( $image, 1, $j*100 + 20, $i*24 + 10, ($tilelocs[$t+1]), $colors[15] );
imagestring( $image, 1, $j*100 + 60, $i*24, ($tilelocs[$t+2]), $colors[15] );
imagestring( $image, 1, $j*100 + 60, $i*24 + 10, ($tilelocs[$t+3]), $colors[15] );
displayTile( $image, $tiles[$t+0], 0, $j*100+0, $i*24 );
displayTile( $image, $tiles[$t+1], 0, $j*100+0, $i*24 +8 );
displayTile( $image, $tiles[$t+2], 0, $j*100+8, $i*24 );
displayTile( $image, $tiles[$t+3], 0, $j*100+8, $i*24 +8 );
$t += 4;
}
}
else
{
// Show map
$m = 0;
for( $r = 0; $r < $level_height; $r++ )
for( $c = 0; $c < $level_width; $c++ )
{
displayBlock( $image, $map[$m++], $c*32,$r*32);
}
}
// Add objects
fseek( $rom, $object_layout_address );
do
{
$num = getByte($rom);
if( $num == 0xFF )
continue;
$r = getWord($rom) - 0x100;
$c = getWord($rom) - 0x100;
$unk = getWord($rom);
$unk = getWord($rom);
imagestring( $image, 1, $r, $c, strtoupper(dechex($num)), $colors[15] );
} while( $num != 0xFF );
// Output
if( strlen( $outputfile ) )
{
imagepng( $image, $outputfile );
}
else
{
header('Content-type: image/png');
imagepng($image);
}
}
////////////////////////////////////////////////////////
// Functions
function decodeTile( &$data_address )
{
global $rom;
fseek( $rom, $data_address );
$dataflags = fread( $rom, 4 );
$data_address += 4;
$data = '';
for( $i=0; $i<32; $i++ )
{
$b = $i % 8;
$c = (int) ($i/8);
if( ord($dataflags[$c]) & pow(2,$b) )
{
$data .= fread( $rom, 1 );
$data_address++;
}
else
{
$data .= chr(0);
}
}
return $data;
}
function binhex( $data )
{
$str = '';
for( $i=0; $i0; $i-- )
{
$map[$m++] = $map[$m2++];
}
}
}
}
}
function getByte( &$source )
{
return ord( fread( $source,1 ) );
}
function getWord( &$source )
{
return getByte( $source ) + getByte( $source ) * 0x100;
}
function echoObjects( &$objects, $object_layout_index, $object_bank, $zone, $act )
{
global $rom;
fseek( $rom, $object_layout_index + 2*$zone );
$object_layout_zone_index = getWord($rom) + $object_bank - 0x8000;
fseek( $rom, $object_layout_zone_index + 2*$act );
$object_layout_address = getWord($rom) + $object_bank - 0x8000;
fseek( $rom, $object_layout_address );
$o = 0;
do
{
$num = getByte($rom);
if( $num == 0xFF )
continue;
echo binhex( chr($num)).":";
echo binhex( fread($rom,2) ).' ';
echo binhex( fread($rom,2) ).' ';
echo binhex( fread($rom,2) ).' ';
echo binhex( fread($rom,2) ).' ';
echo "
";
$o++;
$objects[$num] = '';
} while( $num != 0xFF && $o < 100 );
echo "-- $zone-$act ".dechex($object_layout_zone_index)." ".dechex($object_layout_address)." : $o
";
}
?>