diff options
author | Johannes Schickel | 2007-02-07 19:29:15 +0000 |
---|---|---|
committer | Johannes Schickel | 2007-02-07 19:29:15 +0000 |
commit | e9e62cf67a8690c93a8f4949cabbeca82fd8603d (patch) | |
tree | a35167248ceaf9d84e524fe8f6f7dce916a54a6f /tools/create_kyradat | |
parent | 1421a439694118844abb107f6a15c8693b70a875 (diff) | |
download | scummvm-rg350-e9e62cf67a8690c93a8f4949cabbeca82fd8603d.tar.gz scummvm-rg350-e9e62cf67a8690c93a8f4949cabbeca82fd8603d.tar.bz2 scummvm-rg350-e9e62cf67a8690c93a8f4949cabbeca82fd8603d.zip |
Adds support for FM-Towns version.
(Thanks to Florian Kagerer again for this)
svn-id: r25414
Diffstat (limited to 'tools/create_kyradat')
-rw-r--r-- | tools/create_kyradat/Makefile | 2 | ||||
-rw-r--r-- | tools/create_kyradat/create_kyradat.cpp | 154 | ||||
-rw-r--r-- | tools/create_kyradat/create_kyradat.h | 8 | ||||
-rw-r--r-- | tools/create_kyradat/misc.h | 122 | ||||
-rw-r--r-- | tools/create_kyradat/towns.h | 121 |
5 files changed, 381 insertions, 26 deletions
diff --git a/tools/create_kyradat/Makefile b/tools/create_kyradat/Makefile index b90f8940b7..ce4fa5ca91 100644 --- a/tools/create_kyradat/Makefile +++ b/tools/create_kyradat/Makefile @@ -19,7 +19,7 @@ clean: rm -f $(BIN) rm -f $(OBJS) -create_kyradat.o: eng.h esp.h fre.h ger.h misc.h pak.h util.h md5.h +create_kyradat.o: eng.h esp.h fre.h ger.h misc.h pak.h towns.h util.h md5.h pak.o: pak.h util.h %.o: %.cpp diff --git a/tools/create_kyradat/create_kyradat.cpp b/tools/create_kyradat/create_kyradat.cpp index 5210dd2054..8a58436614 100644 --- a/tools/create_kyradat/create_kyradat.cpp +++ b/tools/create_kyradat/create_kyradat.cpp @@ -25,7 +25,7 @@ #include "md5.h" enum { - kKyraDatVersion = 14, + kKyraDatVersion = 15, kIndexSize = 12 }; @@ -36,11 +36,12 @@ enum { #include "esp.h" #include "fre.h" #include "ger.h" +#include "towns.h" -bool extractRaw(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename); -bool extractStrings(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename); -bool extractRooms(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename); -bool extractShapes(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename); +bool extractRaw(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch = 0); +bool extractStrings(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch = 0); +bool extractRooms(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch = 0); +bool extractShapes(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch = 0); void createFilename(char *dstFilename, const int lang, const int special, const char *filename); void createLangFilename(char *dstFilename, const int lang, const int special, const char *filename); @@ -159,7 +160,10 @@ const ExtractFilename extractFilenames[] = { { kPaletteList33, kTypeRawData, "PALTABLE33.PAL" }, // FM-TOWNS specific - { kKyra1TownsSFXTable, kTypeRawData, "SFXTABLE.TSX" }, + { kKyra1TownsSFXTable, kTypeRawData, "SFXTABLE" }, + { kCreditsStrings, kTypeRawData, "CREDITS" }, + { kMenuSKB, kTypeStringList, "MENUSKB" }, + { kSjisVTable, kTypeRawData, "SJISTABLE" }, { -1, 0, 0 } }; @@ -282,32 +286,111 @@ bool hasNeededEntries(const Game *game, const PAKFile *file) { // extraction -bool extractRaw(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename) { - uint8 *buffer = new uint8[size]; - assert(buffer); - memcpy(buffer, data, size); +bool extractRaw(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch) { + uint8 *buffer = 0; + + if (fmtPatch == 2) { + buffer = new uint8[0x12602]; + assert(buffer); + memcpy(buffer, data, 0x7EE5); + memcpy(buffer + 0x7EE5, data + 0x7EE7, 0x7FFF); + memcpy(buffer + 0xFEE4, data + 0xFEE8, 0x271E); + } else { + buffer = new uint8[size]; + assert(buffer); + memcpy(buffer, data, size); + } + return out.addFile(filename, buffer, size); } -bool extractStrings(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename) { +bool extractStrings(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch) { uint32 entries = 0; + uint32 targetsize = size + 4; for (uint32 i = 0; i < size; ++i) { - if (!data[i]) + if (!data[i]) { ++entries; + if (g->special == kFMTownsVersionE || g->special == kFMTownsVersionJ) { + // prevents creation of empty entries (which we have mostly between all strings in the fm-towns version) + while (!data[++i]) { + if (i == size) + break; + targetsize--; + } + if (fmtPatch == 1) { + // Here is the first step of the extra treatment for all fm-towns string arrays that + // contain more than one string and which the original code + // addresses via stringname[boolJapanese]. + // We simply skip every other string + if (i == size) + continue; + uint32 size = strlen((const char*) data + i); + i += size; targetsize = --targetsize - size; + while (!data[++i]) { + if (i == size) + break; + targetsize--; + } + } + } + } + } + + if (fmtPatch == 2) { + targetsize++; + entries++; } - uint8 *buffer = new uint8[size + 4]; + uint8 *buffer = new uint8[targetsize]; assert(buffer); uint8 *output = buffer; + uint8 *input = (uint8*) data; WRITE_BE_UINT32(output, entries); output += 4; - memcpy(output, data, size); + if (g->special == kFMTownsVersionE || g->special == kFMTownsVersionJ) { + const byte * c = data + size; + do { + strcpy((char*) output, (const char*) input); + uint32 stringsize = strlen((const char*)output) + 1; + input += stringsize; output += stringsize; + // skip empty entries + while (!*input) { + // Write one empty string into intro strings file + if (fmtPatch == 2) { + if ((g->special == kFMTownsVersionE && input - data == 0x260) || + (g->special == kFMTownsVersionJ && input - data == 0x265)) + *output++ = *input; + } + + if (++input == c) + break; + } + + if (fmtPatch == 1) { + // Here is the extra treatment for all fm-towns string arrays that + // contain more than one string and which the original code + // addresses via stringname[boolJapanese]. + // We simply skip every other string + if (input == c) + continue; + input += strlen((const char*)input); + while (!*input) { + if (++input == c) + break; + } + } + + } while (input < c); + } else { + memcpy(output, data, size); + } - return out.addFile(filename, buffer, size + 4); + return out.addFile(filename, buffer, targetsize); } -bool extractRooms(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename) { - const int countRooms = size / 0x51; +bool extractRooms(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch) { + // different entry size for the fm-towns version + const int countRooms = (g->special == kFMTownsVersionE) ? (size / 0x69) : (size / 0x51); uint8 *buffer = new uint8[countRooms * 9 + 4]; assert(buffer); @@ -322,13 +405,14 @@ bool extractRooms(PAKFile &out, const Game *g, const byte *data, const uint32 si WRITE_BE_UINT16(output, READ_LE_UINT16(src)); output += 2; src += 2; WRITE_BE_UINT16(output, READ_LE_UINT16(src)); output += 2; src += 2; WRITE_BE_UINT16(output, READ_LE_UINT16(src)); output += 2; src += 2; - src += (0x51 - 9); + // different entry size for the fm-towns version + src += (g->special == kFMTownsVersionE) ? 0x60 : (0x51 - 9); } return out.addFile(filename, buffer, countRooms * 9 + 4); } -bool extractShapes(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename) { +bool extractShapes(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch) { byte *buffer = new byte[size + 1 * 4]; assert(buffer); byte *output = buffer; @@ -365,7 +449,7 @@ uint32 getFeatures(const Game *g) { features |= GF_TALKIE; else if (g->special == kDemoVersion) features |= GF_DEMO; - else if (g->special == kFMTownsVersion) + else if (g->special == kFMTownsVersionE || g->special == kFMTownsVersionJ) features |= GF_FMTOWNS; else features |= GF_FLOPPY; @@ -380,6 +464,8 @@ uint32 getFeatures(const Game *g) { features |= GF_SPANISH; else if (g->lang == IT_ITA) features |= GF_ITALIAN; + else if (g->lang == JA_JPN) + features |= GF_JAPANESE; return features; } @@ -501,6 +587,18 @@ int main(int argc, char *argv[]) { if (!process(out, g, buffer, size)) fprintf(stderr, "ERROR: couldn't process file '%s'", argv[i]); + if (g->special == kFMTownsVersionE) { + // The English and non language specific data has now been extracted + // so we switch to Japanese and extract the rest + if (!hasNeededEntries(++g, &out)) { + warning("file '%s' is missing offset entries and thus can't be processed", argv[i]); + delete [] buffer; + continue; + } + if (!process(out, g, buffer, size)) + fprintf(stderr, "ERROR: couldn't process file '%s'", argv[i]); + } + delete [] buffer; } @@ -551,8 +649,18 @@ bool process(PAKFile &out, const Game *g, const byte *data, const uint32 size) { PAKFile::cFileList *list = out.getFileList(); if (list && list->findEntry(filename) != 0) continue; - - if (!tDesc->extract(out, g, data + i->startOff, i->endOff - i->startOff, filename)) { + + int patch = 0; + if (g->special == kFMTownsVersionE || g->special == kFMTownsVersionJ) { + // FM Towns files that need addional patches + if (i->id == kTakenStrings || i->id == kNoDropStrings || i->id == kPoisonGoneString || + i->id == kThePoisonStrings || i->id == kFluteStrings || i->id == kWispJewelStrings) + patch = 1; + else if (i->id == kIntroStrings || i->id == kKyra1TownsSFXTable) + patch = 2; + } + + if (!tDesc->extract(out, g, data + i->startOff, i->endOff - i->startOff, filename, patch)) { fprintf(stderr, "ERROR: couldn't extract id %d\n", i->id); return false; } @@ -573,6 +681,7 @@ const Game *gameDescs[] = { kyra1EspGames, kyra1FreGames, kyra1GerGames, + kyra1TownsGames, 0 }; @@ -599,3 +708,4 @@ const Game *findGame(const byte *buffer, const uint32 size) { printf("file is not supported (unknown md5 \"%s\")\n", md5str); return 0; } + diff --git a/tools/create_kyradat/create_kyradat.h b/tools/create_kyradat/create_kyradat.h index 4bcf289fad..2a75702e01 100644 --- a/tools/create_kyradat/create_kyradat.h +++ b/tools/create_kyradat/create_kyradat.h @@ -134,6 +134,9 @@ enum kExtractID { kConfigStrings, kKyra1TownsSFXTable, + kCreditsStrings, + kSjisVTable, + kMenuSKB, kMaxResIDs }; @@ -153,7 +156,8 @@ struct ExtractFilename { enum kSpecial { kTalkieVersion = 0, kDemoVersion = 1, - kFMTownsVersion = 2 + kFMTownsVersionE = 2, + kFMTownsVersionJ = 3 }; struct SpecialExtension { @@ -195,7 +199,7 @@ enum kExtractType { struct ExtractType { int type; - bool (*extract)(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename); + bool (*extract)(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch); void (*createFilename)(char *dstFilename, const int lang, const int special, const char *filename); }; diff --git a/tools/create_kyradat/misc.h b/tools/create_kyradat/misc.h index 191abf3370..f4fd212839 100644 --- a/tools/create_kyradat/misc.h +++ b/tools/create_kyradat/misc.h @@ -182,9 +182,127 @@ const int kyra1DemoNeed[] = { -1 }; +const int kyra1TownsEngNeed[] = { + kKallakWritingSeq, + kMalcolmTreeSeq, + kWestwoodLogoSeq, + kKyrandiaLogoSeq, + kKallakMalcolmSeq, + kForestSeq, + kIntroCPSStrings, + kIntroCOLStrings, + kIntroWSAStrings, + kIntroStrings, + kRoomList, + kRoomFilenames, + kCharacterImageFilenames, + kDefaultShapes, + kItemNames, + kTakenStrings, + kPlacedStrings, + kDroppedStrings, + kNoDropStrings, + kAmuleteAnimSeq, + kPaletteList1, + kPaletteList2, + kPaletteList3, + kPaletteList4, + kPaletteList5, + kPaletteList6, + kPaletteList7, + kPaletteList8, + kPaletteList9, + kPaletteList10, + kPaletteList11, + kPaletteList12, + kPaletteList13, + kPaletteList14, + kPaletteList15, + kPaletteList16, + kPaletteList17, + kPaletteList18, + kPaletteList19, + kPaletteList20, + kPaletteList21, + kPaletteList22, + kPaletteList23, + kPaletteList24, + kPaletteList25, + kPaletteList26, + kPaletteList27, + kPaletteList28, + kPaletteList29, + kPaletteList30, + kPaletteList31, + kPaletteList32, + kPaletteList33, + kPutDownString, + kWaitAmuletString, + kBlackJewelString, + kHealingTipString, + kPoisonGoneString, + kHealing1Shapes, + kHealing2Shapes, + kThePoisonStrings, + kFluteStrings, + kPoisonDeathShapes, + kFluteShapes, + kWinter1Shapes, + kWinter2Shapes, + kWinter3Shapes, + kDrinkShapes, + kWispShapes, + kMagicAnimShapes, + kBranStoneShapes, + kWispJewelStrings, + kMagicJewelStrings, + kFlaskFullString, + kFullFlaskString, + kOutroReunionSeq, + kOutroHomeString, + kVeryCleverString, + kGUIStrings, + kNewGameString, + kConfigStrings, + + kKyra1TownsSFXTable, + kCreditsStrings, + kMenuSKB, + kSjisVTable, + -1 +}; + +const int kyra1TownsJapNeed[] = { + kIntroStrings, + kItemNames, + kTakenStrings, + kPlacedStrings, + kDroppedStrings, + kNoDropStrings, + kPutDownString, + kWaitAmuletString, + kBlackJewelString, + kHealingTipString, + kPoisonGoneString, + kThePoisonStrings, + kFluteStrings, + kWispJewelStrings, + kMagicJewelStrings, + kFlaskFullString, + kFullFlaskString, + kOutroHomeString, + kVeryCleverString, + kGUIStrings, + kNewGameString, + kConfigStrings, + -1 +}; + const GameNeed gameNeedTable[] = { { kKyra1, -1, kyra1FloppyNeed }, { kKyra1, kTalkieVersion, kyra1CDNeed }, + { kKyra1, kFMTownsVersionE , kyra1TownsEngNeed}, + { kKyra1, kFMTownsVersionJ, kyra1TownsJapNeed}, { kKyra1, kDemoVersion, kyra1DemoNeed }, { -1, -1, 0 } }; @@ -192,7 +310,8 @@ const GameNeed gameNeedTable[] = { const SpecialExtension specialTable[] = { { kTalkieVersion, "CD" }, { kDemoVersion, "DEM" }, - { kFMTownsVersion, "TNS" }, + { kFMTownsVersionE , "TNS" }, + { kFMTownsVersionJ, "TNS" }, { -1, 0 } }; @@ -205,3 +324,4 @@ const Language languageTable[] = { { JA_JPN, "JPN" }, { -1, 0 } }; + diff --git a/tools/create_kyradat/towns.h b/tools/create_kyradat/towns.h new file mode 100644 index 0000000000..ad35ec7ab2 --- /dev/null +++ b/tools/create_kyradat/towns.h @@ -0,0 +1,121 @@ +const ExtractEntry kyra1FMTownsE[] = { + { kKallakWritingSeq, 0x0002F1FF, 0x0002F9F6 }, + { kMalcolmTreeSeq, 0x0002FCC3, 0x0002FEDB }, + { kWestwoodLogoSeq, 0x0002FEDB, 0x0002FF26 }, + { kKyrandiaLogoSeq, 0x0002F9F7, 0x0002FA53 }, + { kKallakMalcolmSeq, 0x0002FA53, 0x0002FCC0 }, + { kForestSeq, 0x0002F067, 0x0002F1FD }, + { kIntroCPSStrings, 0x00027D5A, 0x00027D6F }, + { kIntroWSAStrings, 0x00027D72, 0x00027E05 }, + { kIntroCOLStrings, 0x00027E06, 0x00027E36 }, + { kIntroStrings, 0x00027E36, 0x0002837B }, + { kRoomList, 0x0002FF90, 0x00036478 }, + { kRoomFilenames, 0x00028B20, 0x00028E6C}, + { kCharacterImageFilenames, 0x0002606E, 0x00026165 }, + { kDefaultShapes, 0x00037CF9, 0x00038183 }, + { kItemNames, 0x00029724, 0x00029C29 }, + { kTakenStrings, 0x00028978, 0x00028994 }, + { kPlacedStrings, 0x000289A0, 0x000289A9 }, + { kDroppedStrings, 0x000289E4, 0x000289EE }, + { kNoDropStrings, 0x00027C0E, 0x00027C88 }, + { kAmuleteAnimSeq, 0x0002A814, 0x0002A83E }, + { kPaletteList1, 0x0002E80B, 0x0002E820 }, + { kPaletteList2, 0x0002E823, 0x0002E856 }, + { kPaletteList3, 0x0002E857, 0x0002E88A }, + { kPaletteList4, 0x0002E88B, 0x0002E8BE }, + { kPaletteList5, 0x0002E8BF, 0x0002E8F2 }, + { kPaletteList6, 0x0002E8F3, 0x0002E926 }, + { kPaletteList7, 0x0002E927, 0x0002E95D }, + { kPaletteList8, 0x0002E95F, 0x0002E995 }, + { kPaletteList9, 0x0002E997, 0x0002E9C4 }, + { kPaletteList10, 0x0002E9C7, 0x0002E9F4 }, + { kPaletteList11, 0x0002E9F7, 0x0002EA24 }, + { kPaletteList12, 0x0002EA27, 0x0002EA54 }, + { kPaletteList13, 0x0002EA54, 0x0002EA81 }, + { kPaletteList14, 0x0002EA87, 0x0002EAC3 }, + { kPaletteList15, 0x0002EAC3, 0x0002EAF0 }, + { kPaletteList16, 0x0002EAF3, 0x0002EB14 }, + { kPaletteList17, 0x0002EB17, 0x0002EB38 }, + { kPaletteList18, 0x0002EB3B, 0x0002EB50 }, + { kPaletteList19, 0x0002EB53, 0x0002EB68 }, + { kPaletteList20, 0x0002EB6B, 0x0002EB80 }, + { kPaletteList21, 0x0002EB83, 0x0002EB98 }, + { kPaletteList22, 0x0002EB9B, 0x0002EBB0 }, + { kPaletteList23, 0x0002EBB3, 0x0002EBC8 }, + { kPaletteList24, 0x0002EBCB, 0x0002EBFB }, + { kPaletteList25, 0x0002EBFB, 0x0002EC2B }, + { kPaletteList26, 0x0002EC2B, 0x0002EC5B }, + { kPaletteList27, 0x0002EC5B, 0x0002EC8B }, + { kPaletteList28, 0x0002EC8B, 0x0002ECBB }, + { kPaletteList29, 0x0002ECBB, 0x0002ECEB }, + { kPaletteList30, 0x0002ECEB, 0x0002ED27 }, + { kPaletteList31, 0x0002ED27, 0x0002ED4E }, + { kPaletteList32, 0x0002ED4F, 0x0002ED76 }, + { kPaletteList33, 0x0002ED77, 0x0002EDB3 }, + { kPutDownString, 0x00025BD6, 0x00025BFC }, + { kWaitAmuletString, 0x00025C2A, 0x00025C67 }, + { kBlackJewelString, 0x00025C96, 0x00025CB9 }, + { kHealingTipString, 0x00025CF2, 0x00025D1F }, + { kPoisonGoneString, 0x00025E06, 0x00025E42 }, + { kHealing1Shapes, 0x000381F1, 0x0003828B }, + { kHealing2Shapes, 0x0003828D, 0x0003835F }, + { kThePoisonStrings, 0x000294B8, 0x0002954A }, + { kFluteStrings, 0x00025B1E, 0x00025B78 }, + { kPoisonDeathShapes, 0x0003865D, 0x000386E9 }, + { kFluteShapes, 0x00038561, 0x0003865D }, + { kWinter1Shapes, 0x00038361, 0x00038392 }, + { kWinter2Shapes, 0x00038395, 0x0003848A }, + { kWinter3Shapes, 0x0003848D, 0x000384A9 }, + { kDrinkShapes, 0x00038185, 0x000381EF }, + { kWispShapes, 0x000384A9, 0x0003855F }, + { kMagicAnimShapes, 0x000386E9, 0x0003870C }, + { kBranStoneShapes, 0x0003870D, 0x00038770 }, + { kWispJewelStrings, 0x00025D4E, 0x00025DC3 }, + { kMagicJewelStrings, 0x00025DE2, 0x00025DF5 }, + { kFlaskFullString, 0x00029688, 0x000296A4 }, + { kFullFlaskString, 0x00029568, 0x00029605 }, + { kOutroReunionSeq, 0x0002B529, 0x0002BA70 }, + { kOutroHomeString, 0x00025F7E, 0x00025F83 }, + { kVeryCleverString, 0x00025F8E, 0x00025FC0 }, + { kGUIStrings, 0x000291E0, 0x000293DC }, + { kNewGameString, 0x0002919C, 0x000291B1 }, + { kConfigStrings, 0x00029360, 0x000293AA}, + { kKyra1TownsSFXTable, 0x0003A978, 0x0004CF80 }, + { kCreditsStrings, 0x0002AED8, 0x0002B464 }, + { kMenuSKB, 0x000293DE, 0x000294A7 }, + { kSjisVTable, 0x0003A421, 0x0003A749 }, + { -1, 0, 0 } +}; + +const ExtractEntry kyra1FMTownsJ[] = { + { kIntroStrings, 0x0002837C, 0x00028977 }, + { kItemNames, 0x00029C2C, 0x0002A1B3 }, + { kTakenStrings, 0x00028980, 0x0002899F }, + { kPlacedStrings, 0x000289AC, 0x000289B9 }, + { kDroppedStrings, 0x000289F0, 0x000289FB }, + { kNoDropStrings, 0x00027C3E, 0x00027C9F }, + { kPutDownString, 0x00025BFE, 0x00025C27 }, + { kWaitAmuletString, 0x00025C6A, 0x00025C93 }, + { kBlackJewelString, 0x00025CBA, 0x00025CEF }, + { kHealingTipString, 0x00025D22, 0x00025D4D }, + { kPoisonGoneString, 0x00025E12, 0x00025E4F }, + { kThePoisonStrings, 0x000294C8, 0x00029568 }, + { kFluteStrings, 0x00025B3E, 0x00025B91 }, + { kWispJewelStrings, 0x00025D7A, 0x00025DE1 }, + { kMagicJewelStrings, 0x00025DF6, 0x00025E05 }, + { kFlaskFullString, 0x000296A4, 0x000296C3 }, + { kFullFlaskString, 0x00029608, 0x00029685 }, + { kOutroHomeString, 0x00025F86, 0x00025F8D }, + { kVeryCleverString, 0x00025FC2, 0x00025FF1 }, + { kGUIStrings, 0x000368D1, 0x00036B30 }, + { kNewGameString, 0x000291B4, 0x000291CF}, + { kConfigStrings, 0x000290AC, 0x00029103 }, + { -1, 0, 0 } +}; + +const Game kyra1TownsGames[] = { + { kKyra1, EN_ANY, kFMTownsVersionE, "5a3ad60ccd0f2e29463e0368cd14a60d", kyra1FMTownsE }, + { kKyra1, JA_JPN, kFMTownsVersionJ, "5a3ad60ccd0f2e29463e0368cd14a60d", kyra1FMTownsJ }, + GAME_DUMMY_ENTRY +}; + |