#!/usr/bin/php = 2 && (strtolower($argv[1]) == '--help' || strtolower($argv[1]) == 'help'))) { # Display help echo "Terranigma Data Reader $version -- by Road\n"; echo "Usage: ./".basename($argv[0])." [options]\n"; echo "\n"; echo "Commands:\n"; echo TAB."itemnames Dumps all itemnames\n"; echo TAB."rings Dumps all magic rings\n"; echo TAB."weapons Dumps all weapons\n"; echo TAB."armor Dumps all armor\n"; echo TAB."enemies Dumps all enemies\n"; echo TAB."raw Dump raw data from rom\n"; echo "\n"; echo "Options:\n"; echo TAB."--help Show this help\n"; echo TAB."--language=XX Choose rom language (default: auto, fallback: ".$options['language'].")\n"; echo TAB."--offset=XXXXX Change base offset for the chosen command\n"; echo TAB."--name-offset=XXXXX Change base offset for item name resolution\n"; echo TAB."--start=XXXXX Set start offset for raw output\n"; echo TAB."--end=XXXXX Set end offset for raw output\n"; echo TAB."--binary Output raw as binary\n"; echo TAB."--csv Output raw as csv (Delimiter is ;)\n"; echo TAB."--without-names Disable item name resolution\n"; echo TAB."--enemy-raw Show raw enemy statblock\n"; echo TAB."--autodetect-offset=XXXXX Change offset for rom version autodetection\n"; echo TAB."--header(=XXX) Move all offsets by header size (default: 512)\n"; echo "\n"; echo "Supported ROM Versions: "; foreach($offsets as $language => $val) { echo $language." "; } echo "\n\n"; exit(1); } ### define functions function autodetect_version($auto_offset) { global $offsets; global $file_handle; global $options; if(fseek($file_handle, $auto_offset+$options['header']) == -1) { echo "Invalid autodetect offset\n"; exit(5); } $signature = bin2hex(fread($file_handle, 1)); foreach($offsets as $lang => $arrval) { if(isset($arrval['signature']) && $arrval['signature'] == $signature) { return $lang; } } return $options['language']; } function terra2ascii($tstring) { $tchars = array('20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f','30','31','32','33', '34','35','36','37','38','39','3a','3b','3c','3d','3e','3f','40','41','42','43','44','45','46','47', '48','49','4a','4b','4c','4d','4e','4f','50','51','52','53','54','55','56','57','58','59','5a','5b', '5c','5d','5e','5f','60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f', '70','71','72','73','74','75','76','77','78','79','7a','7b','7c','7d','7e','7f','80'); $achars = array(' ','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X', 'Y','Z','ü','ä','Ä','ö','Ö','','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p', 'q','r','s','t','u','v','w','x','y','z','Ü',' ',' ',' ','ß','?','(',')','0','1','2','3','4','5','6', '7','8','9','!',',',':',' ',' ',' ',' ',' ',' ','"','=','','%','ô','+','-','/','&','.','*'); # Sorry, german table only $output = ''; $arr_string = str_split($tstring, 2); foreach($arr_string as $value) { $output .= str_replace($tchars,$achars,$value); } return $output; } function m_element($element_type) { if(is_numeric($element_type)) $element_type .= ''; # convert to string switch($element_type) { case '00': case '0': return 'Non-Elemental';break; case '08': case '8': return '[LIGHT]';break; case '10': return '[EARTH]';break; case '20': return '[THUNDER]';break; case '40': return '[ICE]';break; case '80': return '[FIRE]';break; default: return 'Invalid Element';break; } } function decode_resistance($hexbytes, $type) { $output = ''; switch($type) { case 'mresist': $data = str_split($hexbytes,2); $data[0] = hexdec($data[0]); $data[1] = hexdec($data[1]); if($data[1] & 8) { # Ignore first byte $res = 0; if($data[1] & 1) $res = 50; if($data[1] & 2) $res = 75; if($res == 0) { $output .= '[LIGHT]:Immunity '; } else { $output .= "[LIGHT]:-$res% "; } } if($data[1] & 16) { $res = 0; if($data[0] & 64) $res = 50; if($data[0] & 128) $res = 75; if($res == 0) { $output .= '[EARTH]:Immunity '; } else { $output .= "[EARTH]:-$res% "; } } if($data[1] & 32) { $res = 0; if($data[0] & 16) $res = 50; if($data[0] & 32) $res = 75; if($res == 0) { $output .= '[THUNDER]:Absorb/Immunity '; } else { $output .= "[THUNDER]:-$res% "; } } if($data[1] & 64) { $res = 0; if($data[0] & 4) $res = 50; if($data[0] & 8) $res = 75; if($res == 0) { $output .= '[ICE]:Absorb/Immunity '; } else { $output .= "[ICE]:-$res% "; } } if($data[1] & 128) { $res = 0; if($data[0] & 1) $res = 50; if($data[0] & 2) $res = 75; if($res == 0) { $output .= '[FIRE]:Absorb/Immunity '; } else { $output .= "[FIRE]:-$res% "; } } if($data[1] & 4) $output .= '(04 Set) '; break; case 'mweak': $data = str_split($hexbytes,2); $data[0] = hexdec($data[0]); $data[1] = hexdec($data[1]); if($data[1] & 8) { # Ignore first byte $res = 0; if($data[1] & 1) $res = 50; if($data[1] & 2) $res = 100; if($res == 0) { $output .= '[LIGHT]:Exclusive '; } else { $output .= "[LIGHT]:+$res% "; } } if($data[1] & 16) { $res = 0; if($data[0] & 64) $res = 50; if($data[0] & 128) $res = 100; if($res == 0) { $output .= '[EARTH]:Exclusive '; } else { $output .= "[EARTH]:+$res% "; } } if($data[1] & 32) { $res = 0; if($data[0] & 16) $res = 50; if($data[0] & 32) $res = 100; if($res == 0) { $output .= '[THUNDER]:Exclusive '; } else { $output .= "[THUNDER]:+$res% "; } } if($data[1] & 64) { $res = 0; if($data[0] & 4) $res = 50; if($data[0] & 8) $res = 100; if($res == 0) { $output .= '[ICE]:Exclusive '; } else { $output .= "[ICE]:+$res% "; } } if($data[1] & 128) { $res = 0; if($data[0] & 1) $res = 50; if($data[0] & 2) $res = 100; if($res == 0) { $output .= '[FIRE]:Exclusive '; } else { $output .= "[FIRE]:+$res% "; } } if($data[1] & 4) $output .= '(04 Set) '; break; case 'presist': $data = str_split($hexbytes,2); $data[0] = hexdec($data[0]); $data[1] = hexdec($data[1]); if($data[1] & 8) { # Ignore first byte $res = 0; if($data[1] & 1) $res = 50; if($data[1] & 2) $res = 75; if($res == 0) { $output .= '[UNKNOWN]:Immunity '; } else { $output .= "[UNKNOWN]:-$res% "; } } if($data[1] & 16) { $res = 0; if($data[0] & 64) $res = 50; if($data[0] & 128) $res = 75; if($res == 0) { $output .= '[SLICER]:Immunity '; } else { $output .= "[SLICER]:-$res% "; } } if($data[1] & 32) { $res = 0; if($data[0] & 16) $res = 50; if($data[0] & 32) $res = 75; if($res == 0) { $output .= '[SLIDER]:Immunity '; } else { $output .= "[SLIDER]:-$res% "; } } if($data[1] & 64) { $res = 0; if($data[0] & 4) $res = 50; if($data[0] & 8) $res = 75; if($res == 0) { $output .= '[SPINNER]:Immunity '; } else { $output .= "[SPINNER]:-$res% "; } } if($data[1] & 128) { $res = 0; if($data[0] & 1) $res = 50; if($data[0] & 2) $res = 75; if($res == 0) { $output .= '[RUSHING]:Immunity '; } else { $output .= "[RUSHING]:-$res% "; } } if($data[1] & 4) $output .= '(04 Set) '; break; case 'pweak': $data = str_split($hexbytes,2); $data[0] = hexdec($data[0]); $data[1] = hexdec($data[1]); if($data[1] & 8) { # Ignore first byte $res = 0; if($data[1] & 1) $res = 50; if($data[1] & 2) $res = 100; if($res == 0) { $output .= '[UNKNOWN]:Exclusive '; } else { $output .= "[UNKNOWN]:+$res% "; } } if($data[1] & 16) { $res = 0; if($data[0] & 64) $res = 50; if($data[0] & 128) $res = 100; if($res == 0) { $output .= '[SLICER]:Exclusive '; } else { $output .= "[SLICER]:+$res% "; } } if($data[1] & 32) { $res = 0; if($data[0] & 16) $res = 50; if($data[0] & 32) $res = 100; if($res == 0) { $output .= '[SLIDER]:Exclusive '; } else { $output .= "[SLIDER]:+$res% "; } } if($data[1] & 64) { $res = 0; if($data[0] & 4) $res = 50; if($data[0] & 8) $res = 100; if($res == 0) { $output .= '[SPINNER]:Exclusive '; } else { $output .= "[SPINNER]:+$res% "; } } if($data[1] & 128) { $res = 0; if($data[0] & 1) $res = 50; if($data[0] & 2) $res = 100; if($res == 0) { $output .= '[RUSHING]:Exclusive '; } else { $output .= "[RUSHING]:+$res% "; } } if($data[1] & 4) $output .= '(04 Set) '; break; } return $output; } function decode_sfx($hexbytes) { $output = ''; $data = str_split($hexbytes,2); $data[0] = hexdec($data[0]); $data[1] = hexdec($data[1]); if($data[0] & 32) $output .= "*Burned* "; if($data[0] & 64) $output .= "*Sleeping* "; if($data[0] & 128) $output .= "*Paralysed* "; if($data[1] & 1) $output .= "*Frozen* "; if($data[1] & 2) $output .= "*DEF down* "; if($data[1] & 4) $output .= "*STR down* "; if($data[1] & 8) $output .= "*Charmed* "; if($data[1] & 16) $output .= "*Confused* "; if($data[1] & 32) $output .= "*Poision* "; if($data[1] & 64) $output .= "*Deadly Poison* "; if($data[1] & 128) $output .= "*Cursed* "; return $output; } function decode_attack_sfx($data) { $output = ''; switch(true) { case (($data & 8) && ($data & 32) && ($data & 64)): $output.= '~Critical~'; break; case (($data & 8) && ($data & 16) && ($data & 64)): $output.= '*Burned*'; break; case (($data & 8) && ($data & 16) && ($data & 32)): $output.= '*DEF down*'; break; case (($data & 16) && ($data & 64)): $output.= '*Sleeping*'; break; case (($data & 8) && ($data & 64)): $output.= '*Paralysed*'; break; case (($data & 16) && ($data & 32)): $output.= '*STR down*'; break; case (($data & 8) && ($data & 32)): $output.= '*Charmed*'; break; case (($data & 8) && ($data & 16)): $output.= '*Poison*'; break; case ($data & 64): $output.= '*Frozen*'; break; case ($data & 32): $output.= '*Confused*'; break; case ($data & 16): $output.= '*Deadly Poison*'; break; case ($data & 8): $output.= '*Cursed*'; break; } return $output; } function read_itemnames($data_offset) { global $file_handle; global $options; if(fseek($file_handle, $data_offset+$options['header']) == -1) { echo "Invalid (itemname data) offset\n"; exit(5); } for($i = 1;$i <= 255;$i++) { # 255 Items $c = 0; $data[$i] = ''; switch($options['language']) { case 'sp': # discard nothing break; default: fread($file_handle,2); # discard 2 bytes break; } while(true) { $stream_byte = bin2hex(fread($file_handle, 1)); if($stream_byte == 'd4' || $c > 100) break; # something is wrong, cut off after 100 chars $data[$i] .= $stream_byte; $c++; } $data[$i] = terra2ascii($data[$i]); } return $data; } function read_enemy_offsets($eoffset) { global $file_handle; global $options; $enemies = array(); if(fseek($file_handle, $eoffset+$options['header']) == -1) { echo "Invalid (enemy index) offset\n"; exit(5); } for($i = 0;$i <= 98;$i++) { $pointer = str_split(bin2hex(fread($file_handle, 2)),2); # 99 Enemies, 2 byte pointers $enemies[$i] = hexdec($pointer[1] . $pointer[0]); # Endian order and conversion } unset($enemies[0]); # unset first (invalid) offset unset($enemies[74]); # also invalid return $enemies; } ### end functions $command = $argv[1]; $filename = $argv[2]; # Read options $option_count = $argc - 3; if($option_count > 0) { for($i = 0;$i <= $option_count;$i++) { # check if it's an option, else ignore if(substr($argv[$i+2], 0, 2) == '--') { if(strpos($argv[$i+2], '=') !== FALSE) { $pos = strpos($argv[$i+2], '='); $has_val = true; } else { $pos = strlen($argv[$i+2]); $has_val = false; } $option = strtolower(substr($argv[$i+2], 2, $pos - 2)); switch($option) { case 'offset': if($has_val) $options['offset'] = intval(substr($argv[$i+2], $pos+1),0); break; case 'start': if($has_val) $options['start'] = intval(substr($argv[$i+2], $pos+1),0); break; case 'end': if($has_val) $options['end'] = intval(substr($argv[$i+2], $pos+1),0); break; case 'language': if($has_val) $options['language'] = substr($argv[$i+2], $pos+1); $language_override = true; break; case 'csv': $options['csv'] = true; break; case 'binary': $options['binary'] = true; break; case 'without-names': $options['without-names'] = true; break; case 'enemy-raw': $options['enemy-raw'] = true; break; case 'name-offset': if($has_val) $options['name-offset'] = intval(substr($argv[$i+2], $pos+1),0); break; case 'autodetect-offset': if($has_val) $options['autodetect-offset'] = intval(substr($argv[$i+2], $pos+1),0); break; case 'header': if($has_val) $options['header'] = intval(substr($argv[$i+2], $pos+1),0); else $options['header'] = 512; break; default: break; } } } } # check if the file really exists if(!file_exists($filename)) { echo "Invalid filename: $filename\n"; exit(2); } $file_handle = @fopen($filename,'rb'); if($file_handle === FALSE) { echo "Cannot open file: $filename\n"; exit(3); } # Try to autodetect language if(!$language_override) $options['language'] = autodetect_version($options['autodetect-offset']); switch($command) { # Dump Raw Data case 'raw': if($options['start'] >= $options['end']) { echo "No data to dump\n"; exit(4); } if(fseek($file_handle, $options['start']+$options['header']) == -1) { echo "Invalid start offset\n"; exit(5); } $size = $options['end'] - $options['start']; for($i = 1;$i <= $size;$i++) { $data = fread($file_handle, 1); if($options['binary']) { echo $data; } elseif($options['csv']) { echo bin2hex($data).';'; } else { echo bin2hex($data).' '; } } if(!($options['binary'] || $options['csv'])) echo "\n"; break; # Dump Ring data case 'rings': $offset = ($options['offset'] == 0) ? $offsets[$options['language']]['rings'] : $options['offset']; if(!$options['without-names']) { $name_offset = ($options['name-offset'] == 0) ? $offsets[$options['language']]['itemnames'] : $options['name-offset']; $itemnames = read_itemnames($name_offset); } if(fseek($file_handle, $offset+$options['header']) == -1) { echo "Invalid (rings) offset\n"; exit(5); } for($i = 1;$i <= 10;$i++) { # Ten rings to bind them... $rings[] = str_split(bin2hex(fread($file_handle, 4)), 2); # 4 Bytes Data } foreach($rings as $index => $ring) { echo "Ring $index ("; if(@isset($itemnames[$index+$offsets[$options['language']]['first_ring_id']])) echo @$itemnames[$index+$offsets[$options['language']]['first_ring_id']]; echo ")\n"; echo TAB."Attack power: ".hexdec($ring[1].$ring[0])." (".$ring[1].$ring[0].")\n"; echo TAB."Element: ".m_element($ring[3])."\n"; } break; # Dump Weapon data case 'weapons': $offset = ($options['offset'] == 0) ? $offsets[$options['language']]['weapons'] : $options['offset']; if(!$options['without-names']) { $name_offset = ($options['name-offset'] == 0) ? $offsets[$options['language']]['itemnames'] : $options['name-offset']; $itemnames = read_itemnames($name_offset); } if(fseek($file_handle, $offset+$options['header']) == -1) { echo "Invalid (weapons) offset\n"; exit(5); } for($i = 1;$i <= 32;$i++) { # 32 weapons (not all are used) $weapons[] = str_split(bin2hex(fread($file_handle, 4)), 2); # 4 Bytes Data } foreach($weapons as $index => $weapon) { echo "Weapon $index ("; if(@isset($itemnames[$index+$offsets[$options['language']]['first_weapon_id']])) echo @$itemnames[$index+$offsets[$options['language']]['first_weapon_id']]; echo ")\n"; echo TAB."Attack power: ".hexdec($weapon[0])." (".$weapon[0].")\n"; if($weapon[1] != '00') { echo TAB."Mod Index: ".strtoupper($weapon[1])." (not yet decoded, this wpn has stat changes)\n"; } if($weapon[3] != '00') { echo TAB."Element: ".m_element($weapon[3])."\n"; } else { echo TAB."Non-elemental Weapon\n"; } } break; # Dump Armor data case 'armor': $offset = ($options['offset'] == 0) ? $offsets[$options['language']]['armor'] : $options['offset']; if(!$options['without-names']) { $name_offset = ($options['name-offset'] == 0) ? $offsets[$options['language']]['itemnames'] : $options['name-offset']; $itemnames = read_itemnames($name_offset); } if(fseek($file_handle, $offset+$options['header']) == -1) { echo "Invalid (armor) offset\n"; exit(5); } # Read the basic attributes for($i = 1;$i <= 32;$i++) { # 32 armors (not all are used) $armors[] = str_split(bin2hex(fread($file_handle, 4)), 2); # 4 Bytes Data } # Now read the status effect immunities for($i = 1;$i <= 32;$i++) { # 32 armors (not all are used) $armors[$i-1]['sfx'] = bin2hex(fread($file_handle, 2)); # 2 Bytes Data } foreach($armors as $index => $armor) { echo "Armor $index ("; if(@isset($itemnames[$index+$offsets[$options['language']]['first_armor_id']])) echo @$itemnames[$index+$offsets[$options['language']]['first_armor_id']]; echo ")\n"; echo TAB."Defense power: ".hexdec($armor[0])." (".$armor[0].")\n"; if($armor[1] != '00') { echo TAB."Mod Index: ".strtoupper($armor[1])." (not yet decoded, this armor has stat changes)\n"; } if($armor[3] != '00') { echo TAB."Elemental Resistances: ".decode_resistance($armor[2].$armor[3],'mresist')."(".$armor[2].$armor[3].")\n"; } if($armor['sfx'] != '0000') { echo TAB."Status Effect Immunities: ".decode_sfx($armor['sfx'])."(".$armor['sfx'].")\n"; } } break; # Dump Item Names case 'itemnames': $offset = ($options['offset'] == 0) ? $offsets[$options['language']]['itemnames'] : $options['offset']; $itemnames = read_itemnames($offset); var_dump($itemnames); break; # Dump enemy data case 'enemies': $e_offsets = read_enemy_offsets($offsets[$options['language']]['enemies_index']); $offset = ($options['offset'] == 0) ? $offsets[$options['language']]['enemies_bank'] : $options['offset']; if(fseek($file_handle, $offset+$options['header']) == -1) { echo "Invalid (enemy bank) offset\n"; exit(5); } foreach($e_offsets as $e_id => $e_offset) { if($options['enemy-raw']) { if(fseek($file_handle, $offset+$options['header']+$e_offset) == -1) { echo "Invalid (enemy) offset\n"; exit(5); } $rawdata = '<'.join(' ',str_split(bin2hex(fread($file_handle, 8)),2)).'>'; $rawdata .= ' <'.join(' ',str_split(bin2hex(fread($file_handle, 1)),2)).'>'; $rawdata .= ' <'.join(' ',str_split(bin2hex(fread($file_handle, 2)),2)).'>'; $rawdata .= ' <'.join(' ',str_split(bin2hex(fread($file_handle, 2)),2)).'>'; $rawdata .= ' <'.join(' ',str_split(bin2hex(fread($file_handle, 2)),2)).'>'; $rawdata .= ' <'.join(' ',str_split(bin2hex(fread($file_handle, 5)),2)).'>'; $rawdata .= ' <'.join(' ',str_split(bin2hex(fread($file_handle, 5)),2)).'>'; if(isset($enemies_extra[$e_id])) { for($i = 1;$i <= $enemies_extra[$e_id];$i++) { $rawdata .= ' <'.join(' ',str_split(bin2hex(fread($file_handle, 5)),2)).'>'; } } echo $rawdata."\n"; } if(fseek($file_handle, $offset+$options['header']+$e_offset) == -1) { echo "Invalid (enemy) offset\n"; exit(5); } # Enemy ID $output[0] = "Monster ID ".$e_id; # First Block # Read magic resistances $data = bin2hex(fread($file_handle, 2)); $output[5] = "Magic Resistance against: ".decode_resistance($data, 'mresist'); # Read physical resistances $data = bin2hex(fread($file_handle, 2)); $output[7] = "Physical Resistance against: ".decode_resistance($data, 'presist'); # Read magic weaknesses $data = bin2hex(fread($file_handle, 2)); $output[6] = "Magic Weakness against: ".decode_resistance($data, 'mweak'); # Read physical weaknesses $data = bin2hex(fread($file_handle, 2)); $output[8] = "Physical Weakness against: ".decode_resistance($data, 'pweak'); # Read Level $data = hexdec(bin2hex(fread($file_handle, 1))); $output[1] = "Level: ".$data; # Read Lifepoints $data = str_split(bin2hex(fread($file_handle, 2)),2); # Endian order $output[2] = "Life: ".hexdec($data[1].$data[0]); # Read Exp Points $data = str_split(bin2hex(fread($file_handle, 2)),2); # Endian order $output[3] = "Exp.: ".intval($data[1].$data[0]); # decimal, not hex # Read Dropped Gems $data = str_split(bin2hex(fread($file_handle, 2)),2); $drop = '100'; $decval = hexdec($data[1]); # extract drop chance if($decval & 128) { $drop = $drop/2; $decval -= hexdec(80); } if($decval & 64) { $drop = $drop/2; $decval -= hexdec(40); } if($decval & 32) { $drop = $drop/2; $decval -= hexdec(20); } if($decval & 16) { $drop = $drop/2; $decval -= hexdec(10); } $output[4] = "Gems: ".intval($decval.$data[0])." (".$drop."%)"; # decimal, not hex # Read Strength and Status Effects of primary attack $data = str_split(bin2hex(fread($file_handle, 2)),2); $data[0] = hexdec($data[0]); $data[1] = hexdec($data[1]); if($data[1] & 1) $data[0] += 256; if($data[1] & 2) $data[0] += 512; $output[10] = "Strength (Primary Attack): ".$data[0]; $output[12] = "Status Effect (Primary Attack): "; $output[12] .= decode_attack_sfx($data[1]); # Read Defense $data = str_split(bin2hex(fread($file_handle, 2)),2); # Endian order $output[9] = "Defense: ".hexdec($data[1].$data[0]); # Read Luck (Primary Attack) $data = bin2hex(fread($file_handle, 1)); $output[11] = "Luck (Primary Attack): ".hexdec($data); # Read Strength and Status Effects of secondary attack $data = str_split(bin2hex(fread($file_handle, 2)),2); $data[0] = hexdec($data[0]); $data[1] = hexdec($data[1]); if($data[1] & 1) $data[0] += 256; if($data[1] & 2) $data[0] += 512; $output[13] = "Strength (Secondary Attack): ".$data[0]; $output[16] = "Status Effect (Secondary Attack): "; $output[16] .= decode_attack_sfx($data[1]); # Read Unknown/Unused Byte and discard fread($file_handle, 1); # Read Element of secondary attack $data = bin2hex(fread($file_handle, 1)); $byte = false; if(hexdec($data) & 4) { $data = dechex(hexdec($data)-4); $byte = true; } $output[15] = "Element (Secondary Attack): ".m_element($data); if($byte) $output[15] .= " (04 Set)"; # Read Luck (Secondary Attack) $data = bin2hex(fread($file_handle, 1)); $output[14] = "Luck (Secondary Attack): ".hexdec($data); # Read extra attack blocks $extra = 0; if(isset($enemies_extra[$e_id])) { $extra = $enemies_extra[$e_id]; for($i = 1;$i <= $extra;$i++) { $data = str_split(bin2hex(fread($file_handle, 2)),2); $data[0] = hexdec($data[0]); $data[1] = hexdec($data[1]); if($data[1] & 1) $data[0] += 256; if($data[1] & 2) $data[0] += 512; $output[13+($i*4)] = "Strength (".(2+$i).". Attack): ".$data[0]; $output[16+($i*4)] = "Status Effect (".(2+$i).". Attack): "; $output[16+($i*4)] .= decode_attack_sfx($data[1]); fread($file_handle, 1); $data = bin2hex(fread($file_handle, 1)); $byte = false; if(hexdec($data) & 4) { $data = dechex(hexdec($data)-4); $byte = true; } $output[15+($i*4)] = "Element (".(2+$i).". Attack): ".m_element($data); if($byte) $output[14+($i*4)] .= " (04 Set)"; $data = bin2hex(fread($file_handle, 1)); $output[14+($i*4)] = "Luck (".(2+$i).". Attack): ".hexdec($data); } } # Output everything in order for($i = 0;$i <= 16+($extra*4);$i++) { echo $output[$i]."\n"; } echo "\n"; } break; default: echo "no command given\n"; break; } exit(0); ?>