From a6150f9308f24f55793b8be07f8756d39763b59b Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 27 Nov 2015 12:12:32 -0500 Subject: ACCESS: Creation of access.dat for holding Access games engine data --- devtools/create_access/create_access_dat.cpp | 430 +++++++++++++++++++++++++++ 1 file changed, 430 insertions(+) create mode 100644 devtools/create_access/create_access_dat.cpp (limited to 'devtools/create_access/create_access_dat.cpp') diff --git a/devtools/create_access/create_access_dat.cpp b/devtools/create_access/create_access_dat.cpp new file mode 100644 index 0000000000..0e57f76395 --- /dev/null +++ b/devtools/create_access/create_access_dat.cpp @@ -0,0 +1,430 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +// HACK to allow building with the SDL backend on MinGW +// see bug #1800764 "TOOLS: MinGW tools building broken" +#ifdef main +#undef main +#endif // main + +#include +#include +#include +#include "common/language.h" +#include "common/rect.h" +#include "create_access_dat.h" +#include "amazon_resources.h" +#include "martian_resources.h" + +/** + * Format of the access.dat file that will be created: + * 4 Bytes - Magic string 'SVMA' to identify valid data file + * 2 bytes - Version number + * 2 Bytes - Number of different games data in the data file + * Series of index entries identifying each game: + * 1 byte - Game type: 1 = Amazon, 2 = Martian Memorandum, 3 = Noctropolis + * 1 byte - disc type: 0 = Floppy, 1 = CD, 2 = Common data shared across + * all variations of the given game + * 1 byte - Is Demo: 0 = Full game, 1 = Demo + * 1 byte - Language (Common::Language) + * 4 bytes - File offset for the data for the game + */ + +File outputFile; + +void writeHeader(int numExecutables); +void writeAmazonCommonData(); +void writeMartianCommonData(); +bool processExecutable(int idx, const char *name); + +void NORETURN_PRE error(const char *s, ...) { + printf("%s\n", s); + exit(1); +} + +int main(int argc, char *argv[]) { + const uint NUM_COMMON_ENTRIES = 2; + + if (argc < 3) { + printf("Format: %s output_filename executable1 [executable2 ..]\n", argv[0]); + exit(0); + } + + // Create the new data file for output + outputFile.open(argv[1], kFileWriteMode); + writeHeader(argc - 2 + NUM_COMMON_ENTRIES); + + // Write out entries containing common data for the games + writeAmazonCommonData(); + writeMartianCommonData(); + + // Iterate through processing each specified executable + outputFile.seek(0, SEEK_END); + for (int idx = 2; idx < argc; ++idx) { + if (!processExecutable(idx - 2 + NUM_COMMON_ENTRIES, argv[idx])) + break; + } + + // Close the output file + outputFile.close(); +} + +void writeHeader(int numExecutables) { + // Write out magic string + const char *MAGIC_STR = "SVMA"; + outputFile.write(MAGIC_STR, 4); + + // Write out version number + outputFile.writeWord(VERSION_NUMBER); + + // Write out the number of entries the data file will contain + outputFile.writeWord(numExecutables); + + // Write out padding for index entries that will be written + outputFile.writeByte(0, 8 * numExecutables); +} + +void writeAmazonCommonData() { + // Write out the header entry + outputFile.seek(8); + outputFile.writeByte(1); // Amazon + outputFile.writeByte(2); // Common data + outputFile.writeByte(0); + outputFile.writeByte(0); + outputFile.writeLong(outputFile.size()); + + // Write out cursor list + outputFile.seek(0, SEEK_END); + outputFile.writeWord(AMAZON_NUM_CURSORS); + + for (uint idx = 0; idx < AMAZON_NUM_CURSORS; ++idx) { + outputFile.writeWord(Amazon::CURSOR_SIZES[idx]); + outputFile.write(Amazon::CURSORS[idx], Amazon::CURSOR_SIZES[idx]); + } + + // Write out font data + outputFile.writeWord(Amazon::FONT2_INDEX_SIZE); + for (uint idx = 0; idx < Amazon::FONT2_INDEX_SIZE; ++idx) + outputFile.writeWord(Amazon::FONT2_INDEX[idx]); + + outputFile.writeWord(Amazon::FONT2_DATA_SIZE); + outputFile.write(Amazon::FONT2_DATA, Amazon::FONT2_DATA_SIZE); + + outputFile.writeWord(Amazon::FONT6x6_INDEX_SIZE); + for (uint idx = 0; idx < Amazon::FONT6x6_INDEX_SIZE; ++idx) + outputFile.writeWord(Amazon::FONT6x6_INDEX[idx]); + + outputFile.writeWord(Amazon::FONT6x6_DATA_SIZE); + outputFile.write(Amazon::FONT2_DATA, Amazon::FONT6x6_DATA_SIZE); +} + + +void writeMartianCommonData() { + // Write out the header entry + outputFile.seek(16); + outputFile.writeByte(2); // Martian + outputFile.writeByte(2); // Common data + outputFile.writeByte(0); + outputFile.writeByte(0); + outputFile.writeLong(outputFile.size()); + + // Write out cursor list + outputFile.seek(0, SEEK_END); + outputFile.writeByte(MARTIAN_NUM_CURSORS); + + for (uint idx = 0; idx < MARTIAN_NUM_CURSORS; ++idx) { + outputFile.writeWord(Martian::CURSOR_SIZES[idx]); + outputFile.write(Martian::CURSORS[idx], Martian::CURSOR_SIZES[idx]); + } +} + +bool processExecutable(int idx, const char *name) { + uint dataSegmentOffset; + uint filenamesOffset, numFilenames; + uint charsStart, charsEnd; + uint roomsStart, roomsEnd, numRooms; + uint travelPosOffset; + const char *const *roomDescs; + const byte *deathScreens; + const char *const *deathText; + uint numDeaths; + uint numItems; + const char *const *itemNames; + const int *comboTable; + byte gameId = 0, discType = 0, demoType = 0; + byte language = Common::EN_ANY; + + // Open up the file for access + File exeFile; + if (!exeFile.open(name)) { + printf("Could not open file - %s\n", name); + return false; + } + + // Total up the first 256 bytes of the executable as a simplified + // means of identifying the different executables we support + uint fileChecksum = 0; + for (int idx = 0; idx < 256; ++idx) + fileChecksum += exeFile.readByte(); + + switch (fileChecksum) { + case 11899: + // Amazon English floppy + gameId = 1; + dataSegmentOffset = 0xC8C0; + filenamesOffset = dataSegmentOffset + 0x3628; + numFilenames = 100; + charsStart = dataSegmentOffset + 0x4234; + charsEnd = dataSegmentOffset + 0x49c6; + roomsStart = dataSegmentOffset + 0x35a8; + roomsEnd = dataSegmentOffset + 0x4234; + travelPosOffset = dataSegmentOffset + 0x5ff7; + numRooms = 64; + roomDescs = &Amazon::ROOM_DESCR[0]; + deathScreens = Amazon::DEATH_SCREENS_ENG; + deathText = &Amazon::DEATH_TEXT_ENG[0]; + numDeaths = sizeof(Amazon::DEATH_SCREENS_ENG); + numItems = 85; + itemNames = &Amazon::INVENTORY_NAMES_ENG[0]; + comboTable = &Amazon::COMBO_TABLE[0][0]; + break; + + case 12360: + // Amazon CD English + gameId = 1; + discType = 1; + dataSegmentOffset = 0xd370; + filenamesOffset = dataSegmentOffset + 0x3EA0; + numFilenames = 116; + charsStart = dataSegmentOffset + 0x4BDC; + charsEnd = dataSegmentOffset + 0x5AF4; + roomsStart = dataSegmentOffset + 0x3E20; + roomsEnd = dataSegmentOffset + 0x4BDC; + travelPosOffset = dataSegmentOffset + 0x7125; + numRooms = 64; + roomDescs = &Amazon::ROOM_DESCR[0]; + deathScreens = Amazon::DEATH_SCREENS_ENG; + deathText = &Amazon::DEATH_TEXT_ENG[0]; + numDeaths = sizeof(Amazon::DEATH_SCREENS_ENG); + numItems = 85; + itemNames = &Amazon::INVENTORY_NAMES_ENG[0]; + comboTable = &Amazon::COMBO_TABLE[0][0]; + break; + + case 11748: + // Amazon English Demo + gameId = 1; + discType = 0; + demoType = 1; + dataSegmentOffset = 0xa2a0; + filenamesOffset = dataSegmentOffset + 0x242C; + numFilenames = 100; + charsStart = dataSegmentOffset + 0x2F1A; + charsEnd = dataSegmentOffset + 0x34FB; + roomsStart = dataSegmentOffset + 0x23AC; + roomsEnd = dataSegmentOffset + 0x2F1A; + travelPosOffset = dataSegmentOffset + 0x494E; + numRooms = 64; + roomDescs = &Amazon::ROOM_DESCR[0]; + deathScreens = Amazon::DEATH_SCREENS_ENG; + deathText = &Amazon::DEATH_TEXT_ENG[0]; + numDeaths = sizeof(Amazon::DEATH_SCREENS_ENG); + numItems = 85; + itemNames = &Amazon::INVENTORY_NAMES_ENG[0]; + comboTable = &Amazon::COMBO_TABLE[0][0]; + break; + + case 1224: + // Martian Memorandum English packed + printf("Martian Memorandum provided that's packed with EXEPACK.\n"); + printf("It needs to be first unpacked before it can be used with this tool.\n"); + return false; + + case 0: + // Martian Memorandum English + gameId = 2; + dataSegmentOffset = 0x8d78; + filenamesOffset = dataSegmentOffset + 0x373A; + numFilenames = 80; + charsStart = dataSegmentOffset + 0x40F2; + charsEnd = dataSegmentOffset + 0x46F8; + roomsStart = dataSegmentOffset + 0x36DA; + roomsEnd = dataSegmentOffset + 0x40F2; + travelPosOffset = dataSegmentOffset + 0x58E9; + numRooms = 48; + roomDescs = &Martian::ROOM_DESCR[0]; + deathScreens = Martian::DEATH_SCREENS_ENG; + deathText = &Martian::DEATH_TEXT_ENG[0]; + numDeaths = sizeof(Martian::DEATH_SCREENS_ENG); + numItems = 85; + itemNames = &Martian::INVENTORY_NAMES_ENG[0]; + comboTable = nullptr; + break; + + default: + printf("Unknown game executable specified - %s\n", name); + exeFile.close(); + return false; + } + + // Write out header entry + uint outputOffset = outputFile.size(); + outputFile.seek(8 + idx * 8); + outputFile.writeByte(gameId); + outputFile.writeByte(discType); + outputFile.writeByte(demoType); + outputFile.writeByte(language); + outputFile.writeLong(outputOffset); + outputFile.seek(0, SEEK_END); + + // Write out list of AP filenames + outputFile.writeWord(numFilenames); + for (uint idx = 0; idx < numFilenames; ++idx) { + exeFile.seek(filenamesOffset + idx * 2); + uint nameOffset = exeFile.readWord(); + + exeFile.seek(dataSegmentOffset + nameOffset); + outputFile.writeString(exeFile); + } + + // Write out the character list + exeFile.seek(charsStart); + Common::Array charOffsets; + charOffsets.push_back(exeFile.readWord()); + assert((dataSegmentOffset + charOffsets[0] - exeFile.pos()) < 512); + + while (exeFile.pos() < (dataSegmentOffset + charOffsets[0])) + charOffsets.push_back(exeFile.readWord()); + + outputFile.writeWord(charOffsets.size()); + charOffsets.push_back(charsEnd); + for (uint idx = 0; idx < charOffsets.size() - 1; ++idx) { + if (charOffsets[idx] == 0) { + outputFile.writeWord(0); + } else { + uint nextOffset = 0xffff; + for (uint idx2 = 0; idx2 < charOffsets.size(); ++idx2) { + if (charOffsets[idx2] && charOffsets[idx2] > charOffsets[idx] && charOffsets[idx2] < nextOffset) + nextOffset = charOffsets[idx2]; + } + uint size = nextOffset - charOffsets[idx]; + + exeFile.seek(dataSegmentOffset + charOffsets[idx]); + outputFile.writeWord(size); + outputFile.write(exeFile, size); + } + } + + // Write out the room data + Common::Array roomOffsets; + Common::Array travelPos; + + exeFile.seek(roomsStart); + for (uint idx = 0; idx < numRooms; ++idx) + roomOffsets.push_back(exeFile.readWord()); + roomOffsets.push_back(roomsEnd); + + exeFile.seek(travelPosOffset); + for (uint idx = 0; idx < numRooms; ++idx) { + int16 xp = (int16)exeFile.readWord(); + int16 yp = (int16)exeFile.readWord(); + travelPos.push_back(Common::Point(xp, yp)); + } + + outputFile.writeWord(numRooms); + for (uint idx = 0; idx < numRooms; ++idx) { + uint dataSize = 0; + + if (roomOffsets[idx] == 0) { + dataSize = 0; + } else { + // Find the offset of the next higher entry that's non-zero + uint offset = 0; + for (uint idx2 = idx + 1; !offset; ++idx2) + offset = roomOffsets[idx2]; + dataSize = offset - roomOffsets[idx]; + exeFile.seek(dataSegmentOffset + roomOffsets[idx]); + } + + // Write out the room description (used only by the debugger) + outputFile.writeString(roomDescs[idx]); + + // Write out travel position + outputFile.writeWord((uint16)travelPos[idx].x); + outputFile.writeWord((uint16)travelPos[idx].y); + + // Write out the data for the room + outputFile.writeWord(dataSize); + if (dataSize > 0) + outputFile.write(exeFile, dataSize); + } + + // Write out the deaths list + outputFile.writeWord(numDeaths); + for (uint idx = 0; idx < numDeaths; ++idx) { + // Write out the screen number and text + outputFile.writeByte(deathScreens[idx]); + outputFile.writeString(deathText[idx]); + } + + // Write out inventory data + outputFile.writeWord(numItems); + for (uint idx = 0; idx < numItems; ++idx) { + outputFile.writeString(itemNames[idx]); + + if (comboTable == nullptr) { + for (uint cIdx = 0; cIdx < 4; ++cIdx) + outputFile.writeWord(0); + } else { + for (uint cIdx = 0; cIdx < 4; ++cIdx, ++comboTable) + outputFile.writeWord((uint16)*comboTable); + } + } + + // Write out game specific strings and other data + if (gameId == 1) { + // Write out miscellaneous strings + outputFile.writeString(Amazon::NO_HELP_MESSAGE_ENG); + outputFile.writeString(Amazon::NO_HINTS_MESSAGE_ENG); + outputFile.writeString(Amazon::RIVER_HIT1_ENG); + outputFile.writeString(Amazon::RIVER_HIT2_ENG); + outputFile.writeString(Amazon::BAR_MESSAGE_ENG); + + for (int idx = 0; idx < 3; ++idx) + outputFile.writeString(Amazon::HELPLVLTXT_ENG[idx]); + for (int idx = 0; idx < 9; ++idx) + outputFile.writeString(Amazon::IQLABELS_ENG[idx]); + + outputFile.writeString(Amazon::CANT_GET_THERE_ENG); + } + + // Do final padding to the next paragraph boundary + if ((outputFile.size() % 16) != 0) + outputFile.writeByte(0, 16 - (outputFile.size() % 16)); + + // Close the executable and signal that it was processed successfully + exeFile.close(); + return true; +} -- cgit v1.2.3 From 2ef9ced7a9a8a2d95f0b017292cca37f681ef4ea Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 12 Dec 2015 06:44:02 +0100 Subject: DEVTOOLS: Silence compiler warnings in create_access. --- devtools/create_access/create_access_dat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'devtools/create_access/create_access_dat.cpp') diff --git a/devtools/create_access/create_access_dat.cpp b/devtools/create_access/create_access_dat.cpp index 0e57f76395..af9ab026c0 100644 --- a/devtools/create_access/create_access_dat.cpp +++ b/devtools/create_access/create_access_dat.cpp @@ -160,7 +160,7 @@ void writeMartianCommonData() { } } -bool processExecutable(int idx, const char *name) { +bool processExecutable(int exeIdx, const char *name) { uint dataSegmentOffset; uint filenamesOffset, numFilenames; uint charsStart, charsEnd; @@ -291,7 +291,7 @@ bool processExecutable(int idx, const char *name) { // Write out header entry uint outputOffset = outputFile.size(); - outputFile.seek(8 + idx * 8); + outputFile.seek(8 + exeIdx * 8); outputFile.writeByte(gameId); outputFile.writeByte(discType); outputFile.writeByte(demoType); -- cgit v1.2.3 From 8392fe4f058d56d5a16ef5faad76e440ffa13400 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 12 Dec 2015 07:02:02 +0100 Subject: DEVTOOLS: More formatting fixes in create_amazon. Powered by astyle. --- devtools/create_access/create_access_dat.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'devtools/create_access/create_access_dat.cpp') diff --git a/devtools/create_access/create_access_dat.cpp b/devtools/create_access/create_access_dat.cpp index af9ab026c0..a1591ef6e5 100644 --- a/devtools/create_access/create_access_dat.cpp +++ b/devtools/create_access/create_access_dat.cpp @@ -46,7 +46,7 @@ * Series of index entries identifying each game: * 1 byte - Game type: 1 = Amazon, 2 = Martian Memorandum, 3 = Noctropolis * 1 byte - disc type: 0 = Floppy, 1 = CD, 2 = Common data shared across - * all variations of the given game + * all variations of the given game * 1 byte - Is Demo: 0 = Full game, 1 = Demo * 1 byte - Language (Common::Language) * 4 bytes - File offset for the data for the game @@ -98,7 +98,7 @@ void writeHeader(int numExecutables) { // Write out version number outputFile.writeWord(VERSION_NUMBER); - + // Write out the number of entries the data file will contain outputFile.writeWord(numExecutables); @@ -109,8 +109,8 @@ void writeHeader(int numExecutables) { void writeAmazonCommonData() { // Write out the header entry outputFile.seek(8); - outputFile.writeByte(1); // Amazon - outputFile.writeByte(2); // Common data + outputFile.writeByte(1); // Amazon + outputFile.writeByte(2); // Common data outputFile.writeByte(0); outputFile.writeByte(0); outputFile.writeLong(outputFile.size()); @@ -144,8 +144,8 @@ void writeAmazonCommonData() { void writeMartianCommonData() { // Write out the header entry outputFile.seek(16); - outputFile.writeByte(2); // Martian - outputFile.writeByte(2); // Common data + outputFile.writeByte(2); // Martian + outputFile.writeByte(2); // Common data outputFile.writeByte(0); outputFile.writeByte(0); outputFile.writeLong(outputFile.size()); @@ -304,7 +304,7 @@ bool processExecutable(int exeIdx, const char *name) { for (uint idx = 0; idx < numFilenames; ++idx) { exeFile.seek(filenamesOffset + idx * 2); uint nameOffset = exeFile.readWord(); - + exeFile.seek(dataSegmentOffset + nameOffset); outputFile.writeString(exeFile); } @@ -319,7 +319,7 @@ bool processExecutable(int exeIdx, const char *name) { charOffsets.push_back(exeFile.readWord()); outputFile.writeWord(charOffsets.size()); - charOffsets.push_back(charsEnd); + charOffsets.push_back(charsEnd); for (uint idx = 0; idx < charOffsets.size() - 1; ++idx) { if (charOffsets[idx] == 0) { outputFile.writeWord(0); @@ -353,7 +353,7 @@ bool processExecutable(int exeIdx, const char *name) { travelPos.push_back(Common::Point(xp, yp)); } - outputFile.writeWord(numRooms); + outputFile.writeWord(numRooms); for (uint idx = 0; idx < numRooms; ++idx) { uint dataSize = 0; -- cgit v1.2.3