aboutsummaryrefslogtreecommitdiff
path: root/devtools
diff options
context:
space:
mode:
authorEugene Sandulenko2013-05-15 09:19:34 -0700
committerEugene Sandulenko2013-05-15 09:19:34 -0700
commit0638308ef13727b4b359d98d54bc09156752aaaa (patch)
treee6f6b131566c593f6731ffa058e396931afc2525 /devtools
parentbf9db9e20d75cc18cb711f148814a5d3aae79483 (diff)
parent32c21754e20afd589556ea862876c6e304b3326b (diff)
downloadscummvm-rg350-0638308ef13727b4b359d98d54bc09156752aaaa.tar.gz
scummvm-rg350-0638308ef13727b4b359d98d54bc09156752aaaa.tar.bz2
scummvm-rg350-0638308ef13727b4b359d98d54bc09156752aaaa.zip
Merge pull request #330 from johndoe123/neverhood
NEVERHOOD: Neverhood engine
Diffstat (limited to 'devtools')
-rw-r--r--devtools/create_neverhood/create_neverhood.cpp537
-rw-r--r--devtools/create_neverhood/create_neverhood.h28
-rw-r--r--devtools/create_neverhood/module.mk12
-rw-r--r--devtools/create_neverhood/tables.h718
-rw-r--r--devtools/create_neverhood/util.cpp152
-rw-r--r--devtools/create_neverhood/util.h57
6 files changed, 1504 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;
+}
diff --git a/devtools/create_neverhood/create_neverhood.h b/devtools/create_neverhood/create_neverhood.h
new file mode 100644
index 0000000000..6382c87375
--- /dev/null
+++ b/devtools/create_neverhood/create_neverhood.h
@@ -0,0 +1,28 @@
+/* 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.
+ *
+ */
+
+#ifndef CREATE_NEVERHOOD_H
+#define CREATE_NEVERHOOD_H
+
+#include "util.h"
+
+#endif
diff --git a/devtools/create_neverhood/module.mk b/devtools/create_neverhood/module.mk
new file mode 100644
index 0000000000..284e19105d
--- /dev/null
+++ b/devtools/create_neverhood/module.mk
@@ -0,0 +1,12 @@
+
+MODULE := devtools/create_neverhood
+
+MODULE_OBJS := \
+ create_neverhood.o \
+ util.o
+
+# Set the name of the executable
+TOOL_EXECUTABLE := create_neverhood
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/devtools/create_neverhood/tables.h b/devtools/create_neverhood/tables.h
new file mode 100644
index 0000000000..ea39aa807d
--- /dev/null
+++ b/devtools/create_neverhood/tables.h
@@ -0,0 +1,718 @@
+/* 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.
+ *
+ */
+
+static const uint32 hitRectListOffsets[] = {
+ // Scene1001
+ 1, 0x004B4860,
+ // Scene1002
+ 1, 0x004B4138,
+ // Scene1201
+ 4, 0x004AEBD0,
+ // Scene1302
+ 1, 0x004B0858,
+ // Scene1705
+ 1, 0x004B69D8,
+ // Scene2203
+ 1, 0x004B8320,
+ // Scene2205
+ 1, 0x004B0620,
+ 0, 0
+};
+
+static const uint32 rectListOffsets[] = {
+ // Scene1001
+ 1, 0x004B49F0,
+ 1, 0x004B4A00,
+ // Scene1002
+ 3, 0x004B43A0,
+ 1, 0x004B4418,
+ 3, 0x004B43A0,
+ // Scene1004
+ 1, 0x004B7C70,
+ // Scene1109
+ 1, 0x004B63A8,
+ 1, 0x004B6398,
+ // Scene1201
+ 1, 0x004AEE58,
+ 1, 0x004AEDC8,
+ 1, 0x004AEE18,
+ 1, 0x004AED88,
+ // Scene1302
+ 2, 0x004B0A38,
+ // Scene1303
+ 1, 0x004AF9E8,
+ // Scene1304
+ 1, 0x004B91A8,
+ // Scene1305
+ 1, 0x004B6E98,
+ // Scene1306
+ 1, 0x004AFD28,
+ 1, 0x004AFD18,
+ // Scene1308
+ 1, 0x004B5990,
+ 1, 0x004B5980,
+ 1, 0x004B59A0,
+ // Scene1401
+ 1, 0x004B6758,
+ // Scene1402
+ 1, 0x004B0C48,
+ 1, 0x004B0C98,
+ // Scene1403
+ 1, 0x004B1FF8,
+ 1, 0x004B2008,
+ // Scene1404
+ 1, 0x004B8D80,
+ // Scene1608
+ 1, 0x004B47D0,
+ 1, 0x004B4810,
+ // Scene1705
+ 1, 0x004B6B40,
+ 1, 0x004B6B30,
+ // Scene1901
+ 1, 0x004B34C8,
+ // Scene2001
+ 1, 0x004B3680,
+ 1, 0x004B3670,
+ // Scene2101
+ 1, 0x004B9008,
+ 1, 0x004B8FF8,
+ // Scene2203
+ 1, 0x004B8420,
+ // Scene2206
+ 1, 0x004B8AF8,
+ 1, 0x004B8B58,
+ // Scene2207
+ 3, 0x004B38B8,
+ 1, 0x004B3948,
+ // Scene2242
+ 1, 0x004B3DC8,
+ 1, 0x004B3E18,
+ // HallOfRecordsScene
+ 1, 0x004B2BF8,
+ 1, 0x004B2BB8,
+ // Scene2247
+ 1, 0x004B5588,
+ 1, 0x004B55C8,
+ // Scene2401
+ 1, 0x004B3140,
+ // Scene2402
+ 1, 0x004AF900,
+ // Scene2403
+ 1, 0x004B5E18,
+ 1, 0x004B5E28,
+ // Scene2406
+ 1, 0x004B78C8,
+ 1, 0x004B78D8,
+ // Scene2501
+ 1, 0x004B2608,
+ // Scene2732
+ 1, 0x004AE360,
+ // Scene2801
+ 1, 0x004B6CE0,
+ 1, 0x004B6CD0,
+ 1, 0x004B6CF0,
+ // Scene2805
+ 1, 0x004AE318,
+ 1, 0x004AE308,
+ // Scene2810
+ 1, 0x004AE810,
+ 1, 0x004AE800,
+ // Scene2812
+ 1, 0x004AF700,
+ 1, 0x004AF710,
+ 0, 0
+};
+
+static const uint32 messageListOffsets[] = {
+ // Scene1001
+ 1, 0x004B4888,
+ 2, 0x004B4898,
+ 1, 0x004B4970,
+ 1, 0x004B4890,
+ 3, 0x004B4910,
+ 5, 0x004B4938,
+ 1, 0x004B4960,
+ 4, 0x004B48A8,
+ 3, 0x004B48C8,
+ // Scene1002
+ 1, 0x004B4270,
+ 1, 0x004B4478,
+ 3, 0x004B4298,
+ 1, 0x004B4470,
+ 4, 0x004B4428,
+ 5, 0x004B4448,
+ 1, 0x004B44B8,
+ 2, 0x004B44A8,
+ 1, 0x004B44A0,
+ 2, 0x004B43D0,
+ 4, 0x004B4480,
+ 2, 0x004B41E0,
+ 5, 0x004B4148,
+ // Scene1004
+ 3, 0x004B7BF0,
+ 2, 0x004B7C08,
+ 1, 0x004B7C18,
+ 2, 0x004B7C20,
+ // Scene1109
+ 1, 0x004B6260,
+ 2, 0x004B6268,
+ 4, 0x004B6318,
+ 2, 0x004B6278,
+ 1, 0x004B6258,
+ // Scene1201
+ 1, 0x004AEC08,
+ 2, 0x004AEC10,
+ 2, 0x004AEC20,
+ 2, 0x004AEC30,
+ 4, 0x004AEC90,
+ 2, 0x004AECB0,
+ 2, 0x004AECC0,
+ 5, 0x004AECF0,
+ 2, 0x004AECD0,
+ 2, 0x004AECE0,
+ 2, 0x004AED38,
+ // Scene1302
+ 4, 0x004B08F0,
+ 3, 0x004B0920,
+ 1, 0x004B0950,
+ 2, 0x004B0940,
+ 1, 0x004B0938,
+ 2, 0x004B0910,
+ 1, 0x004B0968,
+ 2, 0x004B0878,
+ 4, 0x004B0978,
+ 1, 0x004B0870,
+ 1, 0x004B0868,
+ // Scene1303
+ 1, 0x004AF9A0,
+ 2, 0x004AF9B8,
+ // Scene1304
+ 1, 0x004B90E8,
+ 1, 0x004B90F0,
+ 2, 0x004B9158,
+ 2, 0x004B9130,
+ 2, 0x004B9140,
+ // Scene1305
+ 1, 0x004B6E40,
+ 1, 0x004B6E48,
+ // Scene1306
+ 1, 0x004AFAD0,
+ 2, 0x004AFAF0,
+ 1, 0x004AFBC8,
+ 1, 0x004AFC30,
+ 4, 0x004AFC38,
+ 2, 0x004AFB00,
+ 1, 0x004AFBD0,
+ 4, 0x004AFBD8,
+ 2, 0x004AFAE0,
+ 1, 0x004AFAD8,
+ 2, 0x004AFC58,
+ 2, 0x004AFC68,
+ // Scene1308
+ 1, 0x004B57C0,
+ 1, 0x004B57C8,
+ 1, 0x004B58B0,
+ 3, 0x004B57D0,
+ 3, 0x004B57E8,
+ 2, 0x004B5868,
+ 4, 0x004B5848,
+ 3, 0x004B5830,
+ 2, 0x004B5800,
+ 2, 0x004B5868,
+ 2, 0x004B58E0,
+ // Scene1401
+ 1, 0x004B65C8,
+ 1, 0x004B65D0,
+ 1, 0x004B65D8,
+ 1, 0x004B65E8,
+ 3, 0x004B6670,
+ 4, 0x004B6690,
+ 1, 0x004B66B0,
+ 3, 0x004B6658,
+ 2, 0x004B65F0,
+ // Scene1402
+ 1, 0x004B0B48,
+ 1, 0x004B0B50,
+ 1, 0x004B0B58,
+ 1, 0x004B0B60,
+ 2, 0x004B0B68,
+ 3, 0x004B0BB8,
+ 3, 0x004B0BD0,
+ // Scene1403
+ 1, 0x004B1F18,
+ 1, 0x004B1F20,
+ 3, 0x004B1F70,
+ 2, 0x004B1FA8,
+ 4, 0x004B1F88,
+ 3, 0x004B1F58,
+ 2, 0x004B1F28,
+ 2, 0x004B1FB8,
+ // Scene1404
+ 1, 0x004B8C28,
+ 1, 0x004B8C30,
+ 1, 0x004B8C38,
+ 1, 0x004B8D28,
+ 3, 0x004B8CB8,
+ 2, 0x004B8C40,
+ 6, 0x004B8CE8,
+ 3, 0x004B8CA0,
+ 2, 0x004B8CD0,
+ 2, 0x004B8D18,
+ // Scene1608
+ 1, 0x004B46A8,
+ 1, 0x004B46B0,
+ 1, 0x004B47A8,
+ 3, 0x004B4748,
+ 2, 0x004B4770,
+ 2, 0x004B46C8,
+ 2, 0x004B4760,
+ // Scene1705
+ 1, 0x004B69E8,
+ 2, 0x004B6A08,
+ 4, 0x004B6AA0,
+ 2, 0x004B6A18,
+ 1, 0x004B69F0,
+ 2, 0x004B6AC0,
+ // Scene1901
+ 1, 0x004B3408,
+ 1, 0x004B3410,
+ 1, 0x004B3400,
+ // Scene2001
+ 1, 0x004B3538,
+ 2, 0x004B3540,
+ 4, 0x004B35F0,
+ 2, 0x004B3550,
+ 1, 0x004B3530,
+ // Scene2101
+ 1, 0x004B8E48,
+ 3, 0x004B8E50,
+ 4, 0x004B8F58,
+ 2, 0x004B8EB0,
+ 2, 0x004B8EA0,
+ 1, 0x004B8F50,
+ 1, 0x004B8F48,
+ 4, 0x004B8E80,
+ 1, 0x004B8EC8,
+ 2, 0x004B8F78,
+ 3, 0x004B8F00,
+ // Scene2201
+ 1, 0x004B8118,
+ 1, 0x004B8130,
+ 1, 0x004B8178,
+ 2, 0x004B8120,
+ 3, 0x004B81A0,
+ 1, 0x004B81B8,
+ 2, 0x004B8108,
+ 5, 0x004B8150,
+ 4, 0x004B8180,
+ 3, 0x004B8138,
+ 2, 0x004B8108,
+ 2, 0x004B81C8,
+ // Scene2203
+ 1, 0x004B8340,
+ 1, 0x004B8350,
+ 1, 0x004B8358,
+ 1, 0x004B8348,
+ 3, 0x004B83B0,
+ 3, 0x004B83C8,
+ 2, 0x004B8370,
+ 2, 0x004B8360,
+ 2, 0x004B83E0,
+ 2, 0x004B83F0,
+ // Scene2205
+ 1, 0x004B0658,
+ 2, 0x004B0648,
+ 1, 0x004B0640,
+ 4, 0x004B0690,
+ 2, 0x004B0630,
+ // Scene2206
+ 1, 0x004B88A8,
+ 2, 0x004B88B8,
+ 1, 0x004B88C8,
+ 1, 0x004B8A70,
+ 1, 0x004B88B0,
+ 5, 0x004B8948,
+ 2, 0x004B8970,
+ 2, 0x004B8988,
+ 4, 0x004B8998,
+ 4, 0x004B89B8,
+ 4, 0x004B89D8,
+ 5, 0x004B89F8,
+ 5, 0x004B8A20,
+ 5, 0x004B8A48,
+ // Scene2207
+ 1, 0x004B38E8,
+ 4, 0x004B38F0,
+ 2, 0x004B37D8,
+ 2, 0x004B3958,
+ 3, 0x004B3920,
+ // Scene2242
+ 1, 0x004B3C18,
+ 1, 0x004B3D60,
+ 1, 0x004B3D48,
+ 1, 0x004B3C20,
+ 2, 0x004B3D50,
+ 5, 0x004B3CF8,
+ 5, 0x004B3D20,
+ 4, 0x004B3CB8,
+ 4, 0x004B3CD8,
+ // HallOfRecordsScene
+ 1, 0x004B2900,
+ 2, 0x004B2910,
+ 1, 0x004B2B70,
+ 1, 0x004B2908,
+ 2, 0x004B2920,
+ 4, 0x004B2978,
+ 4, 0x004B2998,
+ 4, 0x004B29B8,
+ 4, 0x004B29D8,
+ 4, 0x004B29F8,
+ 4, 0x004B2A18,
+ 4, 0x004B2A38,
+ 5, 0x004B2A58,
+ 5, 0x004B2A80,
+ 5, 0x004B2AA8,
+ 5, 0x004B2AD0,
+ 5, 0x004B2AF8,
+ 5, 0x004B2B20,
+ 5, 0x004B2B48,
+ // Scene2247
+ 1, 0x004B5428,
+ 2, 0x004B5438,
+ 1, 0x004B5530,
+ 1, 0x004B5430,
+ 4, 0x004B54A0,
+ 4, 0x004B54C0,
+ 5, 0x004B54E0,
+ 5, 0x004B5508,
+ // Scene2401
+ 1, 0x004B2F70,
+ 1, 0x004B2F80,
+ 1, 0x004B2F78,
+ 4, 0x004B3090,
+ 2, 0x004B30B0,
+ 6, 0x004B3020,
+ 2, 0x004B3050,
+ 4, 0x004B2FA8,
+ 4, 0x004B2FC8,
+ // Scene2402
+ 1, 0x004AF7C8,
+ 2, 0x004AF7D8,
+ 1, 0x004AF888,
+ 1, 0x004AF7D0,
+ 3, 0x004AF800,
+ 1, 0x004AF818,
+ 2, 0x004AF890,
+ // Scene2403
+ 1, 0x004B5C98,
+ 1, 0x004B5D70,
+ 4, 0x004B5CA0,
+ 2, 0x004B5D98,
+ // Scene2406
+ 1, 0x004B76C8,
+ 3, 0x004B76D8,
+ 1, 0x004B77C0,
+ 1, 0x004B7810,
+ 1, 0x004B76D0,
+ 2, 0x004B77C8,
+ 2, 0x004B77D8,
+ 2, 0x004B7758,
+ 4, 0x004B7738,
+ // Scene2501
+ 7, 0x004B2538,
+ 6, 0x004B2570,
+ // Scene2732
+ 1, 0x004AE328,
+ // Scene2801
+ 1, 0x004B6BB8,
+ 1, 0x004B6BC0,
+ 1, 0x004B6C10,
+ 1, 0x004B6BB0,
+ 2, 0x004B6C40,
+ // Scene2803b
+ 1, 0x004B60D8,
+ 1, 0x004B6100,
+ 1, 0x004B60F8,
+ 1, 0x004B6100,
+ 3, 0x004B6138,
+ 3, 0x004B60E0,
+ 3, 0x004B6180,
+ 1, 0x004B6198,
+ 6, 0x004B6108,
+ 3, 0x004B6150,
+ 3, 0x004B6168,
+ 1, 0x004B61A0,
+ 5, 0x004B61A8,
+ // Scene2803
+ 1, 0x004B79F0,
+ 5, 0x004B79C8,
+ 1, 0x004B7A00,
+ 2, 0x004B7A78,
+ 1, 0x004B79F8,
+ 1, 0x004B79C0,
+ 1, 0x004B7A50,
+ 2, 0x004B7A58,
+ 5, 0x004B7A08,
+ 4, 0x004B7A30,
+ 2, 0x004B7A68,
+ 7, 0x004B7A88,
+ // Scene2805
+ 1, 0x004AE1C8,
+ 2, 0x004AE1D0,
+ 4, 0x004AE288,
+ 2, 0x004AE1E0,
+ 1, 0x004AE1C0,
+ // Scene2806
+ 1, 0x004AF098,
+ 1, 0x004AF098,
+ 3, 0x004AF0C8,
+ 5, 0x004AF0A0,
+ 1, 0x004AF090,
+ 2, 0x004AF0E0,
+ // Scene2809
+ 1, 0x004B5B90,
+ 3, 0x004B5BD0,
+ 5, 0x004B5BA8,
+ 1, 0x004B5B88,
+ 2, 0x004B5B98,
+ 1, 0x004AE438,
+ 3, 0x004AE440,
+ 3, 0x004AE738,
+ 1, 0x004AE6D8,
+ 2, 0x004AE6E8,
+ 1, 0x004AE6E0,
+ 2, 0x004AE428,
+ 2, 0x004AE418,
+ 1, 0x004AE410,
+ 4, 0x004AE458,
+ 5, 0x004AE4A8,
+ 5, 0x004AE4D0,
+ 5, 0x004AE4F8,
+ 5, 0x004AE520,
+ 5, 0x004AE548,
+ 5, 0x004AE570,
+ 5, 0x004AE598,
+ 5, 0x004AE5C0,
+ 5, 0x004AE5E8,
+ 5, 0x004AE610,
+ 5, 0x004AE638,
+ 5, 0x004AE660,
+ 5, 0x004AE688,
+ 2, 0x004AE750,
+ // Scene2812
+ 1, 0x004AF560,
+ 1, 0x004AF588,
+ 1, 0x004AF5F0,
+ 4, 0x004AF568,
+ 2, 0x004AF658,
+ 2, 0x004AF668,
+ 0, 0
+};
+
+static const uint32 navigationListOffsets[] = {
+ // Module1100
+ 2, 0x004B8430,
+ 2, 0x004B8460,
+ 4, 0x004B84F0,
+ 4, 0x004B8490,
+ 2, 0x004B8580,
+ 2, 0x004B8550,
+ // Module1300
+ 6, 0x004B2718,
+ 2, 0x004B27A8,
+ 2, 0x004B27D8,
+ 2, 0x004B2808,
+ 2, 0x004B2838,
+ // Module1600
+ 4, 0x004B39D0,
+ 2, 0x004B3A30,
+ 2, 0x004B3A60,
+ 6, 0x004B3A90,
+ 2, 0x004B3B20,
+ 2, 0x004B3B50,
+ 2, 0x004B3B80,
+ // Module1700
+ 2, 0x004AE8B8,
+ 3, 0x004AE8E8,
+ // Module1800
+ 4, 0x004AFD38,
+ 1, 0x004AFD98,
+ 2, 0x004AFDB0,
+ 4, 0x004AFDE0,
+ 2, 0x004AFE40,
+ // Module2300
+ 2, 0x004B67B8,
+ 6, 0x004B67E8,
+ 2, 0x004B6878,
+ 3, 0x004B68F0,
+ 3, 0x004B68A8,
+ // Module2000
+ 3, 0x004B7B48,
+ 3, 0x004B7B00,
+ // Module2600
+ 2, 0x004B8608,
+ 4, 0x004B8638,
+ 2, 0x004B8698,
+ 2, 0x004B86C8,
+ 4, 0x004B8758,
+ 4, 0x004B86F8,
+ 2, 0x004B87B8,
+ // Module3000
+ 2, 0x004B7C80,
+ 2, 0x004B7CE0,
+ 2, 0x004B7CB0,
+ 3, 0x004B7D58,
+ 3, 0x004B7D10,
+ 4, 0x004B7E60,
+ 4, 0x004B7DA0,
+ 4, 0x004B7E00,
+ 4, 0x004B7F20,
+ 4, 0x004B7EC0,
+ 2, 0x004B7F80,
+ 1, 0x004B7FB0,
+ 0, 0
+};
+
+// Hall of Records scene definitions
+
+static const uint32 sceneInfo140Offsets[] = {
+ 0x004B7180,
+ 0x004B7198,
+ 0x004B71B0,
+ 0x004B71C8,
+ 0x004B71E0,
+ 0x004B71F8,
+ 0x004B7210,
+ 0x004B7228,
+ 0x004B7240,
+ 0x004B7258,
+ 0x004B7270,
+ 0x004B7288,
+ 0x004B72A0,
+ 0x004B72B8,
+ 0x004B72D0,
+ 0x004B72E8,
+ 0x004B7300,
+ 0x004B7318,
+ 0x004B7330,
+ 0x004B7348,
+ 0x004B7360,
+ 0x004B7378,
+ 0x004B7390,
+ 0x004B73A8,
+ 0x004B73C0,
+ 0x004B73D8,
+ 0x004B73F0,
+ 0x004B7408,
+ 0x004B7420,
+ 0x004B7438,
+ 0x004B7450,
+ 0x004B7468,
+ 0x004B7480,
+ 0x004B7498,
+ 0x004B74B0,
+ 0x004B74C8,
+ 0
+};
+
+static const uint32 sceneInfo2700Offsets[] = {
+ //
+ 0x004B1710,
+ 0x004B1738,
+ 0x004B1760,
+ 0x004B1788,
+ 0x004B17B0,
+ 0x004B17D8,
+ 0x004B1800,
+ 0x004B1828,
+ 0x004B1850,
+ 0x004B1878,
+ 0x004B18A0,
+ 0x004B18C8,
+ 0x004B18F0,
+ 0x004B1918,
+ //
+ 0x004B19E0,
+ 0x004B1A08,
+ 0x004B1A30,
+ 0x004B1A58,
+ 0x004B1A80,
+ 0x004B1AA8,
+ 0x004B1AD0,
+ 0x004B1AF8,
+ 0x004B1B20,
+ 0x004B1B48,
+ 0x004B1B70,
+ 0x004B1B98,
+ 0x004B1BC0,
+ 0x004B1BE8,
+ 0x004B1C10,
+ 0x004B1C38,
+ 0x004B1C60,
+ 0x004B1C88,
+ 0x004B1CB0,
+ 0x004B1CD8,
+ 0x004B1D00,
+ 0x004B1D28,
+ 0x004B1D50,
+ 0x004B1D78,
+ //
+ 0x004B1DB0,
+ //
+ 0x004B1DE8,
+ 0x004B1E10,
+ 0x004B1E38,
+ 0x004B1E60,
+ //
+ 0x004B1950,
+ //
+ 0x004B2240,
+ //
+ 0x004B5F68,
+ 0x004B5F8C,
+ 0x004B5FB0,
+ 0x004B5FD8,
+ 0x004B5FFC,
+ 0x004B6020,
+ // Scene2501
+ 0x004B2628,
+ 0x004B264C,
+ 0x004B2670,
+ // Scene2502
+ 0x004B01B8,
+ // Scene2503
+ 0x004B01E0,
+ 0x004B0208,
+ // Scene2505
+ 0x004B0230,
+ // Scene2506
+ 0x004B0268,
+ // Scene2507
+ 0x004B02A0,
+ // Scene2508
+ 0x004B02C8,
+ // Scene2706
+ 0x004B22A0,
+ 0x004B22C4,
+ 0x004B22E8,
+ 0
+};
diff --git a/devtools/create_neverhood/util.cpp b/devtools/create_neverhood/util.cpp
new file mode 100644
index 0000000000..5ce8237b85
--- /dev/null
+++ b/devtools/create_neverhood/util.cpp
@@ -0,0 +1,152 @@
+/* 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
+
+#include "util.h"
+#include <stdarg.h>
+
+#ifdef _MSC_VER
+ #define vsnprintf _vsnprintf
+#endif
+
+void error(const char *s, ...) {
+ char buf[1024];
+ va_list va;
+
+ va_start(va, s);
+ vsnprintf(buf, 1024, s, va);
+ va_end(va);
+
+ fprintf(stderr, "ERROR: %s!\n", buf);
+
+ exit(1);
+}
+
+void warning(const char *s, ...) {
+ char buf[1024];
+ va_list va;
+
+ va_start(va, s);
+ vsnprintf(buf, 1024, s, va);
+ va_end(va);
+
+ fprintf(stderr, "WARNING: %s!\n", buf);
+}
+
+int scumm_stricmp(const char *s1, const char *s2) {
+ byte l1, l2;
+ do {
+ // Don't use ++ inside tolower, in case the macro uses its
+ // arguments more than once.
+ l1 = (byte)*s1++;
+ l1 = tolower(l1);
+ l2 = (byte)*s2++;
+ l2 = tolower(l2);
+ } while (l1 == l2 && l1 != 0);
+ return l1 - l2;
+}
+
+void debug(int level, const char *s, ...) {
+ char buf[1024];
+ va_list va;
+
+ va_start(va, s);
+ vsnprintf(buf, 1024, s, va);
+ va_end(va);
+
+ fprintf(stderr, "DEBUG: %s!\n", buf);
+}
+
+uint8 readByte(FILE *fp) {
+ return fgetc(fp);
+}
+
+uint16 readUint16BE(FILE *fp) {
+ uint16 ret = 0;
+ ret |= fgetc(fp) << 8;
+ ret |= fgetc(fp);
+ return ret;
+}
+
+uint16 readUint16LE(FILE *fp) {
+ uint16 ret = 0;
+ ret |= fgetc(fp);
+ ret |= fgetc(fp) << 8;
+ return ret;
+}
+
+uint32 readUint32BE(FILE *fp) {
+ uint32 ret = 0;
+ ret |= fgetc(fp) << 24;
+ ret |= fgetc(fp) << 16;
+ ret |= fgetc(fp) << 8;
+ ret |= fgetc(fp);
+ return ret;
+}
+
+uint32 readUint32LE(FILE *fp) {
+ uint32 ret = 0;
+ ret |= fgetc(fp);
+ ret |= fgetc(fp) << 8;
+ ret |= fgetc(fp) << 16;
+ ret |= fgetc(fp) << 24;
+ return ret;
+}
+
+void writeByte(FILE *fp, uint8 b) {
+ fwrite(&b, 1, 1, fp);
+}
+
+void writeUint16BE(FILE *fp, uint16 value) {
+ writeByte(fp, (uint8)(value >> 8));
+ writeByte(fp, (uint8)(value));
+}
+
+void writeUint16LE(FILE *fp, uint16 value) {
+ writeByte(fp, (uint8)(value));
+ writeByte(fp, (uint8)(value >> 8));
+}
+
+void writeUint32BE(FILE *fp, uint32 value) {
+ writeByte(fp, (uint8)(value >> 24));
+ writeByte(fp, (uint8)(value >> 16));
+ writeByte(fp, (uint8)(value >> 8));
+ writeByte(fp, (uint8)(value));
+}
+
+void writeUint32LE(FILE *fp, uint32 value) {
+ writeByte(fp, (uint8)(value));
+ writeByte(fp, (uint8)(value >> 8));
+ writeByte(fp, (uint8)(value >> 16));
+ writeByte(fp, (uint8)(value >> 24));
+}
+
+uint32 fileSize(FILE *fp) {
+ uint32 sz;
+ uint32 pos = ftell(fp);
+ fseek(fp, 0, SEEK_END);
+ sz = ftell(fp);
+ fseek(fp, pos, SEEK_SET);
+ return sz;
+}
diff --git a/devtools/create_neverhood/util.h b/devtools/create_neverhood/util.h
new file mode 100644
index 0000000000..a2783cca71
--- /dev/null
+++ b/devtools/create_neverhood/util.h
@@ -0,0 +1,57 @@
+/* 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.
+ *
+ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/util.h"
+
+#ifdef WIN32
+#include <io.h>
+#include <process.h>
+#endif
+
+
+/* File I/O */
+uint8 readByte(FILE *fp);
+uint16 readUint16BE(FILE *fp);
+uint16 readUint16LE(FILE *fp);
+uint32 readUint32BE(FILE *fp);
+uint32 readUint32LE(FILE *fp);
+void writeByte(FILE *fp, uint8 b);
+void writeUint16BE(FILE *fp, uint16 value);
+void writeUint16LE(FILE *fp, uint16 value);
+void writeUint32BE(FILE *fp, uint32 value);
+void writeUint32LE(FILE *fp, uint32 value);
+uint32 fileSize(FILE *fp);
+
+/* Misc stuff */
+void NORETURN_PRE error(const char *s, ...) NORETURN_POST;
+void warning(const char *s, ...);
+void debug(int level, const char *s, ...);
+int scumm_stricmp(const char *s1, const char *s2);
+
+using namespace Common;
+
+#endif