aboutsummaryrefslogtreecommitdiff
path: root/devtools/create_neverhood/create_neverhood.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/create_neverhood/create_neverhood.cpp')
-rw-r--r--devtools/create_neverhood/create_neverhood.cpp537
1 files changed, 537 insertions, 0 deletions
diff --git a/devtools/create_neverhood/create_neverhood.cpp b/devtools/create_neverhood/create_neverhood.cpp
new file mode 100644
index 0000000000..323066d8b1
--- /dev/null
+++ b/devtools/create_neverhood/create_neverhood.cpp
@@ -0,0 +1,537 @@
+/* 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 <vector>
+#include "create_neverhood.h"
+#include "tables.h"
+
+const int DAT_VERSION = 0;
+
+uint32 dataSize;
+byte *data;
+uint32 dataStart = 0x004AE000;
+uint32 fileStart = 0x000AC600;
+
+class HitRectList;
+class RectList;
+class MessageList;
+class NavigationList;
+
+void addMessageList(uint32 messageListCount, uint32 messageListOffset);
+
+void loadExe(const char *filename) {
+ FILE *exe = fopen(filename, "rb");
+ dataSize = fileSize(exe);
+ data = new byte[dataSize];
+ fread(data, dataSize, 1, exe);
+ fclose(exe);
+}
+
+byte *getData(uint32 offset) {
+ return data + offset - dataStart + fileStart;
+}
+
+const char *getStringP(uint32 offset) {
+ return offset != 0 ? (const char*)getData(offset) : NULL;
+}
+
+uint32 calcHash(const char *value) {
+ if (!value)
+ return 0;
+ uint32 hash = 0, shiftValue = 0;
+ while (*value != 0) {
+ char ch = *value++;
+ if (ch >= 'a' && ch <= 'z')
+ ch -= 32;
+ else if (ch >= '0' && ch <= '9')
+ ch += 22;
+ shiftValue += ch - 64;
+ if (shiftValue >= 32)
+ shiftValue -= 32;
+ hash ^= 1 << shiftValue;
+ }
+ return hash;
+}
+
+struct HitRect {
+ int16 x1, y1, x2, y2;
+ uint16 messageNum;
+
+ void load(uint32 offset) {
+ byte *item = getData(offset);
+ x1 = READ_LE_UINT16(item + 0);
+ y1 = READ_LE_UINT16(item + 2);
+ x2 = READ_LE_UINT16(item + 4);
+ y2 = READ_LE_UINT16(item + 6);
+ messageNum = READ_LE_UINT16(item + 8);
+ }
+
+ void save(FILE *fd) {
+ writeUint16LE(fd, x1);
+ writeUint16LE(fd, y1);
+ writeUint16LE(fd, x2);
+ writeUint16LE(fd, y2);
+ writeUint16LE(fd, messageNum);
+ }
+
+ int getItemSize() const {
+ return 10;
+ }
+
+};
+
+struct MessageItem {
+ uint16 messageNum;
+ uint32 messageParam;
+ MessageItem() {}
+ MessageItem(uint16 msgNum, uint32 msgParam) : messageNum(msgNum), messageParam(msgParam) {}
+
+ void load(uint32 offset) {
+ byte *item = getData(offset);
+ messageNum = READ_LE_UINT16(item + 0);
+ messageParam = READ_LE_UINT32(item + 4);
+ }
+
+ void save(FILE *fd) {
+ writeUint16LE(fd, messageNum);
+ writeUint32LE(fd, messageParam);
+ }
+
+ int getItemSize() const {
+ return 8;
+ }
+
+};
+
+struct SubRectItem {
+ int16 x1, y1, x2, y2;
+ uint32 messageListCount;
+ uint32 messageListOffset;
+
+ void load(uint32 offset) {
+ byte *item = getData(offset);
+ x1 = READ_LE_UINT16(item + 0);
+ y1 = READ_LE_UINT16(item + 2);
+ x2 = READ_LE_UINT16(item + 4);
+ y2 = READ_LE_UINT16(item + 6);
+ messageListCount = READ_LE_UINT32(item + 8);
+ messageListOffset = READ_LE_UINT32(item + 12);
+ // Add the message to the message list
+ addMessageList(messageListCount, messageListOffset);
+ }
+
+ void save(FILE *fd) {
+ writeUint16LE(fd, x1);
+ writeUint16LE(fd, y1);
+ writeUint16LE(fd, x2);
+ writeUint16LE(fd, y2);
+ writeUint32LE(fd, messageListOffset);
+ }
+
+ int getItemSize() const {
+ return 16;
+ }
+
+};
+
+struct RectItem {
+ int16 x1, y1, x2, y2;
+ uint32 subRectListCount;
+ uint32 subRectListOffset;
+ std::vector<SubRectItem> subRectItems;
+
+ void load(uint32 offset) {
+ byte *item = getData(offset);
+ uint32 subItemOffset;
+ x1 = READ_LE_UINT16(item + 0);
+ y1 = READ_LE_UINT16(item + 2);
+ x2 = READ_LE_UINT16(item + 4);
+ y2 = READ_LE_UINT16(item + 6);
+ subRectListCount = READ_LE_UINT32(item + 8);
+ subRectListOffset = READ_LE_UINT32(item + 12);
+ subItemOffset = subRectListOffset;
+ for (uint32 j = 0; j < subRectListCount; j++) {
+ SubRectItem subRectItem;
+ subRectItem.load(subItemOffset);
+ subItemOffset += 16;
+ subRectItems.push_back(subRectItem);
+ }
+ }
+
+ void save(FILE *fd) {
+ writeUint16LE(fd, x1);
+ writeUint16LE(fd, y1);
+ writeUint16LE(fd, x2);
+ writeUint16LE(fd, y2);
+ writeUint32LE(fd, subRectItems.size());
+ for (uint32 j = 0; j < subRectItems.size(); j++)
+ subRectItems[j].save(fd);
+ }
+
+ int getItemSize() const {
+ return 16;
+ }
+
+};
+
+struct NavigationItem {
+ uint32 fileHash;
+ uint32 leftSmackerFileHash;
+ uint32 rightSmackerFileHash;
+ uint32 middleSmackerFileHash;
+ byte interactive;
+ byte middleFlag;
+ uint32 mouseCursorFileHash;
+
+ void load(uint32 offset) {
+ byte *item = getData(offset);
+ fileHash = READ_LE_UINT32(item + 0);
+ leftSmackerFileHash = READ_LE_UINT32(item + 4);
+ rightSmackerFileHash = READ_LE_UINT32(item + 8);
+ middleSmackerFileHash = READ_LE_UINT32(item + 12);
+ interactive = item[16];
+ middleFlag = item[17];
+ mouseCursorFileHash = READ_LE_UINT32(item + 20);
+ }
+
+ void save(FILE *fd) {
+ writeUint32LE(fd, fileHash);
+ writeUint32LE(fd, leftSmackerFileHash);
+ writeUint32LE(fd, rightSmackerFileHash);
+ writeUint32LE(fd, middleSmackerFileHash);
+ writeByte(fd, interactive);
+ writeByte(fd, middleFlag);
+ writeUint32LE(fd, mouseCursorFileHash);
+ }
+
+ int getItemSize() const {
+ return 24;
+ }
+
+};
+
+struct SceneInfo140Item {
+ uint32 id;
+ uint32 bgFilename1;
+ uint32 bgFilename2;
+ uint32 txFilename;
+ uint32 bgFilename3;
+ byte xPosIndex;
+ byte count;
+
+ void load(uint32 offset) {
+ byte *item = getData(offset);
+ id = offset;
+ // Only save the hashes instead of the full names
+ bgFilename1 = calcHash(getStringP(READ_LE_UINT32(item + 0)));
+ bgFilename2 = calcHash(getStringP(READ_LE_UINT32(item + 4)));
+ txFilename = calcHash(getStringP(READ_LE_UINT32(item + 8)));
+ bgFilename3 = calcHash(getStringP(READ_LE_UINT32(item + 12)));
+ xPosIndex = item[16];
+ count = item[17];
+ }
+
+ void save(FILE *fd) {
+ writeUint32LE(fd, id);
+ writeUint32LE(fd, bgFilename1);
+ writeUint32LE(fd, bgFilename2);
+ writeUint32LE(fd, txFilename);
+ writeUint32LE(fd, bgFilename3);
+ writeByte(fd, xPosIndex);
+ writeByte(fd, count);
+ }
+
+};
+
+struct SceneInfo2700Item {
+ uint32 id;
+ uint32 bgFilename;
+ uint32 class437Filename;
+ uint32 dataResourceFilename;
+ uint32 pointListName;
+ uint32 rectListName;
+ uint32 exPaletteFilename2;
+ uint32 exPaletteFilename1;
+ uint32 mouseCursorFilename;
+ int16 which1;
+ int16 which2;
+
+ void load(uint32 offset) {
+ byte *item = getData(offset);
+ id = offset;
+ // Only save the hashes instead of the full names
+ bgFilename = calcHash(getStringP(READ_LE_UINT32(item + 0)));
+ class437Filename = calcHash(getStringP(READ_LE_UINT32(item + 4)));
+ dataResourceFilename = calcHash(getStringP(READ_LE_UINT32(item + 8)));
+ pointListName = calcHash(getStringP(READ_LE_UINT32(item + 12)));
+ rectListName = calcHash(getStringP(READ_LE_UINT32(item + 16)));
+ exPaletteFilename2 = calcHash(getStringP(READ_LE_UINT32(item + 20)));
+ exPaletteFilename1 = calcHash(getStringP(READ_LE_UINT32(item + 24)));
+ mouseCursorFilename = calcHash(getStringP(READ_LE_UINT32(item + 28)));
+ which1 = READ_LE_UINT16(item + 32);
+ which2 = READ_LE_UINT16(item + 34);
+ }
+
+ void save(FILE *fd) {
+ writeUint32LE(fd, id);
+ writeUint32LE(fd, bgFilename);
+ writeUint32LE(fd, class437Filename);
+ writeUint32LE(fd, dataResourceFilename);
+ writeUint32LE(fd, pointListName);
+ writeUint32LE(fd, rectListName);
+ writeUint32LE(fd, exPaletteFilename2);
+ writeUint32LE(fd, exPaletteFilename1);
+ writeUint32LE(fd, mouseCursorFilename);
+ writeUint16LE(fd, which1);
+ writeUint16LE(fd, which2);
+ }
+
+};
+
+template<class ITEMCLASS>
+class StaticDataList {
+public:
+ uint32 id;
+ std::vector<ITEMCLASS> items;
+
+ virtual ~StaticDataList() {
+ }
+
+ void add(ITEMCLASS item) {
+ items.push_back(item);
+ }
+
+ int getCount() const {
+ return items.size();
+ }
+
+ ITEMCLASS *getListItem(int index) {
+ return &items[index];
+ }
+
+ virtual bool specialLoadList(uint32 count, uint32 offset) {
+ return false;
+ }
+
+ void loadList(uint32 count, uint32 offset) {
+ id = offset;
+ if (!specialLoadList(count, offset)) {
+ for (uint32 i = 0; i < count; i++) {
+ ITEMCLASS listItem;
+ listItem.load(offset);
+ offset += listItem.getItemSize();
+ add(listItem);
+ }
+ }
+ }
+
+ void saveList(FILE *fd) {
+ writeUint32LE(fd, id);
+ writeUint32LE(fd, getCount());
+ for (int i = 0; i < getCount(); i++) {
+ items[i].save(fd);
+ }
+ }
+
+};
+
+class HitRectList : public StaticDataList<HitRect> {
+};
+
+class RectList : public StaticDataList<RectItem> {
+};
+
+class MessageList : public StaticDataList<MessageItem> {
+public:
+
+ virtual bool specialLoadList(uint32 count, uint32 offset) {
+ // Special code for message lists which are set at runtime (but otherwise constant)
+ switch (offset) {
+ // Scene 1002 rings
+ case 0x004B4200:
+ add(MessageItem(0x4800, 258));
+ add(MessageItem(0x100D, 0x4A845A00));
+ add(MessageItem(0x4805, 1));
+ return true;
+ case 0x004B4218:
+ add(MessageItem(0x4800, 297));
+ add(MessageItem(0x100D, 0x43807801));
+ add(MessageItem(0x4805, 2));
+ return true;
+ case 0x004B4230:
+ add(MessageItem(0x4800, 370));
+ add(MessageItem(0x100D, 0x46C26A01));
+ return true;
+ case 0x004B4240:
+ add(MessageItem(0x4800, 334));
+ add(MessageItem(0x100D, 0x468C7B11));
+ add(MessageItem(0x4805, 1));
+ return true;
+ case 0x004B4258:
+ add(MessageItem(0x4800, 425));
+ add(MessageItem(0x100D, 0x42845B19));
+ add(MessageItem(0x4805, 1));
+ return true;
+ // Scene 1302 rings
+ case 0x004B0888:
+ add(MessageItem(0x4800, 218));
+ add(MessageItem(0x100D, 0x4A845A00));
+ add(MessageItem(0x4805, 1));
+ return true;
+ case 0x004B08A0:
+ add(MessageItem(0x4800, 218 + 32));
+ add(MessageItem(0x100D, 0x43807801));
+ return true;
+ case 0x004B08B0:
+ add(MessageItem(0x4800, 218 + 32 + 32));
+ add(MessageItem(0x100D, 0x46C26A01));
+ add(MessageItem(0x4805, 1));
+ return true;
+ case 0x004B08C8:
+ add(MessageItem(0x4800, 218 + 32 + 32 + 32));
+ add(MessageItem(0x100D, 0x468C7B11));
+ return true;
+ case 0x004B08D8:
+ add(MessageItem(0x4800, 218 + 32 + 32 + 32 + 32));
+ add(MessageItem(0x100D, 0x42845B19));
+ add(MessageItem(0x4805, 4));
+ return true;
+ }
+ return false;
+ }
+
+};
+
+class NavigationList : public StaticDataList<NavigationItem> {
+};
+
+template<class LISTCLASS>
+class StaticDataListVector {
+public:
+ std::vector<LISTCLASS*> lists;
+
+ void add(LISTCLASS *list) {
+ lists.push_back(list);
+ }
+
+ void loadListVector(const uint32 *offsets) {
+ for (int i = 0; offsets[i] != 0; i += 2) {
+ LISTCLASS *list = new LISTCLASS();
+ list->loadList(offsets[i], offsets[i + 1]);
+ bool doAppend = true;
+ // Bad
+ for (typename std::vector<LISTCLASS*>::iterator it = lists.begin(); it != lists.end(); it++) {
+ if ((*it)->id == list->id) {
+ doAppend = false;
+ break;
+ }
+ }
+ if (doAppend)
+ lists.push_back(list);
+ }
+ }
+
+ void saveListVector(FILE *fd) {
+ writeUint32LE(fd, lists.size());
+ for (typename std::vector<LISTCLASS*>::iterator it = lists.begin(); it != lists.end(); it++) {
+ (*it)->saveList(fd);
+ }
+ }
+
+};
+
+template<class ITEMCLASS>
+class StaticDataVector {
+public:
+ std::vector<ITEMCLASS> items;
+
+ void loadVector(const uint32 *offsets) {
+ for (int i = 0; offsets[i] != 0; i++) {
+ ITEMCLASS item;
+ item.load(offsets[i]);
+ items.push_back(item);
+ }
+ }
+
+ void saveVector(FILE *fd) {
+ writeUint32LE(fd, items.size());
+ for (typename std::vector<ITEMCLASS>::iterator it = items.begin(); it != items.end(); it++) {
+ (*it).save(fd);
+ }
+ }
+
+};
+
+StaticDataListVector<HitRectList> hitRectLists;
+StaticDataListVector<RectList> rectLists;
+StaticDataListVector<MessageList> messageLists;
+StaticDataListVector<NavigationList> navigationLists;
+StaticDataVector<SceneInfo140Item> sceneInfo140Items;
+StaticDataVector<SceneInfo2700Item> sceneInfo2700Items;
+
+void addMessageList(uint32 messageListCount, uint32 messageListOffset) {
+ MessageList *messageList = new MessageList();
+ messageList->loadList(messageListCount, messageListOffset);
+ messageLists.add(messageList);
+}
+
+int main(int argc, char *argv[]) {
+
+ FILE *datFile;
+
+ loadExe("nhc.exe");
+
+ hitRectLists.loadListVector(hitRectListOffsets);
+ rectLists.loadListVector(rectListOffsets);
+ messageLists.loadListVector(messageListOffsets);
+ navigationLists.loadListVector(navigationListOffsets);
+ sceneInfo140Items.loadVector(sceneInfo140Offsets);
+ sceneInfo2700Items.loadVector(sceneInfo2700Offsets);
+
+ datFile = fopen("neverhood.dat", "wb");
+
+ writeUint32LE(datFile, 0x11223344); // Some magic
+ writeUint32LE(datFile, DAT_VERSION);
+
+ messageLists.saveListVector(datFile);
+ rectLists.saveListVector(datFile);
+ hitRectLists.saveListVector(datFile);
+ navigationLists.saveListVector(datFile);
+ sceneInfo140Items.saveVector(datFile);
+ sceneInfo2700Items.saveVector(datFile);
+
+ fclose(datFile);
+
+ printf("Done.\n");
+
+ return 0;
+}