/* Copyright (C) 2016 Joel Yliluoma - http://iki.fi/bisqwit/ * Redistribution and modifications are permitted under the rules * of Creative Commons Attribution-ShareAlike 3.0 license * https://creativecommons.org/licenses/by-sa/3.0/ */ #include #include #include #include static std::vector rom; static std::vector space; static std::string TranslateChar(unsigned char c) { switch(c) { case 0xA1: return "1"; case 0xA2: return "2"; case 0xA3: return "3"; case 0x40: return " "; case 0x94: return "-"; case 0x5F: return "!"; case 0x5C: return "."; default: return std::string(1, char(c)); } } static std::string TranslateIntroChar(unsigned char c) { switch(c) { case 0xA3: return "c"; // Copyr case 0xA7: return "1"; case 0xA5: return "9"; case 0xA1: return "8"; case 0xA0: return "0"; case 0xA2: return "2"; case 0x00: return " "; case 0xDC: return "."; case 0xDD: return ","; case 0xC1 ... 0xDA: return std::string(1, char(c-0x80)); case 0x80: return "-"; default: { char Buf[8]; std::sprintf(Buf, "[%02X]", c); return Buf; } } } static std::string TranslateEndingChar(unsigned char c) { switch(c) { case 0x1B: return "r"; case 0x1C: return "."; case 0x1E: return "\\'"; case 0x20: return " "; case 0x30 ... 0x39: return std::string(1, char(c)); case 0x00 ... 0x1A: return std::string(1, char(c + 0x40)); default: { char Buf[8]; std::sprintf(Buf, "[%02X]", c); return Buf; } } } // Read little-endian 16-bit word static unsigned ReadLEword(unsigned address) { return rom[address] + rom[address+1]*256; } // Read big-endian 16-bit word static unsigned ReadBEword(unsigned address) { return rom[address]*256 + rom[address+1]; } static void MarkFree(unsigned fromaddress, unsigned length) { while(length--) space[fromaddress++] = true; } template static void DumpText(unsigned fromaddress, unsigned length, Translator&& Translate) { std::string result; for(unsigned p=0; p> references) { std::printf("SCREENTABLE\n"); MarkFree(tableaddress, tablelength); for(const auto& p: references) std::printf("\tREFERRED_FROM %04X %u\n", p.first, p.second); for(unsigned t=0; t static void DumpFixString(unsigned straddress, unsigned length, Translator&& Translate, std::initializer_list> references = {}) { std::printf("FSTRING %u %X %c", length, straddress, c1); DumpText(straddress, length, std::forward(Translate)); std::printf("%c\n", c2); } static void DumpEndingStringTable(unsigned baseaddress, unsigned tableaddress, unsigned count, std::initializer_list> references) { std::printf("ENDINGTABLE %X\n", count==1 ? tableaddress : 0); for(auto r: references) { std::printf("\tREFERRED_FROM %X %u\n", r.first, r.second); } for(unsigned a=0; a> references) { std::printf("INTROTABLE\n"); for(const auto& p: references) std::printf("\tREFERRED_FROM %04X %u\n", p.first, p.second); for(unsigned t=0; t\n"); MarkFree(baseaddress, 3+textlength); baseaddress += 3+textlength; } } static void DumpFont(unsigned offset, unsigned count) { static const char chr[4] = {' ', '#', '.', 'c'}; for(unsigned begin=0; begin> (7-x)) & 1; unsigned bit2 = (rom[offset + c*16 + y + 8] >> (7-x)) & 1; std::printf("%c", chr[bit2*2+bit1]); } } std::printf(";\n"); } } } int main(int argc, char** argv) { rom.resize(0x40000); space.resize(0x40000); std::ifstream f(argv[1]); f.seekg(0x10); f.read( (char*) &rom[0], rom.size()); std::printf("; Intro copyrights\n"); DumpIntroScreen(0x36E95, // Begin of data 4, // Number of items {{0x35F2C +1,2}, // word to address {0x35F30 +1,2}, // word to address {0x35F37 +1,2}, // word to address {0x35F3E +1,2}, // word to address {0x35F26 +1,7}, // byte to table length }); std::printf("; Dialogs\n"); DumpScreen(0x36FBD, // Table of starting offsets 0x36F39, // Into this data 10, // Table length is this much {{0x362ED+1,2+16}, // word to address+1 {0x362E7+1,2}, // word to address+0 {0x362F5+1,2}, // word to address+0 {0x362F9+1,2}, // word to address+0 {0x36303+1,8+32}, // copies byte #2 from starting offset table {0x3698B+1,6}, // word to starting offset table {0x3698F+1,2}, // word to address+0 {0x36996+1,2}, // word to address+0 {0x3699D+1,2}, // word to address+0 {0x369A5+1,2}, // word to address+0 }); std::printf("; Game over text\n"); DumpFixString<'"','"'>(0x371E0, /*0x3712D,*/ 9, TranslateChar); std::printf("; Equipment upgrades screen\n"); Dump16StringTable(0x37E1A, 20); std::printf("; Ending\n"); DumpEndingStringTable(0x24C95, // Ending text address 0x24C59, // Lengths table address 60, // Number of strings {{0x2467C+1,0}, // data reference low {0x24678+1,1}, // data reference high {0x246C7+1,6} // lengths reference word }); // The "STAFF" text std::printf("; Ending, too\n"); DumpEndingStringTable(0x37ADB, // Text begins here 0x37831, // Lengths table is here 1, // One element {{0x37834+1,2} // data reference word }); std::printf("; Boss select screen\n"); for(unsigned l=0; l<28; ++l) DumpFixString<'\'','\''>(0x2EE40+l*32, 32, TranslateEndingChar); std::printf("; Title screen\n"); for(unsigned l=0; l<28; ++l) DumpFixString<'<','>'>(0x37331+(27-l)*32, 32, TranslateIntroChar); std::printf("; Intro\n"); for(unsigned n=0; n<10; ++n) DumpFixString<'<','>'>(0x36D46+n*0x1B, 0x1B, // begin of strings TranslateIntroChar // {{0x36557+1,0}, // data reference low byte // {0x3655B+1,0}, // data reference high byte // } ); std::printf("; Boss selection screen font\n"); DumpFont(0x20400, 0x5F + 0x21); std::printf("; Pause screen\n"); DumpFont(0x1950, 27); std::printf("; \"READY\"\n"); DumpFont(0x24440, 16); std::printf("; Title and dialog font\n"); DumpFont(0x26600, 0x80); // Fonts are found at: // 20400 (katakana + alphabet) // 1A00 (numbers only?) // 24440 (READY) // 26610 (hiragana, intro font) MarkFree(0x3FF87, 89); MarkFree(0x37FA0, 64); MarkFree(0x27F00, 192); DumpFree(); }