diff --git a/source/exhumed/rsrc/build.bmp b/source/exhumed/rsrc/build.bmp
new file mode 100644
index 000000000..e101f838b
Binary files /dev/null and b/source/exhumed/rsrc/build.bmp differ
diff --git a/source/exhumed/rsrc/build_icon.c b/source/exhumed/rsrc/build_icon.c
new file mode 100644
index 000000000..a9b6fe43b
--- /dev/null
+++ b/source/exhumed/rsrc/build_icon.c
@@ -0,0 +1 @@
+#include "eduke32_icon.c"
diff --git a/source/exhumed/rsrc/build_icon.ico b/source/exhumed/rsrc/build_icon.ico
new file mode 100644
index 000000000..0bfa7fb2c
Binary files /dev/null and b/source/exhumed/rsrc/build_icon.ico differ
diff --git a/source/exhumed/rsrc/buildres.rc b/source/exhumed/rsrc/buildres.rc
new file mode 100644
index 000000000..18557f388
--- /dev/null
+++ b/source/exhumed/rsrc/buildres.rc
@@ -0,0 +1,72 @@
+#define NEED_COMMCTRL_H
+#include "../../build/include/windows_inc.h"
+#include "../../build/include/startwin.editor.h"
+
+RSRC_ICON ICON "build_icon.ico"
+RSRC_BMP BITMAP "build.bmp"
+
+WIN_STARTWIN DIALOGEX DISCARDABLE 20, 40, 260, 200
+STYLE DS_MODALFRAME | DS_CENTER | DS_SETFONT | DS_FIXEDSYS | WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU
+CAPTION "Startup"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "", WIN_STARTWIN_BITMAP, "STATIC", SS_BITMAP | SS_CENTERIMAGE | WS_CHILD | WS_VISIBLE, 0, 0, 66, 172
+ CONTROL "", WIN_STARTWIN_TABCTL, WC_TABCONTROL, WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 5, 5, 250, 170
+ CONTROL "&Start", WIN_STARTWIN_START, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 154, 180, 48, 14
+ CONTROL "&Cancel", WIN_STARTWIN_CANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 207, 180, 48, 14
+
+ CONTROL "", WIN_STARTWIN_MESSAGES, "EDIT", ES_MULTILINE | ES_READONLY | WS_CHILD | WS_VSCROLL, 0, 0, 32, 32
+END
+
+WIN_STARTWINPAGE_CONFIG DIALOGEX DISCARDABLE 20, 40, 279, 168
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "&2D Video mode:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 8, 50, 8
+ CONTROL "", IDC2DVMODE, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 6, 80, 56
+ CONTROL "&Fullscreen", IDCFULLSCREEN, "BUTTON", BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 148, 8, 49, 10
+ CONTROL "&3D Video mode:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 24, 50, 8
+ CONTROL "", IDC3DVMODE, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 22, 80, 56
+ CONTROL "&Always show this window at startup", IDCALWAYSSHOW, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 118, 116, 140, 8
+END
+
+#define FILEVER 1,9,9,9
+#define PRODUCTVER 1,9,9,9
+#define STRFILEVER "2.0.0devel\0"
+#define STRPRODUCTVER "2.0.0devel\0"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION FILEVER
+ PRODUCTVERSION PRODUCTVER
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x3L
+#else
+ FILEFLAGS 0x2L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "Mapster32 for EDuke32"
+ VALUE "FileVersion", STRFILEVER
+ VALUE "InternalName", "Mapster32"
+ VALUE "LegalCopyright", "Copyright © 2018 EDuke32 Developers, 1996, 2003 3D Realms Entertainment"
+ VALUE "LegalTrademarks", "Duke Nukem® is a Registered Trademark of Gearbox Software, LLC."
+ VALUE "OriginalFilename", "mapster32.exe"
+ VALUE "ProductName", "Mapster32"
+ VALUE "ProductVersion", STRPRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+1 24 "manifest.build.xml"
diff --git a/source/exhumed/rsrc/eduke32_icon.c b/source/exhumed/rsrc/eduke32_icon.c
new file mode 100644
index 000000000..4a4da8e81
--- /dev/null
+++ b/source/exhumed/rsrc/eduke32_icon.c
@@ -0,0 +1,20 @@
+
+#include "sdl_inc.h"
+#include "sdlappicon.h"
+
+static Uint8 sdlappicon_pixels[] = {
+#if defined _WIN32 && SDL_MAJOR_VERSION==1
+# include "eduke32_icon_32px.c"
+#else
+# include "eduke32_icon_48px.c"
+#endif
+};
+
+struct sdlappicon sdlappicon = {
+#if defined _WIN32 && SDL_MAJOR_VERSION==1
+ 32,32,
+#else
+ 48,48,
+#endif
+ sdlappicon_pixels
+};
diff --git a/source/exhumed/rsrc/eduke32_icon_32px.c b/source/exhumed/rsrc/eduke32_icon_32px.c
new file mode 100644
index 000000000..84a23fd62
--- /dev/null
+++ b/source/exhumed/rsrc/eduke32_icon_32px.c
@@ -0,0 +1,200 @@
+/* GIMP RGBA C-Source image dump (eduke32_icon_32px.c) */
+#if 0
+static const struct {
+ unsigned int width;
+ unsigned int height;
+ unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */
+ unsigned char pixel_data[32 * 32 * 4 + 1];
+} sdlappicon = {
+ 32, 32, 4,
+#endif
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\11\210\377\33\1\204\377]\15\205\377\225+\224\377\301A\237\377\330"
+ "O\246\377\346M\245\377\3469\233\377\330%\221\377\301\21\207\377\225\11\203"
+ "\377]\11}\377\33\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\5\201\3772\25\211\377\240M\245\377\351\236\315\376\377\307"
+ "\343\377\377\343\361\377\377\365\373\377\377\363\371\377\377\345\362\377"
+ "\377\276\336\376\377\242\317\376\377\217\306\377\377r\267\376\377=\235\377"
+ "\351\23\210\377\240\5\201\3772\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1"
+ "s\377\7\15\205\377\214E\241\377\371\255\326\377\377\361\370\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\375\376\377\377\351\364\377\377\325\352\377\377\274\335\376\377\261\326"
+ "\377\377\263\331\377\377\236\315\376\377I\243\377\371\7\202\377\214\1s\377"
+ "\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\17\206\3772\27\212\377\320v\271\376\377\305\342\377\377"
+ "\335\355\377\377\375\376\377\377\377\377\377\377\361\367\377\377\307\343"
+ "\377\377\244\320\376\377\215\305\377\377\207\302\377\377\221\307\377\377"
+ "\261\330\377\377\321\350\377\377\321\350\377\377\325\352\377\377\327\353"
+ "\377\377\345\361\377\377\242\317\376\377\31\213\377\320\5\201\3772\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\13\204"
+ "\377/\35\215\377\350v\271\376\377\240\316\376\377\265\332\377\377\357\367"
+ "\377\377\312\344\376\377\200\276\376\377M\245\377\3777\232\377\377/\226\377"
+ "\377\37\216\377\377\21\207\377\377\11\203\377\377\17\206\377\377)\223\377"
+ "\377j\263\376\377\303\341\377\377\361\370\377\377\355\366\377\377\377\377"
+ "\377\377\303\341\377\377+\224\377\350\5\201\377/\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\21\207\377,\33\214\377\360p\266\376\377"
+ "\200\276\376\377\276\336\376\377\325\347\377\377`\256\376\377\21\207\377"
+ "\377\27\212\377\377/\226\377\3777\232\377\3779\232\375\3777\231\375\377$"
+ "\217\374\377\20\206\376\377\6\201\376\377\0~\376\377\0\203\376\377\21\207"
+ "\377\377n\265\376\377\357\367\377\377\377\377\377\377\377\377\377\377\324"
+ "\351\376\377)\223\377\360\5\201\377,\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\1g\377\5\25\211\377\322l\264\376\377x\272\376\377\255\326\377\377\305"
+ "\340\377\3777\234\373\377\1\220\377\377\1\204\377\377\37\216\377\377;\233"
+ "\375\377A\236\375\377A\236\375\377;\233\375\377&\220\374\377\27\211\375\377"
+ "\12\203\376\377\10\202\376\377\20\206\376\377\10\202\376\377\15\205\377\377"
+ "S\250\377\377\337\357\377\377\371\374\377\377\335\355\377\377\244\320\376"
+ "\377\31\213\377\322\1g\377\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\11\203\377\213"
+ "h\262\376\377\231\313\377\377\274\335\376\377\300\335\376\377\16\205\364"
+ "\377\0\205\354\377\0\207\372\377\\\253\374\377\\\253\374\377&\220\374\377"
+ ";\233\375\377=\234\375\3773\227\375\377$\217\374\377\20\206\376\377\12\203"
+ "\376\377\10\202\376\3773\227\375\377^\254\374\377&\220\374\377\27\212\377"
+ "\377+\224\377\377\315\346\377\377\343\361\377\377\314\345\376\377~\275\376"
+ "\377\7\202\377\213\0\0\0\0\0\0\0\0\0\0\0\0\5\201\377+9\233\377\372\261\330"
+ "\377\377\257\325\377\377\325\351\377\377$\215\370\377\0\203\350\377\0\177"
+ "\352\377h\262\376\377\364\370\376\377\312\344\376\377\27\211\375\377\5x\343"
+ "\377\6n\316\377\3d\267\377\2b\264\377\7i\305\377\6r\326\377\1\204\363\377"
+ "\232\313\376\377\376\376\376\377\213\302\373\377\27\211\375\377\1\177\377"
+ "\3773\230\377\377\335\355\377\377\274\335\376\377\255\326\377\377;\234\377"
+ "\372\13\204\377+\0\0\0\0\0\0\0\0\21\207\377\242\227\312\377\377\312\344\376"
+ "\377\345\361\377\377Z\253\376\377\0\217\376\377\0\206\370\377e\260\375\377"
+ "\352\364\376\377\213\302\373\377\251\323\375\377R\231\342\377\1U\217\377"
+ "\0P\232\377\0Q\234\377\0Q\234\377\1S\237\377\1R\213\377\7o\317\377\273\332"
+ "\375\377\356\365\376\377\376\376\376\377y\272\375\377\1\177\377\377\1\212"
+ "\377\377X\252\376\377\325\352\377\377\236\315\376\377|\274\376\377\25\211"
+ "\377\242\0\0\0\0\13\204\377\26?\236\377\361\314\345\376\377\341\361\377\377"
+ "\303\341\377\377\7\202\377\377\0\211\376\377D\240\376\377\352\364\376\377"
+ "\217\305\375\3773\227\375\377\302\340\376\377\326\352\376\377\3d\267\377"
+ "\0V\230\377\1T\241\377\1T\241\377\0Q\234\377\0U\226\377\214\276\362\377\316"
+ "\345\376\377\\\253\374\377\326\352\376\377\364\370\376\377D\240\376\377\1"
+ "\220\377\377\0\203\376\377\265\333\377\377\267\333\377\377\234\314\376\377"
+ "5\231\377\361\13\204\377\26\5\201\377\\|\274\376\377\315\346\377\377\347"
+ "\363\377\377p\266\376\377\0~\376\377\20\206\376\377\276\336\376\377\336\356"
+ "\376\377L\244\376\377\266\332\376\377\376\376\376\377\376\376\376\377\204"
+ "\267\354\377\0U\226\377\0V\230\377\0V\230\377\1U\217\377\7o\317\377\372\373"
+ "\376\377\376\376\376\377\273\334\375\377N\245\376\377\330\353\376\377\263"
+ "\330\375\377\0\203\376\377\0\217\376\377b\257\376\377\317\347\377\377\244"
+ "\320\376\377j\263\376\377\11\203\377\\\17\206\377\227\225\311\377\377\314"
+ "\345\376\377\325\352\377\377-\225\377\377\0\203\376\377\\\253\374\377\376"
+ "\376\376\377\242\315\376\377{\273\375\377\376\376\376\377\376\376\376\377"
+ "\376\376\376\377\366\371\376\377\7o\317\377\2`\260\377\7i\305\377\1c\257"
+ "\377\201\270\361\377\376\376\376\377\376\376\376\377\376\376\376\377y\272"
+ "\375\377{\273\375\377\352\364\376\377F\241\376\377\0\211\376\377\35\215\377"
+ "\377\315\346\377\377\261\330\377\377\207\302\377\377\17\206\377\227%\221"
+ "\377\303\242\317\376\377\325\352\377\377\253\323\377\377\16\205\376\377\0"
+ "~\376\377\224\310\376\377\360\366\376\377_\255\375\377\334\355\376\377\376"
+ "\376\376\377\376\376\376\377\376\376\376\377\376\376\376\377\344\360\376"
+ "\377\352\364\376\377\376\376\376\377\312\344\376\377\376\376\376\377\376"
+ "\376\376\377\376\376\376\377\376\376\376\377\334\355\376\377L\244\376\377"
+ "\330\353\376\377\221\306\375\377\0\211\376\377\3\200\377\377\252\324\376"
+ "\377\312\344\376\377\233\314\377\377)\223\377\303;\234\377\330\265\332\377"
+ "\377\340\360\376\377\221\307\377\377\0~\376\377\20\206\376\377\270\333\376"
+ "\377\305\341\375\377F\241\376\377\376\376\376\377\376\376\376\377\376\376"
+ "\376\377\376\376\376\377\376\376\376\377\376\376\376\377\346\361\376\377"
+ "\310\343\376\377\376\376\376\377\376\376\376\377\376\376\376\377\376\376"
+ "\376\377\376\376\376\377\376\376\376\377F\241\376\377\270\333\376\377\264"
+ "\331\376\377\12\203\376\377\1\204\377\377\217\306\377\377\325\352\377\377"
+ "\255\326\377\377=\235\377\330K\244\377\346\315\347\377\377\351\364\377\377"
+ "\207\302\377\377\0~\376\377$\217\374\377\334\355\376\377\324\351\376\377"
+ "\230\312\376\377\376\376\376\377\376\376\376\377\376\376\376\377\376\376"
+ "\376\377\376\376\376\377\305\341\375\377\1c\257\377\0U\226\377+\221\371\377"
+ "\372\373\376\377\376\376\376\377\376\376\376\377\376\376\376\377\376\376"
+ "\376\377\226\311\376\377\314\345\376\377\330\353\376\377\34\213\374\377\1"
+ "\204\377\377\201\277\377\377\337\360\377\377\272\334\376\377E\241\377\346"
+ "M\245\377\346\335\356\377\377\363\371\377\377\211\303\377\377\14\204\376"
+ "\377&\220\374\377\214\303\374\377\241\316\375\377\210\271\354\377\205\267"
+ "\353\377\204\267\354\377\204\267\354\377\214\276\362\377\376\376\376\377"
+ "\210\271\354\377\1R\213\377\1R\213\377\2`\260\377\372\374\376\377\334\355"
+ "\376\377\204\267\354\377\204\267\354\377\205\267\353\377\210\271\354\377"
+ "\224\310\376\377{\273\375\377\16\205\376\377\1\204\377\377\201\277\377\377"
+ "\333\356\377\377\272\334\376\377I\243\377\346E\241\377\330\335\355\377\377"
+ "\373\375\377\377\233\314\377\377\35\215\377\377'\220\373\377\34\213\374\377"
+ "\20\206\376\377\4h\274\377\1R\213\377\0T\224\377\3N\207\377\1c\257\377\354"
+ "\364\376\377\370\372\376\377\7i\305\377\1T\241\377d\250\356\377\376\376\376"
+ "\377M\233\353\377\0U\220\377\0U\220\377\1R\213\377\2b\264\377\0\203\376\377"
+ "\0~\376\377\10\202\376\377\1\177\377\377\217\306\377\377\327\354\377\377"
+ "\257\327\377\377=\235\377\330-\225\377\303\315\346\377\377\375\375\377\377"
+ "\267\333\377\377'\222\377\377&\220\374\377+\221\371\377$\217\374\377\6v\336"
+ "\377\0P\232\377\1T\241\377\1S\237\377\0U\226\377d\242\342\377\376\376\376"
+ "\377\372\373\376\377\356\365\376\377\376\376\376\377\336\355\376\377\7i\305"
+ "\377\0V\230\377\1T\241\377\0P\232\377\6r\326\377\14\204\376\377\16\205\376"
+ "\377\10\202\376\377\15\205\377\377\252\324\376\377\324\352\376\377\244\320"
+ "\376\377)\223\377\303\17\206\377\227\263\331\377\377\365\372\377\377\341"
+ "\360\377\3777\232\377\377\27\211\375\377\40\215\374\377\34\213\374\377\6"
+ "\201\376\377\1V\245\377\0P\232\377\1T\241\377\0P\232\377\1^\255\377\255\323"
+ "\375\377\376\376\376\377\376\376\376\377\376\376\376\377+\221\371\377\1U"
+ "\217\377\1T\241\377\0P\232\377\1V\245\377\1~\375\377\12\203\376\377\16\205"
+ "\376\377\4\200\376\377'\222\377\377\324\351\376\377\307\343\377\377\223\310"
+ "\377\377\17\206\377\227\1\177\377\\\207\302\377\377\343\361\377\377\355\366"
+ "\377\377n\265\376\377\0~\376\377\22\207\376\377\6\201\376\377\4\200\376\377"
+ "\6p\322\377\0P\232\377\1S\237\377\0U\220\377\7o\317\377\370\372\376\377\376"
+ "\376\376\377\376\376\376\377\376\376\376\377\255\323\375\377\0S\232\377\0"
+ "P\232\377\0P\232\377\7o\317\377\4\200\376\377\4\200\376\377\10\202\376\377"
+ "\1\204\377\377d\260\376\377\333\355\377\377\274\335\376\377x\272\376\377"
+ "\5\201\377\\\13\204\377\26?\236\377\361\307\343\377\377\333\356\377\377\276"
+ "\336\376\377\1\177\377\377\0\203\376\377\0~\376\377\4\200\376\377\4\200\376"
+ "\377\5k\313\377\1U\217\377\1c\257\377\370\372\376\377\376\376\376\377\376"
+ "\376\376\377\376\376\376\377\376\376\376\377\376\376\376\377d\245\350\377"
+ "\0U\226\377\5k\313\377\4\200\376\377\0~\376\377\0~\376\377\0\203\376\377"
+ "\1\204\377\377\274\335\376\377\307\343\377\377\255\326\377\377;\234\377\361"
+ "\13\204\377\26\0\0\0\0\17\206\377\242\211\303\377\377\265\332\377\377\331"
+ "\354\377\377U\251\377\377\0\211\376\377\0~\376\377\0~\376\377\4\200\376\377"
+ "\4\200\376\377\4j\300\377c\246\353\377\346\361\376\377\376\376\376\377\376"
+ "\376\376\377\376\376\376\377\376\376\376\377\342\357\376\377\302\340\376"
+ "\377\6v\336\377\0\203\376\377\4\200\376\377\4\200\376\377\0~\376\377\0\216"
+ "\374\377Q\247\377\377\327\353\377\377\250\322\376\377\207\302\377\377\25"
+ "\211\377\242\0\0\0\0\0\0\0\0\5\201\377+1\227\377\372\242\317\376\377\253"
+ "\325\377\377\332\355\376\377%\221\377\377\0\211\376\377\0~\376\377\4\200"
+ "\376\377\0~\376\377_\255\375\377\340\356\376\377a\256\375\377\\\253\374\377"
+ "l\264\376\377j\263\376\377c\257\375\377F\241\376\377\276\336\376\377\322"
+ "\347\376\377\14\204\376\377\0~\376\377\0~\376\377\1\212\377\377%\221\377"
+ "\377\325\352\377\377\240\316\376\377\240\316\376\377;\234\377\372\13\204"
+ "\377+\0\0\0\0\0\0\0\0\0\0\0\0\7\202\377\213f\261\376\377\252\324\376\377"
+ "\314\345\376\377\307\343\377\377\21\213\375\377\0\211\376\377\4\200\376\377"
+ "\0~\376\377\223\307\375\377\376\376\376\377\354\364\376\377\324\350\376\377"
+ "\321\347\375\377\322\347\376\377\321\347\375\377\356\365\376\377\372\374"
+ "\376\377\264\331\376\377\34\213\374\377\1~\375\377\1\212\377\377\17\213\377"
+ "\377\312\344\376\377\312\344\376\377\236\315\376\377n\265\376\377\15\205"
+ "\377\213\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1g\377\5\23\210\377\322|\274\376"
+ "\377\234\314\376\377\303\341\377\377\315\345\377\3777\231\375\377\0\211\376"
+ "\377\4\200\376\377\34\213\374\377N\245\376\377\223\307\375\377\270\333\376"
+ "\377\322\350\376\377\322\350\376\377\270\333\376\377\223\307\375\377N\245"
+ "\376\377\10\202\376\377\0~\376\377\1\212\377\377;\240\377\377\314\345\376"
+ "\377\307\343\377\377\240\316\376\377\207\302\377\377\33\214\377\322\1g\377"
+ "\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\13\204\377,\37\216\377\360\215"
+ "\305\377\377\240\316\376\377\317\347\377\377\335\354\377\377a\256\375\377"
+ "\10\202\376\377\0~\376\377\0\203\376\377\0~\376\377\27\211\375\377'\220\373"
+ "\377+\221\371\377\27\211\375\377\0~\376\377\0\211\376\377\1\204\377\377\1"
+ "\177\377\377`\256\376\377\337\356\377\377\321\350\377\377\242\317\376\377"
+ "\231\313\377\377)\223\377\360\13\204\377,\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\13\204\377/#\220\377\350\205\301\377\377\265\332"
+ "\377\377\300\337\376\377\351\363\377\377\301\340\377\377t\270\376\3775\231"
+ "\377\377\23\210\377\377\14\204\376\377\10\202\376\377\10\202\376\377\14\204"
+ "\376\377\22\207\376\3771\227\377\377p\266\376\377\272\334\376\377\341\357"
+ "\377\377\274\335\376\377\272\334\376\377\221\307\377\377'\222\377\350\13"
+ "\204\377/\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\13\204\3772\27\212\377\320z\273\376\377\305\342\377\377\315\346"
+ "\377\377\343\361\377\377\347\364\377\377\327\353\377\377\263\327\377\377"
+ "\236\315\376\377\213\304\377\377\215\305\377\377\240\316\376\377\263\331"
+ "\377\377\327\353\377\377\343\361\377\377\325\352\377\377\267\333\377\377"
+ "\274\335\376\377\201\277\377\377\33\214\377\320\13\204\3772\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\1s\377\7\11\203\377\214?\236\377\371\231\313\377\377\307\343\377\377\321"
+ "\350\377\377\321\350\377\377\335\357\377\377\347\363\377\377\363\371\377"
+ "\377\367\373\377\377\351\364\377\377\333\355\377\377\315\346\377\377\314"
+ "\345\376\377\276\336\376\377\225\311\377\377A\237\377\371\13\204\377\214"
+ "\1s\377\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\5\201\3772\21\207\377\240"
+ "=\235\377\351~\275\376\377\233\314\377\377\257\327\377\377\307\343\377\377"
+ "\333\355\377\377\335\355\377\377\312\344\376\377\257\327\377\377\227\312"
+ "\377\377|\274\376\377A\237\377\351\25\211\377\240\5\201\3772\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\11}\377\33\3"
+ "\200\377]\15\205\377\225'\222\377\301?\236\377\330K\244\377\346K\244\377"
+ "\346?\236\377\330+\224\377\301\17\206\377\225\3\200\377]\11}\377\33\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0",
+#if 0
+};
+#endif
diff --git a/source/exhumed/rsrc/eduke32_icon_48px.c b/source/exhumed/rsrc/eduke32_icon_48px.c
new file mode 100644
index 000000000..caeb14546
--- /dev/null
+++ b/source/exhumed/rsrc/eduke32_icon_48px.c
@@ -0,0 +1,434 @@
+/* GIMP RGBA C-Source image dump (eduke32_icon_48px.c) */
+#if 0
+static const struct {
+ unsigned int width;
+ unsigned int height;
+ unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */
+ unsigned char pixel_data[48 * 48 * 4 + 1];
+} sdlappicon = {
+ 48, 48, 4,
+#endif
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\1\377\1\31\213"
+ "\377(\31\213\377_\31\213\377\222\31\213\377\270\31\213\377\321\31\213\377"
+ "\343\31\213\377\355\31\213\377\355\31\213\377\343\31\213\377\321\31\213\377"
+ "\270\31\213\377\222\31\213\377_\31\213\377(\1\1\377\1\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\31\213\377\36\31\213\377s\31\213\377\304\31\213\377\365?\236\377\377"
+ "f\261\376\377\205\301\377\377\246\321\376\377\303\341\377\377\305\342\377"
+ "\377\301\340\377\377\253\325\377\377\207\302\377\377h\262\376\377M\245\377"
+ "\3771\227\377\377\31\213\377\365\31\213\377\304\31\213\377s\31\213\377\36"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\33\221\377"
+ "&\31\213\377\222\31\213\377\354E\241\377\377\234\314\376\377\341\357\377"
+ "\377\367\373\377\377\375\376\377\377\375\376\377\377\371\374\377\377\357"
+ "\367\377\377\343\361\377\377\335\355\377\377\321\350\377\377\300\337\376"
+ "\377\272\334\376\377\272\334\376\377\255\326\377\377\240\316\376\377t\270"
+ "\376\3775\231\377\377\31\213\377\354\31\213\377\222\33\221\377&\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\25\203\377\14\31\213\377|\31\213\377\354Q\247\377"
+ "\377\274\335\376\377\353\365\377\377\365\372\377\377\365\372\377\377\371"
+ "\374\377\377\363\371\377\377\365\372\377\377\365\372\377\377\353\365\377"
+ "\377\341\357\377\377\332\354\376\377\315\346\377\377\274\335\376\377\265"
+ "\332\377\377\257\327\377\377\250\322\376\377\246\321\376\377\252\324\376"
+ "\377\265\332\377\377\242\317\376\377K\244\377\377\31\213\377\354\31\213\377"
+ "|\25\203\377\14\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\31\213\3774\31\213\377\3055\231\377\377\236\315\376"
+ "\377\314\345\376\377\327\353\377\377\341\357\377\377\353\365\377\377\361"
+ "\370\377\377\367\373\377\377\371\374\377\377\371\374\377\377\373\375\377"
+ "\377\371\374\377\377\371\374\377\377\367\373\377\377\357\367\377\377\343"
+ "\361\377\377\325\352\377\377\274\335\376\377\244\320\376\377\244\320\376"
+ "\377\250\322\376\377\265\332\377\377\305\342\377\377\314\345\376\377\257"
+ "\327\377\377;\234\377\377\31\213\377\305\31\213\3774\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\213\377Z\31\213\377\356K"
+ "\244\377\377\244\320\376\377\263\331\377\377\276\336\376\377\314\345\376"
+ "\377\332\354\376\377\353\365\377\377\367\373\377\377\375\376\377\377\335"
+ "\355\377\377\253\325\377\377\211\303\377\377p\266\376\377Z\253\376\377S\250"
+ "\377\377^\255\376\377t\270\376\377\234\314\376\377\327\353\377\377\365\372"
+ "\377\377\327\353\377\377\274\335\376\377\300\337\376\377\305\342\377\377"
+ "\312\344\376\377\325\352\377\377\343\361\377\377l\264\376\377\31\213\377"
+ "\356\31\213\377Z\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\213\377"
+ "q\31\213\377\374^\255\376\377\225\311\377\377\231\313\377\377\246\321\376"
+ "\377\267\333\377\377\327\353\377\377\363\371\377\377\325\352\377\377\217"
+ "\306\377\377Q\247\377\377;\234\377\377;\234\377\377;\234\377\3775\231\377"
+ "\377/\226\377\377'\222\377\377\35\215\377\377\23\210\377\377\21\207\377\377"
+ "\15\205\377\377%\221\377\377x\272\376\377\317\347\377\377\357\367\377\377"
+ "\332\354\376\377\317\347\377\377\333\355\377\377\351\364\377\377\355\366"
+ "\377\377\227\312\377\377\31\213\377\374\31\213\377q\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\31\213\377q\23\210\377\377^\255\376\377\211\303\377\377\211\303"
+ "\377\377\221\307\377\377\250\322\376\377\333\355\377\377\324\351\376\377"
+ "`\256\376\377+\224\377\3771\227\377\3779\233\377\377;\234\377\377;\234\377"
+ "\377;\234\377\3779\233\377\377/\226\377\377)\223\377\377\33\214\377\377\23"
+ "\210\377\377\21\207\377\377\11\203\377\377\7\202\377\377\13\204\377\377\27"
+ "\212\377\377^\255\376\377\325\352\377\377\357\367\377\377\345\362\377\377"
+ "\353\365\377\377\351\364\377\377\355\366\377\377\257\327\377\377\37\216\377"
+ "\377\31\213\377q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\213\377Z\31\213\377\374Z\253\376\377"
+ "~\275\376\377|\274\376\377\203\300\377\377\257\327\377\377\373\375\377\377"
+ "x\272\376\377\17\206\377\377\33\214\377\377%\221\377\377/\226\377\3777\232"
+ "\377\377;\234\377\377;\234\377\377;\234\377\3779\233\377\3771\227\377\377"
+ ")\223\377\377\33\214\377\377\23\210\377\377\17\206\377\377\11\203\377\377"
+ "\7\202\377\377\17\206\377\377\31\213\377\377\35\215\377\377#\220\377\377"
+ "\215\305\377\377\375\376\377\377\357\367\377\377\351\364\377\377\343\361"
+ "\377\377\341\357\377\377\244\320\376\377\31\213\377\374\31\213\377Z\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\33\214"
+ "\3771\31\213\377\355Q\247\377\377\200\276\376\377t\270\376\377x\272\376\377"
+ "\267\333\377\377\353\365\377\377?\236\377\377\1\177\377\377\11\203\377\377"
+ "\23\210\377\377!\217\377\377+\224\377\3773\230\377\3779\233\377\377;\234"
+ "\377\377;\234\377\3779\233\377\3771\227\377\377'\222\377\377\33\214\377\377"
+ "\23\210\377\377\15\205\377\377\7\202\377\377\11\203\377\377\25\211\377\377"
+ "\35\215\377\377\37\216\377\377+\224\377\3771\227\377\377l\264\376\377\361"
+ "\370\377\377\357\367\377\377\333\355\377\377\317\347\377\377\314\345\376"
+ "\377\201\277\377\377\31\213\377\355\33\214\3771\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\27\217\377\13\31\213\377\310=\235\377\377"
+ "\217\306\377\377\203\300\377\377~\275\376\377\267\333\377\377\332\354\376"
+ "\377\25\211\377\377\0w\360\377\0{\370\377\1\177\377\377\13\204\377\377\33"
+ "\214\377\377'\222\377\3771\227\377\3779\233\377\377;\234\377\377;\234\377"
+ "\3779\233\377\3771\227\377\377'\222\377\377\33\214\377\377\21\207\377\377"
+ "\15\205\377\377\7\202\377\377\15\205\377\377\31\213\377\377\35\215\377\377"
+ "%\221\377\3771\227\377\3773\230\377\3773\230\377\377M\245\377\377\341\357"
+ "\377\377\345\362\377\377\301\340\377\377\274\335\376\377\303\341\377\377"
+ "U\251\377\377\31\213\377\310\27\217\377\13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\31\213\377|#\220\377\377\231\313\377\377\225\311\377\377"
+ "\213\304\377\377\265\332\377\377\343\361\377\377\11\203\377\377\0u\354\377"
+ "\0v\356\377\0x\362\377\0|\372\377+\224\377\377\257\327\377\3771\227\377\377"
+ "-\225\377\3775\231\377\377;\234\377\377;\234\377\377;\234\377\3771\227\377"
+ "\377'\222\377\377\27\212\377\377\21\207\377\377\13\204\377\377\11\203\377"
+ "\377\23\210\377\377\35\215\377\377x\272\376\377O\246\377\3773\230\377\377"
+ "3\230\377\377/\226\377\377+\224\377\3779\233\377\377\347\363\377\377\325"
+ "\352\377\377\267\333\377\377\267\333\377\377\257\327\377\377'\222\377\377"
+ "\31\213\377|\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\27\212\377\"\31\213"
+ "\377\356\203\300\377\377\250\322\376\377\234\314\376\377\246\321\376\377"
+ "\371\374\377\377+\224\377\377\0u\354\377\0t\352\377\0t\352\377\0v\356\377"
+ "A\237\377\377\363\371\377\377\325\352\377\377\242\317\376\377'\222\377\377"
+ "\35\215\377\377\1\177\377\377\0o\340\377\0b\306\377\0Y\264\377\0Y\264\377"
+ "\0_\300\377\0g\320\377\0p\342\377\0}\374\377\27\212\377\377=\235\377\377"
+ "\373\375\377\377\365\372\377\377n\265\376\3771\227\377\377+\224\377\377!"
+ "\217\377\377\31\213\377\377E\241\377\377\371\374\377\377\276\336\376\377"
+ "\253\325\377\377\244\320\376\377\207\302\377\377\31\213\377\356\27\212\377"
+ "\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\213\377\222;\234\377\377\272\334\376"
+ "\377\253\325\377\377\250\322\376\377\327\353\377\377p\266\376\377\0|\372"
+ "\377\0y\364\377\0w\360\377\0t\352\377X\252\376\377\373\375\377\377\253\325"
+ "\377\377\231\313\377\377\371\374\377\377\17\206\377\377\0V\256\377\0T\252"
+ "\377\0R\246\377\0P\242\377\0O\240\377\0O\240\377\0P\242\377\0R\246\377\0"
+ "T\252\377\0V\256\377\0q\344\377\255\326\377\377\361\370\377\377\361\370\377"
+ "\377\375\376\377\377~\275\376\377!\217\377\377\33\214\377\377\27\212\377"
+ "\377\21\207\377\377x\272\376\377\332\354\376\377\236\315\376\377\234\314"
+ "\376\377\240\316\376\3779\233\377\377\31\213\377\222\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\31\213\377\36\31\213\377\355\234\314\376\377\301\340\377\377\265\332"
+ "\377\377\314\345\376\377\321\350\377\377\11\203\377\377\3\200\377\377\1\177"
+ "\377\377\0z\366\377A\237\377\377\373\375\377\377\223\310\377\377\200\276"
+ "\376\377j\263\376\377\217\306\377\377\234\314\376\377\0P\242\377\0O\240\377"
+ "\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240"
+ "\377\0P\242\377\0s\350\377\333\355\377\377\255\326\377\377\347\363\377\377"
+ "\341\357\377\377\375\376\377\377^\255\376\377\27\212\377\377\21\207\377\377"
+ "\11\203\377\377\7\202\377\377\317\347\377\377\272\334\376\377\223\310\377"
+ "\377\225\311\377\377\203\300\377\377\31\213\377\355\31\213\377\36\0\0\0\0"
+ "\0\0\0\0\31\213\377q3\230\377\377\315\346\377\377\305\342\377\377\300\337"
+ "\376\377\355\366\377\377S\250\377\377\17\206\377\377\13\204\377\377\7\202"
+ "\377\377+\224\377\377\357\367\377\377\250\322\376\377x\272\376\377U\251\377"
+ "\377S\250\377\377\274\335\376\377\377\377\377\377\7\202\377\377\0O\240\377"
+ "\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240"
+ "\377\0O\240\377\236\315\376\377\325\352\377\377S\250\377\377\225\311\377"
+ "\377\305\342\377\377\317\347\377\377\361\370\377\3773\230\377\377\7\202\377"
+ "\377\3\200\377\377\1\177\377\377E\241\377\377\343\361\377\377\225\311\377"
+ "\377\227\312\377\377\240\316\376\377-\225\377\377\31\213\377q\0\0\0\0\1["
+ "\377\3\31\213\377\305z\273\376\377\305\342\377\377\276\336\376\377\315\346"
+ "\377\377\321\350\377\377\31\213\377\377\27\212\377\377\25\211\377\377\21"
+ "\207\377\377\267\333\377\377\312\344\376\377\223\310\377\377f\261\376\377"
+ "S\250\377\377\314\345\376\377\377\377\377\377\377\377\377\377\315\346\377"
+ "\377\0S\250\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0"
+ "O\240\377\0O\240\377\0|\372\377\377\377\377\377\377\377\377\377\314\345\376"
+ "\377S\250\377\377\215\305\377\377\265\332\377\377\317\347\377\377\267\333"
+ "\377\377\3\200\377\377\1\177\377\377\0}\374\377\0}\374\377\314\345\376\377"
+ "\255\326\377\377\231\313\377\377\236\315\376\377h\262\376\377\31\213\377"
+ "\305\1[\377\3\33\214\377'\31\213\377\366\255\326\377\377\272\334\376\377"
+ "\274\335\376\377\345\362\377\377v\271\376\377\33\214\377\377\33\214\377\377"
+ "\33\214\377\377Q\247\377\377\355\366\377\377\261\330\377\377\223\310\377"
+ "\3777\232\377\377\274\335\376\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377E\241\377\377\0O\240\377\0O\240\377\0O\240\377\0"
+ "O\240\377\0O\240\377\0O\240\377\0O\240\377\272\334\376\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\274\335\376\3777\232\377\377\221\307\377"
+ "\377\234\314\376\377\345\362\377\377?\236\377\377\1\177\377\377\1\177\377"
+ "\377\3\200\377\377h\262\376\377\325\352\377\377\227\312\377\377\227\312\377"
+ "\377\223\310\377\377\31\213\377\366\33\214\377'\31\213\377_3\230\377\377"
+ "\272\334\376\377\267\333\377\377\267\333\377\377\375\376\377\377%\221\377"
+ "\377\27\212\377\377\27\212\377\377\33\214\377\377\303\341\377\377\325\352"
+ "\377\377\276\336\376\377j\263\376\377\215\305\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\357\367\377"
+ "\377\0b\306\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\25"
+ "\211\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\215\305\377\377X\252\376\377\227\312\377\377\274\335"
+ "\376\377\276\336\376\377\1\177\377\377\1\177\377\377\1\177\377\377\21\207"
+ "\377\377\373\375\377\377\236\315\376\377\236\315\376\377\246\321\376\377"
+ "/\226\377\377\31\213\377_\31\213\377\222K\244\377\377\272\334\376\377\263"
+ "\331\377\377\303\341\377\377\312\344\376\377\23\210\377\377\23\210\377\377"
+ "\23\210\377\3771\227\377\377\375\376\377\377\300\337\376\377\246\321\376"
+ "\377A\237\377\377\340\360\376\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\203\300\377\377"
+ "\0l\332\377X\252\376\377t\270\376\377)\223\377\377\0]\274\377\315\346\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\340\360\376\377A\237\377\377\205\301\377\377\231\313\377\377"
+ "\373\375\377\377\35\215\377\377\1\177\377\377\3\200\377\377\5\201\377\377"
+ "\307\343\377\377\267\333\377\377\244\320\376\377\255\326\377\377G\242\377"
+ "\377\31\213\377\222\31\213\377\272j\263\376\377\267\333\377\377\261\330\377"
+ "\377\325\352\377\377\225\311\377\377\23\210\377\377\23\210\377\377\23\210"
+ "\377\377l\264\376\377\343\361\377\377\267\333\377\377t\270\376\377~\275\376"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377~\275\376\377b\257\376\377\236\315\376"
+ "\377\333\355\377\377f\261\376\377\7\202\377\377\7\202\377\377\11\203\377"
+ "\377\223\310\377\377\315\346\377\377\246\321\376\377\252\324\376\377n\265"
+ "\376\377\31\213\377\272\31\213\377\321\207\302\377\377\274\335\376\377\265"
+ "\332\377\377\343\361\377\377r\267\376\377\23\210\377\377\21\207\377\377\21"
+ "\207\377\377\234\314\376\377\324\351\376\377\261\330\377\377M\245\377\377"
+ "\261\330\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\261\330\377\377I\243\377"
+ "\377\244\320\376\377\314\345\376\377\227\312\377\377\11\203\377\377\11\203"
+ "\377\377\11\203\377\377n\265\376\377\335\355\377\377\252\324\376\377\255"
+ "\326\377\377\213\304\377\377\31\213\377\321\31\213\377\343\246\321\376\377"
+ "\274\335\376\377\267\333\377\377\353\365\377\377Z\253\376\377\25\211\377"
+ "\377\23\210\377\377\23\210\377\377\276\336\376\377\312\344\376\377\263\331"
+ "\377\3773\230\377\377\332\354\376\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\261\330\377\377\0n\336\377\0O\240\377\3\200\377\377"
+ "\325\352\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\332\354\376\377"
+ "1\227\377\377\252\324\376\377\300\337\376\377\301\340\377\377\15\205\377"
+ "\377\15\205\377\377\15\205\377\377U\251\377\377\347\363\377\377\255\326\377"
+ "\377\257\327\377\377\227\312\377\377\31\213\377\343\31\213\377\355\267\333"
+ "\377\377\307\343\377\377\301\340\377\377\361\370\377\377Q\247\377\377\33"
+ "\214\377\377\33\214\377\377\33\214\377\377\317\347\377\377\315\346\377\377"
+ "\314\345\376\377M\245\377\377\367\373\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\373\375\377\377\0b\306\377\0O\240\377\0O\240\377\0O\240\377"
+ "\1\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\367\373\377\377K\244"
+ "\377\377\300\337\376\377\300\337\376\377\315\346\377\377\17\206\377\377\17"
+ "\206\377\377\17\206\377\377G\242\377\377\355\366\377\377\257\327\377\377"
+ "\261\330\377\377\250\322\376\377\31\213\377\355\31\213\377\355\274\335\376"
+ "\377\315\346\377\377\314\345\376\377\363\371\377\377U\251\377\377!\217\377"
+ "\377!\217\377\377!\217\377\377\257\327\377\377\324\351\376\377\324\351\376"
+ "\377\276\336\376\377\272\334\376\377\272\334\376\377\272\334\376\377\272"
+ "\334\376\377\272\334\376\377\272\334\376\377\343\361\377\377\377\377\377"
+ "\377\312\344\376\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0W\260\377"
+ "\377\377\377\377\377\377\377\377\325\352\377\377\272\334\376\377\272\334"
+ "\376\377\272\334\376\377\272\334\376\377\272\334\376\377\276\336\376\377"
+ "\317\347\377\377\317\347\377\377\250\322\376\377\15\205\377\377\15\205\377"
+ "\377\15\205\377\377E\241\377\377\353\365\377\377\255\326\377\377\257\327"
+ "\377\377\250\322\376\377\31\213\377\355\31\213\377\343\274\335\376\377\325"
+ "\352\377\377\321\350\377\377\361\370\377\377f\261\376\377%\221\377\377'\222"
+ "\377\377'\222\377\377'\222\377\377'\222\377\377'\222\377\377\0a\304\377\0"
+ "P\242\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377S\250\377"
+ "\377\377\377\377\377\363\371\377\377\0[\270\377\0O\240\377\0O\240\377\0O"
+ "\240\377\0t\352\377\377\377\377\377\377\377\377\377\25\211\377\377\0O\240"
+ "\377\0O\240\377\0O\240\377\0O\240\377\0P\242\377\0^\276\377\15\205\377\377"
+ "\15\205\377\377\15\205\377\377\15\205\377\377\15\205\377\377\15\205\377\377"
+ "U\251\377\377\347\363\377\377\255\326\377\377\255\326\377\377\240\316\376"
+ "\377\31\213\377\343\31\213\377\321\246\321\376\377\333\355\377\377\327\353"
+ "\377\377\357\367\377\377~\275\376\377'\222\377\377+\224\377\377+\224\377"
+ "\377+\224\377\377+\224\377\377)\223\377\377\0l\332\377\0R\246\377\0O\240"
+ "\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\35\215\377\377\377\377\377"
+ "\377\377\377\377\377\231\313\377\377\0[\270\377\0O\240\377\0h\322\377\305"
+ "\342\377\377\377\377\377\377\377\377\377\377\0h\322\377\0O\240\377\0O\240"
+ "\377\0O\240\377\0O\240\377\0R\246\377\0g\320\377\17\206\377\377\17\206\377"
+ "\377\15\205\377\377\15\205\377\377\15\205\377\377\15\205\377\377n\265\376"
+ "\377\340\356\376\377\255\326\377\377\261\330\377\377\213\304\377\377\31\213"
+ "\377\321\31\213\377\272\203\300\377\377\340\356\376\377\333\355\377\377\351"
+ "\364\377\377\240\316\376\377)\223\377\377+\224\377\377)\223\377\377)\223"
+ "\377\377%\221\377\377%\221\377\377\0w\360\377\0T\252\377\0O\240\377\0O\240"
+ "\377\0O\240\377\0O\240\377\0O\240\377\0U\254\377\315\346\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\347\363\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\236\315\376\377\0O\240\377\0O\240\377\0"
+ "O\240\377\0O\240\377\0O\240\377\0T\252\377\0r\346\377\15\205\377\377\15\205"
+ "\377\377\15\205\377\377\15\205\377\377\15\205\377\377\17\206\377\377\223"
+ "\310\377\377\324\351\376\377\257\327\377\377\263\331\377\377r\267\376\377"
+ "\31\213\377\272\31\213\377\222^\255\376\377\340\356\376\377\333\355\377\377"
+ "\341\357\377\377\315\346\377\377'\222\377\377%\221\377\377%\221\377\377!"
+ "\217\377\377\37\216\377\377\35\215\377\377\11\203\377\377\0V\256\377\0P\242"
+ "\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0j\326\377\312"
+ "\344\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\242\317\376\377\0]\274\377\0O\240\377\0O\240\377\0O"
+ "\240\377\0O\240\377\0P\242\377\0V\256\377\0|\372\377\13\204\377\377\13\204"
+ "\377\377\15\205\377\377\15\205\377\377\15\205\377\377\15\205\377\377\307"
+ "\343\377\377\301\340\377\377\261\330\377\377\265\332\377\377M\245\377\377"
+ "\31\213\377\222\31\213\377_9\233\377\377\335\355\377\377\327\353\377\377"
+ "\324\351\376\377\375\376\377\3773\230\377\377!\217\377\377\35\215\377\377"
+ "\33\214\377\377\33\214\377\377\25\211\377\377\17\206\377\377\0m\334\377\0"
+ "S\250\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377"
+ "p\266\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377)\223\377\377\0O\240\377\0O\240\377\0O\240\377\0O\240"
+ "\377\0O\240\377\0S\250\377\0l\332\377\5\201\377\377\7\202\377\377\11\203"
+ "\377\377\15\205\377\377\15\205\377\377\15\205\377\377\37\216\377\377\375"
+ "\376\377\377\257\327\377\377\257\327\377\377\265\332\377\3771\227\377\377"
+ "\31\213\377_\33\214\377'\31\213\377\366\303\341\377\377\315\346\377\377\312"
+ "\344\376\377\351\364\377\377v\271\376\377\33\214\377\377\27\212\377\377\25"
+ "\211\377\377\17\206\377\377\7\202\377\377\3\200\377\377\0z\366\377\0V\256"
+ "\377\0Q\244\377\0O\240\377\0O\240\377\0O\240\377\0O\240\377\0t\352\377\373"
+ "\375\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\347\363\377\377\0[\270\377\0O\240\377\0O\240\377\0O"
+ "\240\377\0Q\244\377\0V\256\377\0x\362\377\1\177\377\377\3\200\377\377\5\201"
+ "\377\377\7\202\377\377\11\203\377\377\11\203\377\377j\263\376\377\340\356"
+ "\376\377\253\325\377\377\255\326\377\377\252\324\376\377\31\213\377\366\33"
+ "\214\377'\1[\377\3\31\213\377\305\201\277\377\377\314\345\376\377\305\342"
+ "\377\377\317\347\377\377\315\346\377\377\23\210\377\377\15\205\377\377\11"
+ "\203\377\377\5\201\377\377\1\177\377\377\1\177\377\377\3\200\377\377\0t\352"
+ "\377\0U\254\377\0Q\244\377\0O\240\377\0O\240\377\0Q\244\377\276\336\376\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\203\300\377\377\0O\240\377\0O\240"
+ "\377\0Q\244\377\0U\254\377\0s\350\377\0|\372\377\0|\372\377\0}\374\377\1"
+ "\177\377\377\3\200\377\377\7\202\377\377\11\203\377\377\314\345\376\377\272"
+ "\334\376\377\250\322\376\377\255\326\377\377t\270\376\377\31\213\377\305"
+ "\1[\377\3\0\0\0\0\31\213\377q1\227\377\377\312\344\376\377\274\335\376\377"
+ "\263\331\377\377\351\364\377\377K\244\377\377\5\201\377\377\1\177\377\377"
+ "\1\177\377\377\1\177\377\377\1\177\377\377\1\177\377\377\1\177\377\377\0"
+ "p\342\377\0U\254\377\0Q\244\377\0O\240\377E\241\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\0|\372\377\0Q\244\377"
+ "\0U\254\377\0q\344\377\1\177\377\377\1\177\377\377\0}\374\377\0}\374\377"
+ "\0|\372\377\1\177\377\377\1\177\377\377E\241\377\377\347\363\377\377\244"
+ "\320\376\377\250\322\376\377\257\327\377\377/\226\377\377\31\213\377q\0\0"
+ "\0\0\0\0\0\0\31\213\377\36\31\213\377\355\221\307\377\377\263\331\377\377"
+ "\252\324\376\377\276\336\376\377\317\347\377\377\3\200\377\377\1\177\377"
+ "\377\1\177\377\377\1\177\377\377\1\177\377\377\1\177\377\377\0}\374\377\1"
+ "\177\377\377\0u\354\377\0V\256\377\0k\330\377\357\367\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
+ "\377\377\377\377\377\377\377\377\377\377\377\351\364\377\377\317\347\377"
+ "\377\0Z\266\377\0v\356\377\3\200\377\377\1\177\377\377\3\200\377\377\1\177"
+ "\377\377\0}\374\377\0|\372\377\0|\372\377\1\177\377\377\317\347\377\377\274"
+ "\335\376\377\234\314\376\377\246\321\376\377\217\306\377\377\31\213\377\355"
+ "\31\213\377\36\0\0\0\0\0\0\0\0\0\0\0\0\31\213\377\2221\227\377\377\252\324"
+ "\376\377\234\314\376\377\231\313\377\377\325\352\377\377r\267\376\377\1\177"
+ "\377\377\1\177\377\377\1\177\377\377\0}\374\377\0}\374\377\1\177\377\377"
+ "\7\202\377\377\11\203\377\377\3\200\377\377\257\327\377\377\227\312\377\377"
+ "~\275\376\377\261\330\377\377\332\354\376\377\365\372\377\377\365\372\377"
+ "\377\332\354\376\377\261\330\377\377~\275\376\377A\237\377\377\274\335\376"
+ "\377\207\302\377\377\15\205\377\377\11\203\377\377\3\200\377\377\1\177\377"
+ "\377\1\177\377\377\1\177\377\377\1\177\377\377\0}\374\377n\265\376\377\321"
+ "\350\377\377\221\307\377\377\227\312\377\377\244\320\376\377?\236\377\377"
+ "\31\213\377\222\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\27\212\377\"\31\213\377\356"
+ "x\272\376\377\234\314\376\377\231\313\377\377\253\325\377\377\371\374\377"
+ "\3771\227\377\377\1\177\377\377\0}\374\377\0}\374\377\1\177\377\377\5\201"
+ "\377\377\11\203\377\377\15\205\377\377f\261\376\377\351\364\377\377\246\321"
+ "\376\377x\272\376\377Q\247\377\3775\231\377\377!\217\377\377!\217\377\377"
+ "5\231\377\377O\246\377\377t\270\376\377\236\315\376\377\265\332\377\377\371"
+ "\374\377\3775\231\377\377\15\205\377\377\7\202\377\377\1\177\377\377\1\177"
+ "\377\377\1\177\377\377\1\177\377\3771\227\377\377\371\374\377\377\242\317"
+ "\376\377\217\306\377\377\225\311\377\377\201\277\377\377\31\213\377\356\27"
+ "\212\377\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\213\377|\35\215\377"
+ "\377\234\314\376\377\236\315\376\377\234\314\376\377\301\340\377\377\343"
+ "\361\377\377\33\214\377\377\0}\374\377\1\177\377\377\3\200\377\377\7\202"
+ "\377\377\13\204\377\377\37\216\377\377\353\365\377\377\325\352\377\377\301"
+ "\340\377\377\274\335\376\377\274\335\376\377\303\341\377\377\314\345\376"
+ "\377\315\346\377\377\303\341\377\377\272\334\376\377\267\333\377\377\267"
+ "\333\377\377\315\346\377\377\351\364\377\377\215\305\377\377\15\205\377\377"
+ "\11\203\377\377\5\201\377\377\1\177\377\377\1\177\377\377\33\214\377\377"
+ "\345\362\377\377\301\340\377\377\223\310\377\377\223\310\377\377\227\312"
+ "\377\377+\224\377\377\31\213\377|\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\27\217\377\13\31\213\377\310;\234\377\377\242\317\376\377\227\312"
+ "\377\377\225\311\377\377\307\343\377\377\333\355\377\377#\220\377\377\3\200"
+ "\377\377\5\201\377\377\11\203\377\377\15\205\377\377\23\210\377\377U\251"
+ "\377\377\301\340\377\377\373\375\377\377\347\363\377\377\327\353\377\377"
+ "\333\355\377\377\327\353\377\377\332\354\376\377\333\355\377\377\327\353"
+ "\377\377\345\362\377\377\371\374\377\377\300\337\376\377M\245\377\377\11"
+ "\203\377\377\13\204\377\377\15\205\377\377\13\204\377\377\5\201\377\377#"
+ "\220\377\377\333\355\377\377\314\345\376\377\231\313\377\377\227\312\377"
+ "\377\231\313\377\377O\246\377\377\31\213\377\310\27\217\377\13\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\33\214\3771\31\213\377\355"
+ "\\\254\376\377\231\313\377\377\225\311\377\377\223\310\377\377\305\342\377"
+ "\377\355\366\377\377E\241\377\377\7\202\377\377\15\205\377\377\21\207\377"
+ "\377\27\212\377\377\33\214\377\377\33\214\377\377'\222\377\377h\262\376\377"
+ "\244\320\376\377\255\326\377\377\324\351\376\377\324\351\376\377\255\326"
+ "\377\377\244\320\376\377h\262\376\377#\220\377\377\23\210\377\377\21\207"
+ "\377\377\15\205\377\377\13\204\377\377\15\205\377\377\15\205\377\377E\241"
+ "\377\377\355\366\377\377\305\342\377\377\231\313\377\377\231\313\377\377"
+ "\236\315\376\377r\267\376\377\31\213\377\355\33\214\3771\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\213\377Z\31\213"
+ "\377\374r\267\376\377\234\314\376\377\227\312\377\377\234\314\376\377\301"
+ "\340\377\377\375\376\377\377~\275\376\377\17\206\377\377\23\210\377\377\27"
+ "\212\377\377\31\213\377\377\31\213\377\377\27\212\377\377\25\211\377\377"
+ "\31\213\377\377\35\215\377\377!\217\377\377#\220\377\377\35\215\377\377\27"
+ "\212\377\377\23\210\377\377\23\210\377\377\23\210\377\377\23\210\377\377"
+ "\17\206\377\377\13\204\377\377\13\204\377\377~\275\376\377\375\376\377\377"
+ "\303\341\377\377\236\315\376\377\231\313\377\377\236\315\376\377\203\300"
+ "\377\377\31\213\377\374\31\213\377Z\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\213\377q\27\212\377"
+ "\377v\271\376\377\240\316\376\377\242\317\376\377\244\320\376\377\263\331"
+ "\377\377\340\356\376\377\324\351\376\377O\246\377\377\33\214\377\377\33\214"
+ "\377\377\27\212\377\377\27\212\377\377\25\211\377\377\33\214\377\377\35\215"
+ "\377\377!\217\377\377!\217\377\377\37\216\377\377\31\213\377\377\23\210\377"
+ "\377\23\210\377\377\23\210\377\377\23\210\377\377\17\206\377\377G\242\377"
+ "\377\321\350\377\377\335\355\377\377\265\332\377\377\250\322\376\377\252"
+ "\324\376\377\242\317\376\377\205\301\377\377!\217\377\377\31\213\377q\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\213\377q\31\213\377\374l\264\376\377\244"
+ "\320\376\377\253\325\377\377\253\325\377\377\261\330\377\377\317\347\377"
+ "\377\357\367\377\377\315\346\377\377\201\277\377\3773\230\377\377\25\211"
+ "\377\377\27\212\377\377\33\214\377\377\37\216\377\377#\220\377\377!\217\377"
+ "\377\37\216\377\377\33\214\377\377\27\212\377\377\23\210\377\377/\226\377"
+ "\377~\275\376\377\315\346\377\377\353\365\377\377\307\343\377\377\252\324"
+ "\376\377\255\326\377\377\255\326\377\377\253\325\377\377z\273\376\377\31"
+ "\213\377\374\31\213\377q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\31\213\377Z\31\213\377\356M\245\377\377\257\327\377\377\267\333\377\377"
+ "\267\333\377\377\274\335\376\377\300\337\376\377\317\347\377\377\343\361"
+ "\377\377\367\373\377\377\325\352\377\377\244\320\376\377\200\276\376\377"
+ "x\272\376\377U\251\377\377U\251\377\377z\273\376\377\200\276\376\377\242"
+ "\317\376\377\325\352\377\377\367\373\377\377\340\356\376\377\307\343\377"
+ "\377\257\327\377\377\253\325\377\377\252\324\376\377\263\331\377\377\261"
+ "\330\377\377X\252\376\377\31\213\377\356\31\213\377Z\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\213\3774\31\213\377\305-"
+ "\225\377\377\225\311\377\377\300\337\376\377\303\341\377\377\303\341\377"
+ "\377\300\337\376\377\276\336\376\377\267\333\377\377\305\342\377\377\327"
+ "\353\377\377\345\362\377\377\347\363\377\377\363\371\377\377\363\371\377"
+ "\377\351\364\377\377\345\362\377\377\327\353\377\377\305\342\377\377\272"
+ "\334\376\377\272\334\376\377\265\332\377\377\267\333\377\377\263\331\377"
+ "\377\257\327\377\377\225\311\377\3773\230\377\377\31\213\377\305\31\213\377"
+ "4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\25\203\377\14\31\213\377|\31\213\377\354A\237\377\377\242\317\376"
+ "\377\312\344\376\377\303\341\377\377\276\336\376\377\272\334\376\377\272"
+ "\334\376\377\276\336\376\377\303\341\377\377\305\342\377\377\315\346\377"
+ "\377\317\347\377\377\314\345\376\377\303\341\377\377\274\335\376\377\272"
+ "\334\376\377\267\333\377\377\267\333\377\377\276\336\376\377\272\334\376"
+ "\377\242\317\376\377I\243\377\377\31\213\377\354\31\213\377|\25\203\377\14"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\33\221\377&\31\213\377\222\31\213\377\354"
+ "-\225\377\377z\273\376\377\261\330\377\377\303\341\377\377\305\342\377\377"
+ "\303\341\377\377\307\343\377\377\312\344\376\377\321\350\377\377\324\351"
+ "\376\377\317\347\377\377\312\344\376\377\303\341\377\377\301\340\377\377"
+ "\274\335\376\377\257\327\377\377\200\276\376\3777\232\377\377\31\213\377"
+ "\354\31\213\377\222\33\221\377&\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\31\213\377\36\31\213\377s\31\213\377\304\31\213\377"
+ "\365/\226\377\377M\245\377\377r\267\376\377\223\310\377\377\257\327\377\377"
+ "\272\334\376\377\272\334\376\377\261\330\377\377\225\311\377\377v\271\376"
+ "\377S\250\377\3771\227\377\377\31\213\377\365\31\213\377\304\31\213\377s"
+ "\31\213\377\36\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\1\377\1\31\213\377(\31\213\377_"
+ "\31\213\377\222\31\213\377\270\31\213\377\321\31\213\377\343\31\213\377\355"
+ "\31\213\377\355\31\213\377\343\31\213\377\321\31\213\377\270\31\213\377\222"
+ "\31\213\377_\31\213\377(\1\1\377\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0",
+#if 0
+};
+#endif
diff --git a/source/exhumed/rsrc/fury/build_icon.c b/source/exhumed/rsrc/fury/build_icon.c
new file mode 100644
index 000000000..5489801d7
--- /dev/null
+++ b/source/exhumed/rsrc/fury/build_icon.c
@@ -0,0 +1 @@
+#include "../eduke32_icon.c"
diff --git a/source/exhumed/rsrc/fury/buildres.rc b/source/exhumed/rsrc/fury/buildres.rc
new file mode 100644
index 000000000..e558eef17
--- /dev/null
+++ b/source/exhumed/rsrc/fury/buildres.rc
@@ -0,0 +1,72 @@
+#define NEED_COMMCTRL_H
+#include "windows_inc.h"
+#include "startwin.editor.h"
+
+RSRC_ICON ICON "../build_icon.ico"
+RSRC_BMP BITMAP "../build.bmp"
+
+WIN_STARTWIN DIALOGEX DISCARDABLE 20, 40, 260, 200
+STYLE DS_MODALFRAME | DS_CENTER | DS_SETFONT | DS_FIXEDSYS | WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU
+CAPTION "Startup"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "", WIN_STARTWIN_BITMAP, "STATIC", SS_BITMAP | SS_CENTERIMAGE | WS_CHILD | WS_VISIBLE, 0, 0, 66, 172
+ CONTROL "", WIN_STARTWIN_TABCTL, WC_TABCONTROL, WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 5, 5, 250, 170
+ CONTROL "&Start", WIN_STARTWIN_START, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 154, 180, 48, 14
+ CONTROL "&Cancel", WIN_STARTWIN_CANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 207, 180, 48, 14
+
+ CONTROL "", WIN_STARTWIN_MESSAGES, "EDIT", ES_MULTILINE | ES_READONLY | WS_CHILD | WS_VSCROLL, 0, 0, 32, 32
+END
+
+WIN_STARTWINPAGE_CONFIG DIALOGEX DISCARDABLE 20, 40, 279, 168
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "&2D Video mode:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 8, 50, 8
+ CONTROL "", IDC2DVMODE, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 6, 80, 56
+ CONTROL "&Fullscreen", IDCFULLSCREEN, "BUTTON", BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 148, 8, 49, 10
+ CONTROL "&3D Video mode:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 24, 50, 8
+ CONTROL "", IDC3DVMODE, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 22, 80, 56
+ CONTROL "&Always show this window at startup", IDCALWAYSSHOW, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 118, 116, 140, 8
+END
+
+#define FILEVER 1,9,9,9
+#define PRODUCTVER 1,9,9,9
+#define STRFILEVER "2.0.0devel\0"
+#define STRPRODUCTVER "2.0.0devel\0"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION FILEVER
+ PRODUCTVERSION PRODUCTVER
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x3L
+#else
+ FILEFLAGS 0x2L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "Mapster32 for EDuke32"
+ VALUE "FileVersion", STRFILEVER
+ VALUE "InternalName", "Mapster32"
+ VALUE "LegalCopyright", "Copyright © 2015 EDuke32 Developers, 1996, 2003 3D Realms Entertainment"
+ VALUE "LegalTrademarks", "Duke Nukem® is a Registered Trademark of Gearbox Software, LLC."
+ VALUE "OriginalFilename", "mapster32.exe"
+ VALUE "ProductName", "Mapster32"
+ VALUE "ProductVersion", STRPRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+1 24 "../manifest.build.xml"
diff --git a/source/exhumed/rsrc/fury/game_icon.c b/source/exhumed/rsrc/fury/game_icon.c
new file mode 100644
index 000000000..5489801d7
--- /dev/null
+++ b/source/exhumed/rsrc/fury/game_icon.c
@@ -0,0 +1 @@
+#include "../eduke32_icon.c"
diff --git a/source/exhumed/rsrc/fury/game_icon.ico b/source/exhumed/rsrc/fury/game_icon.ico
new file mode 100644
index 000000000..10c504f1a
Binary files /dev/null and b/source/exhumed/rsrc/fury/game_icon.ico differ
diff --git a/source/exhumed/rsrc/fury/gameres.rc b/source/exhumed/rsrc/fury/gameres.rc
new file mode 100644
index 000000000..5c9cf2635
--- /dev/null
+++ b/source/exhumed/rsrc/fury/gameres.rc
@@ -0,0 +1,66 @@
+#define NEED_COMMCTRL_H
+#include "windows_inc.h"
+#include "startwin.game.h"
+
+RSRC_ICON ICON "game_icon.ico"
+
+WIN_STARTWIN DIALOGEX DISCARDABLE 20, 40, 215, 60
+STYLE DS_MODALFRAME | DS_CENTER | DS_SETFONT | DS_FIXEDSYS | WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU
+CAPTION "Startup"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "", WIN_STARTWIN_BITMAP, "STATIC", SS_BITMAP | SS_CENTERIMAGE | WS_CHILD | WS_VISIBLE, 0, 0, 0, 62
+ CONTROL "", WIN_STARTWIN_TABCTL, WC_TABCONTROL, WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 5, 5, 205, 35
+ CONTROL "&Start", WIN_STARTWIN_START, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 111, 43, 48, 14
+ CONTROL "&Cancel", WIN_STARTWIN_CANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 164, 43, 48, 14
+
+ CONTROL "", WIN_STARTWIN_MESSAGES, "EDIT", ES_MULTILINE | ES_READONLY | WS_CHILD | WS_VSCROLL, 0, 0, 32, 32
+END
+WIN_STARTWINPAGE_CONFIG DIALOGEX DISCARDABLE 20, 40, 229, 58
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "&Video mode:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 6, 50, 8
+ CONTROL "", IDCVMODE, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 4, 86, 56
+ CONTROL "&Fullscreen", IDCFULLSCREEN, "BUTTON", BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 154, 6, 46, 10
+END
+
+#define FILEVER 0,0,0,0
+#define PRODUCTVER 0,0,0,0
+#define STRFILEVER ""
+#define STRPRODUCTVER ""
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION FILEVER
+ PRODUCTVERSION PRODUCTVER
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x3L
+#else
+ FILEFLAGS 0x2L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "Ion Fury"
+ VALUE "FileVersion", STRFILEVER
+ VALUE "InternalName", "Ion Fury"
+ VALUE "LegalCopyright", "© 2019 Voidpoint, LLC and EDuke32 developers"
+ VALUE "OriginalFilename", "fury.exe"
+ VALUE "ProductName", "Ion Fury"
+ VALUE "ProductVersion", STRPRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+1 24 "manifest.game.xml"
diff --git a/source/exhumed/rsrc/fury/manifest.game.xml b/source/exhumed/rsrc/fury/manifest.game.xml
new file mode 100644
index 000000000..58ecaf270
--- /dev/null
+++ b/source/exhumed/rsrc/fury/manifest.game.xml
@@ -0,0 +1,42 @@
+
+
+
+
+ true
+ PerMonitorV2
+
+
+
+ Ion Fury
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/exhumed/rsrc/game.bmp b/source/exhumed/rsrc/game.bmp
new file mode 100644
index 000000000..86433a119
Binary files /dev/null and b/source/exhumed/rsrc/game.bmp differ
diff --git a/source/exhumed/rsrc/game_icon.c b/source/exhumed/rsrc/game_icon.c
new file mode 100644
index 000000000..a9b6fe43b
--- /dev/null
+++ b/source/exhumed/rsrc/game_icon.c
@@ -0,0 +1 @@
+#include "eduke32_icon.c"
diff --git a/source/exhumed/rsrc/game_icon.ico b/source/exhumed/rsrc/game_icon.ico
new file mode 100644
index 000000000..0bfa7fb2c
Binary files /dev/null and b/source/exhumed/rsrc/game_icon.ico differ
diff --git a/source/exhumed/rsrc/gameres.rc b/source/exhumed/rsrc/gameres.rc
new file mode 100644
index 000000000..421fe8402
--- /dev/null
+++ b/source/exhumed/rsrc/gameres.rc
@@ -0,0 +1,80 @@
+#define NEED_COMMCTRL_H
+#include "../../build/include/windows_inc.h"
+#include "../src/startwin.game.h"
+
+RSRC_ICON ICON "game_icon.ico"
+RSRC_BMP BITMAP "game.bmp"
+
+WIN_STARTWIN DIALOGEX DISCARDABLE 20, 40, 260, 200
+STYLE DS_MODALFRAME | DS_CENTER | DS_SETFONT | DS_FIXEDSYS | WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU
+CAPTION "Startup"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "", WIN_STARTWIN_BITMAP, "STATIC", SS_BITMAP | SS_CENTERIMAGE | WS_CHILD | WS_VISIBLE, 0, 0, 66, 172
+ CONTROL "", WIN_STARTWIN_TABCTL, WC_TABCONTROL, WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 5, 5, 250, 170
+ CONTROL "&Start", WIN_STARTWIN_START, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 154, 180, 48, 14
+ CONTROL "&Cancel", WIN_STARTWIN_CANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 207, 180, 48, 14
+
+ CONTROL "", WIN_STARTWIN_MESSAGES, "EDIT", ES_MULTILINE | ES_READONLY | WS_CHILD | WS_VSCROLL, 0, 0, 32, 32
+END
+WIN_STARTWINPAGE_CONFIG DIALOGEX DISCARDABLE 20, 40, 279, 168
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "&Video mode:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 6, 50, 8
+ CONTROL "", IDCVMODE, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 4, 86, 56
+ CONTROL "&Fullscreen", IDCFULLSCREEN, "BUTTON", BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 154, 6, 46, 10
+#if defined POLYMER && POLYMER != 0
+ CONTROL "&Polymer", IDCPOLYMER, "BUTTON", BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 203, 6, 40, 10
+#endif
+ CONTROL "Input devices:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 20, 50, 8
+ CONTROL "", IDCINPUT, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 19, 86, 56
+ CONTROL "&Game:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 35, 100, 8
+ CONTROL "", IDCDATA, "LISTBOX", LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS | LBS_STANDARD | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 10, 45, 226, 43
+
+ CONTROL "Custom game content &directory:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 90, 160, 8
+ CONTROL "", IDCGAMEDIR, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 10, 99, 226, 156
+ CONTROL "&Enable ""autoload"" folder", IDCAUTOLOAD, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 5, 116, 100, 8
+ CONTROL "&Always show this window at startup", IDCALWAYSSHOW, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 118, 116, 140, 8
+END
+
+#define FILEVER 1,9,9,9
+#define PRODUCTVER 1,9,9,9
+#define STRFILEVER "2.0.0devel\0"
+#define STRPRODUCTVER "2.0.0devel\0"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION FILEVER
+ PRODUCTVERSION PRODUCTVER
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x3L
+#else
+ FILEFLAGS 0x2L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "EDuke32"
+ VALUE "FileVersion", STRFILEVER
+ VALUE "InternalName", "EDuke32"
+ VALUE "LegalCopyright", "Copyright © 2018 EDuke32 Developers, 1996, 2003 3D Realms Entertainment"
+ VALUE "LegalTrademarks", "Duke Nukem® is a Registered Trademark of Gearbox Software, LLC."
+ VALUE "OriginalFilename", "eduke32.exe"
+ VALUE "ProductName", "EDuke32"
+ VALUE "ProductVersion", STRPRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+1 24 "manifest.game.xml"
diff --git a/source/exhumed/rsrc/manifest.build.xml b/source/exhumed/rsrc/manifest.build.xml
new file mode 100644
index 000000000..9abe41969
--- /dev/null
+++ b/source/exhumed/rsrc/manifest.build.xml
@@ -0,0 +1,42 @@
+
+
+
+
+ true
+ PerMonitorV2
+
+
+
+ Mapster32 for EDuke32
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/exhumed/rsrc/manifest.game.xml b/source/exhumed/rsrc/manifest.game.xml
new file mode 100644
index 000000000..d11aa9bf6
--- /dev/null
+++ b/source/exhumed/rsrc/manifest.game.xml
@@ -0,0 +1,42 @@
+
+
+
+
+ true
+ PerMonitorV2
+
+
+
+ EDuke32
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/exhumed/rsrc/source/EDuke32_logo_21_large.psd b/source/exhumed/rsrc/source/EDuke32_logo_21_large.psd
new file mode 100644
index 000000000..5aeecef60
Binary files /dev/null and b/source/exhumed/rsrc/source/EDuke32_logo_21_large.psd differ
diff --git a/source/exhumed/rsrc/source/EDuke32_logo_21_large_blue.psd b/source/exhumed/rsrc/source/EDuke32_logo_21_large_blue.psd
new file mode 100644
index 000000000..ff32e9335
Binary files /dev/null and b/source/exhumed/rsrc/source/EDuke32_logo_21_large_blue.psd differ
diff --git a/source/exhumed/rsrc/source/EDuke32_logo_21_large_opaque.psd b/source/exhumed/rsrc/source/EDuke32_logo_21_large_opaque.psd
new file mode 100644
index 000000000..be7b6cbc1
Binary files /dev/null and b/source/exhumed/rsrc/source/EDuke32_logo_21_large_opaque.psd differ
diff --git a/source/exhumed/rsrc/source/game2.psd b/source/exhumed/rsrc/source/game2.psd
new file mode 100644
index 000000000..3b7c1fbf2
Binary files /dev/null and b/source/exhumed/rsrc/source/game2.psd differ
diff --git a/source/exhumed/rsrc/source/game3.psd b/source/exhumed/rsrc/source/game3.psd
new file mode 100644
index 000000000..dc6eaefe9
Binary files /dev/null and b/source/exhumed/rsrc/source/game3.psd differ
diff --git a/source/exhumed/rsrc/source/wii-hbc-icon.xcf b/source/exhumed/rsrc/source/wii-hbc-icon.xcf
new file mode 100644
index 000000000..7dc3df63b
Binary files /dev/null and b/source/exhumed/rsrc/source/wii-hbc-icon.xcf differ
diff --git a/source/exhumed/src/aistuff.cpp b/source/exhumed/src/aistuff.cpp
new file mode 100644
index 000000000..8b9aff0dc
--- /dev/null
+++ b/source/exhumed/src/aistuff.cpp
@@ -0,0 +1,49 @@
+
+#include "aistuff.h"
+extern int localclock;
+
+int TimeSlot[KMaxTimeSlots];
+
+
+void InitTimeSlot()
+{
+ for (int i = 0; i < KMaxTimeSlots; i++) {
+ TimeSlot[i] = 0;
+ }
+}
+
+int GrabTimeSlot(int nVal)
+{
+ return -1;
+
+ // BJD - below code found in an early Powerslave release. Doesn't seem to do anything and is missing in later releases.
+#if 0
+ int ebx = -1;
+ int esi;
+
+ for (int i = 0; i < nVal; i++)
+ {
+ int nSlot = (localclock + i) & 0xF;
+
+ if (ebx >= 0)
+ {
+ if (esi <= TimeSlot[nSlot]) {
+ continue;
+ }
+ }
+
+ esi = TimeSlot[nSlot];
+ ebx = i;
+ }
+
+ esi = localclock;
+
+ int edx = ebx;
+
+ while (edx < 16)
+ {
+ TimeSlot[(edx + esi) & 0xF]++;
+ edx += nVal;
+ }
+#endif
+}
diff --git a/source/exhumed/src/aistuff.h b/source/exhumed/src/aistuff.h
new file mode 100644
index 000000000..7446a29c7
--- /dev/null
+++ b/source/exhumed/src/aistuff.h
@@ -0,0 +1,29 @@
+
+#ifndef __aistuff_h__
+#define __aistuff_h__
+
+#include "anubis.h"
+#include "bubbles.h"
+#include "mummy.h"
+#include "rex.h"
+#include "roach.h"
+#include "scorp.h"
+#include "spider.h"
+#include "lion.h"
+#include "set.h"
+#include "queen.h"
+#include "wasp.h"
+#include "rat.h"
+#include "gun.h"
+#include "grenade.h"
+#include "snake.h"
+#include "fish.h"
+#include "lavadude.h"
+#include "bullet.h"
+
+#define KMaxTimeSlots 16
+
+void InitTimeSlot();
+int GrabTimeSlot(int nVal);
+
+#endif
diff --git a/source/exhumed/src/anims.cpp b/source/exhumed/src/anims.cpp
new file mode 100644
index 000000000..49b9dfead
--- /dev/null
+++ b/source/exhumed/src/anims.cpp
@@ -0,0 +1,328 @@
+
+#include "engine.h"
+#include "anims.h"
+#include "sequence.h"
+#include "runlist.h"
+#include "exhumed.h"
+#include "sound.h"
+#include "random.h"
+#include "init.h"
+#include
+
+#define kMaxAnims 400
+
+short nMagicSeq = -1;
+short nPreMagicSeq = -1;
+short nSavePointSeq = -1;
+short nAnimsFree = 0;
+
+short AnimRunRec[kMaxAnims];
+short AnimsFree[kMaxAnims];
+Anim AnimList[kMaxAnims];
+uchar AnimFlags[kMaxAnims];
+
+
+void InitAnims()
+{
+ for (int i = 0; i < kMaxAnims; i++) {
+ AnimsFree[i] = i;
+ }
+
+ nAnimsFree = kMaxAnims;
+
+ nMagicSeq = SeqOffsets[kSeqItems] + 21;
+ nPreMagicSeq = SeqOffsets[kSeqMagic2];
+ nSavePointSeq = SeqOffsets[kSeqItems] + 12;
+}
+
+void DestroyAnim(int nAnim)
+{
+// if (nAnim == 386) {
+ if (nAnim == 365) {
+ int gasd = 123;
+ }
+
+ short nSprite = AnimList[nAnim].nSprite;
+
+ if (nSprite >= 0)
+ {
+ StopSpriteSound(nSprite);
+ runlist_SubRunRec(AnimRunRec[nAnim]);
+ runlist_DoSubRunRec(sprite[nSprite].extra);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+ }
+
+ AnimsFree[nAnimsFree] = nAnim;
+ nAnimsFree++;
+}
+
+int BuildAnim(int nSprite, int val, int val2, int x, int y, int z, int nSector, int nRepeat, int nFlag)
+{
+ if (!nAnimsFree)
+ return -1;
+
+ if (nSector >= kMaxSectors) {
+ int asdffdg = 123;
+ }
+
+ nAnimsFree--;
+
+ short nAnim = AnimsFree[nAnimsFree];
+
+ // if (nAnim == 386) {
+ if (nAnim == 365) {
+ int blag = 123;
+ }
+
+ if (nSprite == -1) {
+ nSprite = insertsprite(nSector, 500);
+// assert(nSprite != -1);
+ }
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ sprite[nSprite].cstat = 0;
+
+ if (nFlag & 4)
+ {
+ sprite[nSprite].pal = 4;
+ sprite[nSprite].shade = -64;
+ }
+ else
+ {
+ sprite[nSprite].pal = 0;
+ sprite[nSprite].shade = -12;
+ }
+
+ sprite[nSprite].clipdist = 10;
+ sprite[nSprite].xrepeat = nRepeat;
+ sprite[nSprite].yrepeat = nRepeat;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].ang = 0;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+
+ // CHECKME - where is hitag set otherwise?
+ if (sprite[nSprite].statnum < 900) {
+ sprite[nSprite].hitag = -1;
+ }
+
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].owner = -1;
+ sprite[nSprite].extra = runlist_AddRunRec(sprite[nSprite].lotag - 1, nAnim | 0x100000);
+
+ AnimRunRec[nAnim] = runlist_AddRunRec(NewRun, nAnim | 0x100000);
+ AnimList[nAnim].nSprite = nSprite;
+ AnimFlags[nAnim] = nFlag;
+ AnimList[nAnim].field_2 = 0;
+ AnimList[nAnim].nSeq = SeqOffsets[val] + val2;
+ AnimList[nAnim].field_4 = 256;
+
+ if (nFlag & 0x80) {
+ sprite[nSprite].cstat |= 0x2; // set transluscence
+ }
+
+ return nAnim;
+}
+
+short GetAnimSprite(short nAnim)
+{
+ return AnimList[nAnim].nSprite;
+}
+
+void FuncAnim(int a, int, int nRun)
+{
+ short nAnim = RunData[nRun].nVal;
+ assert(nAnim >= 0 && nAnim < kMaxAnims);
+
+ short nSprite = AnimList[nAnim].nSprite;
+ short nSeq = AnimList[nAnim].nSeq;
+
+ assert(nSprite != -1);
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x20000:
+ {
+ short var_1C = AnimList[nAnim].field_2;
+
+ if (!(sprite[nSprite].cstat & 0x8000))
+ {
+ seq_MoveSequence(nSprite, nSeq, var_1C);
+ }
+
+ if (sprite[nSprite].statnum == kStatIgnited)
+ {
+ short nHitag = sprite[nSprite].hitag;
+ if (nHitag > -1)
+ {
+ sprite[nSprite].x = sprite[nHitag].x;
+ sprite[nSprite].y = sprite[nHitag].y;
+ sprite[nSprite].z = sprite[nHitag].z;
+
+ if (sprite[nHitag].sectnum != sprite[nSprite].sectnum)
+ {
+ if (sprite[nHitag].sectnum < 0 || sprite[nHitag].sectnum >= kMaxSectors)
+ {
+ DestroyAnim(nAnim);
+ mydeletesprite(nSprite);
+ return;
+ }
+ else
+ {
+ mychangespritesect(nSprite, sprite[nHitag].sectnum);
+ }
+ }
+
+ if (!var_1C)
+ {
+ if (sprite[nHitag].cstat != 0x8000)
+ {
+ short hitag2 = sprite[nHitag].hitag;
+ sprite[nHitag].hitag--;
+
+ if (hitag2 >= 15)
+ {
+ runlist_DamageEnemy(nHitag, -1, (sprite[nHitag].hitag - 14) * 2);
+ if (sprite[nHitag].shade < 100)
+ {
+ sprite[nHitag].pal = 0;
+ sprite[nHitag].shade++;
+ }
+
+ if (!(sprite[nHitag].cstat & 101))
+ {
+ DestroyAnim(nAnim);
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ goto loc_2D755;
+ }
+ }
+
+ sprite[nHitag].hitag = 1;
+ DestroyAnim(nAnim);
+ mydeletesprite(nSprite);
+ }
+ }
+ }
+
+ // loc_2D755
+loc_2D755:
+
+ AnimList[nAnim].field_2++;
+ if (AnimList[nAnim].field_2 >= SeqSize[nSeq])
+ {
+ if (AnimFlags[nAnim] & 0x10)
+ {
+ AnimList[nAnim].field_2 = 0;
+ }
+ else if (nSeq == nPreMagicSeq)
+ {
+ AnimList[nAnim].field_2 = 0;
+ AnimList[nAnim].nSeq = nMagicSeq;
+ short nAnimSprite = AnimList[nAnim].nSprite;
+ AnimFlags[nAnim] |= 0x10;
+ sprite[nAnimSprite].cstat |= 2;
+ }
+ else if (nSeq == nSavePointSeq)
+ {
+ AnimList[nAnim].field_2 = 0;
+ AnimList[nAnim].nSeq++;
+ AnimFlags[nAnim] |= 0x10;
+ }
+ else
+ {
+ DestroyAnim(nAnim);
+ mydeletesprite(nSprite);
+ }
+ return;
+ }
+
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, nSeq, AnimList[nAnim].field_2, 0x101);
+ tsprite[a & 0xFFFF].owner = -1;
+ return;
+ }
+
+ case 0xA0000:
+ {
+ return;
+ }
+
+ default:
+ {
+ DebugOut("unknown msg %x for anim\n", a & 0x7F0000);
+ return;
+ }
+ }
+}
+
+void BuildExplosion(short nSprite)
+{
+ short nSector = sprite[nSprite].sectnum;
+
+ int edx = 36;
+
+ if (SectFlag[nSector] & kSectUnderwater)
+ {
+ edx = 75;
+ }
+ else if (sprite[nSprite].z == sector[nSector].floorz)
+ {
+ edx = 34;
+ }
+
+ BuildAnim(-1, edx, 0, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum, sprite[nSprite].xrepeat, 4);
+}
+
+int BuildSplash(int nSprite, int nSector)
+{
+ int nRepeat, nSound;
+
+ if (sprite[nSprite].statnum != 200)
+ {
+ nRepeat = sprite[nSprite].xrepeat + (RandomWord() % sprite[nSprite].xrepeat);
+ nSound = kSound0;
+ }
+ else
+ {
+ nRepeat = 20;
+ nSound = kSound1;
+ }
+
+ int bIsLava = SectFlag[nSector] & kSectLava;
+
+ int edx, nFlag;
+
+ if (bIsLava)
+ {
+ edx = 43;
+ nFlag = 4;
+ }
+ else
+ {
+ edx = 35;
+ nFlag = 0;
+ }
+
+ int nAnim = BuildAnim(-1, edx, 0, sprite[nSprite].x, sprite[nSprite].y, sector[nSector].floorz, nSector, nRepeat, nFlag);
+
+ if (!bIsLava)
+ {
+ D3PlayFX(StaticSound[nSound] | 10, AnimList[nAnim].nSprite);
+ }
+
+ return AnimList[nAnim].nSprite;
+}
diff --git a/source/exhumed/src/anims.h b/source/exhumed/src/anims.h
new file mode 100644
index 000000000..646519630
--- /dev/null
+++ b/source/exhumed/src/anims.h
@@ -0,0 +1,27 @@
+
+#ifndef __anims_h__
+#define __anims_h__
+
+#include "typedefs.h"
+
+struct Anim
+{
+ short nSeq;
+ short field_2;
+ short field_4;
+ short nSprite;
+};
+
+extern Anim AnimList[];
+extern uchar AnimFlags[];
+
+void InitAnims();
+void DestroyAnim(int nAnim);
+int BuildAnim(int nSprite, int val, int val2, int x, int y, int z, int nSector, int nRepeat, int nFlag);
+short GetAnimSprite(short nAnim);
+
+void FuncAnim(int, int, int);
+void BuildExplosion(short nSprite);
+int BuildSplash(int nSprite, int nSector);
+
+#endif
diff --git a/source/exhumed/src/anubis.cpp b/source/exhumed/src/anubis.cpp
new file mode 100644
index 000000000..9b80c3cb3
--- /dev/null
+++ b/source/exhumed/src/anubis.cpp
@@ -0,0 +1,471 @@
+
+#include "exhumed.h"
+#include "anubis.h"
+#include "engine.h"
+#include "runlist.h"
+#include "sequence.h"
+#include "move.h"
+#include "bullet.h"
+#include "random.h"
+#include "items.h"
+#include "object.h"
+#include "sound.h"
+#include "trigdat.h"
+#include
+
+#define kMaxAnubis 80
+
+struct Anubis
+{
+ short nHealth;
+ short nFrame;
+ short nAction;
+ short nSprite;
+ short nTarget;
+ short f;
+ short g;
+ short h;
+};
+
+Anubis AnubisList[kMaxAnubis];
+
+short AnubisSprite = -1;
+short AnubisCount = -1;
+
+static actionSeq ActionSeq[] = {
+ { 0, 0 },
+ { 8, 0 },
+ { 16, 0 },
+ { 24, 0 },
+ { 32, 0 },
+ { -1, 0 },
+ { 46, 1 },
+ { 46, 1 },
+ { 47, 1 },
+ { 49, 1 },
+ { 49, 1 },
+ { 40, 1 },
+ { 42, 1 },
+ { 41, 1 },
+ { 43, 1 },
+};
+
+short nAnubisDrum = 0;
+
+
+void InitAnubis()
+{
+ AnubisCount = kMaxAnubis;
+ AnubisSprite = 1;
+ nAnubisDrum = 1;
+}
+
+int BuildAnubis(int nSprite, int x, int y, int z, int nSector, int nAngle, BOOL bIsDrummer)
+{
+ AnubisCount--;
+ short nAnubis = AnubisCount;
+
+ if (nAnubis < 0) {
+ return -1;
+ }
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(nSector, 101);
+ }
+ else
+ {
+ changespritestat(nSprite, 101);
+
+ x = sprite[nSprite].x;
+ y = sprite[nSprite].y;
+ z = sector[sprite[nSprite].sectnum].floorz;
+ nAngle = sprite[nSprite].ang;
+ }
+
+ assert(nSprite >=0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ sprite[nSprite].clipdist = 60;
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].xrepeat = 40;
+ sprite[nSprite].yrepeat = 40;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].extra = -1;
+
+// GrabTimeSlot(3);
+
+ if (bIsDrummer)
+ {
+ AnubisList[nAnubis].nAction = nAnubisDrum + 6;
+ nAnubisDrum++;
+
+ if (nAnubisDrum >= 5) {
+ nAnubisDrum = 0;
+ }
+ }
+ else
+ {
+ AnubisList[nAnubis].nAction = 0;
+ }
+
+ AnubisList[nAnubis].nHealth = 540;
+ AnubisList[nAnubis].nFrame = 0;
+ AnubisList[nAnubis].nSprite = nSprite;
+ AnubisList[nAnubis].nTarget = -1;
+ AnubisList[nAnubis].g = 0;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nAnubis | 0x90000);
+
+ runlist_AddRunRec(NewRun, nAnubis | 0x90000);
+ nCreaturesLeft++;
+
+ return nAnubis | 0x90000;
+}
+
+void FuncAnubis(int a, int nDamage, int nRun)
+{
+ short nAnubis = RunData[nRun].nVal;
+ int var_14 = 0;
+
+ assert(nAnubis >= 0 && nAnubis < kMaxAnubis);
+
+ short nSprite = AnubisList[nAnubis].nSprite;
+ short nAction = AnubisList[nAnubis].nAction;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x20000:
+ {
+ if (nAction < 11) {
+ Gravity(nSprite);
+ }
+
+ short nSeq = SeqOffsets[kSeqAnubis] + ActionSeq[nAction].a;
+
+ seq_MoveSequence(nSprite, nSeq, AnubisList[nAnubis].nFrame);
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, AnubisList[nAnubis].nFrame);
+
+ AnubisList[nAnubis].nFrame++;
+ if (AnubisList[nAnubis].nFrame >= SeqSize[nSeq])
+ {
+ AnubisList[nAnubis].nFrame = 0;
+ var_14 = 1;
+ }
+
+ short nTarget = AnubisList[nAnubis].nTarget;
+
+ short nFrame = SeqBase[nSeq] + AnubisList[nAnubis].nFrame;
+ short nFlag = FrameFlag[nFrame];
+
+ int c;
+
+ if (nAction > 0 && nAction < 11) {
+ c = MoveCreatureWithCaution(nSprite);
+ }
+
+ switch (nAction)
+ {
+ case 0:
+ {
+ if ((nAnubis & 0x1F) == (totalmoves & 0x1F))
+ {
+ if (nTarget < 0) {
+ nTarget = FindPlayer(nSprite, 100);
+ }
+
+ if (nTarget >= 0)
+ {
+ D3PlayFX(StaticSound[kSound8], nSprite);
+ AnubisList[nAnubis].nAction = 1;
+ AnubisList[nAnubis].nFrame = 0;
+ AnubisList[nAnubis].nTarget = nTarget;
+
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
+ }
+ }
+ return;
+ }
+ case 1:
+ {
+ if ((nAnubis & 0x1F) == (totalmoves & 0x1F))
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+
+ sprite[nSprite].xvel = Sin((sprite[nSprite].ang & 0xFFF8) + 512) >> 2;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang & 0xFFF8) >> 2;
+ }
+
+ switch (c & 0xC000)
+ {
+ case 0xC000:
+ {
+ if ((c & 0x3FFF) == nTarget)
+ {
+ int nAng = getangle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+ int nAngDiff = AngleDiff(sprite[nSprite].ang, nAng);
+
+ if (nAngDiff < 64)
+ {
+ AnubisList[nAnubis].nAction = 2;
+ AnubisList[nAnubis].nFrame = 0;
+ }
+ break; // only break if condition met
+ }
+ // else we fall through to 0x8000
+ }
+ case 0x8000:
+ {
+ sprite[nSprite].ang += 256;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
+ break;
+ }
+
+ default:
+ {
+ if (AnubisList[nAnubis].g)
+ {
+ AnubisList[nAnubis].g--;
+ }
+ else
+ {
+ AnubisList[nAnubis].g = 60;
+
+ if (cansee(sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z - GetSpriteHeight(nSprite), sprite[nSprite].sectnum,
+ sprite[nTarget].x, sprite[nTarget].y, sprite[nTarget].z - GetSpriteHeight(nTarget), sprite[nTarget].sectnum))
+ {
+ AnubisList[nAnubis].nAction = 3;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].ang = GetMyAngle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+ AnubisList[nAnubis].nFrame = 0;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 2:
+ {
+ if (nTarget == -1)
+ {
+ AnubisList[nAnubis].nAction = 0;
+ AnubisList[nAnubis].g = 50;
+ }
+ else
+ {
+ if (PlotCourseToSprite(nSprite, nTarget) >= 768)
+ {
+ AnubisList[nAnubis].nAction = 1;
+ }
+ else
+ {
+ if (nFlag & 0x80)
+ {
+ runlist_DamageEnemy(nTarget, nSprite, 7);
+ }
+ }
+ }
+
+ break;
+ }
+ case 3:
+ {
+ if (var_14)
+ {
+ AnubisList[nAnubis].nAction = 1;
+
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
+ AnubisList[nAnubis].nFrame = 0;
+ }
+ else
+ {
+ // loc_25718:
+ if (nFlag & 0x80)
+ {
+ BuildBullet(nSprite, 8, 0, 0, -1, sprite[nSprite].ang, nTarget + 10000, 1);
+ }
+ }
+
+ return;
+ }
+ case 4:
+ case 5:
+ {
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+
+ if (var_14)
+ {
+ AnubisList[nAnubis].nAction = 1;
+ AnubisList[nAnubis].nFrame = 0;
+ }
+ return;
+ }
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ {
+ if (var_14)
+ {
+ AnubisList[nAnubis].nAction = (RandomSize(3) % 5) + 6;
+ AnubisList[nAnubis].nFrame = 0;
+ }
+ return;
+ }
+ case 11:
+ case 12:
+ {
+ if (var_14)
+ {
+ AnubisList[nAnubis].nAction = nAction + 2;
+ AnubisList[nAnubis].nFrame = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+ return;
+ }
+ case 13:
+ case 14:
+ {
+ sprite[nSprite].cstat &= 0xFEFE;
+ return;
+ }
+
+ default:
+ return;
+ }
+
+ // loc_2564C:
+ if (nAction && nTarget != -1)
+ {
+ if (!(sprite[nTarget].cstat & 0x101))
+ {
+ AnubisList[nAnubis].nAction = 0;
+ AnubisList[nAnubis].nFrame = 0;
+ AnubisList[nAnubis].g = 100;
+ AnubisList[nAnubis].nTarget = -1;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+ }
+
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, SeqOffsets[kSeqAnubis] + ActionSeq[nAction].a, AnubisList[nAnubis].nFrame, ActionSeq[nAction].b);
+ break;
+ }
+
+ case 0xA0000: // fall through to next case
+ {
+ if (nAction >= 11) {
+ return;
+ }
+
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ }
+ case 0x80000:
+ {
+ if (nDamage)
+ {
+ if (AnubisList[nAnubis].nHealth <= 0)
+ return;
+
+ AnubisList[nAnubis].nHealth -= nDamage;
+
+ if (AnubisList[nAnubis].nHealth > 0)
+ {
+ short nTarget = a & 0xFFFF;
+
+ // loc_258D6:
+ if (nTarget < 0) {
+ return;
+ }
+
+ if (sprite[nTarget].statnum == 100 || sprite[nTarget].statnum < 199)
+ {
+ if (!RandomSize(5)) {
+ AnubisList[nAnubis].nTarget = nTarget;
+ }
+ }
+
+ if (RandomSize(1))
+ {
+ if (nAction >= 6 && nAction <= 10)
+ {
+ int nThisSprite = insertsprite(sprite[nSprite].sectnum, 98);
+
+ sprite[nThisSprite].x = sprite[nSprite].x;
+ sprite[nThisSprite].y = sprite[nSprite].y;
+ sprite[nThisSprite].z = sector[sprite[nThisSprite].sectnum].floorz;
+ sprite[nThisSprite].yrepeat = 40;
+ sprite[nThisSprite].xrepeat = 40;
+ sprite[nThisSprite].shade = -64;
+
+ BuildObject(nThisSprite, 2, 0);
+ }
+
+ AnubisList[nAnubis].nAction = 4;
+ AnubisList[nAnubis].nFrame = 0;
+ }
+ else
+ {
+ // loc_259B5:
+ D3PlayFX(StaticSound[kSound39], nSprite);
+ }
+ }
+ else
+ {
+ // he ded.
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].z = sector[sprite[nSprite].sectnum].floorz;
+ sprite[nSprite].cstat &= 0xFEFE;
+
+ AnubisList[nAnubis].nHealth = 0;
+
+ nCreaturesLeft--;
+
+ if (nAction < 11)
+ {
+ DropMagic(nSprite);
+ AnubisList[nAnubis].nAction = (nMessage == 0xA0000) + 11;
+ AnubisList[nAnubis].nFrame = 0;
+ }
+ }
+ }
+
+ return;
+ }
+ default:
+ {
+ DebugOut("unknown msg %d for Anubis\n", a & 0x7F0000);
+ return;
+ }
+ }
+}
diff --git a/source/exhumed/src/anubis.h b/source/exhumed/src/anubis.h
new file mode 100644
index 000000000..2324cb4d6
--- /dev/null
+++ b/source/exhumed/src/anubis.h
@@ -0,0 +1,12 @@
+
+#ifndef __anubis_h__
+#define __anubis_h__
+
+#include "typedefs.h"
+
+void InitAnubis();
+int BuildAnubis(int nSprite, int x, int y, int z, int nSector, int nAngle, BOOL bIsDrummer);
+
+void FuncAnubis(int a, int b, int c);
+
+#endif
diff --git a/source/exhumed/src/bubbles.cpp b/source/exhumed/src/bubbles.cpp
new file mode 100644
index 000000000..adebf99fd
--- /dev/null
+++ b/source/exhumed/src/bubbles.cpp
@@ -0,0 +1,223 @@
+
+#include "bubbles.h"
+#include "runlist.h"
+#include "exhumed.h"
+#include "random.h"
+#include "engine.h"
+#include "sequence.h"
+#include "move.h"
+#include "init.h"
+#include "runlist.h"
+#include "init.h"
+#include "anims.h"
+#include
+
+#define kMaxBubbles 200
+#define kMaxMachines 125
+
+struct Bubble
+{
+ short _0;
+ short _2;
+ short nSprite;
+ short _6;
+};
+
+struct machine
+{
+ short _0;
+ short nSprite;
+ short _4;
+};
+
+short BubbleCount = 0;
+
+short nFreeCount;
+short nMachineCount;
+
+uchar nBubblesFree[kMaxBubbles];
+machine Machine[kMaxMachines];
+Bubble BubbleList[kMaxBubbles];
+
+
+void InitBubbles()
+{
+ BubbleCount = 0;
+ nMachineCount = 0;
+
+ for (int i = 0; i < kMaxBubbles; i++) {
+ nBubblesFree[i] = i;
+ }
+
+ nFreeCount = 0;
+}
+
+void DestroyBubble(short nBubble)
+{
+ short nSprite = BubbleList[nBubble].nSprite;
+
+ runlist_DoSubRunRec(sprite[nSprite].lotag - 1);
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_SubRunRec(BubbleList[nBubble]._6);
+
+ mydeletesprite(nSprite);
+
+ nBubblesFree[nFreeCount] = nBubble;
+
+ nFreeCount++;
+}
+
+short GetBubbleSprite(short nBubble)
+{
+ return BubbleList[nBubble].nSprite;
+}
+
+int BuildBubble(int x, int y, int z, short nSector)
+{
+ int nSize = RandomSize(3);
+ if (nSize > 4) {
+ nSize -= 4;
+ }
+
+ if (nFreeCount <= 0) {
+ return -1;
+ }
+
+ nFreeCount--;
+
+ uchar nBubble = nBubblesFree[nFreeCount];
+
+ int nSprite = insertsprite(nSector, 402);
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ sprite[nSprite].cstat = 0;
+ sprite[nSprite].shade = -32;
+ sprite[nSprite].pal = 0;
+ sprite[nSprite].clipdist = 5;
+ sprite[nSprite].xrepeat = 40;
+ sprite[nSprite].yrepeat = 40;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].ang = inita;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = -1200;
+ sprite[nSprite].hitag = -1;
+ sprite[nSprite].extra = -1;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+
+// GrabTimeSlot(3);
+
+ BubbleList[nBubble].nSprite = nSprite;
+ BubbleList[nBubble]._0 = 0;
+ BubbleList[nBubble]._2 = SeqOffsets[kSeqBubble] + nSize;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nBubble | 0x140000);
+
+ BubbleList[nBubble]._6 = runlist_AddRunRec(NewRun, nBubble | 0x140000);
+ return nBubble | 0x140000;
+}
+
+void FuncBubble(int a, int b, int nRun)
+{
+ short nBubble = RunData[nRun].nVal;
+ assert(nBubble >= 0 && nBubble < kMaxBubbles);
+
+ short nSprite = BubbleList[nBubble].nSprite;
+ short dx = BubbleList[nBubble]._2;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x20000:
+ {
+ seq_MoveSequence(nSprite, dx, BubbleList[nBubble]._0);
+
+ BubbleList[nBubble]._0++;
+
+ if (BubbleList[nBubble]._0 >= SeqSize[dx]) {
+ BubbleList[nBubble]._0 = 0;
+ }
+
+ sprite[nSprite].z += sprite[nSprite].zvel;
+
+ short nSector = sprite[nSprite].sectnum;
+
+ if (sprite[nSprite].z <= sector[nSector].ceilingz)
+ {
+ short nSectAbove = SectAbove[nSector];
+
+ if (sprite[nSprite].hitag > -1 && nSectAbove != -1) {
+ BuildAnim(-1, 70, 0, sprite[nSprite].x, sprite[nSprite].y, sector[nSectAbove].floorz, nSectAbove, 64, 0);
+ }
+
+ DestroyBubble(nBubble);
+ }
+
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, dx, BubbleList[nBubble]._0, 1);
+ tsprite[a & 0xFFFF].owner = -1;
+ return;
+ }
+
+ case 0x80000:
+ case 0xA0000:
+ return;
+
+ default:
+ DebugOut("unknown msg %d for Bubble\n", nMessage);
+ return;
+ }
+}
+
+void DoBubbleMachines()
+{
+ for (int i = 0; i < nMachineCount; i++)
+ {
+ Machine[i]._0--;
+
+ if (Machine[i]._0 <= 0)
+ {
+ Machine[i]._0 = (RandomWord() % Machine[i]._4) + 30;
+
+ int nSprite = Machine[i].nSprite;
+ BuildBubble(sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum);
+ }
+ }
+}
+
+void BuildBubbleMachine(int nSprite)
+{
+ if (nMachineCount >= kMaxMachines) {
+ bail2dos("too many bubble machines in level %d\n", levelnew);
+ }
+
+ Machine[nMachineCount]._4 = 75;
+ Machine[nMachineCount].nSprite = nSprite;
+ Machine[nMachineCount]._0 = Machine[nMachineCount]._4;
+ nMachineCount++;
+
+ sprite[nSprite].cstat = 0x8000u;
+}
+
+void DoBubbles(int nPlayer)
+{
+ int x, y, z;
+ short nSector;
+
+ WheresMyMouth(nPlayer, &x, &y, &z, &nSector);
+
+ int nBubble = BuildBubble(x, y, z, nSector);
+ int nSprite = GetBubbleSprite(nBubble);
+
+ sprite[nSprite].hitag = nPlayer;
+}
diff --git a/source/exhumed/src/bubbles.h b/source/exhumed/src/bubbles.h
new file mode 100644
index 000000000..1a1194d5c
--- /dev/null
+++ b/source/exhumed/src/bubbles.h
@@ -0,0 +1,13 @@
+
+#ifndef __bubbles_h__
+#define __bubbles_h__
+
+void InitBubbles();
+
+void BuildBubbleMachine(int nSprite);
+void DoBubbleMachines();
+
+void DoBubbles(int nPlayer);
+void FuncBubble(int, int, int);
+
+#endif
diff --git a/source/exhumed/src/bullet.cpp b/source/exhumed/src/bullet.cpp
new file mode 100644
index 000000000..78600623d
--- /dev/null
+++ b/source/exhumed/src/bullet.cpp
@@ -0,0 +1,894 @@
+
+#include "engine.h"
+#include "bullet.h"
+#include "runlist.h"
+#include "anims.h"
+#include "sequence.h"
+#include "exhumed.h"
+#include "sound.h"
+#include "init.h"
+#include "move.h"
+#include "player.h"
+#include "trigdat.h"
+#include "random.h"
+#include "gun.h"
+#include "names.h"
+#include "lighting.h"
+#include
+#include
+#ifndef __WATCOMC__
+//#include
+#else
+//#include
+#include
+#endif
+
+#define kMaxBullets 500
+
+short BulletFree[kMaxBullets];
+
+// 32 bytes
+struct Bullet
+{
+ short nSeq; // 0
+ short field_2; // 2
+ short nSprite; // 4
+ short field_6;
+ short field_8;
+ short nType;
+ short field_C;
+ short field_E;
+ short field_10;
+ uchar field_12;
+ uchar field_13;
+ int x;
+ int y;
+ int z;
+};
+
+Bullet BulletList[kMaxBullets];
+short nBulletEnemy[kMaxBullets];
+int nBulletsFree;
+int lasthitz, lasthitx, lasthity;
+short lasthitsect, lasthitsprite, lasthitwall;
+
+int nBulletCount = 0;
+short nRadialBullet = 0;
+
+bulletInfo BulletInfo[] = {
+ { 25, 1, 20, -1, -1, 13, 0, 0, -1, 0 },
+ { 25, -1, 65000, -1, 31, 73, 0, 0, -1, 0 },
+ { 15, -1, 60000, -1, 31, 73, 0, 0, -1, 0 },
+ { 5, 15, 2000, -1, 14, 38, 4, 5, 3, 0 },
+ { 250, 100, 2000, -1, 33, 34, 4, 20, -1, 0 },
+ { 200, -1, 2000, -1, 20, 23, 4, 10, -1, 0 },
+ { 200, -1, 60000, 68, 68, -1, -1, 0, -1, 0 },
+ { 300, 1, 0, -1, -1, -1, 0, 50, -1, 0 },
+ { 18, -1, 2000, -1, 18, 29, 4, 0, -1, 0 },
+ { 20, -1, 2000, 37, 11, 30, 4, 0, -1, 0 },
+ { 25, -1, 3000, -1, 44, 36, 4, 15, 90, 0 },
+ { 30, -1, 1000, -1, 52, 53, 4, 20, 48, 0 },
+ { 20, -1, 3500, -1, 54, 55, 4, 30, -1, 0 },
+ { 10, -1, 5000, -1, 57, 76, 4, 0, -1, 0 },
+ { 40, -1, 1500, -1, 63, 38, 4, 10, 40, 0 },
+ { 20, -1, 2000, -1, 60, 12, 0, 0, -1, 0 },
+ { 5, -1, 60000, -1, 31, 76, 0, 0, -1, 0 }
+};
+
+
+void InitBullets()
+{
+ nBulletCount = 0;
+
+ for (int i = 0; i < kMaxBullets; i++) {
+ BulletFree[i] = i;
+ }
+
+ nBulletsFree = kMaxBullets;
+
+ memset(nBulletEnemy, -1, sizeof(nBulletEnemy));
+}
+
+short GrabBullet()
+{
+ nBulletsFree--;
+ return BulletFree[nBulletsFree];
+}
+
+void DestroyBullet(short nBullet)
+{
+ short nSprite = BulletList[nBullet].nSprite;
+
+ runlist_DoSubRunRec(BulletList[nBullet].field_6);
+ runlist_DoSubRunRec(sprite[nSprite].lotag - 1);
+ runlist_SubRunRec(BulletList[nBullet].field_8);
+
+ StopSpriteSound(nSprite);
+
+ mydeletesprite(nSprite);
+
+ BulletFree[nBulletsFree] = nBullet;
+ nBulletsFree++;
+}
+
+void IgniteSprite(int nSprite)
+{
+ sprite[nSprite].hitag += 2;
+
+ int nAnim = BuildAnim(-1, 38, 0, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum, 40, 20);//276);
+ short nAnimSprite = GetAnimSprite(nAnim);
+
+ sprite[nAnimSprite].hitag = nSprite;
+ changespritestat(nAnimSprite, kStatIgnited);
+
+ short yRepeat = (tilesiz[sprite[nAnimSprite].picnum].y * 32) / nFlameHeight;
+ if (yRepeat < 1)
+ yRepeat = 1;
+
+ sprite[nAnimSprite].yrepeat = (uchar)yRepeat;
+}
+
+void BulletHitsSprite(Bullet *pBullet, short nBulletSprite, short nHitSprite, int x, int y, int z, int nSector)
+{
+ assert(nSector >= 0 && nSector < kMaxSectors);
+
+ bulletInfo *pBulletInfo = &BulletInfo[pBullet->nType];
+
+ short nStat = sprite[nHitSprite].statnum;
+
+ switch (pBullet->nType)
+ {
+ case 0:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 10:
+ case 11:
+ {
+ break;
+ }
+
+ case 14:
+ {
+ if (nStat > 107 || nStat == 98) {
+ return;
+ }
+ // else - fall through to below cases
+ }
+ case 1:
+ case 2:
+ case 8:
+ case 9:
+ case 12:
+ case 13:
+ case 15:
+ case 16:
+ {
+ // loc_29E59
+ if (!nStat || nStat > 98) {
+ break;
+ }
+
+ short nSprite = pBullet->nSprite;
+
+ if (nStat == 98)
+ {
+ short nAngle = sprite[nSprite].ang + 256;
+ int nRand = RandomSize(9);
+
+ sprite[nHitSprite].xvel = Sin((nAngle - nRand) + 512) * 2;
+ sprite[nHitSprite].yvel = Sin((nAngle - nRand)) * 2;
+ sprite[nHitSprite].zvel = (-(RandomSize(3) + 1)) << 8;
+ }
+ else
+ {
+ int xVel = sprite[nHitSprite].xvel;
+ int yVel = sprite[nHitSprite].yvel;
+
+ sprite[nHitSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nHitSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
+
+ MoveCreature(nHitSprite);
+
+ sprite[nHitSprite].xvel = xVel;
+ sprite[nHitSprite].yvel = yVel;
+ }
+
+ break;
+ }
+
+ case 3:
+ {
+ if (nStat > 107 || nStat == 98) {
+ return;
+ }
+
+ sprite[nHitSprite].hitag++;
+
+ if (sprite[nHitSprite].hitag == 15) {
+ IgniteSprite(nHitSprite);
+ }
+
+ if (!RandomSize(2)) {
+ BuildAnim(-1, pBulletInfo->field_C, 0, x, y, z, nSector, 40, pBulletInfo->nFlags);
+ }
+
+ return;
+ }
+
+ default:
+ break;
+ }
+
+ // BHS_switchBreak:
+ short nDamage = pBulletInfo->nDamage;
+
+ if (pBullet->field_13 > 1) {
+ nDamage *= 2;
+ }
+
+ runlist_DamageEnemy(nHitSprite, nBulletSprite, nDamage);
+
+ if (nStat <= 90 || nStat >= 199)
+ {
+ BuildAnim(-1, pBulletInfo->field_C, 0, x, y, z, nSector, 40, pBulletInfo->nFlags);
+ return;
+ }
+
+ if (nStat < 98)
+ {
+ if (nStat <= 0)
+ {
+ BuildAnim(-1, 12, 0, x, y, z, nSector, 40, 0);
+ }
+ else if (nStat == 97)
+ {
+ return;
+ }
+ else
+ {
+ // BHS_B
+ BuildAnim(-1, 39, 0, x, y, z, nSector, 40, 0);
+ if (pBullet->nType > 2)
+ {
+ BuildAnim(-1, pBulletInfo->field_C, 0, x, y, z, nSector, 40, pBulletInfo->nFlags);
+ }
+ }
+
+ return;
+ }
+ else
+ {
+ if (nStat == 98 || nStat == 141 || nStat == 152 || nStat == 102)
+ {
+ BuildAnim(-1, 12, 0, x, y, z, nSector, 40, 0);
+ }
+ else
+ {
+ // BHS_B
+ BuildAnim(-1, 39, 0, x, y, z, nSector, 40, 0);
+ if (pBullet->nType > 2)
+ {
+ BuildAnim(-1, pBulletInfo->field_C, 0, x, y, z, nSector, 40, pBulletInfo->nFlags);
+ }
+ }
+
+ return;
+ }
+}
+
+
+void BackUpBullet(int *x, int *y, short nAngle)
+{
+ *x -= Sin(nAngle + 512) >> 11;
+ *y -= Sin(nAngle) >> 11;
+}
+
+int MoveBullet(short nBullet)
+{
+ short hitsect = -1;
+ short hitwall = -1;
+ short hitsprite = -1;
+
+ short nType = BulletList[nBullet].nType;
+ short nSprite = BulletList[nBullet].nSprite;
+
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ int z = sprite[nSprite].z; // ebx
+ short nSectFlag = SectFlag[sprite[nSprite].sectnum];
+
+ int x2, y2, z2;
+
+ short var_3C = BulletList[nBullet].field_10;
+
+ int nVal;
+
+ if (var_3C < 30000)
+ {
+ short nEnemySprite = nBulletEnemy[nBullet];
+
+ if (nBulletEnemy[nBullet] <= -1) {
+ goto MoveBullet_goto_A; // FIXME
+ }
+
+ if (!(sprite[nEnemySprite].cstat & 0x101))
+ {
+ nBulletEnemy[nBullet] = -1;
+MoveBullet_goto_A:
+ if (nType == 3)
+ {
+ if (BulletList[nBullet].field_E >= 8)
+ {
+ sprite[nSprite].xrepeat += 4;
+ sprite[nSprite].yrepeat += 4;
+ }
+ else
+ {
+ sprite[nSprite].xrepeat -= 1;
+ sprite[nSprite].yrepeat += 8;
+
+ BulletList[nBullet].z -= 200;
+
+ if (sprite[nSprite].shade < 90) {
+ sprite[nSprite].shade += 35;
+ }
+
+ if (BulletList[nBullet].field_E == 3)
+ {
+ BulletList[nBullet].nSeq = 45;
+ BulletList[nBullet].field_2 = 0;
+ sprite[nSprite].xrepeat = 40;
+ sprite[nSprite].yrepeat = 40;
+ sprite[nSprite].shade = 0;
+ sprite[nSprite].z += 512;
+ }
+ }
+ }
+
+ // loc_2A1DD
+ nVal = movesprite(nSprite, BulletList[nBullet].x, BulletList[nBullet].y, BulletList[nBullet].z, sprite[nSprite].clipdist >> 1, sprite[nSprite].clipdist >> 1, CLIPMASK1);
+ }
+ else
+ {
+ nVal = AngleChase(nSprite, nEnemySprite, var_3C, 0, 16);
+ }
+
+ if (nVal)
+ {
+ x2 = sprite[nSprite].x;
+ y2 = sprite[nSprite].y;
+ z2 = sprite[nSprite].z;
+ hitsect = sprite[nSprite].sectnum;
+
+ if (nVal & 0x30000)
+ {
+ hitwall = nVal & 0x3FFF;
+ goto loc_2A48A;
+ }
+ else
+ {
+ if ((nVal & 0xC000) == 0x8000)
+ {
+ hitwall = nVal & 0x3FFF;
+ goto loc_2A48A;
+ }
+ else if ((nVal & 0xC000) == 0xC000)
+ {
+ hitsprite = nVal & 0x3FFF;
+ goto loc_2A405;
+ }
+ else {
+ goto loc_2A25F;
+ }
+ }
+ }
+ else
+ {
+loc_2A25F:
+ // sprite[nSprite].sectnum may have changed since we set nSectFlag ?
+ short nFlagVal = nSectFlag ^ SectFlag[sprite[nSprite].sectnum];
+ if (nFlagVal & kSectUnderwater)
+ {
+ DestroyBullet(nBullet);
+ nVal = 1;
+ }
+
+ if (nVal) {
+ return nVal;
+ }
+
+ if (nType == 15)
+ {
+ return nVal;
+ }
+
+ if (nType != 3)
+ {
+ AddFlash(sprite[nSprite].sectnum, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, nVal);
+
+ if (sprite[nSprite].pal != 5) {
+ sprite[nSprite].pal = 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ nVal = 1;
+
+ if (nBulletEnemy[nBullet] > -1)
+ {
+ hitsprite = nBulletEnemy[nBullet];
+ x2 = sprite[hitsprite].x;
+ y2 = sprite[hitsprite].y;
+ z2 = sprite[hitsprite].z - (GetSpriteHeight(hitsprite) >> 1);
+ hitsect = sprite[hitsprite].sectnum;
+ }
+ else
+ {
+ vec3_t startPos = { x, y, z };
+ hitdata_t hitData = { { x2, y2, z2 }, hitsprite, hitsect, hitwall };
+ hitscan(&startPos, sprite[nSprite].sectnum, Sin(sprite[nSprite].ang + 512), Sin(sprite[nSprite].ang), (-Sin(BulletList[nBullet].field_C)) << 3, &hitData, CLIPMASK1);
+ x2 = hitData.pos.x;
+ y2 = hitData.pos.y;
+ z2 = hitData.pos.z;
+ hitsprite = hitData.sprite;
+ hitsect = hitData.sect;
+ hitwall = hitData.wall;
+ }
+
+ lasthitx = x2;
+ lasthity = y2;
+ lasthitz = z2;
+ lasthitsect = hitsect;
+ lasthitwall = hitwall;
+ lasthitsprite = hitsprite;
+
+ if (lasthitsprite > -1)
+ {
+loc_2A405:
+ if (sprite[nSprite].pal != 5 || sprite[hitsprite].statnum != 100)
+ {
+// assert(hitsect <= kMaxSectors);
+
+ BulletHitsSprite(&BulletList[nBullet], sprite[nSprite].owner, hitsprite, x2, y2, z2, hitsect);
+ }
+ else
+ {
+ short nPlayer = GetPlayerFromSprite(hitsprite);
+ if (!PlayerList[nPlayer].bIsMummified)
+ {
+ PlayerList[nPlayer].bIsMummified = kTrue;
+ SetNewWeapon(nPlayer, kWeaponMummified);
+ }
+ }
+ }
+ else if (hitwall > -1)
+ {
+loc_2A48A:
+ if (wall[hitwall].picnum == kEnergy1)
+ {
+ short nSector = wall[hitwall].nextsector;
+ if (nSector > -1)
+ {
+ short nDamage = BulletInfo[BulletList[nBullet].nType].nDamage;
+ if (BulletList[nBullet].field_13 > 1) {
+ nDamage *= 2;
+ }
+
+ short nNormal = GetWallNormal(hitwall) & 0x7FF;
+
+ runlist_DamageEnemy(sector[nSector].extra, nNormal, nDamage);
+ }
+ }
+ }
+
+ // loc_2A4F5:?
+ if (hitsprite < 0 && hitwall < 0)
+ {
+ if ((SectBelow[hitsect] >= 0 && (SectFlag[SectBelow[hitsect]] & kSectUnderwater)) || SectDepth[hitsect])
+ {
+ sprite[nSprite].x = x2;
+ sprite[nSprite].y = y2;
+ sprite[nSprite].z = z2;
+ BuildSplash(nSprite, hitsect);
+ }
+ else
+ {
+ BuildAnim(-1, BulletInfo[nType].field_C, 0, x2, y2, z2, hitsect, 40, BulletInfo[nType].nFlags);
+ }
+ }
+ else
+ {
+// short nType = BulletList[nBullet].nType;
+
+ if (hitwall < 0)
+ {
+ sprite[nSprite].x = x2;
+ sprite[nSprite].y = y2;
+ sprite[nSprite].z = z2;
+
+ mychangespritesect(nSprite, hitsect);
+ }
+ else
+ {
+ BackUpBullet(&x2, &y2, sprite[nSprite].ang);
+
+ if (nType != 3 || !RandomSize(2))
+ {
+ int zOffset = RandomSize(8) << 3;
+
+ if (!RandomBit()) {
+ zOffset = -zOffset;
+ }
+
+ // draws bullet puff on walls when they're shot
+ BuildAnim(-1, BulletInfo[nType].field_C, 0, x2, y2, z2 + zOffset, hitsect, 40, BulletInfo[nType].nFlags);
+ }
+ }
+
+ // loc_2A639:
+ if (BulletInfo[nType].field_10)
+ {
+ nRadialBullet = nType;
+
+ runlist_RadialDamageEnemy(nSprite, BulletInfo[nType].nDamage, BulletInfo[nType].field_10);
+
+ nRadialBullet = -1;
+
+ AddFlash(sprite[nSprite].sectnum, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, 128);
+ }
+ }
+
+ DestroyBullet(nBullet);
+ }
+
+ return nVal;
+}
+
+void SetBulletEnemy(short nBullet, short nEnemy)
+{
+ if (nBullet >= 0) {
+ nBulletEnemy[nBullet] = nEnemy;
+ }
+}
+
+int BuildBullet(short nSprite, int nType, int ebx, int ecx, int val1, int nAngle, int val2, int val3)
+{
+ Bullet sBullet;
+
+ if (BulletInfo[nType].field_4 > 30000)
+ {
+ if (val2 >= 10000)
+ {
+ val2 -= 10000;
+
+ short nTargetSprite = val2;
+
+// assert(sprite[nTargetSprite].sectnum <= kMaxSectors);
+
+ if (sprite[nTargetSprite].cstat & 0x101)
+ {
+ sBullet.nType = nType;
+ sBullet.field_13 = val3;
+
+ sBullet.nSprite = insertsprite(sprite[nSprite].sectnum, 200);
+ sprite[sBullet.nSprite].ang = nAngle;
+
+ int nHeight = GetSpriteHeight(nTargetSprite);
+
+ assert(sprite[nTargetSprite].sectnum >= 0 && sprite[nTargetSprite].sectnum < kMaxSectors);
+
+ BulletHitsSprite(&sBullet, nSprite, nTargetSprite, sprite[nTargetSprite].x, sprite[nTargetSprite].y, sprite[nTargetSprite].z - (nHeight >> 1), sprite[nTargetSprite].sectnum);
+ mydeletesprite(sBullet.nSprite);
+ return -1;
+ }
+ else
+ {
+ val2 = 0;
+ }
+ }
+ }
+
+ if (!nBulletsFree) {
+ return -1;
+ }
+
+ short nSector;
+
+ if (sprite[nSprite].statnum != 100)
+ {
+ nSector = sprite[nSprite].sectnum;
+ }
+ else
+ {
+ nSector = nPlayerViewSect[GetPlayerFromSprite(nSprite)];
+ }
+
+ int nBulletSprite = insertsprite(nSector, 200);
+ int nHeight = GetSpriteHeight(nSprite);
+ nHeight = nHeight - (nHeight >> 2);
+
+ if (val1 == -1) {
+ val1 = -nHeight;
+ }
+
+ sprite[nBulletSprite].x = sprite[nSprite].x;
+ sprite[nBulletSprite].y = sprite[nSprite].y;
+ sprite[nBulletSprite].z = sprite[nSprite].z;
+
+ // why is this done here???
+ assert(nBulletSprite >= 0 && nBulletSprite < kMaxSprites);
+
+ short nBullet = GrabBullet();
+
+ nBulletEnemy[nBullet] = -1;
+
+ sprite[nBulletSprite].cstat = 0;
+ sprite[nBulletSprite].shade = -64;
+
+ if (BulletInfo[nType].nFlags & 4) {
+ sprite[nBulletSprite].pal = 4;
+ }
+ else {
+ sprite[nBulletSprite].pal = 0;
+ }
+
+ sprite[nBulletSprite].clipdist = 25;
+
+ short nRepeat = BulletInfo[nType].xyRepeat;
+ if (nRepeat < 0) {
+ nRepeat = 30;
+ }
+
+ sprite[nBulletSprite].xrepeat = nRepeat;
+ sprite[nBulletSprite].yrepeat = nRepeat;
+ sprite[nBulletSprite].xoffset = 0;
+ sprite[nBulletSprite].yoffset = 0;
+ sprite[nBulletSprite].ang = nAngle;
+ sprite[nBulletSprite].xvel = 0;
+ sprite[nBulletSprite].yvel = 0;
+ sprite[nBulletSprite].zvel = 0;
+ sprite[nBulletSprite].owner = nSprite;
+ sprite[nBulletSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nBulletSprite].extra = -1;
+ sprite[nBulletSprite].hitag = 0;
+
+// GrabTimeSlot(3);
+
+ BulletList[nBullet].field_10 = 0;
+ BulletList[nBullet].field_E = BulletInfo[nType].field_2;
+ BulletList[nBullet].field_2 = 0;
+
+ short nSeq;
+
+ if (BulletInfo[nType].field_8 == -1)
+ {
+ BulletList[nBullet].field_12 = 1;
+ nSeq = BulletInfo[nType].nSeq;
+ }
+ else
+ {
+ BulletList[nBullet].field_12 = 0;
+ nSeq = BulletInfo[nType].field_8;
+ }
+
+ BulletList[nBullet].nSeq = nSeq;
+
+ sprite[nBulletSprite].picnum = seq_GetSeqPicnum(nSeq, 0, 0);
+
+ if (nSeq == kSeqBullet) {
+ sprite[nBulletSprite].cstat |= 0x8000;
+ }
+
+ BulletList[nBullet].field_C = val2 & 0x7FF; // TODO - anglemask?
+ BulletList[nBullet].nType = nType;
+ BulletList[nBullet].nSprite = nBulletSprite;
+ BulletList[nBullet].field_6 = runlist_AddRunRec(sprite[nBulletSprite].lotag - 1, nBullet | 0xB0000);
+ BulletList[nBullet].field_8 = runlist_AddRunRec(NewRun, nBullet | 0xB0000);
+ BulletList[nBullet].field_13 = val3;
+ sprite[nBulletSprite].z += val1;
+
+ int var_18;
+
+ nSector = sprite[nBulletSprite].sectnum;
+
+ while (1)
+ {
+ if (sprite[nBulletSprite].z >= sector[nSector].ceilingz) {
+ break;
+ }
+
+ if (SectAbove[nSector] == -1)
+ {
+ sprite[nBulletSprite].z = sector[nSector].ceilingz;
+ break;
+ }
+
+ nSector = SectAbove[nSector];
+ mychangespritesect(nBulletSprite, nSector);
+ }
+
+ if (val2 < 10000)
+ {
+ var_18 = ((-Sin(val2)) * BulletInfo[nType].field_4) >> 11;
+ }
+ else
+ {
+ val2 -= 10000;
+
+ short nTargetSprite = val2;
+
+ if (BulletInfo[nType].field_4 > 30000)
+ {
+ nBulletEnemy[nBullet] = nTargetSprite;
+ }
+ else
+ {
+ nHeight = GetSpriteHeight(nTargetSprite);
+ int nHeightAdjust;
+
+ if (sprite[nTargetSprite].statnum == 100)
+ {
+ nHeightAdjust = nHeight >> 2;
+ }
+ else
+ {
+ nHeightAdjust = nHeight >> 1;
+ }
+
+ nHeight -= nHeightAdjust;
+
+ int var_20 = sprite[nTargetSprite].z - nHeight;
+
+ int x, y;
+
+ if (nSprite == -1 || sprite[nSprite].statnum == 100)
+ {
+ // loc_2ABA3:
+ x = sprite[nTargetSprite].x - sprite[nBulletSprite].x;
+ y = sprite[nTargetSprite].y - sprite[nBulletSprite].y;
+ }
+ else
+ {
+ x = sprite[nTargetSprite].x;
+ y = sprite[nTargetSprite].y;
+
+ if (sprite[nTargetSprite].statnum == 100)
+ {
+ int nPlayer = GetPlayerFromSprite(nTargetSprite);
+ if (nPlayer > -1)
+ {
+ x += ((nPlayerDX[nPlayer] << 4) - nPlayerDX[nPlayer]);
+ y += ((nPlayerDY[nPlayer] << 4) - nPlayerDY[nPlayer]);
+ }
+ }
+ else
+ {
+ short nXVel = sprite[nTargetSprite].xvel;
+ short nYVel = sprite[nTargetSprite].yvel;
+
+ x += (((nXVel << 2) + nXVel) << 2) >> 6;
+ y += (((nYVel << 2) + nYVel) << 2) >> 6;
+ }
+
+ y -= sprite[nBulletSprite].y;
+ x -= sprite[nBulletSprite].x;
+
+ nAngle = GetMyAngle(x, y);
+ sprite[nSprite].ang = nAngle;
+ }
+
+ int nSqrt = lsqrt(y*y + x*x);
+ if (nSqrt <= 0)
+ {
+ var_18 = 0;
+ }
+ else
+ {
+ var_18 = ((var_20 - sprite[nBulletSprite].z) * BulletInfo[nType].field_4) / nSqrt;
+ }
+ }
+ }
+
+ BulletList[nBullet].z = 0;
+ BulletList[nBullet].x = (sprite[nSprite].clipdist << 2) * Sin(nAngle + 512);
+ BulletList[nBullet].y = (sprite[nSprite].clipdist << 2) * Sin(nAngle);
+ nBulletEnemy[nBullet] = -1;
+
+ if (MoveBullet(nBullet))
+ {
+ nBulletSprite = -1;
+ }
+ else
+ {
+ BulletList[nBullet].field_10 = BulletInfo[nType].field_4;
+ BulletList[nBullet].x = (Sin(nAngle + 512) >> 3) * BulletInfo[nType].field_4;
+ BulletList[nBullet].y = (Sin(nAngle) >> 3) * BulletInfo[nType].field_4;
+ BulletList[nBullet].z = var_18 >> 3;
+ }
+
+ return (nBulletSprite & 0xFFFF) | (nBullet << 16);
+}
+
+void FuncBullet(int a, int b, int nRun)
+{
+ short nBullet = RunData[nRun].nVal;
+ assert(nBullet >= 0 && nBullet < kMaxBullets);
+
+ short nSeq = SeqOffsets[BulletList[nBullet].nSeq];
+ short nSprite = BulletList[nBullet].nSprite;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %x for bullet\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0xA0000:
+ return;
+
+ case 0x90000:
+ {
+ short nSprite2 = a & 0xFFFF;
+ tsprite[nSprite2].statnum = 1000;
+
+ if (BulletList[nBullet].nType == 15)
+ {
+ seq_PlotArrowSequence(nSprite2, nSeq, BulletList[nBullet].field_2);
+ }
+ else
+ {
+ seq_PlotSequence(nSprite2, nSeq, BulletList[nBullet].field_2, 0);
+ tsprite[nSprite2].owner = -1;
+ }
+ return;
+ }
+
+ case 0x20000:
+ {
+ short nFlag = FrameFlag[SeqBase[nSeq] + BulletList[nBullet].field_2];
+
+ seq_MoveSequence(nSprite, nSeq, BulletList[nBullet].field_2);
+
+ if (nFlag & 0x80)
+ {
+ BuildAnim(-1, 45, 0, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum, sprite[nSprite].xrepeat, 0);
+ }
+
+ BulletList[nBullet].field_2++;
+ if (BulletList[nBullet].field_2 >= SeqSize[nSeq])
+ {
+ if (!BulletList[nBullet].field_12)
+ {
+ BulletList[nBullet].nSeq = BulletInfo[BulletList[nBullet].nType].nSeq;
+ BulletList[nBullet].field_12++;
+ }
+
+ BulletList[nBullet].field_2 = 0;
+ }
+
+ if (BulletList[nBullet].field_E == -1)
+ {
+ MoveBullet(nBullet);
+ }
+ else
+ {
+ BulletList[nBullet].field_E--;
+ if (!BulletList[nBullet].field_E) {
+ DestroyBullet(nBullet);
+ }
+ else {
+ MoveBullet(nBullet);
+ }
+ }
+ return;
+ }
+ }
+}
diff --git a/source/exhumed/src/bullet.h b/source/exhumed/src/bullet.h
new file mode 100644
index 000000000..755581f44
--- /dev/null
+++ b/source/exhumed/src/bullet.h
@@ -0,0 +1,38 @@
+
+#ifndef __bullet_h__
+#define __bullet_h__
+
+// 32 bytes
+struct bulletInfo
+{
+ short nDamage; // 0
+ short field_2; // 2
+ int field_4; // 4
+ short field_8; // 8
+ short nSeq; // 10
+ short field_C; // 12
+ short nFlags;
+ short field_10; // damage radius?
+ short xyRepeat;
+ char pad[12];
+};
+
+extern bulletInfo BulletInfo[];
+
+extern short nRadialBullet;
+extern short lasthitsect;
+extern int lasthitz;
+extern int lasthitx;
+extern int lasthity;
+
+void InitBullets();
+short GrabBullet();
+void DestroyBullet(short nRun);
+int MoveBullet(short nBullet);
+void SetBulletEnemy(short nBullet, short nEnemy);
+int BuildBullet(short nSprite, int nType, int ebx, int ecx, int val1, int nAngle, int val2, int val3);
+void IgniteSprite(int nSprite);
+void FuncBullet(int, int, int);
+void BackUpBullet(int *x, int *y, short nAngle);
+
+#endif
diff --git a/source/exhumed/src/cd.cpp b/source/exhumed/src/cd.cpp
new file mode 100644
index 000000000..b839c2f14
--- /dev/null
+++ b/source/exhumed/src/cd.cpp
@@ -0,0 +1,55 @@
+
+#include "cd.h"
+#include
+#include
+
+extern short word_9AC30;
+
+int cd_check_device_present()
+{
+ return 1;
+}
+
+int initcdaudio()
+{
+ if (!cd_check_device_present())
+ {
+ word_9AC30 = 1;
+
+ // return to text video mode
+ printf("No MSCDEX driver installed!\n");
+ exit(0);
+ }
+
+ return 1;
+}
+
+void setCDaudiovolume(int val)
+{
+
+}
+
+int playCDtrack(int nTrack)
+{
+ return 1;
+}
+
+void StartfadeCDaudio()
+{
+
+}
+
+int StepFadeCDaudio()
+{
+ return 0;
+}
+
+int CDplaying()
+{
+ return 1;
+}
+
+void StopCD()
+{
+
+}
\ No newline at end of file
diff --git a/source/exhumed/src/cd.h b/source/exhumed/src/cd.h
new file mode 100644
index 000000000..d18a53721
--- /dev/null
+++ b/source/exhumed/src/cd.h
@@ -0,0 +1,13 @@
+
+#ifndef __cd_h__
+#define __cd_h__
+
+int initcdaudio();
+void setCDaudiovolume(int val);
+int playCDtrack(int nTrack);
+void StartfadeCDaudio();
+int StepFadeCDaudio();
+int CDplaying();
+void StopCD();
+
+#endif
diff --git a/source/exhumed/src/cdaudio.cpp b/source/exhumed/src/cdaudio.cpp
new file mode 100644
index 000000000..14a79057e
--- /dev/null
+++ b/source/exhumed/src/cdaudio.cpp
@@ -0,0 +1,25 @@
+
+#include "cdaudio.h"
+
+int fadecdaudio()
+{
+/* TODO
+ StartfadeCDaudio();
+
+ while (1)
+ {
+ if (!StepFadeCDaudio()) {
+ return 1;
+ }
+ else {
+ WaitTicks(1);
+ }
+ }
+*/
+ return 1;
+}
+
+void CheckCD()
+{
+
+}
diff --git a/source/exhumed/src/cdaudio.h b/source/exhumed/src/cdaudio.h
new file mode 100644
index 000000000..230fc7ff7
--- /dev/null
+++ b/source/exhumed/src/cdaudio.h
@@ -0,0 +1,8 @@
+
+#ifndef __cdaudio_h__
+#define __cdaudio_h__
+
+void CheckCD();
+int fadecdaudio();
+
+#endif
diff --git a/source/exhumed/src/cdrom.cpp b/source/exhumed/src/cdrom.cpp
new file mode 100644
index 000000000..337bb6f4a
--- /dev/null
+++ b/source/exhumed/src/cdrom.cpp
@@ -0,0 +1,12 @@
+
+#include "cdrom.h"
+
+int checkcdrom()
+{
+ return 1;
+}
+
+char GetCDDriveLetter()
+{
+ return 'D';
+}
diff --git a/source/exhumed/src/cdrom.h b/source/exhumed/src/cdrom.h
new file mode 100644
index 000000000..304c0fe8e
--- /dev/null
+++ b/source/exhumed/src/cdrom.h
@@ -0,0 +1,8 @@
+
+#ifndef __cdrom_h__
+#define __cdrom_h__
+
+int checkcdrom();
+char GetCDDriveLetter();
+
+#endif
diff --git a/source/exhumed/src/config.cpp b/source/exhumed/src/config.cpp
new file mode 100644
index 000000000..3212475fd
--- /dev/null
+++ b/source/exhumed/src/config.cpp
@@ -0,0 +1,632 @@
+#include "compat.h"
+#include "renderlayer.h"
+#include "build.h"
+#include "cache1d.h"
+#include "keyboard.h"
+#include "control.h"
+#include "exhumed.h"
+#include "typedefs.h"
+#include "scriplib.h"
+
+#include "config.h"
+
+#include
+#include
+#include
+#include
+
+#define kMaxGameFunctions 40
+#define kMaxGameFuncLen 64
+
+// KEEPINSYNC mact/include/_control.h, build/src/sdlayer.cpp
+#define MAXJOYBUTTONS 32
+#define MAXJOYBUTTONSANDHATS (MAXJOYBUTTONS+4)
+
+// KEEPINSYNC mact/include/_control.h, build/src/sdlayer.cpp
+#define MAXMOUSEAXES 2
+#define MAXMOUSEDIGITAL (MAXMOUSEAXES*2)
+
+// KEEPINSYNC mact/include/_control.h, build/src/sdlayer.cpp
+#define MAXJOYAXES 9
+#define MAXJOYDIGITAL (MAXJOYAXES*2)
+
+// default mouse scale
+#define DEFAULTMOUSEANALOGUESCALE 65536
+
+// default joystick settings
+
+#if defined(GEKKO)
+#define DEFAULTJOYSTICKANALOGUESCALE 16384
+#define DEFAULTJOYSTICKANALOGUEDEAD 1000
+#define DEFAULTJOYSTICKANALOGUESATURATE 9500
+#else
+#define DEFAULTJOYSTICKANALOGUESCALE 65536
+#define DEFAULTJOYSTICKANALOGUEDEAD 2000
+#define DEFAULTJOYSTICKANALOGUESATURATE 9500
+#endif
+
+static const char gamefunctions[kMaxGameFunctions][kMaxGameFuncLen] =
+{
+ "Move_Forward",
+ "Move_Backward",
+ "Turn_Left",
+ "Turn_Right",
+ "Strafe",
+ "Strafe_Left",
+ "Strafe_Right",
+ "Run",
+ "Jump",
+ "Crouch",
+ "Fire",
+ "Open",
+ "Look_Up",
+ "Look_Down",
+ "Look_Straight",
+ "Aim_Up",
+ "Aim_Down",
+ "SendMessage",
+ "Weapon_1",
+ "Weapon_2",
+ "Weapon_3",
+ "Weapon_4",
+ "Weapon_5",
+ "Weapon_6",
+ "Weapon_7",
+ "Mouseview",
+ "Pause",
+ "Map",
+ "Zoom_In",
+ "Zoom_Out",
+ "Gamma_Correction",
+ "Escape",
+ "Shrink_Screen",
+ "Enlarge_Screen",
+ "Inventory",
+ "Inventory_Left",
+ "Inventory_Right",
+ "Mouse_Sensitivity_Up",
+ "Mouse_Sensitivity_Down"
+ "Show_Console",
+};
+
+static const char keydefaults[kMaxGameFunctions * 2][kMaxGameFuncLen] =
+{
+ "Up", "Kpad8",
+ "Down", "Kpad2",
+ "Left", "Kpad4",
+ "Right", "KPad6",
+ "LAlt", "RAlt",
+ ",", "",
+ ".", "",
+ "LShift", "RShift",
+ "A", "",
+ "Z", "",
+ "LCtrl", "RCtrl",
+ "Space", "",
+ "PgUp", "",
+ "PgDn", "",
+ "Home", "",
+ "Insert", "",
+ "Delete", "",
+ "T", "",
+ "1", "",
+ "2", "",
+ "3", "",
+ "4", "",
+ "5", "",
+ "6", "",
+ "7", "",
+ "/", "",
+ "Pause", "",
+ "Tab", "",
+ "=", "",
+ "-", "",
+ "F11", "",
+ "Escape", "",
+ "Kpad-", "",
+ "Kpad+", "",
+ "Enter", "",
+ "[", "",
+ "]", "",
+ "F7", "",
+ "F8", "",
+ "`", "",
+};
+
+static const char *mousedefaults[MAXMOUSEBUTTONS] =
+{
+ "Fire",
+ "Strafe",
+ "Move_Forward"
+ "",
+ "",
+ "",
+};
+
+static const char *mouseclickeddefaults[MAXMOUSEBUTTONS] =
+{
+};
+
+static const char* mouseanalogdefaults[MAXMOUSEAXES] =
+{
+"analog_strafing",
+"analog_moving",
+};
+
+
+static const char* mousedigitaldefaults[MAXMOUSEDIGITAL] =
+{
+};
+
+ud_setup_t gSetup;
+
+#define kMaxSetupFiles 20
+#define kSetupFilename "SETUP.CFG"
+
+static char setupfilename[128] = {kSetupFilename};
+
+int lMouseSens = 32;
+unsigned int dword_1B82E0 = 0;
+
+int32_t FXVolume;
+int32_t MusicVolume;
+int32_t MixRate;
+int32_t MidiPort;
+int32_t NumVoices;
+int32_t NumChannels;
+int32_t NumBits;
+int32_t ReverseStereo;
+int32_t MusicDevice;
+int32_t FXDevice;
+int32_t ControllerType;
+
+int32_t scripthandle;
+int32_t setupread;
+int32_t useprecache;
+int32_t MouseDeadZone, MouseBias;
+int32_t SmoothInput;
+
+// JBF 20031211: Store the input settings because
+// (currently) mact can't regurgitate them
+int32_t MouseFunctions[MAXMOUSEBUTTONS][2];
+int32_t MouseDigitalFunctions[MAXMOUSEAXES][2];
+int32_t MouseAnalogueAxes[MAXMOUSEAXES];
+int32_t MouseAnalogueScale[MAXMOUSEAXES];
+int32_t JoystickFunctions[MAXJOYBUTTONSANDHATS][2];
+int32_t JoystickDigitalFunctions[MAXJOYAXES][2];
+int32_t JoystickAnalogueAxes[MAXJOYAXES];
+int32_t JoystickAnalogueScale[MAXJOYAXES];
+int32_t JoystickAnalogueInvert[MAXJOYAXES];
+int32_t JoystickAnalogueDead[MAXJOYAXES];
+int32_t JoystickAnalogueSaturate[MAXJOYAXES];
+uint8_t KeyboardKeys[kMaxGameFunctions][2];
+
+int32_t MAXCACHE1DSIZE = (96*1024*1024);
+
+
+void SetupGameButtons()
+{
+ CONTROL_DefineFlag(gamefunc_Move_Forward, FALSE);
+ CONTROL_DefineFlag(gamefunc_Move_Backward, FALSE);
+ CONTROL_DefineFlag(gamefunc_Turn_Left, FALSE);
+ CONTROL_DefineFlag(gamefunc_Turn_Right, FALSE);
+ CONTROL_DefineFlag(gamefunc_Strafe, FALSE);
+ CONTROL_DefineFlag(gamefunc_Strafe_Left, FALSE);
+ CONTROL_DefineFlag(gamefunc_Strafe_Right, FALSE);
+ CONTROL_DefineFlag(gamefunc_Jump, FALSE);
+ CONTROL_DefineFlag(gamefunc_Crouch, FALSE);
+ CONTROL_DefineFlag(gamefunc_Fire, FALSE);
+ CONTROL_DefineFlag(gamefunc_Open, FALSE);
+ CONTROL_DefineFlag(gamefunc_Aim_Up, FALSE);
+ CONTROL_DefineFlag(gamefunc_Aim_Down, FALSE);
+ CONTROL_DefineFlag(gamefunc_Look_Up, FALSE);
+ CONTROL_DefineFlag(gamefunc_Look_Down, FALSE);
+ CONTROL_DefineFlag(gamefunc_Look_Straight, FALSE);
+ CONTROL_DefineFlag(gamefunc_Run, FALSE);
+ CONTROL_DefineFlag(gamefunc_SendMessage, FALSE);
+ CONTROL_DefineFlag(gamefunc_Weapon_1, FALSE);
+ CONTROL_DefineFlag(gamefunc_Weapon_2, FALSE);
+ CONTROL_DefineFlag(gamefunc_Weapon_3, FALSE);
+ CONTROL_DefineFlag(gamefunc_Weapon_4, FALSE);
+ CONTROL_DefineFlag(gamefunc_Weapon_5, FALSE);
+ CONTROL_DefineFlag(gamefunc_Weapon_6, FALSE);
+ CONTROL_DefineFlag(gamefunc_Weapon_7, FALSE);
+ CONTROL_DefineFlag(gamefunc_Pause, FALSE);
+ CONTROL_DefineFlag(gamefunc_Map, FALSE);
+ CONTROL_DefineFlag(gamefunc_Gamma_Correction, FALSE);
+ CONTROL_DefineFlag(gamefunc_Escape, FALSE);
+ CONTROL_DefineFlag(gamefunc_Shrink_Screen, FALSE);
+ CONTROL_DefineFlag(gamefunc_Enlarge_Screen, FALSE);
+ CONTROL_DefineFlag(gamefunc_Zoom_In, FALSE);
+ CONTROL_DefineFlag(gamefunc_Zoom_Out, FALSE);
+ CONTROL_DefineFlag(gamefunc_Inventory_Left, FALSE);
+ CONTROL_DefineFlag(gamefunc_Inventory_Right, FALSE);
+ CONTROL_DefineFlag(gamefunc_Mouseview, FALSE);
+ CONTROL_DefineFlag(gamefunc_Inventory, FALSE);
+ CONTROL_DefineFlag(gamefunc_Mouse_Sensitivity_Up, FALSE);
+ CONTROL_DefineFlag(gamefunc_Mouse_Sensitivity_Down, FALSE);
+}
+
+hashtable_t h_gamefuncs = { kMaxGameFunctions<<1, NULL };
+
+int32_t CONFIG_FunctionNameToNum(const char *func)
+{
+ if (!func)
+ return -1;
+
+ return hash_findcase(&h_gamefuncs, func);
+}
+
+
+static char const * CONFIG_FunctionNumToName(int32_t func)
+{
+ if ((unsigned)func >= (unsigned)kMaxGameFunctions)
+ return "";
+ return gamefunctions[func];
+}
+
+
+int32_t CONFIG_AnalogNameToNum(const char *func)
+{
+ if (!func)
+ return -1;
+ else if (!Bstrcasecmp(func, "analog_turning"))
+ return analog_turning;
+ else if (!Bstrcasecmp(func, "analog_strafing"))
+ return analog_strafing;
+ else if (!Bstrcasecmp(func, "analog_moving"))
+ return analog_moving;
+ else if (!Bstrcasecmp(func, "analog_lookingupanddown"))
+ return analog_lookingupanddown;
+ else
+ return -1;
+}
+
+
+static char const * CONFIG_AnalogNumToName(int32_t func)
+{
+ switch (func)
+ {
+ case analog_turning:
+ return "analog_turning";
+ case analog_strafing:
+ return "analog_strafing";
+ case analog_moving:
+ return "analog_moving";
+ case analog_lookingupanddown:
+ return "analog_lookingupanddown";
+ }
+
+ return "";
+}
+
+
+static void CONFIG_SetJoystickButtonFunction(int i, int j, int function)
+{
+ JoystickFunctions[i][j] = function;
+ CONTROL_MapButton(function, i, j, controldevice_joystick);
+}
+static void CONFIG_SetJoystickAnalogAxisScale(int i, int scale)
+{
+ JoystickAnalogueScale[i] = scale;
+ CONTROL_SetAnalogAxisScale(i, scale, controldevice_joystick);
+}
+static void CONFIG_SetJoystickAnalogAxisInvert(int i, int invert)
+{
+ JoystickAnalogueInvert[i] = invert;
+ CONTROL_SetAnalogAxisInvert(i, invert, controldevice_joystick);
+}
+static void CONFIG_SetJoystickAnalogAxisDeadSaturate(int i, int dead, int saturate)
+{
+ JoystickAnalogueDead[i] = dead;
+ JoystickAnalogueSaturate[i] = saturate;
+ joySetDeadZone(i, dead, saturate);
+}
+static void CONFIG_SetJoystickDigitalAxisFunction(int i, int j, int function)
+{
+ JoystickDigitalFunctions[i][j] = function;
+ CONTROL_MapDigitalAxis(i, function, j, controldevice_joystick);
+}
+static void CONFIG_SetJoystickAnalogAxisFunction(int i, int function)
+{
+ JoystickAnalogueAxes[i] = function;
+ CONTROL_MapAnalogAxis(i, function, controldevice_joystick);
+}
+
+
+void CONFIG_SetDefaultKeys(const char (*keyptr)[kMaxGameFunctions], bool lazy/*=false*/)
+{
+ static char const s_gamefunc_[] = "gamefunc_";
+ int constexpr strlen_gamefunc_ = ARRAY_SIZE(s_gamefunc_) - 1;
+
+ if (!lazy)
+ {
+ Bmemset(KeyboardKeys, 0xff, sizeof(KeyboardKeys));
+ CONTROL_ClearAllBinds();
+ }
+
+ for (int i=0; i < ARRAY_SSIZE(gamefunctions); ++i)
+ {
+ if (gamefunctions[i][0] == '\0')
+ continue;
+
+ auto &key = KeyboardKeys[i];
+
+ int const default0 = KB_StringToScanCode(keyptr[i<<1]);
+ int const default1 = KB_StringToScanCode(keyptr[(i<<1)+1]);
+
+ // skip the function if the default key is already used
+ // or the function is assigned to another key
+ if (lazy && (key[0] != 0xff || (CONTROL_KeyIsBound(default0) && Bstrlen(CONTROL_KeyBinds[default0].cmdstr) > strlen_gamefunc_
+ && CONFIG_FunctionNameToNum(CONTROL_KeyBinds[default0].cmdstr + strlen_gamefunc_) >= 0)))
+ {
+#if 0 // defined(DEBUGGINGAIDS)
+ if (key[0] != 0xff)
+ initprintf("Skipping %s bound to %s\n", keyptr[i<<1], CONTROL_KeyBinds[default0].cmdstr);
+#endif
+ continue;
+ }
+
+ key[0] = default0;
+ key[1] = default1;
+
+ if (key[0])
+ CONTROL_FreeKeyBind(key[0]);
+
+ if (key[1])
+ CONTROL_FreeKeyBind(key[1]);
+
+ if (i == gamefunc_Show_Console)
+ OSD_CaptureKey(key[0]);
+ else
+ CONFIG_MapKey(i, key[0], 0, key[1], 0);
+ }
+}
+
+void CONFIG_SetDefaults()
+{
+ FXVolume = 128;
+ MusicVolume = 128;
+ ReverseStereo = 0;
+ ControllerType = controltype_keyboardandmouse;
+ lMouseSens = 8;
+}
+
+int CONFIG_ReadSetup()
+{
+ char tempbuf[1024];
+
+ CONTROL_ClearAssignments();
+ CONFIG_SetDefaults();
+
+ setupread = 1;
+ pathsearchmode = 1;
+
+ if (scripthandle < 0)
+ {
+ if (buildvfs_exists(setupfilename)) // JBF 20031211
+ scripthandle = SCRIPT_Load(setupfilename);
+ else if (buildvfs_exists(kSetupFilename))
+ {
+ int const i = wm_ynbox("Import Configuration Settings",
+ "The configuration file \"%s\" was not found. "
+ "Import configuration data from \"%s\"?",
+ setupfilename, kSetupFilename);
+ if (i)
+ scripthandle = SCRIPT_Load(kSetupFilename);
+ }
+ }
+
+ pathsearchmode = 0;
+
+ if (scripthandle < 0)
+ return -1;
+
+ SCRIPT_GetNumber(scripthandle, "Setup", "ForceSetup", &gSetup.forcesetup);
+ SCRIPT_GetNumber(scripthandle, "Setup", "NoAutoLoad", &gSetup.noautoload);
+
+ int32_t cachesize;
+ SCRIPT_GetNumber(scripthandle, "Setup", "CacheSize", &cachesize);
+
+ if (cachesize > MAXCACHE1DSIZE)
+ MAXCACHE1DSIZE = cachesize;
+
+
+ // TODO:
+ if (/*g_noSetup == 0 && */g_modDir[0] == '/')
+ {
+ SCRIPT_GetString(scripthandle, "Setup","ModDir",&g_modDir[0]);
+
+ if (!buildvfs_isdir(g_modDir))
+ {
+ initprintf("Invalid mod dir in cfg!\n");
+ Bsprintf(g_modDir,"/");
+ }
+ }
+
+ windowx = -1;
+ windowy = -1;
+
+ SCRIPT_GetNumber(scripthandle, "Screen Setup", "MaxRefreshFreq", (int32_t *)&maxrefreshfreq);
+ SCRIPT_GetNumber(scripthandle, "Screen Setup", "ScreenBPP", &gSetup.bpp);
+ SCRIPT_GetNumber(scripthandle, "Screen Setup", "ScreenHeight", &gSetup.ydim);
+ SCRIPT_GetNumber(scripthandle, "Screen Setup", "ScreenMode", &gSetup.fullscreen);
+ SCRIPT_GetNumber(scripthandle, "Screen Setup", "ScreenWidth", &gSetup.xdim);
+ SCRIPT_GetNumber(scripthandle, "Screen Setup", "WindowPosX", (int32_t *)&windowx);
+ SCRIPT_GetNumber(scripthandle, "Screen Setup", "WindowPosY", (int32_t *)&windowy);
+ SCRIPT_GetNumber(scripthandle, "Screen Setup", "WindowPositioning", (int32_t *)&windowpos);
+
+ if (gSetup.bpp < 8) gSetup.bpp = 32;
+
+ setupread = 1;
+}
+
+
+void CONFIG_SetupMouse(void)
+{
+ if (scripthandle < 0)
+ return;
+
+ char str[80];
+ char temp[80];
+
+ for (int i=0; i
+#include
+#include
+
+// static long globhiz, globloz, globhihit, globlohit;
+
+
+void overwritesprite(long thex, long they, short tilenum, signed char shade, char stat, char dapalnum)
+{
+#if 0
+ rotatesprite(thex << 16, they << 16, 0x10000, (short)((flags & 8) << 7), tilenum, shade, dapalnum,
+ (char)(((flags & 1 ^ 1) << 4) + (flags & 2) + ((flags & 4) >> 2) + ((flags & 16) >> 2) ^ ((flags & 8) >> 1)),
+ windowx1, windowy1, windowx2, windowy2);
+#endif
+
+ rotatesprite(thex << 16, they << 16, 65536L, (stat & 8) << 7, tilenum, shade, dapalnum,
+ (((stat & 1) ^ 1) << 4) + (stat & 2) + ((stat & 4) >> 2) + (((stat & 16) >> 2) ^ ((stat & 8) >> 1)),
+ windowxy1.x, windowxy1.y, windowxy2.x, windowxy2.y);
+}
+
+void permanentwritesprite(long thex, long they, short tilenum, signed char shade, long cx1, long cy1, long cx2, long cy2, char dapalnum)
+{
+ rotatesprite(thex << 16, they << 16, 65536L, 0, tilenum, shade, dapalnum, 8 + 16, cx1, cy1, cx2, cy2);
+}
+
+void resettiming()
+{
+ numframes = 0L;
+ totalclock = 0L;
+// TODO totalclocklock = 0L;
+}
+
+void kensetpalette(unsigned char *vgapal)
+{
+ //setbrightness(0, (char*)vgapal, 4 | 2);
+ // TODO
+ Bmemcpy(palette, vgapal, 768);
+ videoSetPalette(0, 0, 4 | 2);
+#if 0
+ char vesapal[1024];
+
+ for(int i = 0; i < 256; i++)
+ {
+ vesapal[i*4+0] = vgapal[i*3+2];
+ vesapal[i*4+1] = vgapal[i*3+1];
+ vesapal[i*4+2] = vgapal[i*3+0];
+ vesapal[i*4+3] = 0;
+ }
+#ifndef __WATCOMC__
+ (0L, 256L, vesapal);
+#endif
+
+#endif
+}
+
+void printext(long x, long y, char *buffer, short tilenum, char invisiblecol)
+{
+ int i;
+ unsigned char ch;
+
+ for (i = 0; buffer[i] != 0; i++)
+ {
+ ch = (unsigned char)buffer[i];
+ rotatesprite((x - ((ch & 15) << 3)) << 16, (y - ((ch >> 4) << 3)) << 16, 65536L, 0, tilenum, 0, 0, 8 + 16 + 128, x, y, x + 7, y + 7);
+ x += 8;
+ }
+
+#if 0
+ long i;
+ char ch;
+
+ for(i=0;buffer[i]!=0;i++)
+ {
+ ch = buffer[i];
+ rotatesprite((x-((8&15)<<3))<<16,(y-((8>>4)<<3))<<16,65536L,0,tilenum,0,0,8+16+64+128,x,y,x+7,y+7);
+ rotatesprite((x-((ch&15)<<3))<<16,(y-((ch>>4)<<3))<<16,65536L,0,tilenum,0,0,8+16+128,x,y,x+7,y+7);
+ x += 8;
+ }
+#endif
+}
+
+void precache()
+{
+ int i;
+
+ for (i = 0; i < numsectors; i++)
+ {
+ short j = sector[i].ceilingpicnum;
+ if (waloff[j] == 0) tileLoad(j);
+ j = sector[i].floorpicnum;
+ if (waloff[j] == 0) tileLoad(j);
+ }
+
+ for (i = 0; i < numwalls; i++)
+ {
+ short j = wall[i].picnum;
+ if (waloff[j] == 0) tileLoad(j);
+ }
+
+ for (i = 0; i < kMaxSprites; i++)
+ {
+ if (sprite[i].statnum < kMaxStatus)
+ {
+ short j = sprite[i].picnum;
+ if (waloff[j] == 0) tileLoad(j);
+ }
+ }
+}
diff --git a/source/exhumed/src/exhumed.cpp b/source/exhumed/src/exhumed.cpp
new file mode 100644
index 000000000..325b1dec8
--- /dev/null
+++ b/source/exhumed/src/exhumed.cpp
@@ -0,0 +1,3737 @@
+
+#include "compat.h"
+#include "baselayer.h"
+#include "keyboard.h"
+#include "control.h"
+#include "typedefs.h"
+#include "engine.h"
+#include "exhumed.h"
+#include "map.h"
+#include "sequence.h"
+#include "movie.h"
+#include "names.h"
+#include "menu.h"
+#include "player.h"
+#include "network.h"
+#include "input.h"
+#include "sound.h"
+#include "cd.h"
+#include "view.h"
+#include "status.h"
+#include "config.h"
+#include "init.h"
+#include "ra.h"
+#include "version.h"
+#include "timer.h"
+#include "runlist.h"
+#include "anubis.h"
+#include "spider.h"
+#include "mummy.h"
+#include "fish.h"
+#include "lion.h"
+#include "light.h"
+#include "move.h"
+#include "lavadude.h"
+#include "rex.h"
+#include "set.h"
+#include "queen.h"
+#include "roach.h"
+#include "wasp.h"
+#include "scorp.h"
+#include "rat.h"
+#include "cdrom.h"
+#include "cdaudio.h"
+#include "serial.h"
+#include "network.h"
+#include "random.h"
+#include "items.h"
+#include "trigdat.h"
+#include "record.h"
+#include "lighting.h"
+#include
+#include // for printf
+#include
+#include
+#include
+#include
+#include
+
+void FinishLevel();
+
+int htimer = 0;
+
+/* these are XORed in the original game executable then XORed back to normal when the game first starts. Here they are normally */
+const char *gString[] =
+{
+ "CINEMAS",
+ "THE ANCIENT EGYPTIAN CITY",
+ "OF KARNAK HAS BEEN SEIZED",
+ "BY UNKNOWN POWERS, AND GREAT",
+ "TURMOIL IS SPREADING INTO",
+ "NEIGHBORING LANDS, POSING",
+ "A GRAVE THREAT TO PLANET",
+ "EARTH. MILITANT FORCES FROM",
+ "ALL PARTS OF THE GLOBE HAVE",
+ "ENTERED THE KARNAK VALLEY,",
+ "BUT NONE HAVE RETURNED. THE",
+ "ONLY KNOWN INFORMATION",
+ "REGARDING THIS CRISIS CAME",
+ "FROM A DYING KARNAK VILLAGER",
+ "WHO MANAGED TO WANDER OUT OF",
+ "THE VALLEY TO SAFETY.",
+ "'THEY'VE STOLEN THE GREAT",
+ "KING'S MUMMY...', MURMURED",
+ "THE DYING VILLAGER, BUT THE",
+ "VILLAGER DIED BEFORE HE",
+ "COULD SAY MORE. WITH NO",
+ "OTHER OPTIONS, WORLD",
+ "LEADERS HAVE CHOSEN TO DROP",
+ "YOU INTO THE VALLEY VIA",
+ "HELICOPTER IN AN ATTEMPT",
+ "TO FIND AND DESTROY THE",
+ "THREATENING FORCES AND",
+ "RESOLVE THE MYSTERY THAT",
+ "HAS ENGULFED THIS ONCE",
+ "PEACEFUL LAND. FLYING AT",
+ "HIGH ALTITUDE TO AVOID",
+ "BEING SHOT DOWN LIKE OTHERS",
+ "BEFORE YOU, YOUR COPTER",
+ "MYSTERIOUSLY EXPLODES IN THE",
+ "AIR AS YOU BARELY ESCAPE,",
+ "WITH NO POSSIBLE CONTACT",
+ "WITH THE OUTSIDE WORLD.",
+ "SCARED AS HELL, YOU DESCEND",
+ "INTO THE HEART OF KARNAK...",
+ "HOME TO THE CELEBRATED",
+ "BURIAL CRYPT OF THE GREAT",
+ "KING RAMSES.",
+ "END",
+ "AN EVIL FORCE KNOWN AS THE",
+ "KILMAAT HAS BESIEGED THE",
+ "SANCTITY OF MY PALACE AND",
+ "IS PULLING AT THE VERY",
+ "TENDRILS OF MY EXISTENCE.",
+ "THESE FORCES INTEND TO",
+ "ENSLAVE ME BY REANIMATING",
+ "MY PRESERVED CORPSE. I HAVE",
+ "PROTECTED MY CORPSE WITH A",
+ "GENETIC KEY. IF YOU ARE",
+ "UNSUCCESSFUL I CANNOT",
+ "PROTECT CIVILIZATION, AND",
+ "CHAOS WILL PREVAIL. I AM",
+ "BEING TORN BETWEEN WORLDS",
+ "AND THIS INSIDIOUS",
+ "EXPERIMENT MUST BE STOPPED.",
+ "END",
+ "I HAVE HIDDEN A MYSTICAL",
+ "GAUNTLET AT EL KAB THAT WILL",
+ "CHANNEL MY ENERGY THROUGH",
+ "YOUR HANDS. FIND THE",
+ "GAUNTLET AND CROSS THE ASWAN",
+ "HIGH DAM TO DEFEAT THE EVIL",
+ "BEAST SET.",
+ "END",
+ "SET WAS A FORMIDABLE FOE.",
+ "NO MORTAL HAS EVEN CONQUERED",
+ "THEIR OWN FEAR, MUCH LESS",
+ "ENTERED MORTAL BATTLE AND",
+ "TAKEN HIS LIFE.",
+ "END",
+ "YOU'VE MADE IT HALFWAY TOWARD",
+ "FULLFILLING YOUR DESTINY.",
+ "THE KILMAAT ARE GROWING",
+ "RESTLESS WITH YOUR PROGRESS.",
+ "SEEK OUT A TEMPLE IN THIS",
+ "CITADEL WHERE I WILL PROVIDE",
+ "MORE INFORMATION",
+ "END",
+ "THE KILMAAT RACE HAS",
+ "CONTINUED THEIR MONSTEROUS",
+ "ANIMAL-HUMAN EXPERIMENTS IN",
+ "AN EFFORT TO SOLVE THE KEY OF",
+ "ANIMATING MY CORPSE. THE",
+ "VICTORY DEFEATING SET DIDN'T",
+ "SLOW YOU DOWN AS MUCH AS",
+ "THEY HAD PLANNED. THEY ARE",
+ "ACTIVELY ROBBING A SLAVE",
+ "GIRL OF HER LIFE TO CREATE",
+ "ANOTHER MONSTEROUS",
+ "ABOMINATION, COMBINING HUMAN",
+ "AND INSECT INTENT ON SLAYING",
+ "YOU. PREPARE YOURSELF FOR",
+ "BATTLE AS SHE WILL BE WAITING",
+ "FOR YOU AT THE LUXOR TEMPLE. ",
+ "END",
+ "YOU'VE DONE WELL TO DEFEAT",
+ "SELKIS. YOU HAVE DISTRACTED",
+ "THE KILMAAT WITH YOUR",
+ "PRESENCE AND THEY HAVE",
+ "TEMPORARILY ABANDONED",
+ "ANIMATION OF MY CORPSE.",
+ "THE ALIEN QUEEN KILMAATIKHAN",
+ "HAS A PERSONAL VENDETTA",
+ "AGAINST YOU. ARROGANCE IS",
+ "HER WEAKNESS, AND IF YOU CAN",
+ "DEFEAT KILMAATIKHAN, THE",
+ "BATTLE WILL BE WON.",
+ "END",
+ "THE KILMAAT HAVE BEEN",
+ "DESTROYED. UNFORTUNATELY,",
+ "YOUR RECKLESSNESS HAS",
+ "DESTROYED THE EARTH AND ALL",
+ "OF ITS INHABITANTS. ALL THAT",
+ "REMAINS IS A SMOLDERING HUNK",
+ "OF ROCK.",
+ "END",
+ "THE KILMAAT HAVE BEEN",
+ "DEFEATED AND YOU SINGLE",
+ "HANDEDLY SAVED THE EARTH",
+ "FROM DESTRUCTION.",
+ " ",
+ " ",
+ " ",
+ "YOUR BRAVERY AND HEROISM",
+ "ARE LEGENDARY.",
+ "END",
+ "ITEMS",
+ "LIFE BLOOD",
+ "LIFE",
+ "VENOM",
+ "YOU'RE LOSING YOUR GRIP",
+ "FULL LIFE",
+ "INVINCIBILITY",
+ "INVISIBILITY",
+ "TORCH",
+ "SOBEK MASK",
+ "INCREASED WEAPON POWER!",
+ "THE MAP!",
+ "AN EXTRA LIFE!",
+ ".357 MAGNUM!",
+ "GRENADE",
+ "M-60",
+ "FLAME THROWER!",
+ "COBRA STAFF!",
+ "THE EYE OF RAH GAUNTLET!",
+ "SPEED LOADER",
+ "AMMO",
+ "FUEL",
+ "COBRA!",
+ "RAW ENERGY",
+ "POWER KEY",
+ "TIME KEY",
+ "WAR KEY",
+ "EARTH KEY",
+ "MAGIC",
+ "LOCATION PRESERVED",
+ "COPYRIGHT",
+ "LOBOTOMY SOFTWARE, INC.",
+ "3D ENGINE BY 3D REALMS",
+ "",
+ "LASTLEVEL",
+ "INCOMING MESSAGE",
+ "",
+ "OUR LATEST SCANS SHOW",
+ "THAT THE ALIEN CRAFT IS",
+ "POWERING UP, APPARENTLY",
+ "IN AN EFFORT TO LEAVE.",
+ "THE BAD NEWS IS THAT THEY",
+ "SEEM TO HAVE LEFT A DEVICE",
+ "BEHIND, AND ALL EVIDENCE",
+ "SAYS ITS GOING TO BLOW A",
+ "BIG HOLE IN OUR FINE PLANET.",
+ "A SQUAD IS TRYING TO DISMANTLE",
+ "IT RIGHT NOW, BUT NO LUCK SO",
+ "FAR, AND TIME IS RUNNING OUT.",
+ "",
+ "GET ABOARD THAT CRAFT NOW",
+ "BEFORE IT LEAVES, THEN FIND",
+ "AND SHOOT ALL THE ENERGY",
+ "TOWERS TO GAIN ACCESS TO THE",
+ "CONTROL ROOM. THERE YOU NEED TO",
+ "TAKE OUT THE CONTROL PANELS AND",
+ "THE CENTRAL POWER SOURCE. THIS",
+ "IS THE BIG ONE BUDDY, BEST OF",
+ "LUCK... FOR ALL OF US.",
+ "",
+ "",
+ "CREDITS",
+ "EXHUMED",
+ "",
+ "EXECUTIVE PRODUCERS",
+ " ",
+ "BRIAN MCNEELY",
+ "PAUL LANGE",
+ "",
+ "GAME CONCEPT",
+ " ",
+ "PAUL LANGE",
+ "",
+ "GAME DESIGN",
+ " ",
+ "BRIAN MCNEELY",
+ "",
+ "ADDITIONAL DESIGN",
+ " ",
+ "PAUL KNUTZEN",
+ "PAUL LANGE",
+ "JOHN VAN DEUSEN",
+ "KURT PFEIFER",
+ "DOMINICK MEISSNER",
+ "DANE EMERSON",
+ "",
+ "GAME PROGRAMMING",
+ " ",
+ "KURT PFEIFER",
+ "JOHN YUILL",
+ "",
+ "ADDITIONAL PROGRAMMING",
+ " ",
+ "PAUL HAUGERUD",
+ "",
+ "ADDITIONAL TECHNICAL SUPPORT",
+ " ",
+ "JOHN YUILL",
+ "PAUL HAUGERUD",
+ "JEFF BLAZIER",
+ "",
+ "LEVEL DESIGN",
+ " ",
+ "PAUL KNUTZEN",
+ "",
+ "ADDITIONAL LEVELS",
+ " ",
+ "BRIAN MCNEELY",
+ "",
+ "MONSTERS AND WEAPONS ",
+ " ",
+ "JOHN VAN DEUSEN",
+ "",
+ "ARTISTS",
+ " ",
+ "BRIAN MCNEELY",
+ "PAUL KNUTZEN",
+ "JOHN VAN DEUSEN",
+ "TROY JACOBSON",
+ "KEVIN CHUNG",
+ "ERIC KLOKSTAD",
+ "RICHARD NICHOLS",
+ "JOE KRESOJA",
+ "JASON WIGGIN",
+ "",
+ "MUSIC AND SOUND EFFECTS",
+ " ",
+ "SCOTT BRANSTON",
+ "",
+ "PRODUCT TESTING",
+ " ",
+ "DOMINICK MEISSNER",
+ "TOM KRISTENSEN",
+ "JASON WIGGIN",
+ "MARK COATES",
+ "",
+ "INSTRUCTION MANUAL",
+ " ",
+ "TOM KRISTENSEN",
+ "",
+ "SPECIAL THANKS",
+ " ",
+ "JACQUI LYONS",
+ "MARJACQ MICRO, LTD.",
+ "MIKE BROWN",
+ "IAN MATHIAS",
+ "CHERYL LUSCHEI",
+ "3D REALMS",
+ "KENNETH SILVERMAN",
+ "GREG MALONE",
+ "MILES DESIGN",
+ "REDMOND AM/PM MINI MART",
+ "7-11 DOUBLE GULP",
+ "",
+ "THANKS FOR PLAYING",
+ "",
+ "THE END",
+ "",
+ "GUESS YOURE STUCK HERE",
+ "UNTIL THE SONG ENDS",
+ "",
+ "MAYBE THIS IS A GOOD",
+ "TIME TO THINK ABOUT ALL",
+ "THE THINGS YOU CAN DO",
+ "AFTER THE MUSIC IS OVER.",
+ "",
+ "OR YOU COULD JUST STARE",
+ "AT THIS SCREEN",
+ "",
+ "AND WATCH THESE MESSAGES",
+ "GO BY...",
+ "",
+ "...AND WONDER JUST HOW LONG",
+ "WE WILL DRAG THIS OUT...",
+ "",
+ "AND BELIEVE ME, WE CAN DRAG",
+ "IT OUT FOR QUITE A WHILE.",
+ "",
+ "SHOULD BE OVER SOON...",
+ "",
+ "ANY MOMENT NOW...",
+ "",
+ " ",
+ "",
+ "SEE YA",
+ "",
+ "END",
+ "PASSWORDS",
+ "HOLLY",
+ "KIMBERLY",
+ "LOBOCOP",
+ "LOBODEITY",
+ "LOBOLITE",
+ "LOBOPICK",
+ "LOBOSLIP",
+ "LOBOSNAKE",
+ "LOBOSPHERE",
+ "LOBOSWAG",
+ "LOBOXY",
+ "",
+ "PASSINFO",
+ "",
+ "HI SWEETIE, I LOVE YOU",
+ "",
+ "",
+ "SNAKE CAM ENABLED",
+ "FLASHES TOGGLED",
+ "FULL MAP",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "EOF",
+ "",
+};
+
+static char g_rootDir[BMAX_PATH];
+char g_modDir[BMAX_PATH] = "/";
+
+buildvfs_kfd kopen4loadfrommod(const char *fileName, char searchfirst)
+{
+ buildvfs_kfd kFile = buildvfs_kfd_invalid;
+
+ if (g_modDir[0] != '/' || g_modDir[1] != 0)
+ {
+ static char staticFileName[BMAX_PATH];
+ Bsnprintf(staticFileName, sizeof(staticFileName), "%s/%s", g_modDir, fileName);
+ kFile = kopen4load(staticFileName, searchfirst);
+ }
+
+ return (kFile == buildvfs_kfd_invalid) ? kopen4load(fileName, searchfirst) : kFile;
+}
+
+int g_useCwd;
+
+#define kSpiritX = 106;
+#define kSpiritY = 97;
+
+short cPupData[300];
+//int worktile[97 * 106] = { 0 };
+uchar worktile[(97*2) * (106*2)] = { 0 };
+int lHeadStartClock;
+short *pPupData;
+int lNextStateChange;
+int nPixels;
+int nHeadTimeStart;
+short curx[97 * 106];
+short cury[97 * 106];
+schar destvelx[97 * 106];
+schar destvely[97 * 106];
+uchar pixelval[97 * 106];
+schar origy[97 * 106];
+schar origx[97 * 106];
+schar velx[97 * 106];
+schar vely[97 * 106];
+short nMouthTile;
+
+short nPupData = 0;
+int headfd = -1;
+
+short word_964E8 = 0;
+short word_964EA = 0;
+short word_964EC = 10;
+
+short nSpiritRepeatX;
+short nSpiritRepeatY;
+short nPixelsToShow;
+
+void CopyTileToBitmap(short nSrcTile, short nDestTile, int xPos, int yPos);
+void DoTitle();
+
+// void TestSaveLoad();
+void EraseScreen(int nVal);
+void LoadStatus();
+int FindGString(const char *str);
+void MySetView(int x1, int y1, int x2, int y2);
+void mysetbrightness(char al);
+void FadeIn();
+
+char sHollyStr[40];
+
+short nFontFirstChar;
+short nBackgroundPic;
+short nShadowPic;
+
+short nCreaturesLeft = 0;
+short bNoSound = kFalse;
+
+short nFreeze;
+short bFullScreen;
+
+short nSnakeCam = -1;
+
+short nBestLevel;
+short nSpiritSprite;
+
+short nLocalSpr;
+short levelnew = 1;
+
+int nNetPlayerCount = 0;
+
+short nClockVal;
+short fps;
+short nRedTicks;
+short lastlevel;
+short bInMove;
+short nAlarmTicks;
+short nButtonColor;
+short nEnergyChan;
+
+
+short bSerialPlay = kFalse;
+short bModemPlay = kFalse;
+int lCountDown = 0;
+short nEnergyTowers = 0;
+
+
+short nHeadStage;
+
+short nCfgNetPlayers = 0;
+FILE *vcrfp = NULL;
+short nTalkTime = 0;
+
+short forcelevel = -1;
+
+int lLocalButtons = 0;
+int lLocalCodes = 0;
+
+short bHiRes = kFalse;
+short bCoordinates = kFalse;
+
+short bNoCDCheck = kFalse;
+int nNetTime = -1;
+
+short nCodeMin = 0;
+short nCodeMax = 0;
+short nCodeIndex = 0;
+
+short levelnum = -1;
+short nScreenWidth = 320;
+short nScreenHeight = 200;
+int moveframes;
+int flash;
+int localclock;
+int totalmoves;
+
+short nCurBodyNum = 0;
+
+short nBodyTotal = 0;
+
+
+short textpages;
+
+short nCDTrackLength = 0;
+
+short lastfps;
+
+short nCDTracks = 0;
+
+short bMapMode = kFalse;
+short bNoCreatures = kFalse;
+
+short nTotalPlayers = 1;
+short socket = 0;
+
+short nFirstPassword = 0;
+short nFirstPassInfo = 0;
+short nPasswordCount = 0;
+
+short word_964B0 = 0;
+
+short word_9AC30 = 0;
+
+short word_96E3C = 0;
+short word_96E3E = -1;
+short word_96E40 = 0;
+
+short nGamma = 0;
+
+short word_CB326;
+
+short screenpage;
+
+short screensize;
+
+short barpages;
+
+short bSnakeCam = kFalse;
+short bRecord = kFalse;
+short bPlayback = kFalse;
+short bPause = kFalse;
+short bInDemo = kFalse;
+short bSlipMode = kFalse;
+short bDoFlashes = kTrue;
+short bHolly = kFalse;
+
+short nItemTextIndex;
+
+short scan_char = 0;
+
+int nStartLevel;
+int nTimeLimit;
+
+char debugBuffer[256];
+
+short wConsoleNode; // TODO - move me into network file
+
+
+void DebugOut(const char *fmt, ...)
+{
+#ifdef _DEBUG
+ va_list args;
+ va_start(args, fmt);
+
+ debugBuffer[0] = '\0';
+
+ vsprintf(debugBuffer, fmt, args);
+
+ printf("%s", debugBuffer);
+ fflush(stdout);
+
+ va_end(args);
+#endif
+}
+
+void bail2dos(const char *fmt, ...)
+{
+ char buf[256];
+
+#ifdef __WATCOMC__
+ setvmode(3);
+#endif
+
+ printf("bailed to dos\n");
+
+ va_list args;
+ va_start(args, fmt);
+
+ vsprintf(buf, fmt, args);
+
+ va_end(args);
+
+ printf(buf);
+
+ StopCD();
+ if (bSerialPlay)
+ {
+ if (bModemPlay) {
+ HangUp();
+ }
+ UnInitSerial();
+ }
+
+ KB_Shutdown();
+ RemoveEngine();
+ UnInitNet();
+ UnInitFX();
+
+ exit(0);
+}
+
+#ifdef __WATCOMC__
+void __interrupt __far timerhandler()
+#else
+void timerhandler()
+#endif
+{
+#ifdef __WATCOMC__
+ totalclock++;
+#endif
+
+ if (!(totalclock & 3) && !bInMove && moveframes < 4) {
+ moveframes++;
+ }
+
+ PlayerInterruptKeys();
+
+ scan_char++;
+ if (scan_char == kTimerTicks)
+ {
+ scan_char = 0;
+ lastfps = fps;
+ fps = 0;
+
+ if (nCDTrackLength > 0) {
+ nCDTrackLength--;
+ }
+ }
+}
+
+int MyGetStringWidth(const char *str)
+{
+ int nLen = strlen(str);
+
+ int nWidth = 0;
+
+ for (int i = 0; i < nLen; i++)
+ {
+ int nPic = seq_GetSeqPicnum(kSeqFont2, 0, str[i] - 32);
+ nWidth += tilesiz[nPic].x + 1;
+ }
+
+ return nWidth;
+}
+
+void UpdateScreenSize()
+{
+ int v0 = ydim * screensize / xdim;
+ int y1 = ((ydim >> 1) - (v0 >> 1));
+
+ MySetView(
+ (xdim >> 1) - (screensize >> 1),
+ y1,
+ (xdim >> 1) - (screensize >> 1) + screensize - 1,
+ (y1 + v0 - 1));
+
+ screenpage = (short)numpages;
+
+ RefreshStatus();
+}
+
+void ResetPassword()
+{
+ nCodeMin = nFirstPassword;
+ nCodeIndex = 0;
+
+ nCodeMax = (nFirstPassword + nPasswordCount) - 1;
+}
+
+void DoPassword(int nPassword)
+{
+ if (nNetPlayerCount) {
+ return;
+ }
+
+ const char *str = gString[nFirstPassInfo + nPassword];
+
+ if (str[0] != '\0') {
+ StatusMessage(750, str);
+ }
+
+ switch (nPassword)
+ {
+ case 0:
+ {
+ if (!nNetPlayerCount) {
+ bHolly = kTrue;
+ }
+ break;
+ }
+
+ case 2: // LOBOCOP
+ {
+ lLocalCodes |= 0x20;
+ break;
+ }
+
+ case 3: // LOBODEITY
+ {
+ lLocalCodes |= 0x40;
+ break;
+ }
+
+ case 4:
+ {
+ if (bDoFlashes == kFalse) {
+ bDoFlashes = kTrue;
+ }
+ else {
+ bDoFlashes = kFalse;
+ }
+ break;
+ }
+
+ case 5:
+ {
+ lLocalCodes |= 0x80;
+ break;
+ }
+
+ case 6:
+ {
+ if (!nNetPlayerCount)
+ {
+ if (bSlipMode == kFalse)
+ {
+ bSlipMode = kTrue;
+ StatusMessage(300, "Slip mode %s", "ON");
+ }
+ else {
+ bSlipMode = kFalse;
+ StatusMessage(300, "Slip mode %s", "OFF");
+ }
+ }
+ break;
+ }
+
+ case 7:
+ {
+ if (!nNetPlayerCount)
+ {
+ if (bSnakeCam == kFalse) {
+ bSnakeCam = kTrue;
+ }
+ else {
+ bSnakeCam = kFalse;
+ }
+ }
+ break;
+ }
+
+ case 8:
+ {
+ GrabMap();
+ bShowTowers = kTrue;
+ break;
+ }
+
+ case 9:
+ {
+ lLocalCodes |= 0x100; // LOBOSWAG?
+ break;
+ }
+
+ case 10:
+ {
+ if (bCoordinates == kFalse) {
+ bCoordinates = kTrue;
+ }
+ else {
+ bCoordinates = kFalse;
+ }
+ break;
+ }
+
+ default:
+ return;
+ }
+}
+
+void mysetbrightness(char nBrightness)
+{
+ g_visibility = 2048 - (nBrightness << 9);
+}
+
+void CheckKeys()
+{
+ int eax;
+
+ if (BUTTON(gamefunc_Enlarge_Screen))
+ {
+ if (bHiRes) {
+ eax = 32;
+ }
+ else {
+ eax = 16;
+ }
+
+ if (screensize == xdim)
+ {
+ if (!bFullScreen)
+ {
+ bFullScreen = kTrue;
+ UnMaskStatus();
+ }
+ }
+ else
+ {
+ screensize += eax;
+ if (screensize > xdim) {
+ screensize = xdim;
+ }
+
+ UpdateScreenSize();
+ }
+ CONTROL_ClearButton(gamefunc_Enlarge_Screen);
+ }
+
+ if (BUTTON(gamefunc_Mouse_Sensitivity_Up))
+ {
+ if (lMouseSens < 64)
+ lMouseSens++;
+
+ CONTROL_ClearButton(gamefunc_Mouse_Sensitivity_Up);
+ StatusMessage(500, "MOUSE SENSITIVITY SET TO %d", lMouseSens);
+ }
+ else
+ {
+ if (BUTTON(gamefunc_Mouse_Sensitivity_Down))
+ {
+ if (lMouseSens >= 1)
+ lMouseSens -= 1;
+
+ CONTROL_ClearButton(gamefunc_Mouse_Sensitivity_Down);
+ StatusMessage(500, "MOUSE SENSITIVITY SET TO %d", lMouseSens);
+ }
+ }
+
+ // F11?
+ if (BUTTON(gamefunc_Gamma_Correction))
+ {
+ nGamma++;
+
+ if (nGamma > 4)
+ nGamma = 0;
+
+ mysetbrightness((uchar)nGamma);
+ CONTROL_ClearButton(gamefunc_Gamma_Correction);
+ }
+
+ if (BUTTON(gamefunc_Shrink_Screen))
+ {
+ if (bHiRes)
+ eax = 32;
+ else
+ eax = 16;
+
+ if (bFullScreen)
+ {
+ bFullScreen = kFalse;
+ }
+ else
+ {
+ if ((screensize - eax) > (xdim >> 2))
+ screensize -= eax;
+ }
+
+ UpdateScreenSize();
+ CONTROL_ClearButton(gamefunc_Shrink_Screen);
+ }
+
+ // print version string?
+ if (KB_KeyDown[sc_V] && KB_KeyDown[sc_LeftAlt])
+ {
+ KB_KeyDown[sc_V] = 0;
+ StatusMessage(300, versionstr);
+ return;
+ }
+
+ // go to 3rd person view?
+ if (KB_KeyDown[sc_C] && KB_KeyDown[sc_LeftAlt])
+ {
+ if (!nFreeze)
+ {
+ if (bCamera) {
+ bCamera = kFalse;
+ }
+ else {
+ bCamera = kTrue;
+ }
+
+ if (bCamera)
+ GrabPalette();
+ }
+ KB_KeyDown[sc_C] = 0;
+ return;
+ }
+
+ if (KB_KeyDown[sc_Pause])
+ {
+ if (!nNetPlayerCount)
+ {
+ if (bPause)
+ {
+ bPause = kFalse;
+ KB_KeyDown[sc_Pause] = 0;
+ }
+ else
+ {
+ bPause = kTrue;
+ NoClip();
+ int nLen = MyGetStringWidth("PAUSED");
+ myprintext((320 - nLen) / 2, 100, "PAUSED", 0);
+ Clip();
+ videoNextPage();
+ }
+ }
+ return;
+ }
+
+ // Handle cheat codes
+ if (!bInDemo && KB_KeyWaiting())
+ {
+ char ch = KB_GetCh();
+
+ if (bHolly)
+ {
+ if (ch)
+ {
+ int nStringLen = strlen(sHollyStr);
+
+ if (ch == asc_Enter)
+ {
+ char *pToken = strtok(sHollyStr, " ");
+
+ // move player to X, Y coordinates
+ if (!strcmp(pToken, "GOTO"))
+ {
+ int nSprite = PlayerList[0].nSprite;
+
+ pToken = strtok(NULL, ",");
+ sprite[nSprite].x = atoi(pToken);
+ pToken = strtok(NULL, ",");
+ sprite[nSprite].y = atoi(pToken);
+
+ setsprite(nSprite, &sprite[nSprite].pos);
+ sprite[nSprite].z = sector[sprite[nSprite].sectnum].floorz;
+ }
+ else if (!strcmp(pToken, "LEVEL"))
+ {
+ pToken = strtok(NULL, " ");
+ levelnew = atoi(pToken);
+ }
+ else if (!strcmp(pToken, "DOORS"))
+ {
+ for (int i = 0; i < kMaxChannels; i++)
+ {
+ // CHECKME - does this toggle?
+ if (sRunChannels[i].c == 0) {
+ runlist_ChangeChannel(i, 1);
+ }
+ else {
+ runlist_ChangeChannel(i, 0);
+ }
+ }
+ }
+ else if (!strcmp(pToken, "EXIT"))
+ {
+ FinishLevel();
+ }
+ else if (!strcmp(pToken, "CREATURE"))
+ {
+ // i = nNetPlayerCount;
+ if (!nNetPlayerCount)
+ {
+ pToken = strtok(NULL, " ");
+ switch (atoi(pToken))
+ {
+ // TODO - enums?
+ case 0:
+ BuildAnubis(-1, initx, inity, sector[initsect].floorz, initsect, inita, kFalse);
+ break;
+ case 1:
+ BuildSpider(-1, initx, inity, sector[initsect].floorz, initsect, inita);
+ break;
+ case 2:
+ BuildMummy(-1, initx, inity, sector[initsect].floorz, initsect, inita);
+ break;
+ case 3:
+ BuildFish(-1, initx, inity, initz + eyelevel[nLocalPlayer], initsect, inita);
+ break;
+ case 4:
+ BuildLion(-1, initx, inity, sector[initsect].floorz, initsect, inita);
+ break;
+ case 5:
+ BuildLava(-1, initx, inity, sector[initsect].floorz, initsect, inita, nNetPlayerCount);
+ break;
+ case 6:
+ BuildRex(-1, initx, inity, sector[initsect].floorz, initsect, inita, nNetPlayerCount);
+ break;
+ case 7:
+ BuildSet(-1, initx, inity, sector[initsect].floorz, initsect, inita, nNetPlayerCount);
+ break;
+ case 8:
+ BuildQueen(-1, initx, inity, sector[initsect].floorz, initsect, inita, nNetPlayerCount);
+ break;
+ case 9:
+ BuildRoach(0, -1, initx, inity, sector[initsect].floorz, initsect, inita);
+ break;
+ case 10:
+ BuildRoach(1, -1, initx, inity, sector[initsect].floorz, initsect, inita);
+ break;
+ case 11:
+ BuildWasp(-1, initx, inity, sector[initsect].floorz - 25600, initsect, inita);
+ break;
+ case 12:
+ BuildScorp(-1, initx, inity, sector[initsect].floorz, initsect, inita, nNetPlayerCount);
+ break;
+ case 13:
+ BuildRat(-1, initx, inity, sector[initsect].floorz, initsect, inita);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (nStringLen == 0)
+ {
+ bHolly = kFalse;
+ StatusMessage(1, " ");
+ }
+ else
+ {
+ for (int i = 0; i < nPasswordCount; ++i)
+ {
+ if (!strcmp(sHollyStr, gString[i + nFirstPassword]))
+ {
+ DoPassword(i);
+ break;
+ }
+ }
+ }
+ }
+ sHollyStr[0] = '\0';
+ }
+ else if (ch == asc_BackSpace)
+ {
+ if (nStringLen != 0) {
+ sHollyStr[nStringLen - 1] = '\0';
+ }
+ }
+ else if (nStringLen < (sizeof(sHollyStr) - 1)) // do we have room to add a char and null terminator?
+ {
+ sHollyStr[nStringLen] = toupper(ch);
+ sHollyStr[nStringLen + 1] = '\0';
+ }
+ }
+ else
+ {
+ KB_GetCh();
+ }
+ }
+
+ if (isalpha(ch))
+ {
+ ch = toupper(ch);
+
+ int ecx = nCodeMin;
+
+ int ebx = nCodeMin;
+ int edx = nCodeMin - 1;
+
+ while (ebx <= nCodeMax)
+ {
+ if (ch == gString[ecx][nCodeIndex])
+ {
+ nCodeMin = ebx;
+ nCodeIndex++;
+
+ if (gString[ecx][nCodeIndex] == 0)
+ {
+ ebx -= nFirstPassword;
+
+ DoPassword(ebx);
+ ResetPassword();
+ }
+
+ break;
+ }
+ else if (gString[ecx][nCodeIndex] < ch)
+ {
+ nCodeMin = ebx + 1;
+ }
+ else if (gString[ecx][nCodeIndex] > ch)
+ {
+ nCodeMax = edx;
+ }
+
+ ecx++;
+ edx++;
+ ebx++;
+ }
+
+ if (nCodeMin > nCodeMax) {
+ ResetPassword();
+ }
+ }
+ }
+}
+
+void DoCredits()
+{
+ NoClip();
+
+ playCDtrack(19);
+
+ int var_20 = 0;
+
+ FadeOut(0);
+
+ int nCreditsIndex = FindGString("CREDITS");
+
+ while (strcmp(gString[nCreditsIndex], "END") != 0)
+ {
+ EraseScreen(overscanindex);
+
+ int nStart = nCreditsIndex;
+
+ // skip blanks
+ while (strlen(gString[nCreditsIndex]) != 0) {
+ nCreditsIndex++;
+ }
+
+ // vars
+ int eax = (10 * (nCreditsIndex - nStart - 1)) / 2;
+
+ if (eax < 0) {
+ eax++;
+ }
+
+ eax >>= 1;
+
+ int y = 100 - eax;
+
+ int edi = nStart;
+
+
+ for (int i = nStart; i < nCreditsIndex; i++)
+ {
+ // var 24 ==
+
+ int nWidth = MyGetStringWidth(gString[edi]);
+ myprintext((320 - nWidth) / 2, y, gString[edi], 0);
+
+ edi++;
+ y += 10;
+ }
+
+ videoNextPage();
+ FadeIn();
+
+ while (totalclock + 600 > totalclock)
+ {
+ if (KB_KeyDown[sc_F12])
+ {
+ var_20++;
+
+ KB_KeyDown[sc_F12] = 0;
+
+ if (var_20 > 5) {
+ return;
+ }
+ }
+ }
+
+ FadeOut(0);
+ }
+
+ while (CDplaying())
+ {
+ if (KB_KeyWaiting()) {
+ KB_GetCh();
+ }
+ }
+
+ Clip();
+}
+
+void FinishLevel()
+{
+ if (levelnum > nBestLevel) {
+ nBestLevel = levelnum - 1;
+ }
+
+ levelnew = levelnum + 1;
+
+ StopAllSounds();
+
+ bCamera = kFalse;
+ bMapMode = kFalse;
+
+ if (levelnum != kMap20)
+ {
+ EraseScreen(4);
+ SetLocalChan(1);
+ PlayLocalSound(StaticSound[59], 0);
+ videoNextPage();
+ WaitTicks(12);
+ WaitVBL();
+ RefreshBackground();
+ RefreshStatus();
+ DrawView();
+ videoNextPage();
+ }
+
+ FadeOut(1);
+ EraseScreen(overscanindex);
+
+ if (levelnum == 0)
+ {
+ nPlayerLives[0] = 0;
+ levelnew = 100;
+ }
+ else
+ {
+ DoAfterCinemaScene(levelnum);
+ if (levelnum == kMap20)
+ {
+ DoCredits();
+ nPlayerLives[0] = 0;
+ }
+ }
+}
+
+void WritePlaybackInputs()
+{
+ fwrite(&moveframes, sizeof(moveframes), 1, vcrfp);
+ fwrite(&sPlayerInput[nLocalPlayer], sizeof(PlayerInput), 1, vcrfp);
+}
+
+BOOL ReadPlaybackInputs()
+{
+ assert(sizeof(PlayerInput) == 32);
+
+ if (fread(&moveframes, 1, sizeof(moveframes), vcrfp))
+ {
+#if 0
+ fread(&sPlayerInput[nLocalPlayer], 1, sizeof(PlayerInput), vcrfp);
+#else
+ /*
+ struct PlayerInput
+ {
+ int xVel;
+ int yVel;
+ short nAngle;
+ short buttons;
+ short nTarget;
+ char horizon;
+ schar nItem;
+ int h;
+ char i;
+ char field_15[11];
+ };
+ */
+ fread(&sPlayerInput[nLocalPlayer].xVel, 1, sizeof(sPlayerInput[nLocalPlayer].xVel), vcrfp);
+ fread(&sPlayerInput[nLocalPlayer].yVel, 1, sizeof(sPlayerInput[nLocalPlayer].yVel), vcrfp);
+ fread(&sPlayerInput[nLocalPlayer].nAngle, 1, sizeof(sPlayerInput[nLocalPlayer].nAngle), vcrfp);
+ fread(&sPlayerInput[nLocalPlayer].buttons, 1, sizeof(sPlayerInput[nLocalPlayer].buttons), vcrfp);
+ fread(&sPlayerInput[nLocalPlayer].nTarget, 1, sizeof(sPlayerInput[nLocalPlayer].nTarget), vcrfp);
+ fread(&sPlayerInput[nLocalPlayer].horizon, 1, sizeof(sPlayerInput[nLocalPlayer].horizon), vcrfp);
+ fread(&sPlayerInput[nLocalPlayer].nItem, 1, sizeof(sPlayerInput[nLocalPlayer].nItem), vcrfp);
+ fread(&sPlayerInput[nLocalPlayer].h, 1, sizeof(sPlayerInput[nLocalPlayer].h), vcrfp);
+ fread(&sPlayerInput[nLocalPlayer].i, 1, sizeof(sPlayerInput[nLocalPlayer].i), vcrfp);
+
+ // skip pad
+ fseek(vcrfp, 11, SEEK_CUR);
+
+
+#endif
+ besttarget = sPlayerInput[nLocalPlayer].nTarget;
+ Ra[nLocalPlayer].nTarget = besttarget;
+ return kTrue;
+ }
+ else
+ {
+ fclose(vcrfp);
+ vcrfp = NULL;
+ bPlayback = kFalse;
+ return kFalse;
+ }
+}
+
+void SetHiRes()
+{
+ nScreenWidth = 640;
+ nScreenHeight = 400;
+ bHiRes = kTrue;
+}
+
+void DoClockBeep()
+{
+ for (int i = headspritestat[407]; i != -1; i = nextspritestat[i]) {
+// TODO PlayFX2(StaticSound[kSound74], i);
+ }
+}
+
+void DoRedAlert(int nVal)
+{
+ if (nVal)
+ {
+ nAlarmTicks = 69;
+ nRedTicks = 30;
+ }
+
+ for (int i = headspritestat[405]; i != -1; i = nextspritestat[i])
+ {
+ if (nVal)
+ {
+// TODO PlayFXAtXYZ(StaticSound[kSoundAlarm], sprite[i].x, sprite[i].y, sprite[i].z, sprite[i].sectnum);
+ AddFlash(sprite[i].sectnum, sprite[i].x, sprite[i].y, sprite[i].z, 192);
+ }
+ }
+}
+
+void LockEnergyTiles()
+{
+ // old loadtilelockmode = 1;
+ tileLoad(kTile3603);
+ tileLoad(kEnergy1);
+ tileLoad(kEnergy2);
+ // old loadtilelockmode = 0;
+}
+
+void DrawClock()
+{
+ int ebp = 49;
+
+ tileLoad(kTile3603);
+
+ nRedTicks = 0;
+ memset((void*)waloff[kTile3603], -1, 4096);
+
+ if (lCountDown / 30 != nClockVal)
+ {
+ nClockVal = lCountDown / 30;
+ DoClockBeep();
+ }
+
+ int nVal = nClockVal;
+
+ while (nVal)
+ {
+ int v2 = nVal & 0xF;
+ int yPos = 32 - tilesiz[v2 + kTile3606].y / 2;
+
+ CopyTileToBitmap(v2 + kTile3606, kTile3603, ebp - tilesiz[v2 + kTile3606].x / 2, yPos);
+
+ ebp -= 15;
+
+ nVal /= 16;
+ }
+
+ DoEnergyTile();
+}
+
+int ExhumedMain(int argc, char *argv[])
+{
+ int i;
+
+ int esi = 1;
+ int edi = esi;
+
+ // REVERT - change back to kTrue
+// short bDoTitle = kFalse;
+
+ wConsoleNode = 0;
+ int var_1C = 0;
+
+ int nMenu; // TEMP
+
+ // Check for any command line arguments
+ for (i = 1; i < argc; i++)
+ {
+ char *pChar = argv[i];
+
+ if (*pChar == '/')
+ {
+ pChar++;
+ strlwr(pChar);
+
+ if (strcmp(pChar, "nocreatures") == 0) {
+ bNoCreatures = kTrue;
+ }
+ else if (strcmp(pChar, "nosound") == 0) {
+ bNoSound = kTrue;
+ }
+ else if (strcmp(pChar, "record") == 0)
+ {
+ if (!bPlayback)
+ {
+ vcrfp = fopen("data.vcr", "wb+");
+ if (vcrfp != NULL) {
+ bRecord = kTrue;
+ }
+ else {
+ DebugOut("Can't open data file for recording\n");
+ }
+ }
+ }
+ else if (strcmp(pChar, "playback") == 0)
+ {
+ if (!bRecord)
+ {
+ vcrfp = fopen("data.vcr", "rb");
+ if (vcrfp != NULL) {
+ bPlayback = kTrue;
+ esi = 0;
+ }
+ else {
+ DebugOut("Can't open data file 'data.vcr' for reading\n");
+ }
+ }
+ }
+ else if (strncmp(pChar, "null", 4) == 0)
+ {
+ pChar += 4;
+
+ bSerialPlay = kTrue;
+ nNetPlayerCount = 1;
+ nTotalPlayers = 2;
+
+ esi = 0;
+
+ char ch = *pChar;
+
+ // bjd - unused/unfished code in original .exe?
+ switch (ch - 1)
+ {
+ default:
+ break;
+
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ break;
+ }
+
+ if (forcelevel < 0)
+ {
+ forcelevel = levelnew;
+ }
+ }
+ else if (strcmp(pChar, "modem") == 0)
+ {
+ bModemPlay = kTrue;
+ bSerialPlay = kTrue;
+ nNetPlayerCount = 1;
+ nTotalPlayers = 2;
+
+ esi = 0;
+
+ if (forcelevel < 0) {
+ forcelevel = levelnew;
+ }
+ }
+ else if (strcmp(pChar, "network") == 0)
+ {
+ nNetPlayerCount = -1;
+ forcelevel = levelnew;
+ bModemPlay = kFalse;
+ bSerialPlay = kFalse;
+
+ esi = 0;
+ }
+ else
+ {
+ char c = tolower(*pChar);
+
+ switch (c)
+ {
+ case 'h':
+ SetHiRes();
+ break;
+ case 's':
+ socket = atoi(pChar + 1);
+ break;
+ case 't':
+ nNetTime = atoi(pChar + 1);
+ if (nNetTime < 0) {
+ nNetTime = 0;
+ }
+ else {
+ nNetTime = nNetTime * 1800;
+ }
+ break;
+ case 'c':
+ {
+ // CHANGEME? - make this a strcmp. this is how the original does it though...
+ if (pChar[1] == 'd' && pChar[2] == 'o' && pChar[3] == 'f' && pChar[4] == 'f') {
+ bNoCDCheck = kTrue;
+ }
+ }
+ default:
+ {
+ if (isdigit(c))
+ {
+ levelnew = atoi(pChar);
+ forcelevel = levelnew;
+
+ esi = 0;
+
+ printf("Jumping to level %d...\n", levelnew);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (nNetPlayerCount && forcelevel == -1) {
+ forcelevel = 1;
+ }
+
+ // Decrypt strings code would normally be here
+#if 0
+
+ for (int i = 0; ; i++)
+ {
+ int j = i - 1;
+
+ while (j >= 0)
+ {
+ if (gString_Enc[i] == gString_Enc[j]) {
+ break;
+ }
+
+ j--;
+ }
+
+ if (j < 0)
+ {
+ int k = 0;
+
+ while (1)
+ {
+ uchar v27 = gString_Enc[i + k];
+ if (v27)
+ {
+ gString_Enc[i + k] = v27 ^ 0xFF;
+
+ k++;
+ }
+ else {
+ break;
+ }
+
+
+ }
+
+// strupr(gString[j]);
+
+ int blah = 123;
+// if (!strcmp(*(char **)((char *)gString + v29), "EOF", v27, v30))
+// break;
+ }
+ }
+#endif
+
+ // loc_115F5:
+ nItemTextIndex = FindGString("ITEMS");
+ nFirstPassword = FindGString("PASSWORDS");
+ nFirstPassInfo = FindGString("PASSINFO");
+
+ // count the number of passwords available
+ for (nPasswordCount = 0; ; nPasswordCount++)
+ {
+#if 0
+ char *pStr = gString[nFirstPassword + nPasswordCount];
+ int nLen = strlen(pStr);
+
+ if (!nLen) {
+ break;
+ }
+#else
+ /* note - can't make sense of what the code is doing but i've added the below breakout code which seems sensible.. */
+
+ // int v32 = (int)&v31[v33];
+ // if (c == 1)
+ // break;
+ if (nFirstPassword + nPasswordCount >= nFirstPassInfo - 1) {
+ break;
+ }
+#endif
+ }
+
+ ResetPassword();
+ nCDTracks = initcdaudio();
+
+ GetCurPal(NULL);
+
+ LoadConfig();
+
+ if (nNetPlayerCount == -1)
+ {
+ nNetPlayerCount = nCfgNetPlayers - 1;
+ nTotalPlayers += nNetPlayerCount;
+ }
+
+ // loc_116A5:
+ InitFX();
+
+ if (nNetPlayerCount)
+ {
+ InitInput();
+ forcelevel = nStartLevel;
+ nNetTime = 1800 * nTimeLimit;
+
+ if (nNetTime == 0) {
+ nNetTime = -1;
+ }
+
+ int nWaitTicks = 0;
+
+ if (!bSerialPlay)
+ {
+ if (InitNet(socket, nTotalPlayers))
+ {
+ DebugOut("Found network players!\n");
+ nWaitTicks = 30;
+ }
+ else
+ {
+ AbortNetworkPlay();
+ DebugOut("Network play aborted\n");
+ printf("Network play aborted\n");
+ nWaitTicks = 60;
+ }
+
+ WaitTicks(nWaitTicks);
+ }
+ }
+
+ // temp - moving InstallEngine(); before FadeOut as we use nextpage() in FadeOut
+ InstallEngine();
+
+ // loc_11745:
+ FadeOut(0);
+// InstallEngine();
+ KB_Startup();
+ SetupInput();
+ InitView();
+ myloadconfig();
+ LoadStaticSounds();
+ setCDaudiovolume(gMusicVolume);
+ seq_LoadSequences();
+ InitStatus();
+ InitTimer();
+
+ for (i = 0; i < kMaxPlayers; i++) {
+ nPlayerLives[i] = kDefaultLives;
+ }
+
+ nBestLevel = 0;
+
+ UpdateScreenSize();
+
+ EraseScreen(overscanindex);
+ ResetEngine();
+ EraseScreen(overscanindex);
+
+ ResetView();
+ GrabPalette();
+
+ if (bSerialPlay && !InitSerial()) {
+ bail2dos("Unable to connect");
+ }
+
+ if (esi)
+ {
+ while (!var_1C)
+ {
+ DoTitle();
+ var_1C = 1;
+ }
+ }
+
+ // loc_11811:
+ if (forcelevel > -1)
+ {
+ levelnew = forcelevel;
+ }
+ else
+ {
+ // no forcelevel specified...
+ if (!bPlayback)
+ {
+ goto main_loc_I;
+ }
+ }
+
+ // multiple points return to here
+main_loc_A:
+ levelnew = 1;
+ levelnum = 1;
+
+ if (!nNetPlayerCount) {
+ FadeOut(0);
+ }
+
+main_loc_B:
+
+ esi = 0;
+
+ bCamera = kFalse;
+ ClearCinemaSeen();
+ PlayerCount = 0;
+ lastlevel = -1;
+
+ // Start main_Loop_1
+ for (i = 0; i < nTotalPlayers; i++)
+ {
+ int nPlayer = GrabPlayer();
+ if (nPlayer < 0) {
+ bail2dos("Can't create local player\n");
+ }
+
+ InitPlayerInventory(nPlayer);
+
+ if (i == wConsoleNode) {
+ PlayerList[nPlayer].someNetVal = -3;
+ }
+ else {
+ PlayerList[nPlayer].someNetVal = -4;
+ }
+ }
+ // End main_Loop_1
+
+ esi = 0;
+
+ nNetMoves = 0;
+
+ if (bPlayback)
+ {
+ menu_GameLoad2(vcrfp);
+ levelnew = GameStats.nMap;
+ levelnum = GameStats.nMap;
+ forcelevel = GameStats.nMap;
+ }
+
+ // Here, we either go into a loop of branch off
+
+ if (forcelevel <= -1) // main_loc_F
+ {
+ // PINK SECTION
+ UpdateInputs();
+ nNetMoves = 1;
+
+ if (nMenu == 2)
+ {
+ esi = 1;
+
+ levelnew = 1;
+ levelnum = 1;
+ levelnew = menu_GameLoad(SavePosition);
+ lastlevel = -1;
+ }
+
+ if (bRecord && !bInDemo) {
+ menu_GameSave2(vcrfp);
+ }
+
+ nBestLevel = levelnew - 1;
+
+ // WE now need to go to main_loc_G:
+ goto main_loc_G;
+ }
+
+ // YELLOW SECTION
+ levelnew = forcelevel;
+ UpdateInputs();
+ forcelevel = -1;
+
+ esi = bRecord;
+
+ if (bRecord && !bInDemo) {
+ menu_GameSave2(vcrfp);
+ }
+
+main_loc_C:
+
+// if (levelnew != -1)
+ while (levelnew != -1)
+ {
+ // CHECKME - this should be here?
+ handleevents();
+
+ // BLUE
+ if (CDplaying()) {
+ fadecdaudio();
+ }
+
+ CheckCD();
+
+ if (!bNoCDCheck)
+ {
+ while (!checkcdrom())
+ {
+ EraseScreen(overscanindex);
+ Query(2, 0, "Insert CD into drive", "(ESC to abort)");
+ KB_ClearKeysDown();
+ if (KB_GetCh() == asc_Escape) {
+ bail2dos("Aborted\n");
+ }
+ }
+ }
+
+ if (levelnew == kMap20)
+ {
+ lCountDown = 81000;
+ esi = 30;
+ edi = 0;
+ nAlarmTicks = 30;
+ nRedTicks = 0;
+ nClockVal = 0;
+ nEnergyTowers = 0;
+ }
+
+ if (!LoadLevel(levelnew)) {
+ // TODO "Can't load level %d...\n", nMap;
+ goto main_Exit;
+ }
+ else {
+ levelnew = -1;
+// goto main_loc_C;
+ }
+ // End BLUE
+ }
+// else // nMap == -1
+ {
+ if (nNetPlayerCount == 0 && lastlevel == levelnum)
+ {
+ RestoreSavePoint(nLocalPlayer, &initx, &inity, &initz, &initsect, &inita);
+ }
+
+ lastlevel = levelnum;
+
+ edi = 0;
+
+ for (i = 0; i < nTotalPlayers; i++)
+ {
+ SetSavePoint(i, initx, inity, initz, initsect, inita);
+ RestartPlayer(i);
+ InitPlayerKeys(i);
+ }
+
+ UpdateScreenSize();
+ fps = 0;
+ lastfps = 0;
+ InitStatus();
+ ResetView();
+ ResetEngine();
+ totalmoves = 0;
+ GrabPalette();
+ ResetMoveFifo();
+ moveframes = 0;
+ bInMove = kFalse;
+
+ edi = 0;
+
+// int esi = totalclock;
+ esi = totalclock;
+
+ nPlayerDAng = 0;
+ lPlayerXVel = 0;
+ lPlayerYVel = 0;
+ movefifopos = movefifoend;
+ nCDTrackLength = 0;
+ RefreshStatus();
+
+ if (bSerialPlay) {
+ ClearSerialInbuf();
+ }
+
+ mysetbrightness((uchar)nGamma);
+ //int edi = totalclock;
+ edi = totalclock;
+
+main_loc_D:
+ // ORANGE
+ if (levelnew >= 0)
+ {
+ goto main_loc_G;
+ }
+ else
+ {
+ // Section B
+ if (!nCDTrackLength && !nFreeze && !nNetPlayerCount)
+ {
+ int nTrack = levelnum;
+ if (nTrack != 0) {
+ nTrack--;
+ }
+
+ nCDTrackLength = playCDtrack((nTrack % 8) + 11);
+
+ if (!nCDTrackLength) {
+ nCDTrackLength = -1;
+ }
+ }
+ // End Section B
+
+ SetView1();
+
+ if (levelnum == kMap20)
+ {
+ LockEnergyTiles();
+ DoEnergyTile();
+ DrawClock();
+ }
+
+ DrawView();
+ UpdateMap();
+
+ if (bMapMode)
+ {
+ if (bHiRes && nViewBottom > nMaskY)
+ {
+ videoSetViewableArea(nViewLeft, nViewTop, nViewRight, nMaskY);
+ DrawMap();
+ videoSetViewableArea(nViewLeft, nViewTop, nViewRight, nViewBottom);
+ }
+ else
+ {
+ DrawMap();
+ }
+ }
+
+ videoNextPage();
+
+ // TEST - trying to fix player unable to restart when dead...
+ handleevents();
+
+// TODO CONTROL_GetButtonInput();
+ CheckKeys();
+ UpdateSounds();
+
+ bInMove = kTrue;
+
+ moveframes = (totalclock - edi) / 4;
+
+ if (moveframes > 4)
+ moveframes = 4;
+
+ if (moveframes != 0)
+ edi = totalclock;
+
+ if (bPlayback)
+ {
+ // YELLOW
+ if ((bInDemo && KB_KeyWaiting() || !ReadPlaybackInputs()) && KB_GetCh())
+ {
+ KB_FlushKeyboardQueue();
+ KB_ClearKeysDown();
+
+ bPlayback = kFalse;
+ bInDemo = kFalse;
+
+ if (vcrfp) {
+ fclose(vcrfp);
+ }
+
+ // now we go to main_loc_I:
+ goto main_loc_I;
+ }
+ }
+ else
+ {
+ // loc_11EE0
+ if (bRecord || moveframes)
+ {
+ GetLocalInput();
+
+ sPlayerInput[nLocalPlayer].xVel = lPlayerXVel;
+ sPlayerInput[nLocalPlayer].yVel = lPlayerYVel;
+ sPlayerInput[nLocalPlayer].buttons = lLocalButtons | lLocalCodes;
+ sPlayerInput[nLocalPlayer].nAngle = nPlayerDAng;
+ sPlayerInput[nLocalPlayer].nTarget = besttarget;
+
+ Ra[nLocalPlayer].nTarget = besttarget;
+
+ lLocalCodes = 0;
+
+ sPlayerInput[nLocalPlayer].horizon = nVertPan[nLocalPlayer];
+ }
+ }
+
+ // loc_11F72:
+ if (bRecord && !bInDemo) {
+ WritePlaybackInputs();
+ }
+
+ if (nNetPlayerCount)
+ {
+ if (moveframes)
+ {
+ UpdateInputs();
+ moveframes = nNetMoveFrames;
+ }
+ }
+ else
+ {
+ // loc_11FBC:
+ while (bPause)
+ {
+ ClearAllKeys();
+ if (WaitAnyKey(-1) != sc_Pause)
+ {
+ bPause = kFalse;
+ }
+ }
+ }
+
+ // loc_11FEE:
+ esi += moveframes * 4;
+
+main_loc_J:
+
+ handleevents();
+
+ if (moveframes && levelnew < 0)
+ {
+ FixPalette();
+
+ if (levelnum == kMap20)
+ {
+ if (lCountDown <= 0)
+ {
+ for (int i = 0; i < nTotalPlayers; i++) {
+ nPlayerLives[i] = 0;
+ }
+
+ DoFailedFinalScene();
+ levelnew = 100;
+
+ goto main_loc_O;
+ }
+ else
+ {
+ // Pink section
+ lCountDown--;
+ DrawClock();
+
+ if (nRedTicks)
+ {
+ nRedTicks--;
+
+ if (nRedTicks <= 0) {
+ DoRedAlert(0);
+ }
+
+ nAlarmTicks--;
+ nButtonColor--;
+
+ if (nAlarmTicks <= 0) {
+ DoRedAlert(1);
+ }
+ }
+ }
+ }
+
+ // YELLOW SECTION
+ MoveThings();
+
+ if (totalvel[nLocalPlayer] == 0)
+ {
+ bobangle = 0;
+ }
+ else
+ {
+ bobangle += 56;
+ bobangle &= kAngleMask;
+ }
+
+ // loc_120E9:
+ totalmoves++;
+ moveframes--;
+
+ if (nNetTime > 0)
+ {
+ nNetTime--;
+
+ if (!nNetTime) {
+ nFreeze = 3;
+ }
+
+ goto main_loc_J;
+ }
+ else if (nNetTime != 0)
+ {
+ goto main_loc_J;
+ }
+ else // nNetTime == 0
+ {
+ if (BUTTON(gamefunc_Open))
+ {
+ CONTROL_ClearButton(gamefunc_Open);
+ goto main_loc_K;
+ }
+ else {
+ goto main_loc_J;
+ }
+ }
+ }
+ // END YELLOW SECTION
+
+ main_loc_O:
+ // loc_12149:
+ if (bInDemo)
+ {
+ while (esi > totalclock) { handleevents(); }
+ esi = totalclock;
+ }
+
+ bInMove = kFalse;
+
+ if (!bInDemo)
+ {
+ if (BUTTON(gamefunc_Escape))
+ {
+ CONTROL_ClearButton(gamefunc_Escape);
+ goto main_loc_K;
+ }
+ else if (KB_KeyDown[sc_PrintScreen])
+ {
+ videoCaptureScreen("captxxxx.pcx", 0);
+ KB_KeyDown[sc_PrintScreen] = 0;
+ }
+ else if (BUTTON(gamefunc_Map)) // e.g. TAB (to show 2D map)
+ {
+ CONTROL_ClearButton(gamefunc_Map);
+
+ if (!nFreeze) {
+ bMapMode = bMapMode == 0;
+ }
+ }
+ else if (BUTTON(gamefunc_Zoom_Out))
+ {
+ lMapZoom -= ldMapZoom;
+
+ if (lMapZoom <= 32)
+ {
+ lMapZoom = 32;
+ }
+ else if (ldMapZoom <= 16)
+ {
+ ldMapZoom = 16;
+ }
+ else
+ {
+ ldMapZoom -= 2;
+ }
+ }
+ else if (BUTTON(gamefunc_Zoom_In))
+ {
+ lMapZoom += ldMapZoom;
+ if (lMapZoom >= 1280)
+ {
+ lMapZoom = 1280;
+ }
+ else if (ldMapZoom >= 128)
+ {
+ ldMapZoom = 128;
+ }
+ else
+ {
+ ldMapZoom += 2;
+ }
+ }
+
+ goto main_loc_L;
+ }
+ else {
+ goto main_loc_N;
+ }
+
+ main_loc_L:
+
+ handleevents();
+
+ if (PlayerList[nLocalPlayer].nHealth <= 0)
+ {
+ SetAirFrame();
+ }
+ else
+ {
+ if (BUTTON(gamefunc_Inventory_Left))
+ {
+ SetPrevItem(nLocalPlayer);
+ CONTROL_ClearButton(gamefunc_Inventory_Left);
+ }
+ if (BUTTON(gamefunc_Inventory_Right))
+ {
+ SetNextItem(nLocalPlayer);
+ CONTROL_ClearButton(gamefunc_Inventory_Right);
+ }
+ if (BUTTON(gamefunc_Inventory))
+ {
+ UseCurItem(nLocalPlayer);
+ CONTROL_ClearButton(gamefunc_Inventory);
+ }
+ }
+
+ goto main_loc_N;
+ }
+ }
+
+main_loc_M:
+
+ if (!nNetPlayerCount)
+ {
+ if (!bPlayback)
+ {
+ if (levelnew > 0 && levelnew <= kMap20)
+ {
+ levelnew = showmap(levelnum, levelnew, nBestLevel);
+ }
+ }
+ }
+
+ if (levelnew > nBestLevel) {
+ nBestLevel = levelnew;
+ }
+
+ goto main_loc_C;
+
+main_loc_N:
+
+ if (record_mode == 3)
+ {
+ if (movefifopos == movefifoend)
+ levelnew = 0;
+ }
+
+ fps++;
+ goto main_loc_D;
+
+main_loc_G:
+
+ if (nPlayerLives[nLocalPlayer] <= 0) {
+ goto main_loc_I;
+ }
+ else
+ {
+ if (levelnew > 99)
+ {
+ goto main_Exit;
+ }
+ else
+ {
+ if (!bInDemo && levelnew > nBestLevel && levelnew != 0 && levelnew <= kMap20 && SavePosition > -1) {
+ menu_GameSave(SavePosition);
+ }
+
+ goto main_loc_M;
+ }
+ }
+
+main_loc_K:
+
+ nMenu = menu_Menu(1);
+
+ switch (nMenu)
+ {
+ default:
+ {
+ RefreshStatus();
+ goto main_loc_L;
+ }
+
+ case 0:
+ {
+ goto main_Exit;
+ break;
+ }
+
+ case 1:
+ {
+ goto main_loc_A;
+ break;
+ }
+
+ case 2:
+ {
+ levelnew = menu_GameLoad(SavePosition);
+ levelnum = levelnew;
+ lastlevel = -1;
+ nBestLevel = levelnew - 1;
+ goto main_loc_M;
+ break;
+ }
+
+ case 3: // When selecting 'Training' from ingame menu when already playing a level
+ {
+ if (levelnum)
+ {
+ if (Query(2, 4, "Quit current game?", "Y/N", 'Y', 13, 'N', 27))
+ {
+ RefreshStatus();
+ goto main_loc_L;
+ }
+ }
+
+ levelnew = 0;
+ levelnum = 0;
+ goto main_loc_B;
+ }
+ }
+
+main_loc_I:
+
+ SavePosition = -1;
+ nMenu = menu_Menu(0);
+
+ if (nMenu < 0) {
+ goto main_loc_I;
+ }
+
+ switch (nMenu)
+ {
+ case 0:
+ {
+ goto main_Exit;
+ break;
+ }
+
+ case 1:
+ case 2:
+ {
+ goto main_loc_A;
+ break;
+ }
+
+ case 3:
+ {
+ forcelevel = 0;
+ goto main_loc_B;
+ break;
+ }
+
+ case 9:
+ {
+ vcrfp = fopen("demo.vcr", "rb");
+ if (vcrfp == NULL) {
+ goto main_loc_I;
+ }
+
+ InitRandom();
+ bInDemo = kTrue;
+ bPlayback = kTrue;
+
+ KB_FlushKeyboardQueue();
+ KB_ClearKeysDown();
+
+ goto main_loc_A;
+ break;
+ }
+ }
+
+main_Exit:
+ if (bRecord) {
+ fclose(vcrfp);
+ }
+
+ FadeSong();
+ if (CDplaying()) {
+ fadecdaudio();
+ }
+
+ StopAllSounds();
+ StopLocalSound();
+ mysaveconfig();
+
+ if (bSerialPlay)
+ {
+ if (nNetPlayerCount != 0) {
+ bSendBye = kTrue;
+ UpdateSerialInputs();
+ }
+ }
+ else
+ {
+ if (nNetPlayerCount != 0) {
+ SendGoodbye();
+ }
+ }
+
+ bail2dos("\n");
+
+ return 0;
+}
+
+void mychangespritesect(int nSprite, int nSector)
+{
+ DoKenTest();
+ changespritesect(nSprite, nSector);
+ DoKenTest();
+}
+
+void mydeletesprite(int nSprite)
+{
+ if (nSprite < 0 || nSprite > kMaxSprites) {
+ bail2dos("bad sprite value %d handed to mydeletesprite", nSprite);
+ }
+
+ deletesprite(nSprite);
+
+ if (nSprite == besttarget) {
+ besttarget = -1;
+ }
+}
+
+
+void KeyFn1()
+{
+ menu_DoPlasma();
+ overwritesprite(160, 100, kSkullHead, 0, 3, kPalNormal);
+ overwritesprite(161, 130, kSkullJaw, 0, 3, kPalNormal);
+ videoNextPage();
+}
+
+void DoGameOverScene()
+{
+ FadeOut(0);
+ ClearAllKeys();
+
+ if (LoadCinemaPalette(16) < 0) {
+ return;
+ }
+
+ SetOverscan(cinemapal);
+ NoClip();
+ overwritesprite(0, 0, kTile3591, 0, 2, kPalNormal);
+ Clip();
+ videoNextPage();
+ CinemaFadeIn();
+ // TODO PlayGameOverSound();
+ WaitAnyKey(3);
+ FadeOut(0);
+ SetOverscan(kenpal);
+}
+
+// TODO - missing some values?
+short word_10010[] = {6, 25, 43, 50, 68, 78, 101, 111, 134, 158, 173, 230, 6000};
+
+void DoTitle()
+{
+ return; // REVERT
+
+ short theArray[13];
+ memcpy(theArray, word_10010, sizeof(word_10010));
+
+ videoSetViewableArea(0, 0, nScreenWidth - 1, nScreenHeight - 1);
+
+ BlackOut();
+
+ overwritesprite(0, 0, kPublisherLogo, 0, 2, kPalNormal);
+ videoNextPage();
+
+ FadeIn();
+
+ ClearAllKeys();
+
+ WaitAnyKey(2);
+
+ FadeOut(0);
+
+ SetOverscan(kenpal);
+
+ int nScreenTile = seq_GetSeqPicnum(kSeqScreens, 0, 0);
+
+ overwritesprite(0, 0, nScreenTile, 0, 2, kPalNormal);
+ videoNextPage();
+
+ FadeIn();
+ // TODO PlayLogoSound();
+
+ WaitAnyKey(2);
+
+ FadeOut(0);
+ ClearAllKeys();
+
+ PlayMovie("book.mov");
+
+ FadeOut(0);
+
+ SetOverscan(kenpal);
+ GrabPalette();
+
+ SetLocalChan(1);
+ PlayLocalSound(StaticSound[59], 0);
+
+ SetLocalChan(0);
+
+ EraseScreen(4);
+
+ playCDtrack(19);
+
+ videoNextPage();
+ FadeIn();
+ WaitVBL();
+
+
+ int String_Copyright = FindGString("COPYRIGHT");
+
+ const char *a = gString[String_Copyright];
+ const char *b = gString[String_Copyright + 1];
+
+ menu_DoPlasma();
+
+ int nTile = kSkullHead;
+
+ overwritesprite(160, 100, kSkullHead, 0, 3, kPalNormal);
+ overwritesprite(161, 130, kSkullJaw, 0, 3, kPalNormal);
+ videoNextPage();
+
+ WaitNoKey(2, KeyFn1);
+
+ if (time(0) & 0xF) {
+ // TODO PlayGameOverSound();
+ }
+ else {
+ PlayLocalSound(StaticSound[61], 0);
+ }
+
+ int nStartTime = totalclock;
+ int nCount = 0;
+ int var_18 = totalclock;
+ int var_4 = 0;
+
+ int esi = 130;
+
+ var_18 += theArray[0];
+
+ while (LocalSoundPlaying())
+ {
+ handleevents();
+
+ menu_DoPlasma();
+ overwritesprite(160, 100, nTile, 0, 3, kPalNormal);
+
+ int nStringWidth = MyGetStringWidth(a);
+
+ int y = nScreenHeight - 24;
+ myprintext((nScreenWidth / 2 - nStringWidth / 2), y, a, 0);
+
+ nStringWidth = MyGetStringWidth(b);
+
+ y = nScreenHeight - 16;
+ myprintext((nScreenWidth / 2 - nStringWidth / 2), y, b, 0);
+
+ if (totalclock > var_18)
+ {
+ nCount++;
+
+ assert(nCount <= 12);
+ var_18 = nStartTime + theArray[nCount];
+
+ var_4 = var_4 == 0;
+ }
+
+ short nTile = kSkullJaw;
+
+ if (var_4)
+ {
+ if (esi >= 135) {
+ nTile = kTile3583;
+ }
+ else {
+ esi += 5;
+ }
+ }
+ else if (esi <= 130)
+ {
+ esi = 130;
+ }
+ else
+ {
+ esi -= 2;
+ }
+
+ y = 0;
+
+ if (nTile == kTile3583)
+ {
+ y = 131;
+ }
+ else
+ {
+ y = esi;
+
+ if (y > 135) {
+ y = 135;
+ }
+ }
+
+ overwritesprite(161, y, nTile, 0, 3, kPalNormal);
+ videoNextPage();
+ }
+
+ WaitNoKey(1, KeyFn1);
+
+ videoSetViewableArea(nViewLeft, nViewTop, nViewRight, nViewBottom);
+}
+
+void CopyTileToBitmap(short nSrcTile, short nDestTile, int xPos, int yPos)
+{
+ int nOffs = tilesiz[nDestTile].y * xPos;
+
+ BYTE *pDest = (BYTE*)waloff[nDestTile] + nOffs + yPos;
+ BYTE *pDestB = pDest;
+
+ tileLoad(nSrcTile);
+
+ int destYSize = tilesiz[nDestTile].y;
+ int srcYSize = tilesiz[nSrcTile].y;
+
+ BYTE *pSrc = (BYTE*)waloff[nSrcTile];
+
+ for (int x = 0; x < tilesiz[nSrcTile].x; x++)
+ {
+ pDest += destYSize;
+
+ for (int y = 0; y < srcYSize; y++)
+ {
+ uchar val = *pSrc;
+ if (val != 0xFF) {
+ *pDestB = val;
+ }
+
+ pDestB++;
+ pSrc++;
+ }
+
+ // reset pDestB
+ pDestB = pDest;
+ }
+}
+
+int CopyCharToBitmap(char nChar, int nTile, int xPos, int yPos)
+{
+ if (nChar == ' ') {
+ return 4;
+ }
+
+ nChar = toupper(nChar);
+ int nFontTile = seq_GetSeqPicnum(kSeqFont2, 0, nChar - 32) + 102;
+ CopyTileToBitmap(nFontTile, nTile, xPos, yPos);
+
+ return tilesiz[nFontTile].x + 1;
+}
+
+// Note: strings passed should be uppercase
+int myprintext(int x, int y, const char *str, int shade)
+{
+ if (y < -15 || y >= 200)
+ return x;
+
+ const char *c = str;
+
+ while (*c != '\0')
+ {
+ int nTile = seq_GetSeqPicnum(kSeqFont2, 0, (*c) - 32);
+ overwritesprite(x, y, nTile, shade, 2, kPalNormal);
+
+ int tileWidth = tilesiz[nTile].x;
+
+ x += tileWidth + 1;
+ c++;
+ }
+
+ return x;
+}
+
+void EraseScreen(int nVal)
+{
+ if (nVal == -1) {
+ nVal = overscanindex;
+ }
+
+ for (int i = 0; i < numpages; i++)
+ {
+ videoClearScreen(nVal);
+ videoNextPage();
+ }
+}
+
+int Query(short nLines, short nKeys, ...)
+{
+ short i;
+
+ char strings[20][80];
+ char keys[20];
+
+ va_list args;
+
+ short bPrevClip = bClip;
+ NoClip();
+
+ short nWidth = 0;
+
+ va_start(args, nKeys);
+
+ for (i = 0; i < nLines; i++)
+ {
+ char *str = va_arg(args, char*);
+ strcpy(strings[i], str);
+ strupr(strings[i]);
+
+ int strWidth = MyGetStringWidth(strings[i]);
+
+ if (strWidth > nWidth) {
+ nWidth = strWidth;
+ }
+ }
+
+ for (i = 0; i < nKeys; i++) {
+ keys[i] = va_arg(args, char);
+ }
+
+ va_end(args);
+
+ int nHeight = (nLines + 1) * 10;
+ int y1 = (200 - nHeight) / 2;
+ int yB = y1;
+
+ // add some padding to left and right sides of text in the box
+ nWidth += 30;
+
+ int x1 = (320 - nWidth) / 2;
+ int x2 = x1 + nWidth;
+
+ if (bHiRes)
+ {
+ x1 *= 2;
+ y1 *= 2;
+ nHeight *= 2;
+ x2 *= 2;
+ }
+
+ // draw background box that the text sits in
+ for (i = 0; i < nHeight; i++) {
+ renderDrawLine(x1 << 12, (y1 + i) << 12, x2 << 12, (y1 + i) << 12, overscanindex);
+ }
+
+ y1 = yB + 5;
+
+ // draw each line of text
+ for (i = 0; i < nLines; i++) {
+ myprintext((320 - MyGetStringWidth(strings[i])) / 2, (y1 + i*10) , strings[i], 0);
+ }
+
+ videoNextPage();
+
+ if (bPrevClip) {
+ Clip();
+ }
+
+ i = 0;
+
+ if (nKeys)
+ {
+ KB_FlushKeyboardQueue();
+
+ while (1)
+ {
+ handleevents();
+
+ char key = toupper(KB_GetCh());
+
+ for (i = 0; i < nKeys; i++)
+ {
+ if (keys[i] == 0 || key == keys[i])
+ {
+ RefreshStatus();
+ ClearAllKeys();
+ bgpages = numpages;
+ return i;
+ }
+ }
+ }
+ }
+
+ RefreshStatus();
+ ClearAllKeys();
+ bgpages = numpages;
+
+ return i;
+}
+
+void InitSpiritHead()
+{
+ char filename[20];
+
+ nPixels = 0;
+
+ tileLoad(kTileRamsesNormal); // Ramses Normal Head
+
+ for (int i = 0; i < kMaxSprites; i++)
+ {
+ if (sprite[i].statnum)
+ {
+ sprite[i].cstat |= 0x8000;
+ }
+ }
+
+ BYTE *pTile = (BYTE*)waloff[kTileRamsesNormal];
+
+ for (int x = 0; x < 97; x++)
+ {
+ for (int y = 0; y < 106; y++)
+ {
+ if (*pTile != 255)
+ {
+ pixelval[nPixels] = *(BYTE*)(waloff[kTileRamsesGold] + x * 106 + y);
+ origx[nPixels] = x - 48;
+ origy[nPixels] = y - 53;
+ curx[nPixels] = 0;
+ cury[nPixels] = 0;
+ vely[nPixels] = 0;
+ velx[nPixels] = 0;
+
+ destvelx[nPixels] = RandomSize(2) + 1;
+
+ if (curx[nPixels] > 0) {
+ destvelx[nPixels] = -destvelx[nPixels];
+ }
+
+ destvely[nPixels] = RandomSize(2) + 1;
+
+ if (cury[nPixels] > 0) {
+ destvely[nPixels] = -destvely[nPixels];
+ }
+
+ nPixels++;
+ }
+
+ pTile++;
+ }
+ }
+
+ waloff[kTileRamsesWorkTile] = (intptr_t)worktile;
+
+ sprite[nSpiritSprite].yrepeat = 140;
+ sprite[nSpiritSprite].xrepeat = 140;
+ sprite[nSpiritSprite].picnum = kTileRamsesWorkTile;
+
+ nHeadStage = 0;
+
+ // work tile is twice as big as the normal head size
+ tilesiz[kTileRamsesWorkTile].x = 97 * 2; // 194;
+ tilesiz[kTileRamsesWorkTile].y = 106 * 2; // 212;
+
+ sprite[nSpiritSprite].cstat &= 0x7FFF;
+
+ nHeadTimeStart = totalclock;
+
+ memset(worktile, -1, sizeof(worktile));
+
+ nPixelsToShow = 0;
+
+ fadecdaudio();
+
+ int nTrack;
+
+ if (levelnum == 1)
+ {
+ nTrack = 3;
+ }
+ else
+ {
+ nTrack = 7;
+ }
+
+ nCDTrackLength = playCDtrack(nTrack);
+
+ bSubTitles = nCDTrackLength == 0;
+
+ StartSwirlies();
+
+ sprintf(filename, "LEV%d.PUP", levelnum);
+ lNextStateChange = totalclock;
+ lHeadStartClock = totalclock;
+
+ headfd = kopen4load(filename, 512); // 512??
+ nPupData = kread(headfd, cPupData, sizeof(cPupData));
+ pPupData = cPupData;
+ kclose(headfd);
+ headfd = -1;
+ nMouthTile = 0;
+ nTalkTime = 1;
+}
+
+void DimSector(short nSector)
+{
+ short startwall = sector[nSector].wallptr;
+ short nWalls = sector[nSector].wallnum;
+
+ for (int i = 0; i < nWalls; i++)
+ {
+ if (wall[startwall+i].shade < 40) {
+ wall[startwall+i].shade++;
+ }
+ }
+
+ if (sector[nSector].floorshade < 40) {
+ sector[nSector].floorshade++;
+ }
+
+ if (sector[nSector].ceilingshade < 40) {
+ sector[nSector].ceilingshade++;
+ }
+}
+
+void CopyHeadToWorkTile(short nTile)
+{
+ tileLoad(nTile);
+
+ BYTE *pSrc = (BYTE*)waloff[nTile];
+ BYTE *pDest = (BYTE*)&worktile[212 * 49 + 53];
+
+ for (int i = 0; i < 97; i++)
+ {
+ memcpy(pDest, pSrc, 106);
+
+ pDest += 212;
+ pSrc += 106;
+ }
+}
+
+#if 1
+int DoSpiritHead()
+{
+ static short word_964E6 = 0;
+
+ nVertPan[0] += (nDestVertPan[0] - nVertPan[0]) / 4;
+
+ if (nHeadStage < 2)
+ {
+ memset(worktile, -1, sizeof(worktile));
+ }
+
+ if (nHeadStage < 2 || nHeadStage != 5)
+ {
+ nPixelsToShow = (totalclock - nHeadTimeStart) * 15;
+
+ if (nPixelsToShow > nPixels) {
+ nPixelsToShow = nPixels;
+ }
+
+ if (nHeadStage < 3)
+ {
+ UpdateSwirlies();
+
+ if (sprite[nSpiritSprite].shade > -127) {
+ sprite[nSpiritSprite].shade--;
+ }
+
+ word_964E6--;
+ if (word_964E6 < 0)
+ {
+ DimSector(sprite[nSpiritSprite].sectnum);
+ word_964E6 = 5;
+ }
+
+ if (!nHeadStage)
+ {
+ if ((totalclock - nHeadTimeStart) > 480)
+ {
+ nHeadStage = 1;
+ nHeadTimeStart = totalclock + 480;
+ }
+
+// int ecx = 0;
+
+ // loc_1362C
+ for (int i = 0; i < nPixelsToShow; i++)
+ {
+ if (destvely[i] >= 0)
+ {
+ vely[i]++;
+
+ if (vely[i] >= destvely[i])
+ {
+ destvely[i] = -(RandomSize(2) + 1);
+ }
+ }
+ else
+ {
+ vely[i]--;
+
+ if (vely[i] <= destvely[i])
+ {
+ destvely[i] = RandomSize(2) + 1;
+ }
+ }
+
+ // loc_13541
+ if (destvelx[i] >= 0)
+ {
+ velx[i]++;
+
+ if (velx[i] >= destvelx[i])
+ {
+ destvelx[i] = -(RandomSize(2) + 1);
+ }
+ }
+ else
+ {
+ velx[i]--;
+
+ if (velx[i] <= destvelx[i])
+ {
+ destvelx[i] = RandomSize(2) + 1;
+ }
+ }
+
+ // loc_13593
+ int esi = vely[i] + (cury[i] >> 8);
+
+ if (esi < 106)
+ {
+ if (esi < -105)
+ {
+ vely[i] = 0;
+ esi = 0;
+ }
+ }
+ else
+ {
+ vely[i] = 0;
+ esi = 0;
+ }
+
+ // loc_135C6
+ int ebx = velx[i] + (curx[i] >> 8);
+
+ if (ebx < 97)
+ {
+ if (ebx < -96)
+ {
+ velx[i] = 0;
+ ebx = 0;
+ }
+ }
+ else
+ {
+ velx[i] = 0;
+ ebx = 0;
+ }
+
+ // loc_135F9
+ curx[i] = ebx << 8;
+ cury[i] = esi << 8;
+
+ //ecx += 2;
+// ecx++;
+
+ esi += (ebx + 97) * 212;
+
+// BYTE *pVal = (BYTE*)worktile;
+
+ worktile[106 + esi] = pixelval[i];
+ //pVal += (106 + esi);
+ //*pVal = pixelval[i];
+ }
+
+ return 1;
+ }
+ else
+ {
+ // loc_13679:
+ if (nHeadStage != 1) {
+ return 1;
+ }
+
+ uchar nXRepeat = sprite[nSpiritSprite].xrepeat;
+ if (nXRepeat > nSpiritRepeatX)
+ {
+ sprite[nSpiritSprite].xrepeat -= 2;
+
+ nXRepeat = sprite[nSpiritSprite].xrepeat;
+ if (nXRepeat < nSpiritRepeatX)
+ {
+ sprite[nSpiritSprite].xrepeat = nSpiritRepeatX;
+ }
+ }
+
+ uchar nYRepeat = sprite[nSpiritSprite].yrepeat;
+ if (nYRepeat > nSpiritRepeatY)
+ {
+ sprite[nSpiritSprite].yrepeat -= 2;
+
+ nYRepeat = sprite[nSpiritSprite].yrepeat;
+ if (nYRepeat < nSpiritRepeatY)
+ {
+ sprite[nSpiritSprite].yrepeat = nSpiritRepeatY;
+ }
+ }
+
+ // loc_13705
+ int esi = 0;
+// int edx = 0;
+
+ // loc_137E7:
+ for (int i = 0; i < nPixels; i++)
+ {
+ int eax = (origx[i] << 8) - curx[i];
+ int ecx = eax;
+
+ if (eax)
+ {
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ if (eax < 8)
+ {
+ curx[i] = origx[i] << 8;
+ ecx = 0;
+ }
+ else {
+ ecx >>= 3;
+ }
+ }
+ else
+ {
+ ecx >>= 3;
+ }
+
+ // loc_1374B
+ int var_1C = (origy[i] << 8) - cury[i];
+ int ebp = var_1C;
+
+ if (var_1C)
+ {
+ eax = ebp;
+
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ if (eax < 8)
+ {
+ cury[i] = origy[i] << 8;
+ var_1C = 0;
+ }
+ else
+ {
+ var_1C >>= 3;
+ }
+ }
+ else
+ {
+ var_1C >>= 3;
+ }
+
+ if (var_1C || ecx)
+ {
+ curx[i] += ecx;
+ cury[i] += var_1C;
+
+ esi++;
+ }
+
+ ecx = (((curx[i] >> 8) + 97) * 212) + (cury[i] >> 8);
+
+// edx++;
+
+// BYTE *pVal = (BYTE*)worktile;
+
+ worktile[106 + ecx] = pixelval[i];
+
+ //pVal += (106 + ecx);
+ //*pVal = pixelval[i];
+ }
+
+ if ((totalclock - lHeadStartClock) > 600) {
+ CopyHeadToWorkTile(kTileRamsesGold);
+ }
+
+ int eax = ((nPixels << 4) - nPixels) / 16;
+
+ if (esi < eax)
+ {
+ // SoundBigEntrance(); // TODO
+ AddGlow(sprite[nSpiritSprite].sectnum, 20);
+ AddFlash(
+ sprite[nSpiritSprite].sectnum,
+ sprite[nSpiritSprite].x,
+ sprite[nSpiritSprite].y,
+ sprite[nSpiritSprite].z,
+ 128);
+
+ nHeadStage = 3;
+ TintPalette(63, 63, 63);
+ CopyHeadToWorkTile(kTileRamsesNormal);
+ }
+
+ return 1;
+ }
+ }
+ else
+ {
+ // loc_138A7
+ FixPalette();
+
+ if (!nPalDiff)
+ {
+ nFreeze = 2;
+ nHeadStage++;
+ }
+
+ return 0;
+ }
+ }
+ else
+ {
+ if (lNextStateChange <= totalclock)
+ {
+ if (nPupData)
+ {
+ short nPupVal = *pPupData;
+ pPupData++;
+ nPupData -= 2;
+
+ if (nPupData > 0)
+ {
+ lNextStateChange = (nPupVal + lHeadStartClock) - 10;
+ nTalkTime = !nTalkTime;
+ }
+ else
+ {
+ nTalkTime = 0;
+ nPupData = 0;
+ }
+ }
+ else if (!bSubTitles)
+ {
+ if (!CDplaying())
+ {
+ levelnew = levelnum + 1;
+ fadecdaudio();
+ }
+ }
+ }
+
+ word_964E8--;
+ if (word_964E8 <= 0)
+ {
+ word_964EA = RandomBit() * 2;
+ word_964E8 = RandomSize(5) + 4;
+ }
+
+ int ebx = 592;
+ word_964EC--;
+
+ if (word_964EC < 3)
+ {
+ ebx = 593;
+ if (word_964EC <= 0) {
+ word_964EC = RandomSize(6) + 4;
+ }
+ }
+
+ ebx += word_964EA;
+
+ tileLoad(ebx);
+
+ // TODO - fixme. How big is worktile?
+ BYTE *pDest = (BYTE*)&worktile[10441];
+ BYTE *pSrc = (BYTE*)waloff[ebx];
+
+ for (int i = 0; i < 97; i++)
+ {
+ memcpy(pDest, pSrc, 106);
+
+ pDest += 212;
+ pSrc += 106;
+ }
+
+ if (nTalkTime)
+ {
+ if (nMouthTile < 2) {
+ nMouthTile++;
+ }
+ }
+ else if (nMouthTile != 0)
+ {
+ nMouthTile--;
+ }
+
+ if (nMouthTile)
+ {
+ tileLoad(nMouthTile + 598);
+
+ short nTileSizeX = tilesiz[nMouthTile + 598].x;
+ short nTileSizeY = tilesiz[nMouthTile + 598].y;
+
+ // TODO - checkme. near loc_133AA
+// BYTE *pDest = (BYTE*)worktile;
+// pDest += (212 * (97 - nTileSizeX / 2)) + (159 - nTileSizeY);
+
+ BYTE *pDest = (BYTE*)&worktile[212 * (97 - nTileSizeX / 2)] + (159 - nTileSizeY);
+ BYTE *pSrc = (BYTE*)waloff[nMouthTile + 598];
+
+ while (nTileSizeX > 0)
+ {
+ memcpy(pDest, pSrc, nTileSizeY);
+
+ nTileSizeX--;
+ pDest += 212;
+ pSrc += nTileSizeY;
+ }
+ }
+
+ return 1;
+ }
+
+ // TEMP FIXME - temporary return value. what to return here? 1?
+
+ return 0;
+}
+#endif
+
+#if 0
+int DoSpiritHead()
+{
+ static short word_964E6 = 0;
+
+ nVertPan[0] += (nDestVertPan[0] - nVertPan[0]) / 4;
+
+ if (nHeadStage < 2)
+ {
+ memset(worktile, -1, sizeof(worktile));
+ }
+ else if (nHeadStage == 5)
+ {
+ if (lNextStateChange <= totalclock)
+ {
+ if (nPupData)
+ {
+ short nPupVal = *pPupData;
+ pPupData++;
+ nPupData -= 2;
+
+ if (nPupData > 0)
+ {
+ lNextStateChange = (nPupVal + lHeadStartClock) - 10;
+ nTalkTime = !nTalkTime;
+ }
+ else
+ {
+ nTalkTime = 0;
+ nPupData = 0;
+ }
+ }
+ else if (!bSubTitles)
+ {
+ if (!CDplaying())
+ {
+ levelnew = levelnum + 1;
+ fadecdaudio();
+ }
+ }
+ }
+
+ word_964E8--;
+ if (word_964E8 <= 0)
+ {
+ word_964EA = RandomBit() * 2;
+ word_964E8 = RandomSize(5) + 4;
+ }
+
+ int ebx = 592;
+ word_964EC--;
+
+ if (word_964EC < 3)
+ {
+ ebx = 593;
+ if (word_964EC <= 0) {
+ word_964EC = RandomSize(6) + 4;
+ }
+ }
+
+ ebx += word_964EA;
+
+ loadtile(ebx);
+
+ // TODO - fixme. How big is worktile?
+ BYTE *pDest = (BYTE*)&worktile[10441];
+ BYTE *pSrc = waloff[ebx];
+
+ for (int i = 0; i < 97; i++)
+ {
+ memcpy(pDest, pSrc, 106);
+
+ pDest += 212;
+ pSrc += 106;
+ }
+
+ if (nTalkTime)
+ {
+ if (nMouthTile < 2) {
+ nMouthTile++;
+ }
+ }
+ else if (nMouthTile != 0)
+ {
+ nMouthTile--;
+ }
+
+ if (nMouthTile)
+ {
+ loadtile(nMouthTile + 598);
+
+ short nTileSizeX = tilesizx[nMouthTile + 598];
+ short nTileSizeY = tilesizy[nMouthTile + 598];
+
+ // TODO - checkme. near loc_133AA
+ // BYTE *pDest = (BYTE*)worktile;
+ // pDest += (212 * (97 - nTileSizeX / 2)) + (159 - nTileSizeY);
+
+ BYTE *pDest = (BYTE*)&worktile[212 * (97 - nTileSizeX / 2)] + (159 - nTileSizeY);
+ BYTE *pSrc = waloff[nMouthTile + 598];
+
+ while (nTileSizeX > 0)
+ {
+ memcpy(pDest, pSrc, nTileSizeY);
+
+ nTileSizeX--;
+ pDest += 212;
+ pSrc += nTileSizeY;
+ }
+ }
+
+ return 1;
+ }
+ nPixelsToShow = (totalclock - nHeadTimeStart) * 15;
+
+ if (nPixelsToShow > nPixels) {
+ nPixelsToShow = nPixels;
+ }
+
+ if (nHeadStage < 3)
+ {
+ UpdateSwirlies();
+
+ if (sprite[nSpiritSprite].shade > -127) {
+ sprite[nSpiritSprite].shade--;
+ }
+
+ word_964E6--;
+ if (word_964E6 < 0)
+ {
+ DimSector(sprite[nSpiritSprite].sectnum);
+ word_964E6 = 5;
+ }
+
+ if (!nHeadStage)
+ {
+ if ((totalclock - nHeadTimeStart) > 480)
+ {
+ nHeadStage = 1;
+ nHeadTimeStart = totalclock + 480;
+ }
+
+ // int ecx = 0;
+
+ // loc_1362C
+ for (int i = 0; i < nPixelsToShow; i++)
+ {
+ if (destvely[i] < 0)
+ {
+ vely[i]--;
+
+ if (vely[i] <= destvely[i])
+ {
+ destvely[i] = RandomSize(2) + 1;
+ }
+ }
+ else
+ {
+ vely[i]++;
+
+ if (vely[i] >= destvely[i])
+ {
+ destvely[i] = -(RandomSize(2) + 1);
+ }
+ }
+
+ // loc_13541
+ if (destvelx[i] >= 0)
+ {
+ velx[i]--;
+
+ if (velx[i] <= destvelx[i])
+ {
+ destvelx[i] = RandomSize(2) + 1;
+ }
+ }
+ else
+ {
+ velx[i]++;
+
+ if (velx[i] >= destvelx[i])
+ {
+ destvelx[i] = -(RandomSize(2) + 1);
+ }
+ }
+
+ // loc_13593
+ int esi = vely[i] + (cury[i] >> 8);
+
+ if (esi >= 106)
+ {
+ vely[i] = 0;
+ esi = 0;
+ }
+ else if (esi < -105)
+ {
+ vely[i] = 0;
+ esi = 0;
+ }
+
+ // loc_135C6
+ int ebx = velx[i] + (curx[i] >> 8);
+
+ if (ebx >= 97)
+ {
+ velx[i] = 0;
+ ebx = 0;
+ }
+ else if (ebx < -96)
+ {
+ velx[i] = 0;
+ ebx = 0;
+ }
+
+ // loc_135F9
+ curx[i] = ebx << 8;
+ cury[i] = esi << 8;
+
+ //ecx += 2;
+ // ecx++;
+
+ // BYTE *pVal = (BYTE*)worktile;
+
+ worktile[106 + esi + (ebx + 97) * 212] = pixelval[i];
+ //pVal += (106 + esi);
+ //*pVal = pixelval[i];
+ }
+ }
+ else if (nHeadStage == 1)
+ {
+ uchar nXRepeat = sprite[nSpiritSprite].xrepeat;
+ if (nXRepeat > nSpiritRepeatX)
+ {
+ sprite[nSpiritSprite].xrepeat -= 2;
+
+ nXRepeat = sprite[nSpiritSprite].xrepeat;
+ if (nXRepeat < nSpiritRepeatX)
+ {
+ sprite[nSpiritSprite].xrepeat = nSpiritRepeatX;
+ }
+ }
+
+ uchar nYRepeat = sprite[nSpiritSprite].yrepeat;
+ if (nYRepeat > nSpiritRepeatY)
+ {
+ sprite[nSpiritSprite].yrepeat -= 2;
+
+ nYRepeat = sprite[nSpiritSprite].yrepeat;
+ if (nYRepeat < nSpiritRepeatY)
+ {
+ sprite[nSpiritSprite].yrepeat = nSpiritRepeatY;
+ }
+ }
+
+ // loc_13705
+ int esi = 0;
+ // int edx = 0;
+
+ // loc_137E7:
+ for (int i = 0; i < nPixels; i++)
+ {
+ int eax = (origx[i] << 8) - curx[i];
+ int ecx = eax;
+
+ if (eax && klabs(eax) < 8)
+ {
+ curx[i] = origx[i] << 8;
+ ecx = 0;
+ }
+ else
+ {
+ ecx >>= 3;
+ }
+
+ // loc_1374B
+ int var_1C = (origy[i] << 8) - cury[i];
+ int ebp = var_1C;
+
+ if (ebp && klabs(ebp) < 8)
+ {
+ cury[i] = origy[i] << 8;
+ var_1C = 0;
+ }
+ else
+ {
+ var_1C >>= 3;
+ }
+
+ if (var_1C | ecx)
+ {
+ curx[i] += ecx;
+ cury[i] += var_1C;
+
+ esi++;
+ }
+
+ // edx++;
+
+ // BYTE *pVal = (BYTE*)worktile;
+
+ worktile[106 + (((curx[i] >> 8) + 97) * 212) + (cury[i] >> 8)] = pixelval[i];
+
+ //pVal += (106 + ecx);
+ //*pVal = pixelval[i];
+ }
+
+ if ((totalclock - lHeadStartClock) > 600) {
+ CopyHeadToWorkTile(kTileRamsesGold);
+ }
+
+ int eax = (nPixels * 15) / 16;
+
+ if (esi < eax)
+ {
+ // SoundBigEntrance(); // TODO
+ AddGlow(sprite[nSpiritSprite].sectnum, 20);
+ AddFlash(
+ sprite[nSpiritSprite].sectnum,
+ sprite[nSpiritSprite].x,
+ sprite[nSpiritSprite].y,
+ sprite[nSpiritSprite].z,
+ 128);
+
+ nHeadStage = 3;
+ TintPalette(63, 63, 63);
+ CopyHeadToWorkTile(kTileRamsesNormal);
+ }
+
+ }
+ return 1;
+ }
+ // loc_138A7
+ FixPalette();
+
+ if (!nPalDiff)
+ {
+ nFreeze = 2;
+ nHeadStage++;
+ }
+
+ return 0;
+}
+#endif
diff --git a/source/exhumed/src/exhumed.h b/source/exhumed/src/exhumed.h
new file mode 100644
index 000000000..6da4d18dd
--- /dev/null
+++ b/source/exhumed/src/exhumed.h
@@ -0,0 +1,169 @@
+#ifndef __exhumed_h__
+#define __exhumed_h__
+
+#define kTimerTicks 120
+
+#ifdef __WATCOMC__
+void handleevents();
+#endif
+
+void DebugOut(const char *fmt, ...);
+void bail2dos(const char *fmt, ...);
+int ExhumedMain(int argc, char *argv[]);
+
+void FinishLevel();
+
+void SetHiRes();
+
+void BlackOut();
+
+void DoGameOverScene();
+
+int Query(short n, short l, ...);
+
+extern unsigned char curpal[];
+
+void TintPalette(int a, int b, int c);
+void MySetPalette(unsigned char *palette);
+void GetCurPal(unsigned char *palette);
+
+void EraseScreen(int eax);
+
+void RestorePalette();
+
+int FindGString(const char *str);
+
+void WaitTicks(int nTicks);
+
+void FadeIn();
+void FadeOut(int bFadeMusic);
+
+int myprintext(int x, int y, const char *str, int shade);
+int MyGetStringWidth(const char *str);
+
+void mychangespritesect(int nSprite, int nSector);
+void mydeletesprite(int nSprite);
+
+void GrabPalette();
+
+void mysetbrightness(char nBrightness);
+
+void StartFadeIn();
+int DoFadeIn();
+
+void InitSpiritHead();
+
+int CopyCharToBitmap(char nChar, int nTile, int xPos, int yPos);
+
+// TODO - relocate
+void StatusMessage(int messageTime, const char *fmt, ...);
+
+int DoSpiritHead();
+
+extern buildvfs_kfd kopen4loadfrommod(const char* filename, char searchfirst);
+
+extern short nCDTrackLength;
+
+extern char sHollyStr[];
+
+extern int localclock;
+
+extern int moveframes;
+
+extern short bSerialPlay;
+
+extern int nNetPlayerCount;
+
+extern int htimer;
+
+extern int nNetTime;
+extern short barpages;
+
+extern short nTotalPlayers;
+
+extern short nFontFirstChar;
+extern short nBackgroundPic;
+extern short nShadowPic;
+
+extern short nCreaturesLeft;
+
+extern int lLocalButtons;
+
+extern short nEnergyTowers;
+
+extern short nEnergyChan;
+
+extern short nSpiritSprite;
+
+extern short bNoCDCheck;
+
+extern short bInDemo;
+
+extern short nFreeze;
+
+extern short nCurBodyNum;
+extern short nBodyTotal;
+
+extern short bSnakeCam;
+
+extern short levelnum;
+extern short nScreenWidth;
+extern short nScreenHeight;
+
+extern short bMapMode;
+
+extern short nButtonColor;
+
+extern short nHeadStage;
+
+extern short lastfps;
+
+extern int flash;
+
+extern short bNoCreatures;
+
+extern short nLocalSpr;
+extern short levelnew;
+
+extern short textpages;
+
+extern short nSnakeCam;
+
+extern short bHiRes;
+extern short bCoordinates;
+extern short bFullScreen;
+
+extern short bHolly;
+
+extern short screensize;
+
+extern int totalmoves;
+
+extern short nGamma;
+
+extern short screenpage;
+
+extern int lCountDown;
+
+extern short bSlipMode;
+
+extern short nItemTextIndex;
+extern const char *gString[];
+
+extern char g_modDir[BMAX_PATH];
+enum {
+ kPalNormal = 0,
+ kPalNoDim,
+ kPalTorch,
+ kPalNoTorch,
+ kPalBrite,
+ kPalRedBrite,
+ kPalGreenBrite,
+ kPalNormal2,
+ kPalNoDim2,
+ kPalTorch2,
+ kPalNoTorch2,
+ kPalBrite2
+};
+
+#endif
diff --git a/source/exhumed/src/exscript.cpp b/source/exhumed/src/exscript.cpp
new file mode 100644
index 000000000..bfc411b68
--- /dev/null
+++ b/source/exhumed/src/exscript.cpp
@@ -0,0 +1,424 @@
+
+// Our replacement for the MACT scripting library as the one Exhumed/Powerslave uses is from an older version. This code is based on that older version
+
+#include "typedefs.h"
+#include "exscript.h"
+#include
+#include
+#include
+
+#if 0
+
+// 16 bytes in size?
+struct Script
+{
+ char * _0;
+ Script *_4;
+ Script * _8;
+ Script * _12;
+};
+
+int ScriptGrabbed = 0;
+Script *currentsection = 0;
+int scriptline = 0;
+
+Script *script = 0;
+BYTE *scriptbuffer = 0;
+BYTE *script_p = 0;
+BYTE *scriptend_p = 0;
+int tokenready = 0;
+
+char scriptfilename[128];
+
+
+void FreeScriptSection()
+{
+
+}
+
+void FreeScript()
+{
+
+}
+
+void Error(const char *fmt, ...)
+{
+ // TODO
+ exit(-1);
+}
+
+bool TokenAvailable(int nLine)
+{
+ BYTE *pOffs = script_p;
+ if (pOffs >= scriptend_p) {
+ return false;
+ }
+
+ while (1)
+ {
+ char c = *pOffs;
+
+ if (c > ' ')
+ {
+ if (c != ';') {
+ return true;
+ }
+
+ while (1)
+ {
+ c = *pOffs;
+
+ if (c == 0xA) {
+ break;
+ }
+
+ if (pOffs >= scriptend_p) {
+ return 0;
+ }
+
+ pOffs++;
+ }
+ }
+ else
+ {
+ if (c == 0x0A && !nLine)
+ {
+ Error("Line %i is incomplete\nin file %s\n", scriptline, scriptfilename);
+ }
+
+ pOffs++;
+
+ if (pOffs >= scriptend_p) {
+ return false;
+ }
+ }
+ }
+}
+
+void CheckParseOverflow()
+{
+ if (script_p >= scriptend_p) {
+ Error("End of script reached prematurely\n");
+ }
+}
+
+void SkipWhiteSpace(int nLine)
+{
+ while (1)
+ {
+ CheckParseOverflow();
+
+ char c = *script_p;
+
+ if (c > ' ')
+ {
+ if (c != ';') {
+ return;
+ }
+
+ while (1)
+ {
+ c = *script_p;
+
+ if (c == 0xA || script_p >= scriptend_p) {
+ continue;
+ }
+
+ script_p++;
+ }
+ }
+ else
+ {
+ script_p++;
+ if (c != 0xA) {
+ continue;
+ }
+
+ if (!nLine)
+ {
+ Error("Line %i is incomplete\nin file %s\n");
+ }
+
+ scriptline++;
+ }
+ }
+}
+
+void AddScriptEntry(char *entry, Script *pScript)
+{
+ Script *eax = 0;
+
+ if (!currentsection) {
+ Error("No current section adding %s", entry);
+ }
+
+ if (currentsection->_4->_8 != currentsection->_4)
+ {
+ while (1)
+ {
+ if (stricmp(entry, currentsection->_4->_8->_0) == 0)
+ {
+ eax = currentsection->_4->_8;
+ break;
+ }
+
+ if (currentsection->_4->_8->_8 == currentsection->_4)
+ {
+ break;
+ }
+ }
+ }
+
+ if (!eax)
+ {
+ Script *pScript = new Script;
+
+ Script *ecx = currentsection->_4;
+ pScript->_8 = currentsection->_4;
+ pScript->_12 = ecx->_12;
+
+ ecx = currentsection->_4;
+ ecx->_12->_8 = pScript;
+ currentsection->_4->_12 = pScript;
+ pScript->_0 = entry;
+ pScript->_4 = pScript;
+ }
+ else
+ {
+ eax = 0;
+
+ if (currentsection->_4->_8 != currentsection->_4)
+ {
+ while (1)
+ {
+ if (stricmp(entry, currentsection->_4->_8->_0) == 0)
+ {
+ eax = currentsection->_4->_8;
+ break;
+ }
+
+ if (currentsection->_4->_8->_8 == currentsection->_4) {
+ break;
+ }
+ }
+ }
+
+ eax->_0 = entry;
+ eax->_4 = pScript;
+ }
+}
+
+void AddScriptSection(char *section)
+{
+ Script *eax = 0;
+
+ if (script->_8 != script)
+ {
+ while (1)
+ {
+ if (stricmp(section, script->_8->_0))
+ {
+ if (script->_8 == script) {
+ eax = 0;
+ break;
+ }
+ }
+ else {
+ eax = script->_8;
+ break;
+ }
+ }
+ }
+
+ if (!eax)
+ {
+ Script *pNew = new Script;
+ pNew->_8 = script;
+ Script *ebx = script->_12;
+ pNew->_12 = ebx;
+ ebx->_8 = pNew;
+ script->_12 = pNew;
+ pNew->_0 = section;
+
+ pNew->_4 = new Script;
+ pNew->_4->_12 = pNew->_4;
+ pNew->_4->_8 = pNew->_4;
+ }
+
+ eax = 0;
+
+ if (script->_8 != script)
+ {
+ while (1)
+ {
+ if (!stricmp(section, script->_8->_0))
+ {
+ eax = script->_8;
+ break;
+ }
+
+ if (script->_8->_8 == script)
+ {
+ break;
+ }
+ }
+ }
+
+ currentsection = eax;
+}
+
+void DecodeToken()
+{
+ char c = *script_p;
+
+ if (c == '[')
+ {
+ char *pSection = (char*)script_p;
+
+ while (1)
+ {
+ c = *script_p;
+
+ if (c <= ' ' || c == '=') {
+ break;
+ }
+
+ script_p++;
+ CheckParseOverflow();
+ }
+
+ c = *script_p;
+
+ if (c != '=')
+ {
+ script_p = '\0';
+ SkipWhiteSpace(1);
+
+ c = *script_p;
+ if (c != '=')
+ {
+ Error("No entry separator found for %s\n", pSection);
+ }
+
+ script_p = '\0';
+ SkipWhiteSpace(1);
+
+ AddScriptEntry(pSection, script_p);
+
+ while (1)
+ {
+
+ }
+ }
+ }
+ else
+ {
+ script_p++;
+ char *pSection = (char*)script_p;
+
+ while (1)
+ {
+ c = *script_p;
+
+ if (c != ']')
+ {
+ if (c == 0xA) {
+ Error("No matching bracket found for section %s", pSection);
+ }
+
+ script_p++;
+ CheckParseOverflow();
+ }
+ else
+ {
+ script_p = '\0';
+
+ AddScriptSection(pSection);
+
+ while (1)
+ {
+ c = *script_p;
+
+ if (c == 0xA) {
+ return;
+ }
+
+ if (script_p >= scriptend_p) {
+ return;
+ }
+
+ script_p++;
+ }
+ }
+ }
+ }
+}
+
+void LoadScript(char *filename, int nVal)
+{
+ if (!ScriptGrabbed) {
+ FreeScript();
+ }
+
+ script = new Script;
+ currentsection = 0;
+ script->_12 = script;
+ script->_8 = script;
+
+ int nScriptSize = 0;
+// LoadFile(filename);
+ {
+ FILE *fp = fopen(filename, "rb");
+ if (!fp) {
+ // TODO - do error message
+ return;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ nScriptSize = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ scriptbuffer = new BYTE[nScriptSize];
+ if (!scriptbuffer) {
+ // TODO - do error message
+ return;
+ }
+
+ fread(scriptbuffer, 1, nScriptSize, fp);
+ fclose(fp);
+ }
+
+ strcpy(scriptfilename, filename);
+
+
+ scriptline = 1;
+ script_p = scriptbuffer;
+ tokenready = 0;
+ scriptend_p = scriptbuffer + nScriptSize;
+
+ int edx = 0;
+
+ if (nVal)
+ {
+ int nLine = 1;
+
+ while (1)
+ {
+ if (edx) {
+ return;
+ }
+
+ if (TokenAvailable(nLine))
+ {
+ SkipWhiteSpace(nLine);
+ DecodeToken();
+ }
+ else
+ {
+ edx = nLine;
+ }
+ }
+ }
+}
+
+#endif
diff --git a/source/exhumed/src/exscript.h b/source/exhumed/src/exscript.h
new file mode 100644
index 000000000..9fbde3553
--- /dev/null
+++ b/source/exhumed/src/exscript.h
@@ -0,0 +1,7 @@
+
+#ifndef __exscript_h__
+#define __exscript_h__
+
+
+
+#endif
diff --git a/source/exhumed/src/fish.cpp b/source/exhumed/src/fish.cpp
new file mode 100644
index 000000000..99eb40e02
--- /dev/null
+++ b/source/exhumed/src/fish.cpp
@@ -0,0 +1,572 @@
+
+#include "fish.h"
+#include "anims.h"
+#include "engine.h"
+#include "sequence.h"
+#include "random.h"
+#include "runlist.h"
+#include "exhumed.h"
+#include "move.h"
+#include "trigdat.h"
+#include "init.h"
+#include
+
+#define kMaxFishes 128
+#define kMaxChunks 128
+
+short FishSprite = -1;
+short FishCount = 0;
+
+static actionSeq ActionSeq[] = {
+ {8, 0},
+ {8, 0},
+ {0, 0},
+ {24, 0},
+ {8, 0},
+ {32, 1},
+ {33, 1},
+ {34, 1},
+ {35, 1},
+ {39, 1}
+};
+
+short nChunksFree;
+
+int nFreeChunk[kMaxChunks] = { 0 };
+
+struct Fish
+{
+ short nHealth;
+ short field_2;
+ short nAction;
+ short nSprite;
+ short nTarget;
+ short field_A;
+ short field_C;
+ short field_E;
+};
+
+struct Chunk
+{
+ short nSprite;
+ short field_2;
+ short field_4;
+ short field_6;
+};
+
+Fish FishList[kMaxFishes];
+Chunk FishChunk[kMaxChunks];
+
+
+void InitFishes()
+{
+ FishCount = 0;
+ FishSprite = 1;
+ nChunksFree = kMaxChunks;
+
+ for (int i = 0; i < kMaxChunks; i++) {
+ nFreeChunk[i] = i;
+ }
+}
+
+int BuildFishLimb(short nFish, short edx)
+{
+ if (nChunksFree <= 0) {
+ return -1;
+ }
+
+ short nSprite = FishList[nFish].nSprite;
+
+ nChunksFree--;
+
+ int nFree = nFreeChunk[nChunksFree];
+
+ int nSprite2 = insertsprite(sprite[nSprite].sectnum, 99);
+ assert(nSprite2 >= 0 && nSprite2 < kMaxSprites);
+
+ FishChunk[nFree].nSprite = nSprite2;
+ FishChunk[nFree].field_4 = edx + 40;
+ FishChunk[nFree].field_2 = RandomSize(3) % SeqSize[SeqOffsets[kSeqFish] + edx + 40];
+
+ sprite[nSprite2].x = sprite[nSprite].x;
+ sprite[nSprite2].y = sprite[nSprite].y;
+ sprite[nSprite2].z = sprite[nSprite].z;
+ sprite[nSprite2].cstat = 0;
+ sprite[nSprite2].shade = -12;
+ sprite[nSprite2].pal = 0;
+ sprite[nSprite2].xvel = (RandomSize(5) - 16) << 8;
+ sprite[nSprite2].yvel = (RandomSize(5) - 16) << 8;
+ sprite[nSprite2].xrepeat = 64;
+ sprite[nSprite2].yrepeat = 64;
+ sprite[nSprite2].xoffset = 0;
+ sprite[nSprite2].yoffset = 0;
+ sprite[nSprite2].zvel = (-(RandomByte() + 512)) * 2;
+
+ // not sure what's going on here... return value doesn't seem to be used
+ seq_GetSeqPicnum(kSeqFish, FishChunk[nFree].field_4, 0);
+
+ sprite[nSprite2].picnum = edx;
+ sprite[nSprite2].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite2].clipdist = 0;
+
+// GrabTimeSlot(3);
+
+ sprite[nSprite2].extra = -1;
+ sprite[nSprite2].owner = runlist_AddRunRec(sprite[nSprite2].lotag - 1, nFree | 0x200000);
+ sprite[nSprite2].hitag = runlist_AddRunRec(NewRun, nFree | 0x200000);
+
+ return nFree | 0x200000;
+}
+
+void BuildBlood(int x, int y, int z, short nSector)
+{
+ BuildAnim(-1, kSeqFish, 36, x, y, z, nSector, 75, 128);
+}
+
+void FuncFishLimb(int a, int nDamage, int nRun)
+{
+ short nFish = RunData[nRun].nVal;
+ short nSprite = FishChunk[nFish].nSprite;
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ int nSeq = SeqOffsets[kSeqFish] + FishChunk[nFish].field_4;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x20000:
+ {
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, FishChunk[nFish].field_2);
+
+ Gravity(nSprite);
+
+ FishChunk[nFish].field_2++;
+
+ if (FishChunk[nFish].field_2 >= SeqSize[nSeq])
+ {
+ FishChunk[nFish].field_2 = 0;
+ if (RandomBit()) {
+ BuildBlood(sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum);
+ }
+ }
+
+ int FloorZ = sector[sprite[nSprite].sectnum].floorz;
+
+ if (FloorZ <= sprite[nSprite].z)
+ {
+ sprite[nSprite].z += 256;
+
+ if ((sprite[nSprite].z - FloorZ) > 25600)
+ {
+ sprite[nSprite].zvel = 0;
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+ runlist_SubRunRec(sprite[nSprite].hitag);
+ mydeletesprite(nSprite);
+ }
+ else if ((sprite[nSprite].z - FloorZ) > 0)
+ {
+ sprite[nSprite].zvel = 1024;
+ }
+
+ return;
+ }
+ else
+ {
+ if (movesprite(nSprite, sprite[nSprite].xvel << 8, sprite[nSprite].yvel << 8, sprite[nSprite].zvel, 2560, -2560, CLIPMASK1))
+ {
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+ }
+
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, nSeq, FishChunk[nFish].field_2, 1);
+ return;
+ }
+ }
+}
+
+int BuildFish(int nSprite, int x, int y, int z, int nSector, int nAngle)
+{
+ short nFish = FishCount;
+ FishCount++;
+
+ if (nFish >= kMaxFishes) {
+ return -1;
+ }
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(nSector, 103);
+ }
+ else
+ {
+ x = sprite[nSprite].x;
+ y = sprite[nSprite].y;
+ z = sprite[nSprite].z;
+ nAngle = sprite[nSprite].ang;
+ changespritestat(nSprite, 103);
+ }
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].clipdist = 80;
+ sprite[nSprite].xrepeat = 40;
+ sprite[nSprite].yrepeat = 40;
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].picnum = seq_GetSeqPicnum(kSeqFish, ActionSeq[0].a, 0);
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].extra = -1;
+
+// GrabTimeSlot(3);
+
+ FishList[nFish].nAction = 0;
+ FishList[nFish].nHealth = 200;
+ FishList[nFish].nSprite = nSprite;
+ FishList[nFish].nTarget = -1;
+ FishList[nFish].field_C = 60;
+ FishList[nFish].field_2 = 0;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nFish | 0x120000);
+ FishList[nFish].field_E = runlist_AddRunRec(NewRun, nFish | 0x120000);
+
+ nCreaturesLeft++;
+
+ return nFish | 0x120000;
+}
+
+void IdleFish(short nFish, short edx)
+{
+ short nSprite = FishList[nFish].nSprite;
+ short nAngle = sprite[nSprite].ang;
+
+ sprite[nSprite].ang += ((256 - RandomSize(9)) + 1024) & kAngleMask;
+
+ sprite[nSprite].xvel = (sprite[nSprite].ang + 512) >> 8;
+ sprite[nSprite].yvel = (sprite[nSprite].ang) >> 8;
+
+ FishList[nFish].nAction = 0;
+ FishList[nFish].field_2 = 0;
+
+ sprite[nSprite].zvel = RandomSize(9);
+
+ if (!edx)
+ {
+ if (RandomBit()) {
+ sprite[nSprite].zvel = -sprite[nSprite].zvel;
+ }
+ }
+ else if (edx < 0)
+ {
+ sprite[nSprite].zvel = -sprite[nSprite].zvel;
+ }
+}
+
+void DestroyFish(short nFish)
+{
+ short nSprite = FishList[nFish].nSprite;
+
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+ runlist_SubRunRec(FishList[nFish].field_E);
+ mydeletesprite(nSprite);
+}
+
+void FuncFish(int a, int nDamage, int nRun)
+{
+ short nFish = RunData[nRun].nVal;
+ assert(nFish >= 0 && nFish < kMaxFishes);
+
+ short nSprite = FishList[nFish].nSprite;
+ short nAction = FishList[nFish].nAction;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Fish\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ if (FishList[nFish].nHealth <= 0) {
+ return;
+ }
+ else
+ {
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ if (!nDamage) {
+ return;
+ }
+ else
+ {
+ FishList[nFish].field_C = 10;
+ }
+ }
+ // fall through
+ }
+ case 0x80000:
+ {
+ if (!nDamage) {
+ return;
+ }
+
+ FishList[nFish].nHealth -= nDamage;
+ if (FishList[nFish].nHealth <= 0)
+ {
+ FishList[nFish].nHealth = 0;
+ nCreaturesLeft--;
+
+ sprite[nSprite].cstat &= 0xFEFE;
+
+ if (nMessage == 0x80000)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ BuildFishLimb(nFish, i);
+ }
+
+// TODO PlayFXAtXYZ(StaticSound[kSound40], sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum);
+ DestroyFish(nFish);
+ }
+ else
+ {
+ FishList[nFish].nAction = 9;
+ FishList[nFish].field_2 = 0;
+ }
+
+ return;
+ }
+ else
+ {
+ short nTarget = a & 0xFFFF;
+ if (nTarget >= 0 && sprite[nTarget].statnum < 199)
+ {
+ FishList[nFish].nTarget = nTarget;
+ }
+
+ FishList[nFish].nAction = 4;
+ FishList[nFish].field_2 = 0;
+ FishList[nFish].field_C += 10;
+ }
+
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, SeqOffsets[kSeqFish] + ActionSeq[nAction].a, FishList[nFish].field_2, ActionSeq[nAction].b);
+ tsprite[a & 0xFFFF].owner = -1;
+ return;
+ }
+
+ case 0x20000:
+ {
+ if (!(SectFlag[sprite[nSprite].sectnum] & kSectUnderwater))
+ {
+ Gravity(nSprite);
+ }
+
+ short nSeq = SeqOffsets[kSeqFish] + ActionSeq[nAction].a;
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, FishList[nFish].field_2);
+
+ seq_MoveSequence(nSprite, nSeq, FishList[nFish].field_2);
+
+ FishList[nFish].field_2++;
+ if (FishList[nFish].field_2 >= SeqSize[nSeq]) {
+ FishList[nFish].field_2 = 0;
+ }
+
+ short nTarget = FishList[nFish].nTarget;
+
+ switch (nAction)
+ {
+ default:
+ return;
+
+ case 0:
+ {
+ FishList[nFish].field_C--;
+ if (FishList[nFish].field_C <= 0)
+ {
+ nTarget = FindPlayer(nSprite, 60);
+ if (nTarget >= 0)
+ {
+ FishList[nFish].nTarget = nTarget;
+ FishList[nFish].nAction = 2;
+ FishList[nFish].field_2 = 0;
+
+ int nAngle = GetMyAngle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].z - sprite[nSprite].z);
+ sprite[nSprite].zvel = Sin(nAngle) >> 5;
+
+ FishList[nFish].field_C = RandomSize(6) + 90;
+ }
+ else
+ {
+ IdleFish(nFish, 0);
+ }
+ }
+
+ break;
+ }
+
+ case 1:
+ return;
+
+ case 2:
+ case 3:
+ {
+ FishList[nFish].field_C--;
+ if (FishList[nFish].field_C <= 0)
+ {
+ IdleFish(nFish, 0);
+ return;
+ }
+ else
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+ int nHeight = GetSpriteHeight(nSprite) >> 1;
+
+ int z = sprite[nTarget].z - sprite[nSprite].z;
+
+ if (z < 0) {
+ z = -z;
+ }
+
+ if (z <= nHeight)
+ {
+ sprite[nSprite].xvel = (Sin(sprite[nSprite].ang + 512) >> 5) - (Sin(sprite[nSprite].ang + 512) >> 7);
+ sprite[nSprite].yvel = ((Sin(sprite[nSprite].ang) >> 5) >> 5) - ((Sin(sprite[nSprite].ang) >> 5) >> 7);
+ }
+ else
+ {
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+
+ sprite[nSprite].zvel = (sprite[nTarget].z - sprite[nSprite].z) >> 3;
+ }
+ break;
+ }
+
+ case 4:
+ {
+ if (!FishList[nFish].field_2)
+ {
+ IdleFish(nFish, 0);
+ }
+ return;
+ }
+
+ case 8:
+ {
+ return;
+ }
+
+ case 9:
+ {
+ if (!FishList[nFish].field_2)
+ {
+ DestroyFish(nFish);
+ }
+ return;
+ }
+ }
+
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ int z = sprite[nSprite].z;
+ short nSector = sprite[nSprite].sectnum;
+
+ // loc_2EF54
+ int nVal = movesprite(nSprite, sprite[nSprite].xvel << 13, sprite[nSprite].yvel << 13, sprite[nSprite].zvel << 2, 0, 0, CLIPMASK0);
+
+ if (!(SectFlag[sprite[nSprite].sectnum] & kSectUnderwater))
+ {
+ mychangespritesect(nSprite, nSector);
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+
+ IdleFish(nFish, 0);
+ return;
+ }
+ else
+ {
+ if (nAction >= 5) {
+ return;
+ }
+
+ if (!nVal)
+ {
+ if (nAction == 3)
+ {
+ FishList[nFish].nAction = 2;
+ FishList[nFish].field_2 = 0;
+ }
+ return;
+ }
+
+ if (nVal != 0x30000)
+ {
+ if ((nVal & 0xC000) == 0x8000)
+ {
+ IdleFish(nFish, 0);
+ }
+ else if ((nVal & 0xC000) == 0xC000)
+ {
+ if (sprite[nVal & 0x3FFF].statnum == 100)
+ {
+ FishList[nFish].nTarget = nVal & 0x3FFF;
+ sprite[nSprite].ang = GetMyAngle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+
+ if (nAction != 3)
+ {
+ FishList[nFish].nAction = 3;
+ FishList[nFish].field_2 = 0;
+ }
+
+ if (!FishList[nFish].field_2)
+ {
+ runlist_DamageEnemy(nTarget, nSprite, 2);
+ }
+ }
+ }
+ }
+ else if (nVal == 0x20000)
+ {
+ IdleFish(nFish, -1);
+ }
+ else
+ {
+ IdleFish(nFish, 1);
+ }
+ }
+
+ return;
+ }
+ }
+}
diff --git a/source/exhumed/src/fish.h b/source/exhumed/src/fish.h
new file mode 100644
index 000000000..31a4178b9
--- /dev/null
+++ b/source/exhumed/src/fish.h
@@ -0,0 +1,11 @@
+
+#ifndef __fish_h__
+#define __fish_h__
+
+void InitFishes();
+int BuildFish(int nSprite, int x, int y, int z, int nSector, int nAngle);
+
+void FuncFish(int, int, int);
+void FuncFishLimb(int a, int b, int c);
+
+#endif
diff --git a/source/exhumed/src/grenade.cpp b/source/exhumed/src/grenade.cpp
new file mode 100644
index 000000000..71c466af9
--- /dev/null
+++ b/source/exhumed/src/grenade.cpp
@@ -0,0 +1,419 @@
+
+#include "grenade.h"
+#include "engine.h"
+#include "player.h"
+#include "runlist.h"
+#include "exhumed.h"
+#include "sound.h"
+#include "move.h"
+#include "init.h"
+#include "bullet.h"
+#include "gun.h"
+#include "anims.h"
+#include "lighting.h"
+#include "sequence.h"
+#include "random.h"
+#include
+
+int nGrenadeCount = 0;
+int nGrenadesFree;
+
+short GrenadeFree[kMaxGrenades];
+
+struct Grenade
+{
+ short field_0;
+ short field_2;
+ short nSprite;
+ short field_6;
+ short field_8;
+ short field_A;
+ short field_C;
+ short field_E;
+ int field_10;
+ int x;
+ int y;
+};
+
+Grenade GrenadeList[kMaxGrenades];
+
+
+void InitGrenades()
+{
+ nGrenadeCount = 0;
+
+ for (int i = 0; i < kMaxGrenades; i++) {
+ GrenadeFree[i] = i;
+ }
+
+ nGrenadesFree = kMaxGrenades;
+}
+
+short GrabGrenade()
+{
+ return GrenadeFree[--nGrenadesFree];
+}
+
+void DestroyGrenade(short nGrenade)
+{
+ runlist_DoSubRunRec(GrenadeList[nGrenade].field_6);
+ runlist_SubRunRec(GrenadeList[nGrenade].field_8);
+ runlist_DoSubRunRec(sprite[GrenadeList[nGrenade].nSprite].lotag - 1);
+
+ mydeletesprite(GrenadeList[nGrenade].nSprite);
+ GrenadeFree[nGrenadesFree] = nGrenade;
+
+ nGrenadesFree++;
+}
+
+void BounceGrenade(short nGrenade, short nAngle)
+{
+ GrenadeList[nGrenade].field_10 >>= 1;
+
+ GrenadeList[nGrenade].x = (Sin(nAngle + 512) >> 5) * GrenadeList[nGrenade].field_10;
+ GrenadeList[nGrenade].y = (Sin(nAngle) >> 5) * GrenadeList[nGrenade].field_10;
+
+ D3PlayFX(StaticSound[kSound3], GrenadeList[nGrenade].nSprite);
+}
+
+int ThrowGrenade(short nPlayer, int edx, int ebx, int ecx, int push1)
+{
+ if (nPlayerGrenade[nPlayer] < 0)
+ return -1;
+
+ short nGrenade = nPlayerGrenade[nPlayer];
+
+ short nGrenadeSprite = GrenadeList[nGrenade].nSprite;
+ short nPlayerSprite = PlayerList[nPlayer].nSprite;
+
+ mychangespritesect(nGrenadeSprite, nPlayerViewSect[nPlayer]);
+
+ short nAngle = sprite[nPlayerSprite].ang;
+
+ sprite[nGrenadeSprite].x = sprite[nPlayerSprite].x;
+ sprite[nGrenadeSprite].y = sprite[nPlayerSprite].y;
+ sprite[nGrenadeSprite].z = sprite[nPlayerSprite].z;
+
+ if (nAngle < 0) {
+ nAngle = sprite[nPlayerSprite].ang; // TODO - checkme
+ }
+
+ sprite[nGrenadeSprite].cstat &= 0x7FFF;
+ sprite[nGrenadeSprite].ang = nAngle;
+
+ if (push1 >= -3000)
+ {
+ int nVel = totalvel[nPlayer] << 5;
+
+ GrenadeList[nGrenade].field_10 = ((90 - GrenadeList[nGrenade].field_E) * (90 - GrenadeList[nGrenade].field_E)) + nVel;
+ sprite[nGrenadeSprite].zvel = (-64 * push1) - 4352;
+
+ int nMov = movesprite(nGrenadeSprite, Sin(nAngle + 512) * (sprite[nPlayerSprite].clipdist << 3), Sin(nAngle) * (sprite[nPlayerSprite].clipdist << 3), ecx, 0, 0, CLIPMASK1);
+ if (nMov & 0x8000)
+ {
+ nAngle = GetWallNormal(nMov & 0x3FFF);
+ BounceGrenade(nGrenade, nAngle);
+ }
+ }
+ else
+ {
+ GrenadeList[nGrenade].field_10 = 0;
+ sprite[nGrenadeSprite].zvel = sprite[nPlayerSprite].zvel;
+ }
+
+ GrenadeList[nGrenade].x = Sin(nAngle + 512) >> 4;
+ GrenadeList[nGrenade].x *= GrenadeList[nGrenade].field_10;
+
+ GrenadeList[nGrenade].y = Sin(nAngle) >> 4;
+ GrenadeList[nGrenade].y *= GrenadeList[nGrenade].field_10;
+
+ nPlayerGrenade[nPlayer] = -1;
+
+ return nGrenadeSprite;
+}
+
+int BuildGrenade(int nPlayer)
+{
+ if (nGrenadesFree == 0)
+ return -1;
+
+ int nGrenade = GrabGrenade();
+
+ int nSprite = insertsprite(nPlayerViewSect[nPlayer], 201);
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ int nPlayerSprite = PlayerList[nPlayer].nSprite;
+
+ sprite[nSprite].x = sprite[nPlayerSprite].x;
+ sprite[nSprite].y = sprite[nPlayerSprite].y;
+ sprite[nSprite].z = sprite[nPlayerSprite].z - 3840;
+ sprite[nSprite].shade = -64;
+ sprite[nSprite].xrepeat = 20;
+ sprite[nSprite].yrepeat = 20;
+ sprite[nSprite].cstat = 0x8000u;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].pal = 0;
+ sprite[nSprite].clipdist = 30;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].ang = sprite[nPlayerSprite].ang;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].owner = nPlayerSprite;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].extra = -1;
+
+// GrabTimeSlot(3);
+
+ GrenadeList[nGrenade].field_E = 90;
+ GrenadeList[nGrenade].field_2 = 0;
+ GrenadeList[nGrenade].field_0 = 16;
+ GrenadeList[nGrenade].field_10 = -1;
+ GrenadeList[nGrenade].nSprite = nSprite;
+ GrenadeList[nGrenade].field_A = 0;
+ GrenadeList[nGrenade].field_C = 0;
+ GrenadeList[nGrenade].field_6 = runlist_AddRunRec(sprite[nSprite].lotag - 1, nGrenade | 0x0F0000);
+ GrenadeList[nGrenade].field_8 = runlist_AddRunRec(NewRun, nGrenade | 0x0F0000);
+
+ nGrenadePlayer[nGrenade] = nPlayer;
+ nPlayerGrenade[nPlayer] = nGrenade;
+
+ return nSprite;
+}
+
+void ExplodeGrenade(short nGrenade)
+{
+ int var_28, var_20;
+
+ short nPlayer = nGrenadePlayer[nGrenade];
+ int nGrenadeSprite = GrenadeList[nGrenade].nSprite;
+ short nGrenadeSect = sprite[nGrenadeSprite].sectnum;
+
+ GrenadeList[nGrenade].field_C = 1;
+
+ if (SectFlag[nGrenadeSect] & kSectUnderwater)
+ {
+ var_28 = 75;
+ var_20 = 60;
+ }
+ else
+ {
+ if (sprite[nGrenadeSprite].z < sector[nGrenadeSect].floorz)
+ {
+ var_20 = 200;
+ var_28 = 36;
+
+// TODO MonoOut("GRENPOW\n");
+ }
+ else
+ {
+ var_28 = 34;
+ var_20 = 150;
+
+// TODO MonoOut("GRENBOOM\n");
+ }
+ }
+
+ if (GrenadeList[nGrenade].field_10 < 0)
+ {
+ short nPlayerSprite = PlayerList[nPlayer].nSprite;
+ short nAngle = sprite[nPlayerSprite].ang;
+
+ sprite[nGrenadeSprite].z = sprite[nPlayerSprite].z;
+ sprite[nGrenadeSprite].x = (Sin(nAngle + 512) >> 5) + sprite[nPlayerSprite].x;
+ sprite[nGrenadeSprite].y = (Sin(nAngle) >> 5) + sprite[nPlayerSprite].y;
+
+ changespritesect(nGrenadeSprite, sprite[nPlayerSprite].sectnum);
+
+ if (!PlayerList[nPlayer].invincibility) {
+ PlayerList[nPlayer].nHealth = 1;
+ }
+ }
+
+ short nDamage = BulletInfo[kWeaponGrenade].nDamage;
+
+ if (nPlayerDouble[nPlayer] > 0) {
+ nDamage *= 2;
+ }
+
+ runlist_RadialDamageEnemy(nGrenadeSprite, nDamage, BulletInfo[kWeaponGrenade].field_10);
+
+ BuildAnim(-1, var_28, 0, sprite[nGrenadeSprite].x, sprite[nGrenadeSprite].y, sprite[nGrenadeSprite].z, sprite[nGrenadeSprite].sectnum, var_20, 4);
+ AddFlash(sprite[nGrenadeSprite].sectnum, sprite[nGrenadeSprite].x, sprite[nGrenadeSprite].y, sprite[nGrenadeSprite].z, 128);
+
+ nGrenadePlayer[nGrenade] = -1;
+ DestroyGrenade(nGrenade);
+}
+
+void FuncGrenade(int a, int nDamage, int nRun)
+{
+ short nGrenade = RunData[nRun].nVal;
+ assert(nGrenade >= 0 && nGrenade < kMaxGrenades);
+
+ short nGrenadeSprite = GrenadeList[nGrenade].nSprite;
+ short nSeq;
+
+ if (GrenadeList[nGrenade].field_C)
+ {
+ nSeq = SeqOffsets[kSeqGrenBoom];
+ }
+ else
+ {
+ nSeq = SeqOffsets[kSeqGrenRoll] + GrenadeList[nGrenade].field_A;
+ }
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, nSeq, GrenadeList[nGrenade].field_2 >> 8, 1);
+ break;
+ }
+
+ default:
+ {
+ DebugOut("unknown msg %d for bullet\n", a & 0x7F0000); // TODO - change 'bullet' to 'grenade' ?
+ return;
+ }
+
+ case 0x20000:
+ {
+ seq_MoveSequence(nGrenadeSprite, nSeq, GrenadeList[nGrenade].field_2 >> 8);
+ sprite[nGrenadeSprite].picnum = seq_GetSeqPicnum2(nSeq, GrenadeList[nGrenade].field_2 >> 8);
+
+ GrenadeList[nGrenade].field_E--;
+ if (!GrenadeList[nGrenade].field_E)
+ {
+ short nPlayer = nGrenadePlayer[nGrenade];
+
+ if (GrenadeList[nGrenade].field_10 < 0)
+ {
+ PlayerList[nPlayer].field_3A = 0;
+ PlayerList[nPlayer].field_34 = 0;
+
+ if (PlayerList[nPlayer].nAmmo[kWeaponGrenade])
+ {
+ PlayerList[nPlayer].bIsFiring = kFalse;
+ }
+ else
+ {
+ SelectNewWeapon(nPlayer);
+
+ PlayerList[nPlayer].nCurrentWeapon = PlayerList[nPlayer].field_38;
+ PlayerList[nPlayer].field_38 = -1;
+ }
+ }
+
+ ExplodeGrenade(nGrenade);
+ return;
+ }
+ else
+ {
+ if (GrenadeList[nGrenade].field_10 < 0) {
+ return;
+ }
+
+ int ebp = (GrenadeList[nGrenade].field_2 + GrenadeList[nGrenade].field_0) >> 8;
+
+ GrenadeList[nGrenade].field_2 += GrenadeList[nGrenade].field_0;
+
+ if (ebp < 0)
+ {
+ GrenadeList[nGrenade].field_2 += SeqSize[nSeq] << 8;
+ }
+ else
+ {
+ if (ebp >= SeqSize[nSeq])
+ {
+ if (GrenadeList[nGrenade].field_C)
+ {
+ DestroyGrenade(nGrenade);
+ return;
+ }
+ else
+ {
+ GrenadeList[nGrenade].field_2 = GrenadeList[nGrenade].field_C;
+ }
+ }
+ }
+
+ if (GrenadeList[nGrenade].field_C) {
+ return;
+ }
+
+ int zVel = sprite[nGrenadeSprite].zvel;
+
+ Gravity(nGrenadeSprite);
+ int nMov = movesprite(nGrenadeSprite, GrenadeList[nGrenade].x, GrenadeList[nGrenade].y, sprite[nGrenadeSprite].zvel, sprite[nGrenadeSprite].clipdist >> 1, sprite[nGrenadeSprite].clipdist >> 1, CLIPMASK1);
+
+ if (!nMov)
+ return;
+
+ if (nMov & 0x20000)
+ {
+ if (zVel)
+ {
+ if (SectDamage[sprite[nGrenadeSprite].sectnum] > 0)
+ {
+ ExplodeGrenade(nGrenade);
+ return;
+ }
+
+ GrenadeList[nGrenade].field_0 = (uchar)totalmoves; // limit to 8bits?
+
+ D3PlayFX(StaticSound[kSound3], nGrenadeSprite);
+
+ sprite[nGrenadeSprite].zvel = -(zVel >> 1);
+
+ if (sprite[nGrenadeSprite].zvel > -1280)
+ {
+ D3PlayFX(StaticSound[kSound5], nGrenadeSprite);
+ GrenadeList[nGrenade].field_0 = 0;
+ GrenadeList[nGrenade].field_2 = 0;
+ sprite[nGrenadeSprite].zvel = 0;
+ GrenadeList[nGrenade].field_A = 1;
+ }
+ }
+
+ GrenadeList[nGrenade].field_0 = 255 - (RandomByte() * 2);
+ GrenadeList[nGrenade].x -= (GrenadeList[nGrenade].x >> 4);
+ GrenadeList[nGrenade].y -= (GrenadeList[nGrenade].y >> 4);
+ }
+
+ // loc_2CF60:
+ if ((nMov & 0xC000) >= 0x8000)
+ {
+ if ((nMov & 0xC000) <= 0x8000)
+ {
+ BounceGrenade(nGrenade, GetWallNormal(nMov & 0x3FFF));
+ }
+ else if ((nMov & 0xC000) == 0xC000)
+ {
+ BounceGrenade(nGrenade, sprite[nMov & 0x3FFF].ang);
+ }
+ }
+
+ GrenadeList[nGrenade].field_2 = 0;
+ return;
+ }
+
+ break;
+ }
+
+ case 0xA0000:
+ {
+ if (nGrenadeSprite != nRadialSpr && !GrenadeList[nGrenade].field_C)
+ {
+ if (runlist_CheckRadialDamage(nGrenadeSprite) > 280)
+ {
+ GrenadeList[nGrenade].field_E = RandomSize(4) + 1;
+ }
+ }
+ break;
+ }
+ }
+}
diff --git a/source/exhumed/src/grenade.h b/source/exhumed/src/grenade.h
new file mode 100644
index 000000000..6f11b0e38
--- /dev/null
+++ b/source/exhumed/src/grenade.h
@@ -0,0 +1,13 @@
+
+#ifndef __grenade_h__
+#define __grenade_h__
+
+#define kMaxGrenades 50
+
+void InitGrenades();
+int BuildGrenade(int nPlayer);
+void DestroyGrenade(short nGrenade);
+int ThrowGrenade(short nPlayer, int edx, int ebx, int ecx, int push1);
+void FuncGrenade(int, int, int);
+
+#endif
diff --git a/source/exhumed/src/gun.cpp b/source/exhumed/src/gun.cpp
new file mode 100644
index 000000000..f09ca3001
--- /dev/null
+++ b/source/exhumed/src/gun.cpp
@@ -0,0 +1,1101 @@
+
+#include "gun.h"
+#include "engine.h"
+#include "init.h"
+#include "player.h"
+#include "exhumed.h"
+#include "view.h"
+#include "move.h"
+#include "status.h"
+#include "bubbles.h"
+#include "typedefs.h"
+#include "sound.h"
+#include "ra.h"
+#include "snake.h"
+#include "grenade.h"
+#include "lighting.h"
+#include "input.h"
+#include "util.h"
+#include "anims.h"
+#include "runlist.h"
+#include "bullet.h"
+#include "trigdat.h"
+#include "object.h"
+#include
+#include
+
+/*
+struct Weapon
+{
+ short nSeq;
+ short b[12]; // seq offsets?
+ short nAmmoType;
+ short c;
+ short d;
+ short bFireUnderwater;
+ short pad[15];
+};
+*/
+
+Weapon WeaponInfo[] = {
+ { kSeqSword, { 0, 1, 3, 7, -1, 2, 4, 5, 6, 8, 9, 10 }, 0, 0, 0, kTrue },
+ { kSeqPistol, { 0, 3, 2, 4, -1, 1, 0, 0, 0, 0, 0, 0 }, 1, 0, 1, kFalse },
+ { kSeqM60, { 0, 5, 6, 16, -1, 21, 0, 0, 0, 0, 0, 0 }, 2, 0, 1, kFalse },
+ { kSeqFlamer, { 0, 2, 5, 5, 6, 1, 0, 0, 0, 0, 0, 0 }, 3, 4, 1, kFalse },
+ { kSeqGrenade, { 0, 2, 3, 4, -1, 1, 0, 0, 0, 0, 0, 0 }, 4, 0, 1, kTrue },
+ { kSeqCobra, { 0, 1, 2, 2, -1, 4, 0, 0, 0, 0, 0, 0 }, 5, 0, 1, kTrue },
+ { kSeqRavolt, { 0, 1, 2, 3, -1, 4, 0, 0, 0, 0, 0, 0 }, 6, 0, 1, kTrue },
+ { kSeqRothands,{ 0, 1, 2, -1, -1, -1, 0, 0, 0, 0, 0, 0 }, 7, 0, 0, kTrue },
+ { kSeqDead, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 1, 0, kFalse },
+ { kSeqDeadEx, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 1, 0, kFalse },
+ { kSeqDeadBrn, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 1, 0, kFalse }
+};
+
+short nTemperature[kMaxPlayers];
+short nMinAmmo[] = { 0, 24, 51, 50, 1, 0, 0 };
+short word_96E26 = 0;
+
+
+void RestoreMinAmmo(short nPlayer)
+{
+ for (int i = 0; i < kMaxWeapons; i++)
+ {
+ if (i == kWeaponGrenade) {
+ continue;
+ }
+
+ if ((1 << i) & nPlayerWeapons[nPlayer])
+ {
+ if (nMinAmmo[i] > PlayerList[nPlayer].nAmmo[i]) {
+ PlayerList[nPlayer].nAmmo[i] = nMinAmmo[i];
+ }
+ }
+ }
+
+ CheckClip(nPlayer);
+}
+
+void FillWeapons(short nPlayer)
+{
+ nPlayerWeapons[nPlayer] = 0xFFFF; // turn on all bits
+
+ StatusMessage(150, "All weapons ON");
+
+ for (int i = 0; i < kMaxWeapons; i++)
+ {
+ if (WeaponInfo[i].d) {
+ PlayerList[nPlayer].nAmmo[i] = 99;
+ }
+ }
+
+ CheckClip(nPlayer);
+
+ if (nPlayer == nLocalPlayer)
+ {
+ short nWeapon = PlayerList[nPlayer].nCurrentWeapon;
+ SetCounter(PlayerList[nPlayer].nAmmo[nWeapon]);
+ }
+}
+
+void ResetPlayerWeapons(short nPlayer)
+{
+ for (int i = 0; i < kMaxWeapons; i++)
+ {
+ PlayerList[nPlayer].nAmmo[i] = 0;
+ }
+
+ PlayerList[nPlayer].nCurrentWeapon = 0;
+ PlayerList[nPlayer].field_3A = 0;
+ PlayerList[nPlayer].field_34 = 0;
+
+ nPlayerGrenade[nPlayer] = -1;
+ nPlayerWeapons[nPlayer] = 0x1; // turn on bit 1 only
+}
+
+void InitWeapons()
+{
+ memset(nPlayerGrenade, 0, sizeof(nPlayerGrenade));
+ memset(nGrenadePlayer, 0, sizeof(nGrenadePlayer));
+}
+
+void SetNewWeapon(short nPlayer, short nWeapon)
+{
+ if (nWeapon == kWeaponMummified)
+ {
+ PlayerList[nPlayer].field_3C = PlayerList[nPlayer].nCurrentWeapon;
+ PlayerList[nPlayer].bIsFiring = kFalse;
+ PlayerList[nPlayer].field_3A = 5;
+ SetPlayerMummified(nPlayer, kTrue);
+
+ PlayerList[nPlayer].field_34 = 0;
+ }
+ else
+ {
+ if (nWeapon < 0)
+ {
+ nPlayerOldWeapon[nPlayer] = PlayerList[nPlayer].nCurrentWeapon;
+ }
+ else if (nWeapon != kWeaponGrenade || PlayerList[nPlayer].nAmmo[kWeaponGrenade] > 0)
+ {
+ short nCurrentWeapon = PlayerList[nPlayer].nCurrentWeapon;
+
+ if (nCurrentWeapon != kWeaponMummified)
+ {
+ if (PlayerList[nPlayer].bIsFiring || nWeapon == nCurrentWeapon) {
+ return;
+ }
+ }
+ else
+ {
+ PlayerList[nPlayer].nCurrentWeapon = nWeapon;
+ PlayerList[nPlayer].field_34 = 0;
+ }
+ }
+ else {
+ return;
+ }
+ }
+
+ PlayerList[nPlayer].field_38 = nWeapon;
+
+ if (nPlayer == nLocalPlayer)
+ {
+ int nCounter;
+
+ if (nWeapon >= kWeaponSword && nWeapon <= kWeaponRing) {
+ nCounter = PlayerList[nPlayer].nAmmo[nWeapon];
+ }
+ else {
+ nCounter = 0;
+ }
+
+ SetCounterImmediate(nCounter);
+ }
+}
+
+void SetNewWeaponImmediate(short nPlayer, short nWeapon)
+{
+ SetNewWeapon(nPlayer, nWeapon);
+
+ PlayerList[nPlayer].nCurrentWeapon = nWeapon;
+ PlayerList[nPlayer].field_38 = -1;
+ PlayerList[nPlayer].field_34 = 0;
+ PlayerList[nPlayer].field_3A = 0;
+}
+
+void SetNewWeaponIfBetter(short nPlayer, short nWeapon)
+{
+ if (nWeapon > PlayerList[nPlayer].nCurrentWeapon) {
+ SetNewWeapon(nPlayer, nWeapon);
+ }
+}
+
+void SelectNewWeapon(short nPlayer)
+{
+ int nWeapon = 6;
+ ushort di = nPlayerWeapons[nPlayer];
+
+ ushort dx = 0x40; // bit 7 turned on
+
+ while (dx)
+ {
+ if (di & dx)
+ {
+ // we have this weapon
+ if (!WeaponInfo[nWeapon].d || PlayerList[nPlayer].nAmmo[WeaponInfo[nWeapon].nAmmoType])
+ break;
+ }
+
+ nWeapon--;
+ dx >>= 1;
+ }
+
+ if (nWeapon < 0)
+ nWeapon = 0;
+
+ PlayerList[nPlayer].bIsFiring = kFalse;
+
+ SetNewWeapon(nPlayer, nWeapon);
+}
+
+void StopFiringWeapon(short nPlayer)
+{
+ PlayerList[nPlayer].bIsFiring = kFalse;
+}
+
+void FireWeapon(short nPlayer)
+{
+ if (!PlayerList[nPlayer].bIsFiring) {
+ PlayerList[nPlayer].bIsFiring = kTrue;
+ }
+}
+
+void SetWeaponStatus(short nPlayer)
+{
+ if (nPlayer != nLocalPlayer)
+ return;
+
+ short nWeapon = PlayerList[nPlayer].nCurrentWeapon;
+
+ if (nWeapon < 0)
+ {
+ nCounterBullet = -1;
+ SetCounterImmediate(0);
+ }
+ else
+ {
+ nCounterBullet = WeaponInfo[nWeapon].nAmmoType;
+ SetCounterImmediate(PlayerList[nPlayer].nAmmo[nCounterBullet]);
+ }
+}
+
+BOOL WeaponCanFire(short nPlayer)
+{
+ short nWeapon = PlayerList[nPlayer].nCurrentWeapon;
+ short nSector = nPlayerViewSect[nPlayer];
+
+ if (!(SectFlag[nSector] & kSectUnderwater) || WeaponInfo[nWeapon].bFireUnderwater)
+ {
+ short nAmmoType = WeaponInfo[nWeapon].nAmmoType;
+
+ if (WeaponInfo[nWeapon].d <= PlayerList[nPlayer].nAmmo[nAmmoType]) {
+ return kTrue;
+ }
+ }
+
+ return kFalse;
+}
+
+// UNUSED
+void ResetSwordSeqs()
+{
+ WeaponInfo[kWeaponSword].b[2] = 3;
+ WeaponInfo[kWeaponSword].b[3] = 7;
+}
+
+int CheckCloseRange(short nPlayer, int *x, int *y, int *z, short *nSector)
+{
+ short hitSect, hitWall, hitSprite;
+ int hitX, hitY, hitZ;
+
+ short nSprite = PlayerList[nPlayer].nSprite;
+
+ int xVect = Sin(sprite[nSprite].ang + 512);
+ int yVect = Sin(sprite[nSprite].ang);
+
+ hitscan(*x, *y, *z, *nSector, xVect, yVect, 0, &hitSect, &hitWall, &hitSprite, &hitX, &hitY, &hitZ, CLIPMASK1);
+
+ int ecx = sintable[150] >> 3;
+
+ if (ksqrt((hitX - *x) * (hitX - *x) + (hitY - *y) * (hitY - *y)) >= ecx)
+ return 0;
+
+ *x = hitX;
+ *y = hitY;
+ *z = hitZ;
+ *nSector = hitSect;
+
+ if (hitSprite > -1) {
+ hitSprite |= 0xC000;
+ }
+ else
+ {
+ if (hitWall > -1) {
+ hitSprite |= 0x8000;
+ }
+ else {
+ hitSprite = 0;
+ }
+ }
+
+ return hitSprite;
+}
+
+void CheckClip(short nPlayer)
+{
+ if (nPlayerClip[nPlayer] <= 0)
+ {
+ nPlayerClip[nPlayer] = PlayerList[nPlayer].nAmmo[kWeaponM60];
+
+ if (nPlayerClip[nPlayer] > 99) {
+ nPlayerClip[nPlayer] = 99;
+ }
+ }
+}
+
+void MoveWeapons(short nPlayer)
+{
+ static int dword_96E22 = 0;
+
+ short nSectFlag = SectFlag[nPlayerViewSect[nPlayer]];
+
+ if ((nSectFlag & kSectUnderwater) && (totalmoves & 1)) {
+ return;
+ }
+
+ nPilotLightFrame++;
+
+ if (nPilotLightFrame >= nPilotLightCount)
+ nPilotLightFrame = 0;
+
+ if (!PlayerList[nPlayer].bIsFiring || (nSectFlag & kSectUnderwater))
+ nTemperature[nPlayer] = 0;
+
+ short nPlayerSprite = PlayerList[nPlayer].nSprite;
+ short nWeapon = PlayerList[nPlayer].nCurrentWeapon;
+
+ if (nWeapon < -1)
+ {
+ if (PlayerList[nPlayer].field_38 != -1)
+ {
+ PlayerList[nPlayer].nCurrentWeapon = PlayerList[nPlayer].field_38;
+ PlayerList[nPlayer].field_3A = 0;
+ PlayerList[nPlayer].field_34 = 0;
+ PlayerList[nPlayer].field_38 = -1;
+ }
+
+ return;
+ }
+
+ // loc_26ACC
+ short eax = PlayerList[nPlayer].field_3A;
+ short nSeq = WeaponInfo[nWeapon].nSeq;
+
+ short var_3C = WeaponInfo[nWeapon].b[eax] + SeqOffsets[nSeq];
+
+ int var_1C = (nPlayerDouble[nPlayer] > 0) + 1;
+
+ frames = var_1C - 1;
+
+ for (frames = var_1C; frames > 0; frames--)
+ {
+ seq_MoveSequence(nPlayerSprite, var_3C, PlayerList[nPlayer].field_34);
+
+ PlayerList[nPlayer].field_34++;
+
+ dword_96E22++;
+ if (dword_96E22 >= 15) {
+ dword_96E22 = 0;
+ }
+
+ if (PlayerList[nPlayer].field_34 >= SeqSize[var_3C])
+ {
+ if (PlayerList[nPlayer].field_38 == -1)
+ {
+ switch (PlayerList[nPlayer].field_3A)
+ {
+ default:
+ break;
+
+ case 0:
+ {
+ PlayerList[nPlayer].field_3A = 1;
+ SetWeaponStatus(nPlayer);
+ break;
+ }
+ case 1:
+ {
+ if (PlayerList[nPlayer].bIsFiring)
+ {
+ if (!WeaponCanFire(nPlayer))
+ {
+ if (!dword_96E22) {
+ D3PlayFX(StaticSound[4], PlayerList[nPlayer].nSprite);
+ }
+ }
+ else
+ {
+ if (nWeapon == kWeaponRing)
+ {
+ if (Ra[nPlayer].nTarget == -1)
+ break;
+
+ Ra[nPlayer].field_0 = 0;
+ Ra[nPlayer].field_2 = 0;
+ Ra[nPlayer].field_C = 1;
+ }
+
+ PlayerList[nPlayer].field_3A = 2;
+
+ if (nWeapon == 0)
+ break;
+
+ if (nWeapon == kWeaponGrenade)
+ {
+ BuildGrenade(nPlayer);
+ AddAmmo(nPlayer, 4, -1);
+ }
+ else if (nWeapon == kWeaponStaff)
+ {
+ ShootStaff(nPlayer);
+ }
+ }
+ }
+ break;
+ }
+
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ {
+ if (nWeapon == kWeaponPistol && nPistolClip[nPlayer] <= 0)
+ {
+ PlayerList[nPlayer].field_3A = 3;
+ PlayerList[nPlayer].field_34 = 0;
+
+ nPistolClip[nPlayer] = Min(6, PlayerList[nPlayer].nAmmo[kWeaponPistol]);
+ break;
+ }
+ else if (nWeapon == kWeaponGrenade)
+ {
+ if (!PlayerList[nPlayer].bIsFiring)
+ {
+ PlayerList[nPlayer].field_3A = 3;
+ break;
+ }
+ else
+ {
+ PlayerList[nPlayer].field_34 = SeqSize[var_3C] - 1;
+ continue;
+ }
+ }
+ else if (nWeapon == kWeaponMummified)
+ {
+ PlayerList[nPlayer].field_3A = 0;
+ PlayerList[nPlayer].nCurrentWeapon = PlayerList[nPlayer].field_3C;
+
+ nWeapon = PlayerList[nPlayer].nCurrentWeapon;
+
+ SetPlayerMummified(nPlayer, kFalse);
+ break;
+ }
+ else
+ {
+ // loc_26D88:
+ if (PlayerList[nPlayer].bIsFiring && WeaponCanFire(nPlayer))
+ {
+ if (nWeapon != kWeaponM60 && nWeapon != kWeaponPistol) {
+ PlayerList[nPlayer].field_3A = 3;
+ }
+ }
+ else
+ {
+ if (WeaponInfo[nWeapon].b[4] == -1)
+ {
+ PlayerList[nPlayer].field_3A = 1;
+ }
+ else
+ {
+ if (nWeapon == kWeaponFlamer && (nSectFlag & kSectUnderwater))
+ {
+ PlayerList[nPlayer].field_3A = 1;
+ }
+ else
+ {
+ PlayerList[nPlayer].field_3A = 4;
+ }
+ }
+ }
+
+ break;
+ }
+ }
+
+ case 3:
+ case 9:
+ case 10:
+ case 11:
+ {
+ if (nWeapon == kWeaponMummified)
+ {
+ PlayerList[nPlayer].nCurrentWeapon = PlayerList[nPlayer].field_3C;
+
+ nWeapon = PlayerList[nPlayer].nCurrentWeapon;
+
+ PlayerList[nPlayer].field_3A = 0;
+ break;
+ }
+ else if (nWeapon == kWeaponRing)
+ {
+ if (!WeaponInfo[nWeapon].d || PlayerList[nPlayer].nAmmo[WeaponInfo[nWeapon].nAmmoType])
+ {
+ if (!PlayerList[nPlayer].bIsFiring) {
+ PlayerList[nPlayer].field_3A = 1;
+ }
+ else {
+ break;
+ }
+ }
+ else
+ {
+ SelectNewWeapon(nPlayer);
+ }
+
+ Ra[nPlayer].field_C = 0;
+ break;
+ }
+ else if (nWeapon == kWeaponM60)
+ {
+ CheckClip(nPlayer);
+ PlayerList[nPlayer].field_3A = 1;
+ break;
+ }
+ else if (nWeapon == kWeaponGrenade)
+ {
+ if (!WeaponInfo[nWeapon].d || PlayerList[nPlayer].nAmmo[WeaponInfo[nWeapon].nAmmoType])
+ {
+ PlayerList[nPlayer].field_3A = 0;
+ break;
+ }
+ else
+ {
+ SelectNewWeapon(nPlayer);
+ PlayerList[nPlayer].field_3A = 5;
+
+ PlayerList[nPlayer].field_34 = SeqSize[WeaponInfo[kWeaponGrenade].b[SeqOffsets[nSeq]]] - 1; // CHECKME
+ goto loc_flag; // FIXME
+ }
+ }
+ else
+ {
+ if (PlayerList[nPlayer].bIsFiring && WeaponCanFire(nPlayer)) {
+ PlayerList[nPlayer].field_3A = 2;
+ break;
+ }
+
+ if (WeaponInfo[nWeapon].b[4] == -1)
+ {
+ PlayerList[nPlayer].field_3A = 1;
+ break;
+ }
+
+ if (nWeapon == kWeaponFlamer && (nSectFlag & kSectUnderwater))
+ {
+ PlayerList[nPlayer].field_3A = 1;
+ }
+ else
+ {
+ PlayerList[nPlayer].field_3A = 4;
+ }
+ }
+ break;
+ }
+
+ case 4:
+ {
+ PlayerList[nPlayer].field_3A = 1;
+ break;
+ }
+
+ case 5:
+ {
+ PlayerList[nPlayer].nCurrentWeapon = PlayerList[nPlayer].field_38;
+
+ nWeapon = PlayerList[nPlayer].nCurrentWeapon;
+
+ PlayerList[nPlayer].field_3A = 0;
+ PlayerList[nPlayer].field_38 = -1;
+
+ SetWeaponStatus(nPlayer);
+ break;
+ }
+ }
+
+ // loc_26FC5
+ var_3C = SeqOffsets[WeaponInfo[nWeapon].nSeq] + WeaponInfo[nWeapon].b[PlayerList[nPlayer].field_3A];
+ PlayerList[nPlayer].field_34 = 0;
+ }
+ else
+ {
+ if (PlayerList[nPlayer].field_3A == 5)
+ {
+ PlayerList[nPlayer].nCurrentWeapon = PlayerList[nPlayer].field_38;
+
+ nWeapon = PlayerList[nPlayer].nCurrentWeapon;
+
+ PlayerList[nPlayer].field_38 = -1;
+ PlayerList[nPlayer].field_3A = 0;
+ }
+ else
+ {
+ PlayerList[nPlayer].field_3A = 5;
+ }
+
+ PlayerList[nPlayer].field_34 = 0;
+ continue;
+ }
+ } // end of if (PlayerList[nPlayer].field_34 >= SeqSize[var_3C])
+
+loc_flag:
+
+ // loc_27001
+ short nFrameFlag = seq_GetFrameFlag(var_3C, PlayerList[nPlayer].field_34);
+
+ if (((!(nSectFlag & kSectUnderwater)) || nWeapon == kWeaponRing) && (nFrameFlag & 4))
+ {
+ BuildFlash(nPlayer, sprite[nPlayerSprite].sectnum, 512);
+ AddFlash(
+ sprite[nPlayerSprite].sectnum,
+ sprite[nPlayerSprite].x,
+ sprite[nPlayerSprite].y,
+ sprite[nPlayerSprite].z,
+ 0);
+ }
+
+ if (nFrameFlag & 0x80)
+ {
+ int nAction = PlayerList[nPlayer].nAction;
+
+ int var_38 = 1;
+
+ if (nAction < 10 || nAction > 12) {
+ var_38 = 0;
+ }
+
+ if (nPlayer == nLocalPlayer) {
+ bobangle = 512;
+ }
+
+ if (nWeapon == kWeaponFlamer && (!(nSectFlag & kSectUnderwater)))
+ {
+ nTemperature[nPlayer]++;
+
+ if (nTemperature[nPlayer] > 50)
+ {
+ nTemperature[nPlayer] = 0;
+ PlayerList[nPlayer].field_3A = 4;
+ PlayerList[nPlayer].field_34 = 0;
+ }
+ }
+
+ short nAmmoType = WeaponInfo[nWeapon].nAmmoType;
+ short nAngle = sprite[nPlayerSprite].ang;
+ int theX = sprite[nPlayerSprite].x;
+ int theY = sprite[nPlayerSprite].y;
+ int theZ = sprite[nPlayerSprite].z;
+
+ int ebp = Sin(nAngle + 512) * (sprite[nPlayerSprite].clipdist << 3);
+ int ebx = Sin(nAngle) * (sprite[nPlayerSprite].clipdist << 3);
+
+ if (WeaponInfo[nWeapon].c)
+ {
+ int ecx;
+
+ int theVal = (totalmoves + 101) & (WeaponInfo[nWeapon].c - 1);
+ if (theVal & 1)
+ ecx = -theVal;
+ else
+ ecx = theVal;
+
+ int var_44 = (nAngle + 512) & kAngleMask;
+ ebp += ((Sin(var_44 + 512) >> 11) * ecx);
+ ebx += (Sin(var_44) >> 11) * ecx;
+ }
+
+ int nHeight = (-GetSpriteHeight(nPlayerSprite)) >> 1;
+
+ if (nAction < 6)
+ {
+ nHeight -= 1792;
+ }
+ else
+ {
+ if (!var_38)
+ {
+ nHeight += 1024;
+ }
+ else {
+ nHeight -= 2560;
+ }
+ }
+
+ short nSectorB = sprite[nPlayerSprite].sectnum;
+
+ switch (nWeapon)
+ {
+ // loc_27266:
+ case kWeaponSword:
+ {
+ nHeight += (92 - sPlayerInput[nPlayer].horizon) << 6;
+
+ theZ += nHeight;
+
+ int var_28;
+
+ if (PlayerList[nPlayer].field_3A == 2) {
+ var_28 = 6;
+ }
+ else {
+ var_28 = 9;
+ }
+
+ int cRange = CheckCloseRange(nPlayer, &theX, &theY, &theZ, &nSectorB);
+
+ if (cRange)
+ {
+ short nDamage = BulletInfo[kWeaponSword].nDamage;
+
+ if (nPlayerDouble[nPlayer]) {
+ nDamage *= 2;
+ }
+
+ if ((cRange & 0xC000) >= 0x8000)
+ {
+ if ((cRange & 0xC000) == 0x8000) // hit wall
+ {
+ // loc_2730E:
+ var_28 += 2;
+ }
+ else if ((cRange & 0xC000) == 0xC000) // hit sprite
+ {
+ short nSprite2 = cRange & 0x3FFF;
+
+ if (sprite[nSprite2].cstat & 0x50)
+ {
+ var_28 += 2;
+ }
+ else if (sprite[nSprite2].statnum > 90 && sprite[nSprite2].statnum <= 199)
+ {
+ runlist_DamageEnemy(nSprite2, nPlayerSprite, nDamage);
+
+ if (sprite[nSprite2].statnum < 102) {
+ var_28++;
+ }
+ else if (sprite[nSprite2].statnum == 102)
+ {
+ // loc_27370:
+ BuildAnim(-1, 12, 0, theX, theY, theZ, nSectorB, 30, 0);
+ }
+ else if (sprite[nSprite2].statnum == kStatExplodeTrigger) {
+ var_28 += 2;
+ }
+ else {
+ var_28++;
+ }
+ }
+ else
+ {
+ // loc_27370:
+ BuildAnim(-1, 12, 0, theX, theY, theZ, nSectorB, 30, 0);
+ }
+ }
+ }
+ }
+
+ // loc_27399:
+ PlayerList[nPlayer].field_3A = var_28;
+ PlayerList[nPlayer].field_34 = 0;
+ break;
+ }
+ case kWeaponFlamer:
+ {
+ if (nSectFlag & kSectUnderwater)
+ {
+ DoBubbles(nPlayer);
+ PlayerList[nPlayer].field_3A = 1;
+ PlayerList[nPlayer].field_34 = 0;
+ StopSpriteSound(nPlayerSprite);
+ break;
+ }
+ else
+ {
+ if (var_38) {
+ nHeight += 768;
+ }
+ else {
+ nHeight -= 2560;
+ }
+
+ // fall through to case 1 (kWeaponPistol)
+ }
+ }
+
+ case kWeaponM60:
+ {
+ if (nWeapon == kWeaponM60) { // hack(?) to do fallthrough from kWeapon3 into kWeaponPistol without doing the nQuake[] change
+ nQuake[nPlayer] = 128;
+ }
+ // fall through
+ }
+ case kWeaponPistol:
+ {
+ int var_50 = (sPlayerInput[nPlayer].horizon - 92) << 2;
+ nHeight -= var_50;
+
+ short thetargetthin = sPlayerInput[nPlayer].nTarget;
+
+ assert(sprite[sPlayerInput[nPlayer].nTarget].sectnum < kMaxSectors);
+
+ if (sPlayerInput[nPlayer].nTarget >= 0)
+ {
+ var_50 = sPlayerInput[nPlayer].nTarget + 10000;
+ }
+
+ BuildBullet(nPlayerSprite, nAmmoType, ebp, ebx, nHeight, nAngle, var_50, var_1C);
+ break;
+ }
+
+ case kWeaponGrenade:
+ {
+ ThrowGrenade(nPlayer, ebp, ebx, nHeight - 2560, sPlayerInput[nPlayer].horizon - 92);
+ break;
+ }
+ case kWeaponStaff:
+ {
+ BuildSnake(nPlayer, nHeight);
+ nQuake[nPlayer] = 512;
+
+ nXDamage[nPlayer] -= Sin(sprite[nPlayerSprite].ang + 512) << 9;
+ nYDamage[nPlayer] -= Sin(sprite[nPlayerSprite].ang) << 9;
+ break;
+ }
+ case kWeaponRing:
+ break;
+
+ case kWeaponMummified:
+ {
+ short nDamage = BulletInfo[kWeaponMummified].nDamage;
+ if (nPlayerDouble[nPlayer]) {
+ nDamage *= 2;
+ }
+
+ runlist_RadialDamageEnemy(nPlayerSprite, nDamage, BulletInfo[kWeaponMummified].field_10);
+ break;
+ }
+ }
+
+ // end of switch, loc_2753E:
+ if (nWeapon < kWeaponMummified)
+ {
+ if (nWeapon != kWeaponGrenade)
+ {
+ short nAmmo = -WeaponInfo[nWeapon].d; // negative
+
+ if (nAmmo) {
+ AddAmmo(nPlayer, nAmmoType, nAmmo);
+ }
+
+ if (nWeapon == kWeaponM60) {
+ nPlayerClip[nPlayer] -= WeaponInfo[nWeapon].d;
+ }
+ else if (nWeapon == kWeaponPistol) {
+ nPistolClip[nPlayer]--;
+ }
+ }
+
+ if (!WeaponInfo[nWeapon].d || PlayerList[nPlayer].nAmmo[WeaponInfo[nWeapon].nAmmoType])
+ {
+ if (nWeapon == kWeaponM60 && nPlayerClip[nPlayer] <= 0)
+ {
+ PlayerList[nPlayer].field_3A = 3;
+ PlayerList[nPlayer].field_34 = 0;
+ // goto loc_27609:
+ }
+ }
+ else if (nWeapon != kWeaponGrenade)
+ {
+ SelectNewWeapon(nPlayer);
+ // go to loc_27609:
+ }
+ }
+ }
+ }
+}
+
+void DrawWeapons()
+{
+ if (bCamera) {
+ return;
+ }
+
+ short nWeapon = PlayerList[nLocalPlayer].nCurrentWeapon;
+ if (nWeapon < -1) {
+ return;
+ }
+
+ short var_34 = PlayerList[nLocalPlayer].field_3A;
+
+ short var_30 = SeqOffsets[WeaponInfo[nWeapon].nSeq];
+
+ short var_28 = var_30 + WeaponInfo[nWeapon].b[var_34];
+
+ schar nShade = sector[initsect].ceilingshade;
+
+ int nDouble = nPlayerDouble[nLocalPlayer];
+ int nPal = 0;
+
+ if (nDouble)
+ {
+ if (word_96E26) {
+ nPal = 5;
+ }
+
+ word_96E26 = word_96E26 == 0;
+ }
+
+ int nVal = totalvel[nLocalPlayer] >> 1;
+
+ // CHECKME - not & 0x7FF?
+ int yOffset = (nVal * (sintable[bobangle & 0x3FF] >> 8)) >> 9;
+
+ int xOffset = 0;
+
+ if (var_34 == 1)
+ {
+ xOffset = ((Sin(bobangle + 512) >> 8) * nVal) >> 8;
+ }
+ else
+ {
+ xOffset = 0;
+ bobangle = 512;
+ }
+
+ if (nWeapon == 3 && var_34 == 1) {
+ seq_DrawPilotLightSeq(xOffset, yOffset);
+ }
+
+ if (nWeapon < 0) {
+ nShade = sprite[PlayerList[nLocalPlayer].nSprite].shade;
+ }
+
+ seq_DrawGunSequence(var_28, PlayerList[nLocalPlayer].field_34, xOffset, yOffset, nShade, nPal);
+
+ if (nWeapon != kWeaponM60)
+ return;
+
+ switch (var_34)
+ {
+ default:
+ return;
+
+ case 0:
+ {
+ int nClip = nPlayerClip[nLocalPlayer];
+
+ if (nClip <= 0)
+ return;
+
+ int nSeqOffset;
+
+ if (nClip <= 3)
+ {
+ nSeqOffset = var_30 + 1;
+ }
+ else if (nClip <= 6)
+ {
+ nSeqOffset = var_30 + 2;
+ }
+ else if (nClip <= 25)
+ {
+ nSeqOffset = var_30 + 3;
+ }
+ else if (nClip > 25)
+ {
+ nSeqOffset = var_30 + 4;
+ }
+
+ seq_DrawGunSequence(nSeqOffset, PlayerList[nLocalPlayer].field_34, xOffset, yOffset, nShade, nPal);
+ return;
+ }
+ case 1:
+ {
+ int nClip = nPlayerClip[nLocalPlayer];
+
+ short edx = (nClip % 3) * 4;
+
+ if (nClip <= 0) {
+ return;
+ }
+
+ seq_DrawGunSequence(var_30 + 8, edx, xOffset, yOffset, nShade, nPal);
+
+ if (nClip <= 3) {
+ return;
+ }
+
+ seq_DrawGunSequence(var_30 + 9, edx, xOffset, yOffset, nShade, nPal);
+
+ if (nClip <= 6) {
+ return;
+ }
+
+ seq_DrawGunSequence(var_30 + 10, edx, xOffset, yOffset, nShade, nPal);
+
+ if (nClip <= 25) {
+ return;
+ }
+
+ seq_DrawGunSequence(var_30 + 11, edx, xOffset, yOffset, nShade, nPal);
+ return;
+ }
+ case 2:
+ {
+ int nClip = nPlayerClip[nLocalPlayer];
+
+ short dx = PlayerList[nLocalPlayer].field_34;
+
+ if (nClip <= 0) {
+ return;
+ }
+
+ seq_DrawGunSequence(var_30 + 8, dx, xOffset, yOffset, nShade, nPal);
+
+ if (nClip <= 3) {
+ return;
+ }
+
+ seq_DrawGunSequence(var_30 + 9, dx, xOffset, yOffset, nShade, nPal);
+
+ if (nClip <= 6) {
+ return;
+ }
+
+ seq_DrawGunSequence(var_30 + 10, dx, xOffset, yOffset, nShade, nPal);
+
+ if (nClip <= 25) {
+ return;
+ }
+
+ seq_DrawGunSequence(var_30 + 11, dx, xOffset, yOffset, nShade, nPal);
+ return;
+ }
+
+ case 3:
+ case 4:
+ return;
+
+ case 5:
+ {
+ int nClip = nPlayerClip[nLocalPlayer];
+
+ short ax = PlayerList[nLocalPlayer].field_34;
+
+ if (nClip <= 0) {
+ return;
+ }
+
+ int nSeqOffset;
+
+ if (nClip <= 3)
+ {
+ nSeqOffset = var_30 + 20;
+ }
+ else if (nClip <= 6)
+ {
+ nSeqOffset = var_30 + 19;
+ }
+ else if (nClip <= 25)
+ {
+ nSeqOffset = var_30 + 18;
+ }
+ else
+ {
+ nSeqOffset = var_30 + 17;
+ }
+
+ seq_DrawGunSequence(nSeqOffset, ax, xOffset, yOffset, nShade, nPal);
+ return;
+ }
+ }
+}
diff --git a/source/exhumed/src/gun.h b/source/exhumed/src/gun.h
new file mode 100644
index 000000000..955750ef3
--- /dev/null
+++ b/source/exhumed/src/gun.h
@@ -0,0 +1,49 @@
+
+#ifndef __gun_h__
+#define __gun_h__
+
+#include "sequence.h"
+
+#define kMaxWeapons 7
+
+enum
+{
+ kWeaponSword = 0,
+ kWeaponPistol,
+ kWeaponM60,
+ kWeaponFlamer,
+ kWeaponGrenade,
+ kWeaponStaff,
+ kWeaponRing,
+ kWeaponMummified
+};
+
+struct Weapon
+{
+ short nSeq;
+ short b[12]; // seq offsets?
+ short nAmmoType;
+ short c;
+ short d; // default or min ammo? or ammo used per 'shot' ?
+ short bFireUnderwater;
+// short pad[15];
+};
+
+extern Weapon WeaponInfo[];
+extern short nTemperature[];
+
+void RestoreMinAmmo(short nPlayer);
+void FillWeapons(short nPlayer);
+void ResetPlayerWeapons(short nPlayer);
+void InitWeapons();
+void SetNewWeapon(short nPlayer, short nWeapon);
+void SetNewWeaponImmediate(short nPlayer, short nWeapon);
+void SetNewWeaponIfBetter(short nPlayer, short nWeapon);
+void SelectNewWeapon(short nPlayer);
+void StopFiringWeapon(short nPlayer);
+void FireWeapon(short nPlayer);
+void CheckClip(short nPlayer);
+void MoveWeapons(short nPlayer);
+void DrawWeapons();
+
+#endif
diff --git a/source/exhumed/src/init.cpp b/source/exhumed/src/init.cpp
new file mode 100644
index 000000000..23c932742
--- /dev/null
+++ b/source/exhumed/src/init.cpp
@@ -0,0 +1,1209 @@
+
+#include "init.h"
+#include "runlist.h"
+#include "switch.h"
+#include "object.h"
+#include "aistuff.h"
+#include "player.h"
+#include "mummy.h"
+#include "move.h"
+#include "ra.h"
+#include "view.h"
+#include "runlist.h"
+#include "engine.h"
+#include "sound.h"
+#include "exhumed.h"
+#include "config.h"
+#include "items.h"
+#include "light.h"
+#include "map.h"
+#include "menu.h"
+#include "lighting.h"
+#include "anims.h"
+#include "input.h"
+#include "util.h"
+#include
+#include
+
+enum
+{
+ kTagRamses = 61,
+};
+
+int ototalclock = 0;
+
+int initx, inity, initz;
+short inita, initsect;
+
+short nCurChunkNum = 0;
+
+short nBodyGunSprite[50];
+int movefifoend;
+int movefifopos;
+
+short nCurBodyGunNum;
+
+short SectSoundSect[kMaxSectors] = { 0 };
+short SectSound[kMaxSectors] = { 0 };
+short SectFlag[kMaxSectors] = { 0 };
+int SectDepth[kMaxSectors] = { 0 };
+int SectAbove[kMaxSectors] = { 0 };
+short SectDamage[kMaxSectors] = { 0 };
+short SectSpeed[kMaxSectors] = { 0 };
+int SectBelow[kMaxSectors] = { 0 };
+
+
+BOOL bIsVersion6 = kTrue;
+
+// definitions for map version 6 structures
+#pragma pack(1)
+
+// 37 bytes
+struct Sector_6
+{
+ ushort wallptr, wallnum;
+ short ceilingpicnum, floorpicnum;
+ short ceilingheinum, floorheinum;
+ long ceilingz, floorz;
+ schar ceilingshade, floorshade;
+ uchar ceilingxpanning, floorxpanning;
+ uchar ceilingypanning, floorypanning;
+ uchar ceilingstat, floorstat;
+ uchar ceilingpal, floorpal;
+ uchar visibility;
+ short lotag, hitag, extra;
+};
+
+struct Wall_6
+{
+ long x, y;
+ short point2, nextsector, nextwall;
+ short picnum, overpicnum;
+ schar shade;
+ uchar pal;
+ short cstat;
+ uchar xrepeat, yrepeat, xpanning, ypanning;
+ short lotag, hitag, extra;
+};
+
+// 43 bytes
+struct Sprite_6
+{
+ long x, y, z;
+ short cstat;
+ schar shade;
+ uchar pal, clipdist;
+ uchar xrepeat, yrepeat;
+ schar xoffset, yoffset;
+ short picnum, ang, xvel, yvel, zvel, owner;
+ short sectnum, statnum;
+ short lotag, hitag, extra;
+};
+
+#pragma pack()
+
+static Sector_6 sector_6[1024];
+static Wall_6 wall_6[8192];
+static Sprite_6 sprite_6[4096];
+
+
+
+BOOL LoadLevel(int nMap)
+{
+ char fileName_1[80];
+ char fileName_2[32];
+
+ initspritelists();
+
+// nMap = 1;
+
+// sprintf(fileName_2, "queen");
+ sprintf(fileName_2, "lev%d", nMap);
+// sprintf(fileName_2, "sentry");
+// sprintf(fileName_2, "bjd");
+// sprintf(fileName_2, "door");
+// sprintf(fileName_2, "ceil");
+// sprintf(fileName_2, "scarab");
+// sprintf(fileName_2, "guns");
+// sprintf(fileName_2, "wasp");
+// sprintf(fileName_2, "items");
+
+ fileName_1[0] = '\0';
+ strcat(fileName_1, fileName_2);
+ strcat(fileName_1, ".map");
+
+ // init stuff
+ {
+ StopAllSounds();
+ nCreaturesLeft = 0;
+ nFreeze = 0;
+ nSpiritSprite = -1;
+
+ InitLion();
+ InitRexs();
+ InitSets();
+ InitQueens();
+ InitRoachs();
+ InitWasps();
+ InitRats();
+ InitBullets();
+ InitWeapons();
+ InitGrenades();
+ InitAnims();
+ InitSnakes();
+ InitFishes();
+ InitLights();
+ InitMap();
+ InitBubbles();
+ InitObjects();
+ InitLava();
+ InitPushBlocks();
+ InitAnubis();
+ InitSpider();
+ InitMummy();
+ InitScorp();
+ InitPlayer();
+ InitItems();
+ InitInput();
+
+ if (nMap == kMap20) {
+ InitEnergyTile();
+ }
+ }
+
+ if (nMap > 15)
+ {
+ nSwitchSound = 35;
+ nStoneSound = 23;
+ nElevSound = 51;
+ nStopSound = 35;
+ }
+ else
+ {
+ nSwitchSound = 33;
+ nStoneSound = 23;
+ nElevSound = 23;
+ nStopSound = 66;
+ }
+
+ if (nMap < 0) {
+ return kFalse;
+ }
+
+ {
+ // going to load the map without loadboard() - to take care of version 6 to 7 map conversion
+ //int hFile = kopen4load(fileName_1, 1);
+ int hFile = kopen4load(fileName_1, 0);
+ // int hFile = open(fileName_1, O_BINARY | O_RDONLY);
+ if (hFile == -1) {
+ return kFalse;
+ }
+
+ int version;
+
+ kread(hFile, &version, sizeof(version));
+ if (version != 6) {
+ bIsVersion6 = kFalse;
+ }
+
+ initspritelists();
+
+ memset(show2dsector, 0, sizeof(show2dsector));
+ memset(show2dsprite, 0, sizeof(show2dsprite));
+ memset(show2dwall, 0, sizeof(show2dwall));
+
+ // replacement for build's loadboard()
+ kread(hFile, &initx, 4);
+ kread(hFile, &inity, 4);
+ kread(hFile, &initz, 4);
+ kread(hFile, &inita, 2);
+ kread(hFile, &initsect, 2);
+
+ // sectors
+ short nSectors;
+ kread(hFile, &nSectors, sizeof(nSectors));
+
+ if (bIsVersion6) {
+ kread(hFile, sector_6, sizeof(Sector_6) * nSectors);
+ }
+ else {
+ kread(hFile, sector, sizeof(SECTOR) * nSectors);
+ }
+
+ // walls
+ short nWalls;
+ kread(hFile, &nWalls, sizeof(nWalls));
+
+ if (bIsVersion6) {
+ kread(hFile, wall_6, sizeof(Wall_6) * nWalls);
+ }
+ else {
+ kread(hFile, wall, sizeof(WALL) * nWalls);
+ }
+
+ // sprites
+ short nSprites;
+ kread(hFile, &nSprites, sizeof(nSprites));
+
+ if (bIsVersion6) {
+ kread(hFile, sprite_6, sizeof(Sprite_6) * nSprites);
+ }
+ else {
+ kread(hFile, sprite, sizeof(SPRITE) * nSprites);
+ }
+
+ // set engine variables
+ numsectors = nSectors;
+ numwalls = nWalls;
+
+ // load in our version 6 structs to the engines v7 structs if required
+ if (bIsVersion6)
+ {
+ for (int nSector = 0; nSector < nSectors; nSector++)
+ {
+ sector[nSector].ceilingz = sector_6[nSector].ceilingz;
+ sector[nSector].floorz = sector_6[nSector].floorz;
+ sector[nSector].wallptr = sector_6[nSector].wallptr;
+ sector[nSector].wallnum = sector_6[nSector].wallnum;
+ sector[nSector].ceilingpicnum = sector_6[nSector].ceilingpicnum;
+ sector[nSector].ceilingheinum = Max(Min(((long)sector_6[nSector].ceilingheinum) << 5, 32767), -32768);
+
+ if ((sector_6[nSector].ceilingstat & 2) == 0) {
+ sector[nSector].ceilingheinum = 0;
+ }
+
+ sector[nSector].ceilingshade = sector_6[nSector].ceilingshade;
+ sector[nSector].ceilingpal = sector_6[nSector].ceilingpal;
+ sector[nSector].ceilingxpanning = sector_6[nSector].ceilingxpanning;
+ sector[nSector].ceilingypanning = sector_6[nSector].ceilingypanning;
+ sector[nSector].floorpicnum = sector_6[nSector].floorpicnum;
+ sector[nSector].floorheinum = Max(Min(((long)sector_6[nSector].floorheinum) << 5, 32767), -32768);
+
+ if ((sector_6[nSector].floorstat & 2) == 0) {
+ sector[nSector].floorheinum = 0;
+ }
+
+ sector[nSector].floorshade = sector_6[nSector].floorshade;
+ sector[nSector].floorpal = sector_6[nSector].floorpal;
+ sector[nSector].floorxpanning = sector_6[nSector].floorxpanning;
+ sector[nSector].floorypanning = sector_6[nSector].floorypanning;
+ sector[nSector].ceilingstat = sector_6[nSector].ceilingstat;
+ sector[nSector].floorstat = sector_6[nSector].floorstat;
+ sector[nSector].visibility = sector_6[nSector].visibility;
+ sector[nSector].filler = 0;
+ sector[nSector].lotag = sector_6[nSector].lotag;
+ sector[nSector].hitag = sector_6[nSector].hitag;
+ sector[nSector].extra = sector_6[nSector].extra;
+ }
+
+ for (int nWall = 0; nWall < nWalls; nWall++)
+ {
+ wall[nWall].x = wall_6[nWall].x;
+ wall[nWall].y = wall_6[nWall].y;
+ wall[nWall].point2 = wall_6[nWall].point2;
+ wall[nWall].nextwall = wall_6[nWall].nextwall;
+ wall[nWall].nextsector = wall_6[nWall].nextsector;
+ wall[nWall].cstat = wall_6[nWall].cstat;
+ wall[nWall].picnum = wall_6[nWall].picnum;
+ wall[nWall].overpicnum = wall_6[nWall].overpicnum;
+ wall[nWall].shade = wall_6[nWall].shade;
+ wall[nWall].pal = wall_6[nWall].pal;
+ wall[nWall].xrepeat = wall_6[nWall].xrepeat;
+ wall[nWall].yrepeat = wall_6[nWall].yrepeat;
+ wall[nWall].xpanning = wall_6[nWall].xpanning;
+ wall[nWall].ypanning = wall_6[nWall].ypanning;
+ wall[nWall].lotag = wall_6[nWall].lotag;
+ wall[nWall].hitag = wall_6[nWall].hitag;
+ wall[nWall].extra = wall_6[nWall].extra;
+ }
+
+ for (int nSprite = 0; nSprite < nSprites; nSprite++)
+ {
+ sprite[nSprite].x = sprite_6[nSprite].x;
+ sprite[nSprite].y = sprite_6[nSprite].y;
+ sprite[nSprite].z = sprite_6[nSprite].z;
+ sprite[nSprite].cstat = sprite_6[nSprite].cstat;
+ sprite[nSprite].picnum = sprite_6[nSprite].picnum;
+ sprite[nSprite].shade = sprite_6[nSprite].shade;
+ sprite[nSprite].pal = sprite_6[nSprite].pal;
+ sprite[nSprite].clipdist = sprite_6[nSprite].clipdist;
+ sprite[nSprite].filler = 0;
+ sprite[nSprite].xrepeat = sprite_6[nSprite].xrepeat;
+ sprite[nSprite].yrepeat = sprite_6[nSprite].yrepeat;
+ sprite[nSprite].xoffset = sprite_6[nSprite].xoffset;
+ sprite[nSprite].yoffset = sprite_6[nSprite].yoffset;
+ sprite[nSprite].sectnum = sprite_6[nSprite].sectnum;
+ sprite[nSprite].statnum = sprite_6[nSprite].statnum;
+ sprite[nSprite].ang = sprite_6[nSprite].ang;
+ sprite[nSprite].owner = sprite_6[nSprite].owner;
+ sprite[nSprite].xvel = sprite_6[nSprite].xvel;
+ sprite[nSprite].yvel = sprite_6[nSprite].yvel;
+ sprite[nSprite].zvel = sprite_6[nSprite].zvel;
+ sprite[nSprite].lotag = sprite_6[nSprite].lotag;
+ sprite[nSprite].hitag = sprite_6[nSprite].hitag;
+ sprite[nSprite].extra = sprite_6[nSprite].extra;
+ }
+ }
+
+ for (int nSprite = 0; nSprite < nSprites; nSprite++) {
+ insertsprite(sprite[nSprite].sectnum, sprite[nSprite].statnum);
+ }
+
+ updatesector(initx, inity, &initsect);
+
+ kclose(hFile);
+ hFile = -1;
+ }
+ // loadboard has finished
+
+ int i;
+
+ for (i = 0; i < kMaxPlayers; i++)
+ {
+ PlayerList[i].nSprite = -1;
+ }
+
+ pskyoff[0] = 0;
+ pskyoff[1] = 0;
+ pskyoff[2] = 0;
+ pskyoff[3] = 0;
+ parallaxtype = 0;
+ visibility = 2048;
+ parallaxyoffs = 256;
+ flash = 0;
+ pskybits = 2;
+ precache();
+
+ LoadObjects();
+
+ levelnum = nMap;
+
+ // TEMP - show full 2D map// TEMP
+ for (i = 0; i < (kMaxWalls >> 3); i++)
+ show2dwall[i] = 0xFF;
+ for (i = 0; i < (kMaxSprites >> 3); i++)
+ show2dsprite[i] = 0xFF;
+ for (i = 0; i < numsectors; i++) {
+ show2dsector[i >> 3] |= (1 << (i & 7));
+ }
+
+ return kTrue;
+}
+
+void ResetEngine()
+{
+ uchar blankPal[768];
+
+ memset(blankPal, 0, sizeof(blankPal));
+ MySetPalette(blankPal);
+
+ SetOverscan(kenpal);
+
+ EraseScreen(-1);
+
+ resettiming();
+
+ totalclock = 0;
+ ototalclock = totalclock;
+ localclock = totalclock;
+
+ numframes = 0;
+}
+
+void InstallEngine()
+{
+ initgroupfile("stuff.dat");
+
+ // TEMP
+
+ nScreenWidth *= 2;
+ nScreenHeight *= 2;
+ bHiRes = kTrue;
+ // TEMP
+
+ initengine();
+
+#ifdef __WATCOMC__
+ setgamemode(2, nScreenWidth, nScreenHeight);
+#else
+ setgamemode(0, nScreenWidth, nScreenHeight, 8);
+#endif
+
+#ifdef __WATCOMC__
+ loadpics("tiles000.art");
+#else
+ loadpics("tiles000.art", 32 * 1048576);
+#endif
+
+ LoadPaletteLookups();
+ MyLoadPalette();
+}
+
+void RemoveEngine()
+{
+ uninitengine();
+ uninitgroupfile();
+}
+
+void SetBelow(short nCurSector, short nBelowSector)
+{
+ SectBelow[nCurSector] = nBelowSector;
+}
+
+void SetAbove(short nCurSector, short nAboveSector)
+{
+ SectAbove[nCurSector] = nAboveSector;
+}
+
+void SnapSectors(short nSectorA, short nSectorB, short b)
+{
+ // edx - nSectorA
+ // eax - nSectorB
+
+ short nWallA = sector[nSectorA].wallptr;
+ short nWallB = sector[nSectorB].wallptr;
+
+ short num1 = sector[nSectorA].wallnum;
+ short num2 = sector[nSectorB].wallnum;
+
+ int nCount = 0;
+
+ while (num1 > nCount)
+ {
+ short dx = nWallB;
+
+ int esi = 0x7FFFFFF;
+ int edi = esi;
+
+ int x = wall[nWallA].x;
+ int y = wall[nWallA].y;
+
+ int var_14 = 0;
+
+ int nCount2 = 0;
+
+ while (nCount2 < num2)
+ {
+ int eax = x - wall[dx].x;
+ int ebx = y - wall[dx].y;
+
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ int var_38 = eax;
+
+ if (ebx < 0) {
+ ebx = -ebx;
+ }
+
+ int var_3C = ebx;
+
+ var_38 += var_3C;
+
+ eax = esi;
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ var_3C = eax;
+
+ eax = edi;
+// int var_34 = edi;
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ int var_34 = eax;
+
+ var_34 += var_3C;
+
+ if (var_38 < var_34)
+ {
+ esi = x - wall[dx].x;
+ edi = y - wall[dx].y;
+ var_14 = dx;
+ }
+
+ dx++;
+ nCount2++;
+ }
+
+ dragpoint(var_14, wall[var_14].x + esi, wall[var_14].y + edi);
+
+ nCount++;
+ nWallA++;
+ }
+
+ if (b) {
+ sector[nSectorB].ceilingz = sector[nSectorA].floorz;
+ }
+
+ if (SectFlag[nSectorA] & 0x1000) {
+ SnapBobs(nSectorA, nSectorB);
+ }
+}
+
+void InitSectFlag()
+{
+ for (int i = 0; i < kMaxSectors; i++)
+ {
+ SectSoundSect[i] = -1;
+ SectSound[i] = -1;
+ SectAbove[i] = -1;
+ SectBelow[i] = -1;
+ SectDepth[i] = 0;
+ SectFlag[i] = 0;
+ SectSpeed[i] = 0;
+ SectDamage[i] = 0;
+ }
+}
+
+void ProcessSpriteTag(short nSprite, short lotag, short hitag)
+{
+ int nChannel = runlist_AllocChannel(hitag % 1000);
+// int ebp = nChannel;
+
+ int nHitag2 = hitag / 1000;
+
+ int nLotag2 = lotag / 1000;
+ if (nLotag2 == 0) {
+ nLotag2 = 1;
+ }
+
+ if (lotag > 1000) {
+ int blahgh = 123;
+ }
+
+ // this value can change in the below code but we also need to retain the original hitag value
+ int nVal = hitag;
+
+ if (lotag >= 900 && lotag <= 949)
+ {
+ ProcessTrailSprite(nSprite, lotag, hitag);
+ return;
+ }
+
+ // handle tags 6 to 60
+ switch (lotag)
+ {
+ case 8: // M-60 ammo belt
+ {
+ nVal = 3 * (hitag / 3);
+ // fall through to 6,7 etc
+ }
+ case 6:
+ case 7:
+ case 9:
+ case 10:
+ case 11:
+ case 15:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 26:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
+ case 58:
+ case 60:
+ {
+ sprite[nSprite].hitag = nVal;
+ changespritestat(nSprite, lotag + 900);
+ sprite[nSprite].cstat &= 0xFEFE;
+ BuildItemAnim(nSprite);
+ return;
+ }
+ case 12: // berry twig
+ {
+ sprite[nSprite].hitag = 40;
+ changespritestat(nSprite, lotag + 900);
+ sprite[nSprite].cstat &= 0xFEFE;
+ BuildItemAnim(nSprite);
+ return;
+ }
+ case 13: // blood bowl
+ {
+ sprite[nSprite].hitag = 160;
+ changespritestat(nSprite, lotag + 900);
+ sprite[nSprite].cstat &= 0xFEFE;
+ BuildItemAnim(nSprite);
+ return;
+ }
+ case 14: // venom bowl
+ {
+ sprite[nSprite].hitag = -200;
+ changespritestat(nSprite, lotag + 900);
+ sprite[nSprite].cstat &= 0xFEFE;
+ BuildItemAnim(nSprite);
+ return;
+ }
+
+ case 16:
+ // reserved
+ mydeletesprite(nSprite);
+ return;
+
+ case 25:
+ case 59:
+ {
+ // extra life or checkpoint scarab. Delete for multiplayer
+ if (nNetPlayerCount != 0)
+ {
+ mydeletesprite(nSprite);
+ return;
+ }
+ else
+ {
+ sprite[nSprite].hitag = nVal;
+ changespritestat(nSprite, lotag + 900);
+ sprite[nSprite].cstat &= 0xFEFE;
+ BuildItemAnim(nSprite);
+ return;
+ }
+ }
+ case 27:
+ {
+ sprite[nSprite].hitag = 1;
+ changespritestat(nSprite, 9 + 900);
+ sprite[nSprite].cstat &= 0xFEFE;
+ BuildItemAnim(nSprite);
+ return;
+ }
+
+ case 38: // raw energy
+ {
+ nVal++;
+ nVal--; // CHECKME ??
+ sprite[nSprite].hitag = nVal;
+ changespritestat(nSprite, lotag + 900);
+ sprite[nSprite].cstat &= 0xFEFE;
+ BuildItemAnim(nSprite);
+ return;
+ }
+ }
+
+ int v6 = lotag % 1000;
+
+ if (!bNoCreatures || v6 < 100 || v6 > 118)
+ {
+ if (v6 > 999) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ switch (v6)
+ {
+ case 999:
+ {
+ AddFlicker(sprite[nSprite].sectnum, nLotag2);
+ break;
+ }
+ case 998:
+ {
+ AddGlow(sprite[nSprite].sectnum, nLotag2);
+ break;
+ }
+ case 118: // Anubis with drum
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildAnubis(nSprite, 0, 0, 0, 0, 0, 1);
+ return;
+ }
+ case 117:
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildWasp(nSprite, 0, 0, 0, 0, 0);
+ return;
+ }
+ case 116:
+ {
+ BuildRat(nSprite, 0, 0, 0, 0, -1);
+ return;
+ }
+ case 115: // Rat (eating)
+ {
+ BuildRat(nSprite, 0, 0, 0, 0, 0);
+ return;
+ }
+ case 113:
+ {
+ BuildQueen(nSprite, 0, 0, 0, 0, 0, nChannel);
+ return;
+ }
+ case 112:
+ {
+ BuildScorp(nSprite, 0, 0, 0, 0, 0, nChannel);
+ return;
+ }
+ case 111:
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildSet(nSprite, 0, 0, 0, 0, 0, nChannel);
+ return;
+ }
+ case 108:
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildLava(nSprite, 0, 0, 0, 0, 0, nChannel);
+ return;
+ }
+ case 107:
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildRex(nSprite, 0, 0, 0, 0, 0, nChannel);
+ return;
+ }
+ case 106:
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildFish(nSprite, 0, 0, 0, 0, 0);
+ return;
+ }
+ case 105:
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildSpider(nSprite, 0, 0, 0, 0, 0);
+ return;
+ }
+ case 104:
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildRoach(1, nSprite, 0, 0, 0, 0, 0);
+ return;
+ }
+ case 103:
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildRoach(0, nSprite, 0, 0, 0, 0, 0);
+ return;
+ }
+ case 102:
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildLion(nSprite, 0, 0, 0, 0, 0);
+ return;
+ }
+ case 101:
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildMummy(nSprite, 0, 0, 0, 0, 0);
+ return;
+ }
+ case 100:
+ {
+ if (bNoCreatures) {
+ mydeletesprite(nSprite);
+ return;
+ }
+
+ BuildAnubis(nSprite, 0, 0, 0, 0, 0, 0);
+ return;
+ }
+ case 99: // underwater type 2
+ {
+ short nSector = sprite[nSprite].sectnum;
+ SetAbove(nSector, hitag);
+ SectFlag[nSector] |= kSectUnderwater;
+
+ mydeletesprite(nSprite);
+ return;
+ }
+ case 98:
+ {
+ short nSector = sprite[nSprite].sectnum;
+ SetBelow(nSector, hitag);
+ SnapSectors(nSector, hitag, 1);
+
+ mydeletesprite(nSprite);
+ return;
+ }
+ case 97:
+ {
+ AddSectorBob(sprite[nSprite].sectnum, hitag, 1);
+
+ mydeletesprite(nSprite);
+ return;
+ }
+ case 96: // Lava sector
+ {
+ hitag /= 4; // hitag is damage level?
+ if (hitag == 0) {
+ hitag = 1;
+ }
+
+ short nSector = sprite[nSprite].sectnum;
+
+ SectDamage[nSector] = hitag;
+ SectFlag[nSector] |= kSectLava;
+
+ mydeletesprite(nSprite);
+ return;
+ }
+ case 95:
+ {
+ AddSectorBob(sprite[nSprite].sectnum, hitag, 0);
+
+ mydeletesprite(nSprite);
+ return;
+ }
+ case 94: // water
+ {
+ short nSector = sprite[nSprite].sectnum;
+ SectDepth[nSector] = hitag << 8;
+
+ mydeletesprite(nSprite);
+ return;
+ }
+ case 93:
+ {
+ BuildBubbleMachine(nSprite);
+ return;
+ }
+ case 90:
+ {
+ BuildObject(nSprite, 3, hitag);
+ return;
+ }
+ case 79:
+ case 89:
+ {
+ short nSector = sprite[nSprite].sectnum;
+
+ SectSpeed[nSector] = nLotag2;
+ SectFlag[nSector] |= sprite[nSprite].ang;
+
+ mydeletesprite(nSprite);
+ return;
+ }
+ case 88:
+ {
+ AddFlow(nSprite, nLotag2, 0);
+
+ mydeletesprite(nSprite);
+ return;
+ }
+ case 80: // underwater
+ {
+ short nSector = sprite[nSprite].sectnum;
+ SectFlag[nSector] |= kSectUnderwater;
+
+ mydeletesprite(nSprite);
+ return;
+ }
+ case 78:
+ {
+ AddFlow(nSprite, nLotag2, 1);
+
+ short nSector = sprite[nSprite].sectnum;
+ SectFlag[nSector] |= 0x8000;
+
+ mydeletesprite(nSprite);
+ return;
+ }
+ case 77:
+ {
+ int nArrow = BuildArrow(nSprite, nLotag2);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nArrow);
+ return;
+ }
+ case 76: // Explosion Trigger (Exploding Fire Cauldron)
+ {
+ BuildObject(nSprite, 0, hitag);
+ return;
+ }
+ case 75: // Explosion Target (Cauldrons, fireballs and grenades will destroy nearby 75 sprites)
+ {
+ BuildObject(nSprite, 1, hitag);
+ return;
+ }
+ case 71:
+ {
+ int nFireball = BuildFireBall(nSprite, hitag, nLotag2);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nFireball);
+ return;
+ }
+ case 70:
+ {
+ BuildDrip(nSprite);
+ return;
+ }
+ case 63:
+ {
+ changespritestat(nSprite, 405);
+ sprite[nSprite].cstat = 0x8000;
+ return;
+ }
+ case 62:
+ {
+ nNetStartSprite[nNetStartSprites] = nSprite;
+ sprite[nSprite].cstat = 0x8000;
+
+ nNetStartSprites++;
+ return;
+ }
+ case kTagRamses: // Ramses head
+ {
+ nSpiritSprite = nSprite;
+ sprite[nSprite].cstat |= 0x8000;
+ return;
+ }
+ default: // TODO - checkme!
+ {
+ mydeletesprite(nSprite);
+ return;
+ }
+ }
+ }
+
+ mydeletesprite(nSprite);
+}
+
+void ExamineSprites()
+{
+ nNetStartSprites = 0;
+ nCurStartSprite = 0;
+
+ for (int nSprite = 0; nSprite < kMaxSprites; nSprite++)
+ {
+ int nStatus = sprite[nSprite].statnum;
+ if (!nStatus)
+ {
+ short lotag = sprite[nSprite].lotag;
+ short hitag = sprite[nSprite].hitag;
+
+ if ((nStatus < kMaxStatus) && lotag)
+ {
+ sprite[nSprite].lotag = 0;
+ sprite[nSprite].hitag = 0;
+
+ ProcessSpriteTag(nSprite, lotag, hitag);
+ }
+ else
+ {
+ changespritestat(nSprite, 0);
+ }
+ }
+ }
+
+ if (nNetPlayerCount)
+ {
+ int nSprite = insertsprite(initsect, 0);
+ sprite[nSprite].x = initx;
+ sprite[nSprite].y = inity;
+ sprite[nSprite].z = initz;
+ sprite[nSprite].cstat = 0x8000;
+ nNetStartSprite[nNetStartSprites] = nSprite;
+ nNetStartSprites++;
+ }
+}
+
+void LoadObjects()
+{
+ runlist_InitRun();
+ runlist_InitChan();
+ InitLink();
+ InitPoint();
+ InitSlide();
+ InitSwitch();
+ InitElev();
+ InitWallFace();
+ InitTimeSlot();
+ InitSectFlag();
+
+ for (int nSector = 0; nSector < numsectors; nSector++)
+ {
+ short hitag = sector[nSector].hitag;
+ short lotag = sector[nSector].lotag;
+
+ sector[nSector].hitag = 0;
+ sector[nSector].lotag = 0;
+ sector[nSector].extra = -1;
+
+ if (hitag || lotag)
+ {
+ sector[nSector].lotag = runlist_HeadRun() + 1;
+ sector[nSector].hitag = lotag;
+
+ runlist_ProcessSectorTag(nSector, lotag, hitag);
+ }
+ }
+
+ for (int nWall = 0; nWall < numwalls; nWall++)
+ {
+ wall[nWall].extra = -1;
+
+ short lotag = wall[nWall].lotag;
+ short hitag = wall[nWall].hitag;
+
+ wall[nWall].lotag = 0;
+
+ if (hitag || lotag)
+ {
+ wall[nWall].lotag = runlist_HeadRun() + 1;
+ runlist_ProcessWallTag(nWall, lotag, hitag);
+ }
+ }
+
+ ExamineSprites();
+ PostProcess();
+ InitRa();
+ InitChunks();
+
+ for (int nSprite = 0; nSprite < kMaxSprites; nSprite++)
+ {
+ runlist_ChangeChannel(nSprite, 0);
+ runlist_ReadyChannel(nSprite);
+ }
+
+ nCamerax = initx;
+ nCameray = inity;
+ nCameraz = initz;
+}
+
+int myloadconfig()
+{
+ FILE *fp = fopen("psa.ini", "rb");
+
+ if (fp == NULL)
+ {
+ gFXVolume = 200;
+ nGamma = 2;
+ gMusicVolume = 200;
+ bFullScreen = 0;
+ mysetbrightness((uchar)nGamma);
+
+ lMouseSens = 8;
+ return -1;
+ }
+
+ fread(&gFXVolume, sizeof(gFXVolume), 1, fp);
+ fread(&gMusicVolume, sizeof(gMusicVolume), 1, fp);
+ fread(&screensize, sizeof(screensize), 1, fp);
+ fread(&bFullScreen, sizeof(bFullScreen), 1, fp);
+ fread(&nGamma, sizeof(nGamma), 1, fp);
+ fread(&lMouseSens, sizeof(lMouseSens), 1, fp);
+
+ if (bHiRes) {
+ screensize *= 2;
+ }
+
+ if (screensize > nScreenWidth || screensize < xdim >> 2) {
+ screensize = nScreenWidth;
+ }
+
+ fclose(fp);
+
+ if (gFXVolume > 255) {
+ gFXVolume = 125;
+ }
+
+ if (gMusicVolume > 255) {
+ gMusicVolume = 125;
+ }
+
+ return 1;
+}
+
+int mysaveconfig()
+{
+ FILE *fp = fopen("psa.ini", "wb");
+ if (fp == NULL) {
+ return -1;
+ }
+
+ fwrite(&gFXVolume, sizeof(gFXVolume), 1, fp);
+ fwrite(&gMusicVolume, sizeof(gMusicVolume), 1, fp);
+
+ short nSize = screensize;
+
+ if (bHiRes)
+ {
+ nSize = screensize / 2;
+ }
+
+ fwrite(&nSize, sizeof(nSize), 1, fp);
+ fwrite(&bFullScreen, sizeof(bFullScreen), 1, fp);
+ fwrite(&nGamma, sizeof(nGamma), 1, fp);
+ fwrite(&lMouseSens, sizeof(lMouseSens), 1, fp);
+
+ fclose(fp);
+ return 1;
+}
diff --git a/source/exhumed/src/init.h b/source/exhumed/src/init.h
new file mode 100644
index 000000000..c933b13fa
--- /dev/null
+++ b/source/exhumed/src/init.h
@@ -0,0 +1,49 @@
+
+#ifndef __init_h__
+#define __init_h__
+
+#include "typedefs.h"
+
+#define kMap20 20
+
+enum {
+ kSectUnderwater = 0x2000,
+ kSectLava = 0x4000,
+};
+
+extern int ototalclock;
+
+extern int initx;
+extern int inity;
+extern int initz;
+extern short inita;
+extern short initsect;
+
+extern short nCurChunkNum;
+extern short nBodyGunSprite[50];
+extern int movefifoend;
+extern int movefifopos;
+extern short nCurBodyGunNum;
+
+void SnapSectors(short nSectorA, short nSectorB, short b);
+
+extern short SectSound[];
+extern short SectDamage[];
+extern short SectSpeed[];
+extern int SectBelow[];
+extern short SectFlag[];
+extern int SectDepth[];
+extern short SectSoundSect[];
+extern int SectAbove[];
+
+BOOL LoadLevel(int nMap);
+void InstallEngine();
+void ResetEngine();
+void RemoveEngine();
+void LoadObjects();
+
+int myloadconfig();
+int mysaveconfig();
+
+
+#endif
diff --git a/source/exhumed/src/input.cpp b/source/exhumed/src/input.cpp
new file mode 100644
index 000000000..ae0a4dc6d
--- /dev/null
+++ b/source/exhumed/src/input.cpp
@@ -0,0 +1,253 @@
+
+#include "input.h"
+#include "engine.h"
+#include "exhumed.h"
+#include "player.h"
+#include "serial.h"
+#include "network.h"
+#include "types.h"
+#include "keyboard.h"
+#include "control.h"
+#include "config.h"
+#include
+
+int nNetMoves = 0;
+
+short nInputStack = 0;
+
+short bStackNode[kMaxPlayers];
+
+short nTypeStack[kMaxPlayers];
+PlayerInput sPlayerInput[kMaxPlayers];
+
+int *pStackPtr;
+
+// (nInputStack * 32) - 11;
+
+void PushInput(PlayerInput *pInput, int edx)
+{
+ if (!bStackNode[edx])
+ {
+// memcpy(sInputStack[nInputStack], pInput,
+ }
+}
+
+int PopInput()
+{
+ if (!nInputStack)
+ return -1;
+
+ nInputStack--;
+
+ // TEMP
+ return 0;
+}
+
+void InitInput()
+{
+ memset(nTypeStack, 0, sizeof(nTypeStack));
+ nInputStack = 0;
+ memset(bStackNode, 0, sizeof(bStackNode));
+
+// pStackPtr = &sInputStack;
+}
+
+void ClearSpaceBar(short nPlayer)
+{
+ sPlayerInput[nPlayer].buttons &= 0x0FB;
+ CONTROL_ClearButton(gamefunc_Open);
+}
+
+void GetLocalInput()
+{
+ int ebx = 6;
+ int eax = 24;
+ int edx = -8;
+ uchar cl;
+
+ uint32 esi;
+
+ while (ebx >= 0)
+ {
+ if (eax <= 31)
+ {
+ esi = CONTROL_ButtonState1;
+ cl = eax;
+ }
+ else
+ {
+ esi = CONTROL_ButtonState2;
+ cl = edx;
+ }
+
+ if ((esi >> cl) & 1)
+ break;
+
+ eax--;
+ edx--;
+ ebx--;
+ }
+
+ ebx++;
+
+ if (PlayerList[nLocalPlayer].nHealth)
+ {
+ eax = (BUTTON(gamefunc_Crouch) << 4) | (BUTTON(gamefunc_Fire) << 3);
+
+ edx = BUTTON(gamefunc_Jump);
+
+ ebx <<= 13;
+
+ eax |= edx;
+ eax |= ebx;
+
+ lLocalButtons = eax;
+ }
+ else
+ {
+ lLocalButtons = 0;
+ }
+
+ lLocalButtons |= BUTTON(gamefunc_Open) << 2;
+
+ if (BUTTON(gamefunc_Open)) {
+ int breakme = 123;
+ }
+
+// TODO ExecRecord(&sPlayerInput[nLocalPlayer], sizeof(PlayerInput));
+}
+
+void BackupInput()
+{
+
+}
+
+void SendInput()
+{
+
+}
+
+void LogoffPlayer(int nPlayer)
+{
+ if (nPlayer == nLocalPlayer)
+ return;
+
+ if (PlayerList[nPlayer].someNetVal == -1)
+ return;
+
+ memset(&sPlayerInput[nPlayer], 0, sizeof(sPlayerInput));
+
+ sprite[nDoppleSprite[nPlayer]].cstat = 0x8000u;
+ sprite[nPlayerFloorSprite[nPlayer]].cstat = 0x8000u;
+ sprite[PlayerList[nPlayer].nSprite].cstat = 0x8000u;
+
+ PlayerList[nPlayer].someNetVal = -1;
+
+ StatusMessage(150, "Player %d has left the game", nPlayer);
+
+// TODO ClearPlayerInput(&sPlayerInput[nPlayer]);
+ nNetPlayerCount--;
+}
+
+void UpdateInputs()
+{
+ nNetMoveFrames = moveframes;
+
+ if (nNetPlayerCount)
+ {
+ if (bSerialPlay) {
+ UpdateSerialInputs();
+ }
+ else {
+ UpdateNetInputs();
+ }
+
+ nNetMoves++;
+
+ if (!nNetMoves) {
+ nNetMoves++;
+ }
+ }
+}
+
+/*
+ClearSpaceBar_
+ GetLocalInput_
+ GetModemInput_
+ BackupInput_
+ SendInput_
+ SendToUnAckd_
+ LogoffPlayer_
+ UpdateInputs_
+ faketimerhandler_
+*/
+
+void ClearAllKeys()
+{
+ KB_ClearKeysDown();
+ KB_FlushKeyboardQueue();
+}
+
+void WaitNoKey(int nSecs, void (*pFunc) (void))
+{
+ int nTotalTime = (kTimerTicks * nSecs) + totalclock;
+
+ while (nTotalTime > totalclock)
+ {
+#ifdef _MSC_VER
+ handleevents();
+#endif
+ if (pFunc) {
+ pFunc();
+ }
+ }
+}
+
+int WaitAnyKey(int nSecs)
+{
+ int nTotalTime = totalclock + (kTimerTicks * nSecs);
+
+ while (1)
+ {
+#ifdef _MSC_VER
+ handleevents();
+#endif
+ if (nTotalTime <= totalclock || nSecs == -1) {
+ return -1;
+ }
+
+ int i = 0;
+
+ do
+ {
+ if (KB_KeyDown[i])
+ {
+ KB_KeyDown[i] = 0;
+ return i;
+ }
+
+ i++;
+
+ } while (i < 106);
+ }
+}
+
+
+/*
+ Name: _nLocalPlayer
+ Name: _nNetPlayerCount
+ Name: _nModemPlayer
+ Name: _nNetMoves
+ Name: _lLocalButtons
+ Name: _lLocalCodes
+ Name: _nInputStack
+ Name: _bSyncNet
+ Name: _lStartupTime
+ Name: _bStackNode
+ Name: _sSync
+ Name: _nTypeStack
+ Name: _sPlayerInput
+ Name: _pStackPtr
+ Name: _sInputStack
+
+ */
\ No newline at end of file
diff --git a/source/exhumed/src/input.h b/source/exhumed/src/input.h
new file mode 100644
index 000000000..18da04953
--- /dev/null
+++ b/source/exhumed/src/input.h
@@ -0,0 +1,47 @@
+
+#ifndef __input_h__
+#define __input_h__
+
+#include "typedefs.h"
+
+enum {
+ kButtonJump = 0x1,
+ kButtonOpen = 0x4,
+ kButtonFire = 0x8,
+ kButtonCrouch = 0x10,
+ kButtonCheatGuns = 0x20,
+ kButtonCheatGodMode = 0x40,
+ kButtonCheatKeys = 0x80,
+ kButtonCheatItems = 0x100,
+};
+
+// 32 bytes
+struct PlayerInput
+{
+ int xVel;
+ int yVel;
+ short nAngle;
+ ushort buttons;
+ short nTarget;
+ schar horizon;
+ schar nItem;
+ int h;
+ char i;
+ char field_15[11];
+};
+
+void InitInput();
+void ClearAllKeys();
+void WaitNoKey(int nSecs, void (*pFunc) (void));
+int WaitAnyKey(int nSecs);
+
+void UpdateInputs();
+
+void ClearSpaceBar(short nPlayer);
+
+void GetLocalInput();
+
+extern PlayerInput sPlayerInput[];
+extern int nNetMoves;
+
+#endif
diff --git a/source/exhumed/src/items.cpp b/source/exhumed/src/items.cpp
new file mode 100644
index 000000000..1927202ea
--- /dev/null
+++ b/source/exhumed/src/items.cpp
@@ -0,0 +1,477 @@
+
+#include "items.h"
+#include "anims.h"
+#include "player.h"
+#include "exhumed.h"
+#include "lighting.h"
+#include "sound.h"
+#include "status.h"
+#include "engine.h"
+#include "random.h"
+#include "init.h"
+#include "input.h"
+#include "object.h"
+
+struct AnimInfo
+{
+ short a;
+ short repeat;
+};
+
+AnimInfo nItemAnimInfo[] = {
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { 6, 64 },
+ { -1, 48 },
+ { 0, 64 },
+ { 1, 64 },
+ { -1, 32 },
+ { 4, 64 },
+ { 5, 64 },
+ { 16, 64 },
+ { 10, 64 },
+ { -1, 32 },
+ { 8, 64 },
+ { 9, 64 },
+ { -1, 40 },
+ { -1, 32 },
+ { 7, 64 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { 14, 64 },
+ { 15, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { 17, 48 },
+ { 18, 48 },
+ { 19, 48 },
+ { 20, 48 },
+ { 24, 64 },
+ { 21, 64 },
+ { 23, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { 11, 30 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 },
+ { -1, 32 }
+};
+
+short nItemMagic[] = { 500, 1000, 100, 500, 400, 200, 700, 0 };
+
+/*
+
+short something
+short x/y repeat
+
+*/
+
+short nRegenerates;
+short nFirstRegenerate;
+short nMagicCount;
+
+
+void BuildItemAnim(short nSprite)
+{
+ int nItem = sprite[nSprite].statnum - 906;
+
+ if (nItemAnimInfo[nItem].a >= 0)
+ {
+ int nAnim = BuildAnim(nSprite, 41, nItemAnimInfo[nItem].a, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum, nItemAnimInfo[nItem].repeat, 20);
+ int nAnimSprite = GetAnimSprite(nAnim);
+
+ if (nItem == 44) {
+ sprite[nAnimSprite].cstat |= 2;
+ }
+
+ changespritestat(nAnimSprite, sprite[nSprite].statnum);
+
+ sprite[nAnimSprite].owner = nAnim;
+ sprite[nAnimSprite].hitag = sprite[nSprite].hitag;
+ }
+ else
+ {
+ sprite[nSprite].owner = -1;
+ sprite[nSprite].yrepeat = nItemAnimInfo[nItem].repeat;
+ sprite[nSprite].xrepeat = nItemAnimInfo[nItem].repeat;
+ }
+}
+
+void DestroyItemAnim(short nSprite)
+{
+ short nAnim = sprite[nSprite].owner;
+
+ if (nAnim >= 0) {
+ DestroyAnim(nAnim);
+ }
+}
+
+void ItemFlash()
+{
+ TintPalette(4, 4, 4);
+}
+
+void FillItems(short nPlayer)
+{
+ for (int i = 0; i < 6; i++)
+ {
+ PlayerList[nPlayer].items[i] = 5;
+ }
+
+ PlayerList[nPlayer].nMagic = 1000;
+
+ if (nPlayer == nLocalPlayer)
+ {
+ ItemFlash();
+ SetMagicFrame();
+ }
+
+ if (nPlayerItem[nPlayer] == -1) {
+ SetPlayerItem(nPlayer, 0);
+ }
+}
+
+void UseEye(short nPlayer)
+{
+ if (nPlayerInvisible[nPlayer] >= 0) {
+ nPlayerInvisible[nPlayer] = 900;
+ }
+
+ int nSprite = PlayerList[nPlayer].nSprite;
+
+ sprite[nSprite].cstat |= 0x8000;
+
+ if (nPlayerFloorSprite[nPlayer] >= 0) {
+ sprite[nSprite].cstat |= 0x8000;
+ }
+
+ if (nPlayer == nLocalPlayer)
+ {
+ ItemFlash();
+ D3PlayFX(StaticSound[kSound31], nSprite);
+ }
+}
+
+void UseMask(short nPlayer)
+{
+ PlayerList[nPlayer].nMaskAmount = 1350;
+ PlayerList[nPlayer].nAir = 100;
+
+ if (nPlayer == nLocalPlayer)
+ {
+ SetAirFrame();
+ D3PlayFX(StaticSound[kSound31], PlayerList[nPlayer].nSprite);
+ }
+}
+
+void UseTorch(short nPlayer)
+{
+ if (!nPlayerTorch[nPlayer]) {
+ SetTorch(nPlayer, 1);
+ }
+
+ nPlayerTorch[nPlayer] = 900;
+}
+
+void UseHeart(short nPlayer)
+{
+ if (PlayerList[nPlayer].nHealth < kMaxHealth) {
+ PlayerList[nPlayer].nHealth = kMaxHealth;
+ }
+
+ if (nPlayer == nLocalPlayer)
+ {
+ ItemFlash();
+ SetHealthFrame(1);
+ D3PlayFX(StaticSound[kSound31], PlayerList[nPlayer].nSprite);
+ }
+}
+
+// invincibility
+void UseScarab(short nPlayer)
+{
+ if (PlayerList[nPlayer].invincibility < 900) {
+ PlayerList[nPlayer].invincibility = 900;
+ }
+
+ if (nPlayer == nLocalPlayer)
+ {
+ ItemFlash();
+ D3PlayFX(StaticSound[kSound31], PlayerList[nPlayer].nSprite);
+ }
+}
+
+// faster firing
+void UseHand(short nPlayer)
+{
+ nPlayerDouble[nPlayer] = 1350;
+
+ if (nPlayer == nLocalPlayer)
+ {
+ ItemFlash();
+ D3PlayFX(StaticSound[kSound31], PlayerList[nPlayer].nSprite);
+ }
+}
+
+void UseItem(short nPlayer, short nItem)
+{
+ switch (nItem)
+ {
+ case 0:
+ UseHeart(nPlayer);
+ break;
+ case 1:
+ UseScarab(nPlayer);
+ break;
+ case 2:
+ UseTorch(nPlayer);
+ break;
+ case 3:
+ UseHand(nPlayer);
+ break;
+ case 4:
+ UseEye(nPlayer);
+ break;
+ case 5:
+ UseMask(nPlayer);
+ break;
+ default:
+ break;
+ }
+
+ PlayerList[nPlayer].items[nItem]--;
+ int nItemCount = PlayerList[nPlayer].items[nItem];
+
+ int nMagic = nItemMagic[nItem];
+
+ if (nPlayer == nLocalPlayer)
+ {
+ BuildStatusAnim(nItemCount * 2 + 156, 0);
+ }
+
+ if (!nItemCount)
+ {
+ for (nItem = 0; nItem < 6; nItem++)
+ {
+ if (PlayerList[nPlayer].items[nItem] > 0) {
+ break;
+ }
+ }
+
+ if (nItem == 6) {
+ nItem = -1;
+ }
+ }
+
+ PlayerList[nPlayer].nMagic -= nMagic;
+ SetPlayerItem(nPlayer, nItem);
+
+ if (nPlayer == nLocalPlayer) {
+ SetMagicFrame();
+ }
+}
+
+void UseCurItem(short nPlayer)
+{
+ int nItem = nPlayerItem[nPlayer];
+
+ if (nItem >= 0)
+ {
+ if (PlayerList[nPlayer].items[nItem] > 0)
+ {
+ if (nItemMagic[nItem] <= PlayerList[nPlayer].nMagic)
+ {
+ sPlayerInput[nPlayer].nItem = nItem;
+ }
+ }
+ }
+}
+
+// TODO - bool return type?
+int GrabItem(short nPlayer, short nItem)
+{
+ if (PlayerList[nPlayer].items[nItem] >= 5) {
+ return 0;
+ }
+
+ PlayerList[nPlayer].items[nItem]++;
+
+ if (nPlayerItem[nPlayer] < 0 || nItem == nPlayerItem[nPlayer]) {
+ SetPlayerItem(nPlayer, nItem);
+ }
+
+ return 1;
+}
+
+void DropMagic(short nSprite)
+{
+ if (lFinaleStart) {
+ return;
+ }
+
+ nMagicCount--;
+
+ if (nMagicCount <= 0)
+ {
+ int nAnim = BuildAnim(
+ -1,
+ 64,
+ 0,
+ sprite[nSprite].x,
+ sprite[nSprite].y,
+ sprite[nSprite].z,
+ sprite[nSprite].sectnum,
+ 48,
+ 4);
+
+ int nAnimSprite = GetAnimSprite(nAnim);
+
+ sprite[nAnimSprite].owner = nAnim;
+
+ AddFlash(sprite[nAnimSprite].sectnum, sprite[nAnimSprite].x, sprite[nAnimSprite].y, sprite[nAnimSprite].z, 128);
+ changespritestat(nAnimSprite, 950);
+
+ nMagicCount = RandomSize(2);
+ }
+}
+
+void InitItems()
+{
+ nRegenerates = 0;
+ nFirstRegenerate = -1;
+ nMagicCount = 0;
+}
+
+void StartRegenerate(short nSprite)
+{
+ SPRITE *pSprite = &sprite[nSprite];
+
+ int edi = -1;
+
+ int nReg = nFirstRegenerate;
+
+ int i = 0;
+
+// for (int i = 0; i < nRegenerates; i++)
+ while (1)
+ {
+ if (i >= nRegenerates)
+ {
+ // ?? CHECKME
+ pSprite->xvel = pSprite->xrepeat;
+ pSprite->zvel = pSprite->shade;
+ pSprite->yvel = pSprite->pal;
+ break;
+ }
+ else
+ {
+ if (nReg != nSprite)
+ {
+ edi = nReg;
+ nReg = sprite[nReg].ang;
+ i++;
+ continue;
+ }
+ else
+ {
+ if (edi == -1)
+ {
+ nFirstRegenerate = pSprite->ang;
+ }
+ else
+ {
+ sprite[edi].ang = sprite[nSprite].ang;
+ }
+
+ nRegenerates--;
+ }
+ }
+ }
+
+ pSprite->extra = 1350;
+ pSprite->ang = nFirstRegenerate;
+
+ if (levelnum <= kMap20)
+ {
+ pSprite->ang /= 5;
+ }
+
+ pSprite->cstat = 0x8000;
+ pSprite->xrepeat = 1;
+ pSprite->yrepeat = 1;
+ pSprite->pal = 1;
+
+ nRegenerates++;
+ nFirstRegenerate = nSprite;
+}
+
+void DoRegenerates()
+{
+ int nSprite = nFirstRegenerate;
+
+ for (int i = nRegenerates; i > 0; i--, nSprite = sprite[nSprite].ang)
+ {
+ if (sprite[nSprite].extra > 0)
+ {
+ sprite[nSprite].extra--;
+
+ if (sprite[nSprite].extra <= 0)
+ {
+ BuildAnim(-1, 38, 0, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum, 64, 4);
+ D3PlayFX(StaticSound[kSoundTorchOn], i);
+ }
+ }
+ else
+ {
+ if (sprite[nSprite].xrepeat < sprite[nSprite].xvel)
+ {
+ sprite[nSprite].xrepeat += 2;
+ sprite[nSprite].yrepeat += 2;
+ continue;
+ }
+ }
+
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].yrepeat = sprite[nSprite].xvel;
+ sprite[nSprite].xrepeat = sprite[nSprite].xvel;
+ sprite[nSprite].pal = sprite[nSprite].yvel;
+ sprite[nSprite].yvel = sprite[nSprite].zvel; // setting to 0
+ sprite[nSprite].xvel = sprite[nSprite].zvel; // setting to 0
+ nRegenerates--;
+
+ if (sprite[nSprite].statnum == kStatExplodeTrigger) {
+ sprite[nSprite].cstat = 0x101;
+ }
+ else {
+ sprite[nSprite].cstat = 0;
+ }
+
+ if (nRegenerates == 0) {
+ nFirstRegenerate = -1;
+ }
+ }
+}
diff --git a/source/exhumed/src/items.h b/source/exhumed/src/items.h
new file mode 100644
index 000000000..d6aa5f30a
--- /dev/null
+++ b/source/exhumed/src/items.h
@@ -0,0 +1,35 @@
+
+#ifndef __items_h__
+#define __items_h__
+
+enum
+{
+ kItemHeart = 0,
+ kItemInvincibility,
+ kItemTorch,
+ kItemDoubleDamage,
+ kItemInvisibility,
+ kItemMask,
+};
+
+extern short nItemMagic[];
+
+void BuildItemAnim(short nSprite);
+void DestroyItemAnim(short nSprite);
+void ItemFlash();
+void FillItems(short nPlayer);
+void UseEye(short nPlayer);
+void UseMask(short nPlayer);
+void UseTorch(short nPlayer);
+void UseHeart(short nPlayer);
+void UseScarab(short nPlayer);
+void UseHand(short nPlayer);
+void UseItem(short nPlayer, short nItem);
+void UseCurItem(short nPlayer);
+int GrabItem(short nPlayer, short nItem);
+void DropMagic(short nSprite);
+void InitItems();
+void StartRegenerate(short nSprite);
+void DoRegenerates();
+
+#endif
diff --git a/source/exhumed/src/lavadude.cpp b/source/exhumed/src/lavadude.cpp
new file mode 100644
index 000000000..0abab8da7
--- /dev/null
+++ b/source/exhumed/src/lavadude.cpp
@@ -0,0 +1,499 @@
+
+#include "engine.h"
+#include "lavadude.h"
+#include "random.h"
+#include "runlist.h"
+#include "sequence.h"
+#include "exhumed.h"
+#include "move.h"
+#include "trigdat.h"
+#include "move.h"
+#include "bullet.h"
+#include "sound.h"
+#include
+
+#define kMaxLavas 20
+
+struct Lava
+{
+ short nSprite;
+ short field_2;
+ short nAction;
+ short nTarget;
+ short nHealth;
+ short field_10;
+ short field_12;
+};
+
+Lava LavaList[kMaxLavas];
+
+short LavaCount = 0;
+short LavaSprite = -1;
+
+static actionSeq ActionSeq[] = {
+ {0, 1},
+ {0, 1},
+ {1, 0},
+ {10, 0},
+ {19, 0},
+ {28, 1},
+ {29, 1},
+ {33, 0},
+ {42, 1}
+};
+
+// done
+void InitLava()
+{
+ LavaCount = 0;
+ LavaSprite = 1;
+}
+
+int BuildLavaLimb(int nSprite, int edx, int ebx)
+{
+ short nSector = sprite[nSprite].sectnum;
+
+ int nLimbSprite = insertsprite(nSector, 118);
+ assert(nLimbSprite >= 0 && nLimbSprite < kMaxSprites);
+
+ sprite[nLimbSprite].x = sprite[nSprite].x;
+ sprite[nLimbSprite].y = sprite[nSprite].y;
+ sprite[nLimbSprite].z = sprite[nSprite].z - RandomLong() % ebx;
+ sprite[nLimbSprite].cstat = 0;
+ sprite[nLimbSprite].shade = -127;
+ sprite[nLimbSprite].pal = 1;
+ sprite[nLimbSprite].xvel = (RandomSize(5) - 16) << 8;
+ sprite[nLimbSprite].yvel = (RandomSize(5) - 16) << 8;
+ sprite[nLimbSprite].zvel = 2560 - (RandomSize(5) << 8);
+ sprite[nLimbSprite].yoffset = 0;
+ sprite[nLimbSprite].xoffset = 0;
+ sprite[nLimbSprite].xrepeat = 90;
+ sprite[nLimbSprite].yrepeat = 90;
+ sprite[nLimbSprite].picnum = (edx & 3) % 3;
+ sprite[nLimbSprite].hitag = 0;
+ sprite[nLimbSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nLimbSprite].clipdist = 0;
+
+// GrabTimeSlot(3);
+
+ sprite[nLimbSprite].extra = -1;
+ sprite[nLimbSprite].owner = runlist_AddRunRec(sprite[nLimbSprite].lotag - 1, nLimbSprite | 0x160000);
+ sprite[nLimbSprite].hitag = runlist_AddRunRec(NewRun, nLimbSprite | 0x160000);
+
+ return nLimbSprite;
+}
+
+void FuncLavaLimb(int eax, int ebx, int nRun)
+{
+ short nSprite = RunData[nRun].nVal;
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ int nMessage = eax & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x20000:
+ {
+ sprite[nSprite].shade += 3;
+
+ int nRet = movesprite(nSprite, sprite[nSprite].xvel << 12, sprite[nSprite].yvel << 12, sprite[nSprite].zvel, 2560, -2560, CLIPMASK1);
+
+ if (nRet || sprite[nSprite].shade > 100)
+ {
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+ runlist_SubRunRec(sprite[nSprite].hitag);
+
+ mydeletesprite(nSprite);
+ }
+ break;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(eax, (SeqOffsets[kSeqLavag] + 30) + sprite[nSprite].picnum, 0, 1);
+ break;
+ }
+
+ default:
+ return;
+ }
+}
+
+int BuildLava(short nSprite, int x, int y, int z, short nSector, short nAngle, int lastArg)
+{
+ short nLava = LavaCount;
+ LavaCount++;
+
+ if (nLava >= kMaxLavas) {
+ return -1;
+ }
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(nSector, 118);
+ }
+ else
+ {
+ nSector = sprite[nSprite].sectnum;
+ nAngle = sprite[nSprite].ang;
+ x = sprite[nSprite].x;
+ y = sprite[nSprite].y;
+
+ changespritestat(nSprite, 118);
+ }
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = sector[nSector].floorz;
+ sprite[nSprite].cstat = 0x8000u;
+ sprite[nSprite].xrepeat = 200;
+ sprite[nSprite].yrepeat = 200;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].pal = 0;
+ sprite[nSprite].clipdist = 127;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].picnum = seq_GetSeqPicnum(kSeqLavag, ActionSeq[3].a, 0);
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+
+// GrabTimeSlot(3);
+
+ sprite[nSprite].extra = -1;
+
+ LavaList[nLava].nAction = 0;
+ LavaList[nLava].nHealth = 4000;
+ LavaList[nLava].nSprite = nSprite;
+ LavaList[nLava].nTarget = -1;
+ LavaList[nLava].field_12 = lastArg;
+ LavaList[nLava].field_10 = 0;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nLava | 0x150000);
+ LavaList[nLava].field_2 = runlist_AddRunRec(NewRun, nLava | 0x150000);
+
+ nCreaturesLeft++;
+
+ return nLava | 0x150000;
+}
+
+void FuncLava(int a, int nDamage, int nRun)
+{
+ short nLava = RunData[nRun].nVal;
+ assert(nLava >= 0 && nLava < kMaxLavas);
+
+ short nAction = LavaList[nLava].nAction;
+
+ short nSeq = ActionSeq[nAction].a + SeqOffsets[kSeqLavag];
+
+ short nSprite = LavaList[nLava].nSprite;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Lava\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, nSeq, LavaList[nLava].field_10, ActionSeq[nAction].b);
+ tsprite[a & 0xFFFF].owner = -1;
+ return;
+ }
+
+ case 0xA0000:
+ {
+ return;
+ }
+
+ case 0x80000:
+ {
+ if (!nDamage) {
+ return;
+ }
+
+ LavaList[nLava].nHealth -= nDamage;
+
+ if (LavaList[nLava].nHealth <= 0)
+ {
+ LavaList[nLava].nHealth = 0;
+ LavaList[nLava].nAction = 5;
+ LavaList[nLava].field_10 = 0;
+
+ nCreaturesLeft--;
+
+ sprite[nSprite].cstat &= 0xFEFE;
+ }
+ else
+ {
+ short nTarget = a & 0xFFFF;
+
+ if (nTarget >= 0)
+ {
+ if (sprite[nTarget].statnum < 199)
+ {
+ LavaList[nLava].nTarget = nTarget;
+ }
+ }
+
+ if (nAction == 3)
+ {
+ if (!RandomSize(2))
+ {
+ LavaList[nLava].nAction = 4;
+ LavaList[nLava].field_10 = 0;
+ sprite[nSprite].cstat = 0;
+ }
+ }
+
+ BuildLavaLimb(nSprite, totalmoves, 0xFA00);
+ }
+
+ return;
+ }
+
+ case 0x20000:
+ {
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, LavaList[nLava].field_10);
+ int var_38 = LavaList[nLava].field_10;
+
+ short nFlag = FrameFlag[SeqBase[nSeq] + var_38];
+
+ int var_1C;
+
+ if (nAction)
+ {
+ seq_MoveSequence(nSprite, nSeq, var_38);
+
+ LavaList[nLava].field_10++;
+ if (LavaList[nLava].field_10 >= SeqSize[nSeq])
+ {
+ var_1C = 1;
+ LavaList[nLava].field_10 = 0;
+ }
+ else
+ {
+ var_1C = 0;
+ }
+ }
+
+ short nTarget = LavaList[nLava].nTarget;
+
+ if (nTarget >= 0 && nAction < 4)
+ {
+ if (!(sprite[nTarget].cstat & 0x101) || sprite[nTarget].sectnum >= 1024)
+ {
+ nTarget = -1;
+ LavaList[nLava].nTarget = -1;
+ }
+ }
+
+ switch (nAction)
+ {
+ case 0:
+ {
+ if ((nLava & 0x1F) == (totalmoves & 0x1F))
+ {
+ if (nTarget < 0)
+ {
+ nTarget = FindPlayer(nSprite, 76800);
+ }
+
+ PlotCourseToSprite(nSprite, nTarget);
+
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512);
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang);
+
+ if (nTarget >= 0 && !RandomSize(1))
+ {
+ LavaList[nLava].nTarget = nTarget;
+ LavaList[nLava].nAction = 2;
+ sprite[nSprite].cstat = 0x101;
+ LavaList[nLava].field_10 = 0;
+ break;
+ }
+ }
+
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ int z = sprite[nSprite].z;
+ short nSector = sprite[nSprite].sectnum;
+
+ int nVal = movesprite(nSprite, sprite[nSprite].xvel << 8, sprite[nSprite].yvel << 8, 0, 0, 0, CLIPMASK0);
+
+ if (nSector != sprite[nSprite].sectnum)
+ {
+ changespritesect(nSprite, nSector);
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+
+ sprite[nSprite].ang = (sprite[nSprite].ang + ((RandomWord() & 0x3FF) + 1024)) & 0x7FF;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512);
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang);
+ break;
+ }
+
+ if (!nVal) {
+ break;
+ }
+
+ if ((nVal & 0x0C000) == 0x8000)
+ {
+ sprite[nSprite].ang = (sprite[nSprite].ang + ((RandomWord() & 0x3FF) + 1024)) & 0x7FF;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512);
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang);
+ break;
+ }
+ else if ((nVal & 0x0C000) == 0x0C000)
+ {
+ if ((nVal & 0x3FFF) == nTarget)
+ {
+ int nAng = getangle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+ if (AngleDiff(sprite[nSprite].ang, nAng) < 64)
+ {
+ LavaList[nLava].nAction = 2;
+ sprite[nSprite].cstat = 0x101;
+ LavaList[nLava].field_10 = 0;
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+
+ case 1:
+ case 6:
+ {
+ break;
+ }
+
+ case 2:
+ {
+ if (var_1C)
+ {
+ LavaList[nLava].nAction = 3;
+ LavaList[nLava].field_10 = 0;
+
+ PlotCourseToSprite(nSprite, nTarget);
+
+ sprite[nSprite].cstat |= 0x101;
+ }
+
+ break;
+ }
+
+ case 3:
+ {
+ if (nFlag & 0x80 && nTarget > -1)
+ {
+ int nHeight = GetSpriteHeight(nSprite);
+ GetUpAngle(nSprite, 0x0FFFF0600, nTarget, (-(nHeight >> 1)));
+
+ BuildBullet(nSprite, 10, Sin(sprite[nSprite].ang + 512) << 8, Sin(sprite[nSprite].ang) << 8, -1, sprite[nSprite].ang, nTarget + 10000, 1);
+ break;
+ }
+ else if (var_1C)
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+ LavaList[nLava].nAction = 7;
+ LavaList[nLava].field_10 = 0;
+ break;
+ }
+ }
+
+ case 4:
+ {
+ if (var_1C)
+ {
+ LavaList[nLava].nAction = 7;
+ sprite[nSprite].cstat &= 0xFEFE;
+ }
+
+ break;
+ }
+
+ case 5:
+ {
+ if (nFlag & 0x40)
+ {
+ int nLimbSprite = BuildLavaLimb(nSprite, LavaList[nLava].field_10, 0xFA00u);
+ D3PlayFX(StaticSound[kSound26], nLimbSprite);
+ }
+
+ if (LavaList[nLava].field_10)
+ {
+ if (nFlag & 0x80)
+ {
+ int ecx = 0;
+ do
+ {
+ BuildLavaLimb(nSprite, ecx, 0xFA00u);
+ ecx++;
+ }
+ while (ecx < 20);
+ runlist_ChangeChannel(LavaList[nLava].field_12, 1);
+ }
+ }
+ else
+ {
+ int ecx = 0;
+
+ do
+ {
+ BuildLavaLimb(nSprite, ecx, 256);
+ ecx++;
+ }
+ while (ecx < 30);
+
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+ runlist_SubRunRec(LavaList[nLava].field_2);
+ mydeletesprite(nSprite);
+ }
+
+ break;
+ }
+
+ case 7:
+ {
+ if (var_1C)
+ {
+ LavaList[nLava].nAction = 8;
+ LavaList[nLava].field_10 = 0;
+ }
+ break;
+ }
+
+ case 8:
+ {
+ if (var_1C)
+ {
+ LavaList[nLava].nAction = 0;
+ LavaList[nLava].field_10 = 0;
+ sprite[nSprite].cstat = 0x8000;
+ }
+ break;
+ }
+ }
+
+ // loc_31521:
+ sprite[nSprite].pal = 1;
+ }
+ }
+}
diff --git a/source/exhumed/src/lavadude.h b/source/exhumed/src/lavadude.h
new file mode 100644
index 000000000..f42684cb7
--- /dev/null
+++ b/source/exhumed/src/lavadude.h
@@ -0,0 +1,11 @@
+
+#ifndef __lavadude_h__
+#define __lavadude_h__
+
+void InitLava();
+int BuildLava(short nSprite, int x, int y, int z, short nSector, short nAngle, int lastArg);
+int BuildLavaLimb(int nSprite, int edx, int ebx);
+void FuncLavaLimb(int, int, int);
+void FuncLava(int, int, int);
+
+#endif
diff --git a/source/exhumed/src/light.cpp b/source/exhumed/src/light.cpp
new file mode 100644
index 000000000..a492204b3
--- /dev/null
+++ b/source/exhumed/src/light.cpp
@@ -0,0 +1,598 @@
+
+#include "light.h"
+#include "engine.h"
+#include "exhumed.h"
+#include "view.h"
+#include "cd.h"
+#include
+#include
+#include
+
+#ifdef __WATCOMC__
+#include
+#include
+#include
+
+void handleevents()
+{
+}
+#else
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int handleevents(void);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#define kMaxGrads 12
+
+char *GradList[kMaxGrads] = {
+ "normal.rmp",
+ "nodim.rmp",
+ "torch.rmp",
+ "notorch.rmp",
+ "brite.rmp",
+ "redbrite.rmp",
+ "grnbrite.rmp",
+ "normal.rmp",
+ "nodim.rmp",
+ "torch.rmp",
+ "notorch.rmp",
+ "brite.rmp"
+};
+
+int rtint = 0;
+int gtint = 0;
+int btint = 0;
+char *origpalookup[kMaxPalookups];
+unsigned char curpal[768];
+unsigned char kenpal[768];
+unsigned char *fadedestpal;
+unsigned char *fadecurpal;
+short nPalDelay;
+short nPalDiff;
+short overscanindex;
+
+// keep a local copy of the palette that would have been sent to the VGA display adapter
+uchar vgaPalette[768];
+
+
+void MyLoadPalette()
+{
+ int hFile = kopen4load("PALETTE.DAT", 1);
+ if (hFile == -1)
+ {
+ printf("Error reading palette 'PALETTE.DAT'\n");
+ return;
+ }
+
+ kread(hFile, kenpal, sizeof(kenpal));
+ kclose(hFile);
+
+ SetOverscan(kenpal);
+}
+
+int LoadPaletteLookups()
+{
+ free(palookup[0]);
+
+ palookup[0] = NULL;
+ numpalookups = 64;
+
+ for (int i = 0; i < kMaxGrads; i++)
+ {
+ int hFile = kopen4load(GradList[i], 1);
+ if (hFile == -1)
+ {
+ printf("Error reading palette lookup '%s'\n", GradList[i]);
+ return 0;
+ }
+
+ makepalookup(i, NULL, 0, 0, 0, 0);
+ kread(hFile, palookup[i], 16384);
+ kclose(hFile);
+
+ origpalookup[i] = palookup[i];
+ }
+
+ return 1;
+}
+
+void SetGreenPal()
+{
+ for (int i = 0; i < 12; i++)
+ {
+ palookup[i] = palookup[6];
+ }
+
+ palookup[5] = origpalookup[5];
+}
+
+void RestoreGreenPal()
+{
+ for (int i = 0; i < 12; i++)
+ {
+ palookup[i] = origpalookup[i];
+ }
+}
+
+void WaitVBL()
+{
+#ifdef __WATCOMC__
+ while (!(inp(0x3da) & 8));
+#endif
+}
+
+void MySetPalette(unsigned char *palette)
+{
+ WaitVBL();
+
+#ifdef __WATCOMC__
+ outp(0x3C8, 0);
+
+ int i;
+ for (i = 0; i < 768; i++)
+ {
+ outp(0x3C9, *palette);
+ palette++;
+ }
+
+#else
+ // TODO
+ kensetpalette(palette);
+
+ memcpy(vgaPalette, palette, sizeof(vgaPalette));
+#endif
+}
+
+void GetCurPal(unsigned char *palette)
+{
+#ifdef __WATCOMC__
+ if (!palette) {
+ palette = curpal;
+ }
+
+ outp(0x3C7, 0);
+
+ int i;
+ for (i = 0; i < 256; i++)
+ {
+ *palette = inp(0x3C9);
+ palette++;
+ *palette = inp(0x3C9);
+ palette++;
+ *palette = inp(0x3C9);
+ palette++;
+ }
+
+#else
+ if (!palette) {
+ memcpy(curpal, vgaPalette, sizeof(curpal));
+ }
+ else {
+ memcpy(palette, vgaPalette, sizeof(curpal));
+ }
+#endif
+}
+
+void GrabPalette()
+{
+ SetOverscan(kenpal);
+
+ memcpy(curpal, kenpal, sizeof(curpal));
+
+ MySetPalette(kenpal);
+
+ nPalDiff = 0;
+ nPalDelay = 0;
+
+ btint = 0;
+ gtint = 0;
+ rtint = 0;
+}
+
+void BlackOut()
+{
+ memset(curpal, 0, sizeof(curpal));
+ MySetPalette(curpal);
+}
+
+void RestorePalette()
+{
+ memcpy(curpal, kenpal, sizeof(curpal));
+ MySetPalette(curpal);
+}
+
+void WaitTicks(int nTicks)
+{
+ if (htimer)
+ {
+ nTicks += totalclock;
+ while (nTicks > totalclock) { handleevents(); }
+ }
+ else
+ {
+ while (nTicks > 0) {
+ nTicks--;
+ WaitVBL();
+ }
+ }
+}
+
+// unused
+void DoFadeToRed()
+{
+ for (int i = 0; i < 256; i += 3)
+ {
+ if (curpal[i + 1] > 0)
+ {
+ curpal[i + 1]--;
+ }
+
+ if (curpal[i + 2] > 0)
+ {
+ curpal[i + 1]--;
+ }
+ }
+
+ MySetPalette(curpal);
+}
+
+void FadeToWhite()
+{
+ int ebx = 0;
+
+ for (int i = 0; i < 64; i++)
+ {
+ uchar *pPal = curpal;
+
+ for (int j = 0; j < 256; j++)
+ {
+ for (int k = 0; k < 3; k++)
+ {
+ if (*pPal < 63)
+ {
+ (*pPal)++;
+
+ ebx++;
+ }
+
+ pPal++;
+ }
+ }
+
+ MySetPalette(curpal);
+ WaitTicks(2);
+
+ // need to page flip in each iteration of the loop for non DOS version
+ nextpage();
+
+ if (!ebx) {
+ return;
+ }
+ }
+}
+
+void FadeOut(int bFadeMusic)
+{
+ if (bFadeMusic) {
+ StartfadeCDaudio();
+ }
+
+ for (int i = 64; i > 0; i--)
+ {
+ int v4 = 0;
+
+ for (int j = 0; j < 768; j++)
+ {
+ if (curpal[j] > 0)
+ {
+ curpal[j]--;
+ v4++;
+ }
+ }
+
+ MySetPalette(curpal);
+ WaitTicks(2);
+
+ // need to page flip in each iteration of the loop for non DOS version
+ nextpage();
+
+ if (v4 == 0) {
+ break;
+ }
+
+ if (bFadeMusic) {
+ StepFadeCDaudio();
+ }
+ }
+
+ if (bFadeMusic) {
+ while (StepFadeCDaudio() != 0) {}
+ }
+
+ EraseScreen(overscanindex);
+}
+
+void StartFadeIn()
+{
+ fadedestpal = kenpal;
+ fadecurpal = curpal;
+}
+
+int DoFadeIn()
+{
+ int v2 = 0;
+
+ for (int i = 0; i < 768; i++)
+ {
+ v2++;
+
+ if (fadecurpal[i] < fadedestpal[i])
+ {
+ fadecurpal[i]++;
+ }
+
+ else
+ {
+ if (fadecurpal[i] == fadedestpal[i])
+ {
+ v2--;
+ }
+ else {
+ fadecurpal[i]--;
+ }
+ }
+ }
+
+ MySetPalette(fadecurpal);
+
+ return v2;
+}
+
+void FadeIn()
+{
+ StartFadeIn();
+
+ while (1)
+ {
+ int val = DoFadeIn();
+ WaitTicks(2);
+
+ // need to page flip in each iteration of the loop for non DOS version
+ nextpage();
+
+ if (!val) {
+ break;
+ }
+ }
+}
+
+void FixPalette()
+{
+ if (!nPalDiff) {
+ return;
+ }
+
+ if (nPalDelay > 0)
+ {
+ nPalDelay--;
+ return;
+ }
+
+ nPalDelay = 5;
+
+ for (int i = 0; i < 768; i++)
+ {
+ short nVal = curpal[i] - kenpal[i];
+ if (nVal > 0)
+ {
+ if (nVal > 5)
+ {
+ curpal[i] -= 5;
+ }
+ else
+ {
+ curpal[i] = kenpal[i];
+ }
+ }
+ }
+
+ nPalDiff -= 5;
+ gtint -= 5;
+ rtint -= 5;
+
+ if (gtint < 0) {
+ gtint = 0;
+ }
+
+ if (rtint < 0) {
+ rtint = 0;
+ }
+
+ if (nPalDiff < 0) {
+ nPalDiff = 0;
+ }
+
+ MySetPalette(curpal);
+}
+
+void TintPalette(int r, int g, int b)
+{
+ int r2 = r;
+ int g2 = g;
+ int b2 = b;
+
+ uchar *pPal = curpal;
+
+ if (bCamera) {
+ return;
+ }
+
+ // range limit R between 5 and 63 if positive
+ if (r > 63)
+ {
+ r = 63;
+ }
+ else
+ {
+ if (r && r < 5) {
+ r = 5;
+ }
+ }
+
+ // range limit G between 5 and 63 if positive
+ if (g > 63)
+ {
+ g = 63;
+ }
+ else
+ {
+ if (g && g < 5) {
+ g = 5;
+ }
+ }
+
+ // range limit B between 5 and 63 if positive
+ if (b > 63)
+ {
+ b = 63;
+ }
+ else
+ {
+ if (b && b < 5) {
+ b = 5;
+ }
+ }
+
+ // loc_17EFA
+ if (g && gtint > 8) {
+ return;
+ }
+
+ gtint += g;
+
+ if (r && rtint > 64) {
+ return;
+ }
+
+ rtint += r;
+
+ // do not modify r, g or b variables from this point on
+ r2 = r;
+ g2 = g;
+ b2 = b;
+
+ if (r2 < 0) {
+ r2 = -r2;
+ }
+
+ // loc_17F3A
+ if (g2 < 0) {
+ g2 = -g2;
+ }
+
+ int nVal;
+
+ // loc_17F49
+ if (r2 > g2) {
+ nVal = r;
+ }
+ else {
+ nVal = g;
+ }
+
+ if (nVal < 0) {
+ nVal = -nVal;
+ }
+
+ if (b2 < 0) {
+ b2 = -b2;
+ }
+
+ if (nVal > b2) {
+ nVal = b2;
+ }
+ else {
+ if (b < 0) {
+ nVal = -b;
+ }
+ }
+
+ nPalDiff += nVal;
+
+ for (int i = 0; i < 256; i++)
+ {
+ *pPal += r;
+ if (*pPal > 63) {
+ *pPal = 63;
+ }
+
+ pPal++;
+
+ *pPal += g;
+ if (*pPal > 63) {
+ *pPal = 63;
+ }
+
+ pPal++;
+
+ *pPal += b;
+ if (*pPal > 63) {
+ *pPal = 63;
+ }
+
+ pPal++;
+ }
+
+ nPalDelay = 0;
+}
+
+void DoOverscanSet(short someval)
+{
+#ifdef __WATCOMC__
+ union REGS regs;
+
+ regs.h.al = 1;
+ regs.h.ah = 0x10;
+ regs.h.ch = someval;
+
+ int386(0x10, ®s, ®s);
+
+#endif
+}
+
+// unused
+void SetWhiteOverscan()
+{
+
+}
+
+void SetOverscan(unsigned char *palette)
+{
+ int edi = 1000;
+ overscanindex = 0;
+
+ for (int i = 0; i < 256; i++)
+ {
+ int ebx = 0;
+
+ for (int j = 0; j < 3; j++)
+ {
+ uchar cl = *palette;
+ palette++;
+ ebx += cl;
+ }
+
+ if (ebx < edi)
+ {
+ edi = ebx;
+ overscanindex = i;
+ }
+ }
+
+ DoOverscanSet(overscanindex);
+}
diff --git a/source/exhumed/src/light.h b/source/exhumed/src/light.h
new file mode 100644
index 000000000..bb824b84e
--- /dev/null
+++ b/source/exhumed/src/light.h
@@ -0,0 +1,23 @@
+
+#ifndef __light_h__
+#define __light_h__
+
+void MyLoadPalette();
+int LoadPaletteLookups();
+void WaitVBL();
+void SetGreenPal();
+void RestoreGreenPal();
+void FixPalette();
+void FadeToWhite();
+
+extern void DoOverscanSet(short someval);
+void SetOverscan(unsigned char *palette);
+
+extern unsigned char kenpal[];
+extern short overscanindex;
+
+extern char *origpalookup[];
+
+extern short nPalDiff;
+
+#endif
diff --git a/source/exhumed/src/lighting.cpp b/source/exhumed/src/lighting.cpp
new file mode 100644
index 000000000..c5cc57268
--- /dev/null
+++ b/source/exhumed/src/lighting.cpp
@@ -0,0 +1,761 @@
+
+#include "typedefs.h"
+#include "lighting.h"
+#include "player.h"
+#include "engine.h"
+#include "exhumed.h"
+#include "sound.h"
+#include "light.h"
+#include "random.h"
+#include
+#include
+
+#define kMaxFlashes 2000
+#define kMaxFlickerMask 25
+#define kMaxGlows 50
+#define kMaxFlickers 100
+#define kMaxFlows 375
+
+struct Flash
+{
+ char field_0;
+ short field_1;
+ schar shade;
+};
+
+struct Glow
+{
+ short field_0;
+ short field_2;
+ short nSector;
+ short field_6;
+};
+
+struct Flicker
+{
+ short field_0;
+ short nSector;
+ unsigned int field_4;
+};
+
+struct Flow
+{
+ short field_0;
+ short field_2;
+ int field_4;
+ int field_8;
+ int field_C;
+ int field_10;
+ int field_14;
+ int field_18;
+};
+
+Flash sFlash[kMaxFlashes];
+
+Glow sGlow[kMaxGlows];
+short nNextFlash[kMaxFlashes];
+Flicker sFlicker[kMaxFlickers];
+short nFreeFlash[kMaxFlashes];
+Flow sFlowInfo[kMaxFlows];
+int flickermask[kMaxFlickerMask];
+
+short bTorch = 0;
+short nFirstFlash = -1;
+short nLastFlash = -1;
+short nFlashDepth = 2;
+short nFlashes;
+short nFlowCount;
+short nFlickerCount;
+short nGlowCount;
+
+int bDoFlicks = 0;
+int bDoGlows = 0;
+
+// done
+int GrabFlash()
+{
+ if (nFlashes >= kMaxFlashes) {
+ return -1;
+ }
+
+ short nFlash = nFreeFlash[nFlashes];
+ nNextFlash[nFlash] = -1;
+
+ nFlashes++;
+
+ if (nLastFlash <= -1)
+ {
+ nFirstFlash = nFlash;
+ }
+ else
+ {
+ nNextFlash[nLastFlash] = nFlash;
+ }
+
+ nLastFlash = nFlash;
+
+ return nLastFlash;
+}
+
+void InitLights()
+{
+ int i;
+ nFlickerCount = 0;
+
+ for (i = 0; i < kMaxFlickerMask; i++) {
+ flickermask[i] = RandomSize(0x1F) * 2;
+ }
+
+ nGlowCount = 0;
+ nFlowCount = 0;
+ nFlashes = 0;
+ bDoFlicks = kFalse;
+ bDoGlows = kFalse;
+
+ for (i = 0; i < kMaxFlashes; i++) {
+ nFreeFlash[i] = i;
+ }
+
+ nFirstFlash = -1;
+ nLastFlash = -1;
+}
+
+void AddFlash(short nSector, int x, int y, int z, int val)
+{
+ assert(nSector >= 0 && nSector < kMaxSectors);
+
+ int var_28 = 0;
+ unsigned int var_1C = val >> 8;
+
+ if (var_1C >= nFlashDepth) {
+ return;
+ }
+
+ unsigned int var_20 = val & 0x80;
+ unsigned int var_18 = val & 0x40;
+
+ val = ((var_1C + 1) << 8) | char(val);
+
+ int var_14 = 0;
+
+ short startwall = sector[nSector].wallptr;
+ short endwall = sector[nSector].wallptr + sector[nSector].wallnum;
+
+ for (int i = startwall; i < endwall; i++)
+ {
+ short wall2 = wall[i].point2;
+
+ int xAverage = (wall[i].x + wall[wall2].x) / 2;
+ int yAverage = (wall[i].y + wall[wall2].y) / 2;
+
+ SECTOR *pNextSector = NULL;
+ if (wall[i].nextsector > -1) {
+ pNextSector = §or[wall[i].nextsector];
+ }
+
+ int ebx = -255;
+
+ if (!var_18)
+ {
+ int x2 = x - xAverage;
+ if (x2 < 0) {
+ x2 = -x2;
+ }
+
+ ebx = x2;
+
+ int y2 = y - yAverage;
+ if (y2 < 0) {
+ y2 = -y2;
+ }
+
+ ebx = ((y2 + ebx) >> 4) - 255;
+ }
+
+ if (ebx < 0)
+ {
+ var_14++;
+ var_28 += ebx;
+
+ if (wall[i].pal < 5)
+ {
+ if (!pNextSector || pNextSector->floorz < sector[nSector].floorz)
+ {
+ short nFlash = GrabFlash();
+ if (nFlash < 0) {
+ return;
+ }
+
+ sFlash[nFlash].field_0 = var_20 | 2;
+ sFlash[nFlash].shade = wall[i].shade;
+ sFlash[nFlash].field_1 = i;
+
+ wall[i].pal += 7;
+
+ ebx += wall[i].shade;
+ int eax = ebx;
+
+ if (ebx < -127) {
+ eax = -127;
+ }
+
+ wall[i].shade = eax;
+
+ if (!var_1C && !wall[i].overpicnum && pNextSector)
+ {
+ AddFlash(wall[i].nextsector, x, y, z, val);
+ }
+ }
+ }
+ }
+ }
+
+ if (var_14 && sector[nSector].floorpal < 4)
+ {
+ short nFlash = GrabFlash();
+ if (nFlash < 0) {
+ return;
+ }
+
+ sFlash[nFlash].field_0 = var_20 | 1;
+ sFlash[nFlash].field_1 = nSector;
+ sFlash[nFlash].shade = sector[nSector].floorshade;
+
+ sector[nSector].floorpal += 7;
+
+ int edx = sector[nSector].floorshade + var_28;
+ int eax = edx;
+
+ if (edx < -127) {
+ eax = -127;
+ }
+
+ sector[nSector].floorshade = eax;
+
+ if (!(sector[nSector].ceilingstat & 1))
+ {
+ if (sector[nSector].ceilingpal < 4)
+ {
+ short nFlash2 = GrabFlash();
+ if (nFlash2 >= 0)
+ {
+ sFlash[nFlash2].field_0 = var_20 | 3;
+ sFlash[nFlash2].field_1 = nSector;
+ sFlash[nFlash2].shade = sector[nSector].ceilingshade;
+
+ sector[nSector].ceilingpal += 7;
+
+ int edx = sector[nSector].ceilingshade + var_28;
+ int eax = edx;
+
+ if (edx < -127) {
+ eax = -127;
+ }
+
+ sector[nSector].ceilingshade = eax;
+ }
+ }
+ }
+
+ for (short nSprite = headspritesect[nSector]; nSprite >= 0; nSprite = nextspritesect[nSprite])
+ {
+ if (sprite[nSprite].pal < 4)
+ {
+ short nFlash3 = GrabFlash();
+ if (nFlash3 >= 0)
+ {
+ sFlash[nFlash3].field_0 = var_20 | 4;
+ sFlash[nFlash3].shade = sprite[nSprite].shade;
+ sFlash[nFlash3].field_1 = nSprite;
+
+ sprite[nSprite].pal += 7;
+
+ int eax = -255;
+
+ if (!var_18)
+ {
+ int xDiff = x - sprite[nSprite].x;
+ if (xDiff < 0) {
+ xDiff = -xDiff;
+ }
+
+ int yDiff = y - sprite[nSprite].y;
+ if (yDiff < 0) {
+ yDiff = -yDiff;
+ }
+
+ eax = ((xDiff + yDiff) >> 4) - 255;
+ }
+
+ if (eax < 0)
+ {
+ short shade = sprite[nSprite].shade + eax;
+ if (shade < -127) {
+ shade = -127;
+ }
+
+ sprite[nSprite].shade = shade;
+ }
+ }
+ }
+ }
+ }
+}
+
+void UndoFlashes()
+{
+ if (!nFlashes) {
+ return;
+ }
+
+ int var_24 = 0; // CHECKME - Watcom error "initializer for variable var_24 may not execute
+
+ int edi = -1;
+
+ for (short nFlash = nFirstFlash; nFlash >= 0; nFlash = nNextFlash[nFlash])
+ {
+ assert(nFlash < 2000 && nFlash >= 0);
+
+ uchar var_28 = sFlash[nFlash].field_0 & 0x3F;
+ short nIndex = sFlash[nFlash].field_1;
+
+ if (sFlash[nFlash].field_0 & 0x80)
+ {
+ int var_20 = var_28 - 1;
+ assert(var_20 >= 0);
+
+ schar *pShade = NULL;
+
+ switch (var_20)
+ {
+ case 0:
+ {
+ assert(nIndex >= 0 && nIndex < kMaxSectors);
+
+ pShade = §or[nIndex].floorshade;
+ break;
+ }
+
+ case 1:
+ {
+ assert(nIndex >= 0 && nIndex < kMaxWalls);
+
+ pShade = &wall[nIndex].shade;
+ break;
+ }
+
+ case 2:
+ {
+ assert(nIndex >= 0 && nIndex < kMaxSectors);
+
+ pShade = §or[nIndex].ceilingshade;
+ break;
+ }
+
+ case 3:
+ {
+ assert(nIndex >= 0 && nIndex < kMaxSprites);
+
+ if (sprite[nIndex].pal >= 7)
+ {
+ pShade = &sprite[nIndex].shade;
+ }
+ else {
+ goto loc_1868A;
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ assert(pShade != NULL);
+
+ short var_2C = (*pShade) + 6;
+ int var_30 = sFlash[nFlash].shade;
+
+ if (var_2C < var_30)
+ {
+ *pShade = var_2C;
+ edi = nFlash;
+ continue;
+ }
+ }
+
+ // loc_185FE
+ var_24 = var_28 - 1; // CHECKME - Watcom error "initializer for variable var_24 may not execute
+ assert(var_24 >= 0);
+
+ switch (var_24)
+ {
+ default:
+ break;
+
+ case 0:
+ {
+ sector[nIndex].floorpal -= 7;
+ sector[nIndex].floorshade = sFlash[nFlash].shade;
+ break;
+ }
+
+ case 1:
+ {
+ wall[nIndex].pal -= 7;
+ wall[nIndex].shade = sFlash[nFlash].shade;
+ break;
+ }
+
+ case 2:
+ {
+ sector[nIndex].ceilingpal -= 7;
+ sector[nIndex].ceilingshade = sFlash[nFlash].shade;
+ break;
+ }
+
+ case 3:
+ {
+ if (sprite[nIndex].pal >= 7)
+ {
+ sprite[nIndex].pal -= 7;
+ sprite[nIndex].shade = sFlash[nFlash].shade;
+ }
+
+ break;
+ }
+ }
+
+loc_1868A:
+
+ nFlashes--;
+ assert(nFlashes >= 0);
+
+ nFreeFlash[nFlashes] = nFlash;
+
+ if (edi != -1)
+ {
+ nNextFlash[edi] = nNextFlash[nFlash];
+ }
+
+ if (nFlash == nFirstFlash)
+ {
+ nFirstFlash = nNextFlash[nFirstFlash];
+ }
+
+ if (nFlash == nLastFlash)
+ {
+ nLastFlash = edi;
+ }
+ }
+}
+
+void AddGlow(short nSector, int nVal)
+{
+ if (nGlowCount >= kMaxGlows) {
+ return;
+ }
+
+ sGlow[nGlowCount].field_6 = nVal;
+ sGlow[nGlowCount].nSector = nSector;
+ sGlow[nGlowCount].field_0 = -1;
+ sGlow[nGlowCount].field_2 = 0;
+
+ nGlowCount++;
+}
+
+// ok
+void AddFlicker(short nSector, int nVal)
+{
+ if (nFlickerCount >= kMaxFlickers) {
+ return;
+ }
+
+ sFlicker[nFlickerCount].field_0 = nVal;
+ sFlicker[nFlickerCount].nSector = nSector;
+
+ if (nVal >= 25) {
+ nVal = 24;
+ }
+
+ sFlicker[nFlickerCount].field_4 = flickermask[nVal];
+
+ nFlickerCount++;
+}
+
+void DoGlows()
+{
+ bDoGlows++;
+
+ if (bDoGlows < 3) {
+ return;
+ }
+
+ bDoGlows = 0;
+
+ for (int i = 0; i < nGlowCount; i++)
+ {
+ sGlow[i].field_2++;
+
+ short nSector = sGlow[i].nSector;
+ short nShade = sGlow[i].field_0;
+
+ if (sGlow[i].field_2 >= sGlow[i].field_6)
+ {
+ sGlow[i].field_2 = 0;
+ sGlow[i].field_0 = -sGlow[i].field_0;
+ }
+
+ sector[nSector].ceilingshade += nShade;
+ sector[nSector].floorshade += nShade;
+
+ int startwall = sector[nSector].wallptr;
+ int endwall = startwall + sector[nSector].wallnum - 1;
+
+ for (int nWall = startwall; nWall <= endwall; nWall++)
+ {
+ wall[nWall].shade += nShade;
+
+ // CHECKME - ASM has edx decreasing here. why?
+ }
+ }
+}
+
+void DoFlickers()
+{
+ bDoFlicks ^= 1;
+ if (!bDoFlicks) {
+ return;
+ }
+
+ for (int i = 0; i < nFlickerCount; i++)
+ {
+ short nSector = sFlicker[i].nSector;
+
+ unsigned int eax = (sFlicker[i].field_4 & 1);
+ unsigned int edx = (sFlicker[i].field_4 & 1) << 31;
+ unsigned int ebp = sFlicker[i].field_4 >> 1;
+
+ ebp |= edx;
+ edx = ebp & 1;
+
+ sFlicker[i].field_4 = ebp;
+
+ if (edx ^ eax)
+ {
+ short shade;
+
+ if (eax)
+ {
+ shade = sFlicker[i].field_0;
+ }
+ else
+ {
+ shade = -sFlicker[i].field_0;
+ }
+
+ sector[nSector].ceilingshade += shade;
+ sector[nSector].floorshade += shade;
+
+ int startwall = sector[nSector].wallptr;
+ int endwall = startwall + sector[nSector].wallnum - 1;
+
+ for (int nWall = endwall; nWall >= startwall; nWall--)
+ {
+ wall[nWall].shade += shade;
+
+ // CHECKME - ASM has edx decreasing here. why?
+ }
+ }
+ }
+}
+
+// nWall can also be passed in here via nSprite parameter - TODO - rename nSprite parameter :)
+void AddFlow(int nSprite, int a, int b)
+{
+ if (nFlowCount >= kMaxFlows)
+ return;
+
+ short nFlow = nFlowCount;
+ nFlowCount++;
+
+ short var_18;
+
+ if (b < 2)
+ {
+ var_18 = sprite[nSprite].sectnum;
+ short nPic = sector[var_18].floorpicnum;
+ short nAngle = sprite[nSprite].ang;
+
+ sFlowInfo[nFlow].field_14 = (tilesizx[nPic] << 14) - 1;
+ sFlowInfo[nFlow].field_18 = (tilesizy[nPic] << 14) - 1;
+ sFlowInfo[nFlow].field_C = (-Sin(nAngle + 512)) * a;
+ sFlowInfo[nFlow].field_10 = (-Sin(nAngle)) * a;
+ }
+ else
+ {
+ short nAngle;
+
+ if (b == 2) {
+ nAngle = 512;
+ }
+ else {
+ nAngle = 1536;
+ }
+
+ var_18 = nSprite;
+ short nPic = wall[var_18].picnum;
+
+ sFlowInfo[nFlow].field_14 = (tilesizx[nPic] * wall[var_18].xrepeat) << 8;
+ sFlowInfo[nFlow].field_18 = (tilesizy[nPic] * wall[var_18].yrepeat) << 8;
+ sFlowInfo[nFlow].field_C = (-Sin(nAngle + 512)) * a;
+ sFlowInfo[nFlow].field_10 = (-Sin(nAngle)) * a;
+ }
+
+ sFlowInfo[nFlow].field_8 = 0;
+ sFlowInfo[nFlow].field_4 = 0;
+ sFlowInfo[nFlow].field_0 = var_18;
+ sFlowInfo[nFlow].field_2 = b;
+}
+
+void DoFlows()
+{
+ for (int i = 0; i < nFlowCount; i++)
+ {
+ sFlowInfo[i].field_4 += sFlowInfo[i].field_C;
+ sFlowInfo[i].field_8 += sFlowInfo[i].field_10;
+
+ switch (sFlowInfo[i].field_2)
+ {
+ case 0:
+ {
+ sFlowInfo[i].field_4 &= sFlowInfo[i].field_14;
+ sFlowInfo[i].field_8 &= sFlowInfo[i].field_18;
+
+ short nSector = sFlowInfo[i].field_0;
+ sector[nSector].floorxpanning = sFlowInfo[i].field_4 >> 14;
+ sector[nSector].floorypanning = sFlowInfo[i].field_8 >> 14;
+ break;
+ }
+
+ case 1:
+ {
+ short nSector = sFlowInfo[i].field_0;
+
+ sector[nSector].ceilingxpanning = sFlowInfo[i].field_4 >> 14;
+ sector[nSector].ceilingypanning = sFlowInfo[i].field_8 >> 14;
+
+ sFlowInfo[i].field_4 &= sFlowInfo[i].field_14;
+ sFlowInfo[i].field_8 &= sFlowInfo[i].field_18;
+ break;
+ }
+
+ case 2:
+ {
+ short nWall = sFlowInfo[i].field_0;
+
+ wall[nWall].xpanning = sFlowInfo[i].field_4 >> 14;
+ wall[nWall].ypanning = sFlowInfo[i].field_8 >> 14;
+
+ if (sFlowInfo[i].field_4 < 0)
+ {
+ sFlowInfo[i].field_4 += sFlowInfo[i].field_14;
+ }
+
+ if (sFlowInfo[i].field_8 < 0)
+ {
+ sFlowInfo[i].field_8 += sFlowInfo[i].field_18;
+ }
+
+ break;
+ }
+
+ case 3:
+ {
+ short nWall = sFlowInfo[i].field_0;
+
+ wall[nWall].xpanning = sFlowInfo[i].field_4 >> 14;
+ wall[nWall].ypanning = sFlowInfo[i].field_8 >> 14;
+
+ if (sFlowInfo[i].field_4 >= sFlowInfo[i].field_14)
+ {
+ sFlowInfo[i].field_4 -= sFlowInfo[i].field_14;
+ }
+
+ if (sFlowInfo[i].field_8 >= sFlowInfo[i].field_18)
+ {
+ sFlowInfo[i].field_8 -= sFlowInfo[i].field_18;
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+void DoLights()
+{
+ DoFlickers();
+ DoGlows();
+ DoFlows();
+}
+
+void SetTorch(int nPlayer, int bTorchOnOff)
+{
+ char buf[40];
+
+ if (bTorchOnOff == bTorch) {
+ return;
+ }
+
+ if (nPlayer != nLocalPlayer) {
+ return;
+ }
+
+ char *pTempPal = origpalookup[kPalTorch];
+ palookup[kPalTorch] = palookup[kPalNoTorch];
+ palookup[kPalNoTorch] = pTempPal;
+
+ pTempPal = origpalookup[kPalTorch];
+ origpalookup[kPalTorch] = origpalookup[kPalNoTorch];
+ origpalookup[kPalNoTorch] = pTempPal;
+
+ pTempPal = origpalookup[kPalTorch2];
+ origpalookup[kPalTorch2] = origpalookup[kPalNoTorch2];
+ origpalookup[kPalNoTorch2] = pTempPal;
+
+ pTempPal = palookup[kPalTorch2];
+ palookup[kPalNoTorch2] = palookup[kPalTorch2];
+ palookup[kPalTorch2] = pTempPal;
+
+ if (bTorchOnOff == 2) {
+ bTorch = bTorch == 0;
+ }
+ else {
+ bTorch = bTorchOnOff;
+ }
+
+ if (bTorch) {
+ PlayLocalSound(kSoundTorchOn, 0);
+ }
+
+ strcpy(buf, "TORCH IS ");
+
+ if (bTorch) {
+ strcat(buf, "LIT");
+ }
+ else {
+ strcat(buf, "OUT");
+ }
+
+ StatusMessage(150, buf);
+}
+
+void BuildFlash(short nPlayer, short nSector, int nVal)
+{
+ if (nPlayer == nLocalPlayer)
+ {
+ flash = nVal;
+ flash = -nVal; // ???
+ }
+}
diff --git a/source/exhumed/src/lighting.h b/source/exhumed/src/lighting.h
new file mode 100644
index 000000000..35e24c0ae
--- /dev/null
+++ b/source/exhumed/src/lighting.h
@@ -0,0 +1,17 @@
+
+#ifndef __lighting_h__
+#define __lighting_h__
+
+extern short nFlashDepth;
+
+void InitLights();
+void AddFlash(short nSector, int x, int y, int z, int val);
+void SetTorch(int nPlayer, int bTorchOnOff);
+void UndoFlashes();
+void DoLights();
+void AddFlow(int nSprite, int a, int b);
+void BuildFlash(short nPlayer, short nSector, int nVal);
+void AddGlow(short nSector, int nVal);
+void AddFlicker(short nSector, int nVal);
+
+#endif
\ No newline at end of file
diff --git a/source/exhumed/src/lion.cpp b/source/exhumed/src/lion.cpp
new file mode 100644
index 000000000..34f4615ed
--- /dev/null
+++ b/source/exhumed/src/lion.cpp
@@ -0,0 +1,562 @@
+
+#include "lion.h"
+#include "engine.h"
+#include "runlist.h"
+#include "exhumed.h"
+#include "sequence.h"
+#include "move.h"
+#include "sound.h"
+#include "random.h"
+#include "trigdat.h"
+#include "items.h"
+#include
+
+#define kMaxLions 40
+
+short LionCount = -1;
+
+short MoveHook[kMaxLions];
+
+static actionSeq ActionSeq[] = {{54, 1}, {18, 1}, {0, 0}, {10, 0}, {44, 0}, {18, 0}, {26, 0}, {34, 0}, {8, 1}, {9, 1}, {52, 1}, {53, 1}};
+
+struct Lion
+{
+ short nHealth;
+ short _b;
+ short nAction;
+ short nSprite;
+ short nTarget;
+ short _f;
+ short _g;
+ short _h;
+};
+
+Lion LionList[kMaxLions];
+
+
+void InitLion()
+{
+ LionCount = kMaxLions;
+}
+
+int BuildLion(short nSprite, int x, int y, int z, short nSector, short nAngle)
+{
+ LionCount--;
+ short nLion = LionCount;
+
+ if (LionCount < 0) {
+ return -1;
+ }
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(nSector, 104);
+ }
+ else
+ {
+ changespritestat(nSprite, 104);
+ x = sprite[nSprite].x;
+ y = sprite[nSprite].y;
+ z = sector[sprite[nSprite].sectnum].floorz;
+ nAngle = sprite[nSprite].ang;
+
+ }
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].clipdist = 60;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].xrepeat = 40;
+ sprite[nSprite].yrepeat = 40;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].extra = -1;
+
+// GrabTimeSlot(3);
+
+ LionList[nLion].nAction = 0;
+ LionList[nLion].nHealth = 500;
+ LionList[nLion]._b = 0;
+ LionList[nLion].nSprite = nSprite;
+ LionList[nLion].nTarget = -1;
+ LionList[nLion]._g = 0;
+ LionList[nLion]._f = nLion;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nLion | 0x130000);
+
+ MoveHook[nLion] = runlist_AddRunRec(NewRun, nLion | 0x130000);
+
+ nCreaturesLeft++;
+
+ return nLion | 0x130000;
+}
+
+void FuncLion(int a, int nDamage, int nRun)
+{
+ int var_18 = 0;
+
+ short nLion = RunData[nRun].nVal;
+ assert(nLion >= 0 && nLion < kMaxLions);
+
+ short nSprite = LionList[nLion].nSprite;
+ short nAction = LionList[nLion].nAction;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Lion\n", nMessage);
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a, SeqOffsets[kSeqLion] + ActionSeq[nAction].a, LionList[nLion]._b, ActionSeq[nAction].b);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ // now fall through to 0x80000
+ }
+ case 0x80000:
+ {
+ if (nDamage && LionList[nLion].nHealth > 0)
+ {
+ LionList[nLion].nHealth -= nDamage;
+ if (LionList[nLion].nHealth <= 0)
+ {
+ // R.I.P.
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ LionList[nLion].nHealth = 0;
+ sprite[nSprite].cstat &= 0xFEFE;
+
+ nCreaturesLeft--;
+
+ if (nAction < 10)
+ {
+ DropMagic(nSprite);
+
+ if (nMessage == 0xA0000) {
+ LionList[nLion].nAction = 11;
+ }
+ else
+ {
+ LionList[nLion].nAction = 10;
+ }
+
+ LionList[nLion]._b = 0;
+ return;
+ }
+ }
+ else
+ {
+ if (a >= 0)
+ {
+ short nTarget = a & 0xFFFF;
+
+ if (sprite[nTarget].statnum < 199) {
+ LionList[nLion].nTarget = nTarget;
+ }
+
+ if (nAction != 6)
+ {
+ if (RandomSize(8) <= (LionList[nLion].nHealth >> 2))
+ {
+ LionList[nLion].nAction = 4;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+ else if (RandomSize(1))
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+ LionList[nLion].nAction = 5;
+ LionList[nLion]._g = RandomSize(3);
+
+ sprite[nSprite].ang = (sprite[nSprite].ang - (RandomSize(1) << 8)) + (RandomSize(1) << 8);
+ }
+
+ LionList[nLion]._b = 0;
+ return;
+ }
+ }
+ return;
+ }
+ }
+ return;
+ }
+
+ case 0x20000:
+ {
+ if (nAction != 7) {
+ Gravity(nSprite);
+ }
+
+ short nSeq = SeqOffsets[kSeqLion] + ActionSeq[nAction].a;
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, LionList[nLion]._b);
+
+ seq_MoveSequence(nSprite, nSeq, LionList[nLion]._b);
+
+ LionList[nLion]._b++;
+ if (LionList[nLion]._b >= SeqSize[nSeq])
+ {
+ LionList[nLion]._b = 0;
+ var_18 = 1;
+ }
+
+ short nFlag = FrameFlag[SeqBase[nSeq] + LionList[nLion]._b];
+ short nTarget = LionList[nLion].nTarget;
+
+ int nVal = MoveCreatureWithCaution(nSprite);
+
+ switch (nAction)
+ {
+ default:
+ return;
+
+ case 0:
+ case 1:
+ {
+ if ((LionList[nLion]._f & 31) == (totalmoves & 31))
+ {
+ if (nTarget < 0)
+ {
+ nTarget = FindPlayer(nSprite, 40);
+ if (nTarget >= 0)
+ {
+ D3PlayFX(StaticSound[kSound24], nSprite);
+ LionList[nLion].nAction = 2;
+ LionList[nLion]._b = 0;
+
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 1;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 1;
+ LionList[nLion].nTarget = nTarget;
+ return;
+ }
+ }
+ }
+
+ if (nAction)
+ {
+ LionList[nLion]._g--;
+ if (LionList[nLion]._g <= 0)
+ {
+ if (RandomBit())
+ {
+ sprite[nSprite].ang = RandomWord() & kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 1;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 1;
+ }
+ else
+ {
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+
+ LionList[nLion]._g = 100;
+ }
+ }
+
+ return;
+ }
+
+ case 2:
+ {
+ if ((totalmoves & 0x1F) == (LionList[nLion]._f & 0x1F))
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+
+ short nAng = sprite[nSprite].ang & 0xFFF8;
+
+ if (sprite[nSprite].cstat & 0x8000)
+ {
+ sprite[nSprite].xvel = Sin(nAng + 512) * 2;
+ sprite[nSprite].yvel = Sin(nAng) * 2;
+ }
+ else
+ {
+ sprite[nSprite].xvel = Sin(nAng + 512) >> 1;
+ sprite[nSprite].yvel = Sin(nAng) >> 1;
+ }
+ }
+
+ if ((nVal & 0xC000) < 0x8000)
+ {
+ break;
+ }
+ else if ((nVal & 0xC000) == 0x8000)
+ {
+ // loc_378FA:
+ sprite[nSprite].ang = (sprite[nSprite].ang + 256) & kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 1;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 1;
+ break;
+ }
+ else if ((nVal & 0xC000) == 0xC000)
+ {
+ if ((nVal & 0x3FFF) == nTarget)
+ {
+ if (sprite[nSprite].cstat == 0x8000)
+ {
+ int nAng = getangle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+
+ if (AngleDiff(sprite[nSprite].ang, nAng) < 64)
+ {
+ LionList[nLion].nAction = 3;
+ }
+ }
+ else
+ {
+ LionList[nLion].nAction = 9;
+ sprite[nSprite].cstat &= 0x7FFF;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+
+ LionList[nLion]._b = 0;
+ break;
+ }
+ else
+ {
+ // loc_378FA:
+ sprite[nSprite].ang = (sprite[nSprite].ang + 256) & kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 1;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 1;
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 3:
+ {
+ if (nTarget == -1)
+ {
+ LionList[nLion].nAction = 1;
+ LionList[nLion]._g = 50;
+ }
+ else
+ {
+ if (PlotCourseToSprite(nSprite, nTarget) >= 768)
+ {
+ LionList[nLion].nAction = 2;
+ }
+ else if (nFlag & 0x80)
+ {
+ runlist_DamageEnemy(nTarget, nSprite, 10);
+ }
+ }
+
+ break;
+ }
+
+ case 4:
+ {
+ if (var_18)
+ {
+ LionList[nLion].nAction = 2;
+ LionList[nLion]._b = 0;
+ }
+
+ if (nVal & 0x20000)
+ {
+ sprite[nSprite].xvel >>= 1;
+ sprite[nSprite].yvel >>= 1;
+ }
+
+ return;
+ }
+
+ case 5:
+ {
+ LionList[nLion]._g--;
+ if (LionList[nLion]._g <= 0)
+ {
+ sprite[nSprite].zvel = -4000;
+ LionList[nLion]._g = 0;
+
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ int z = sprite[nSprite].z - (GetSpriteHeight(nSprite) >> 1);
+
+ int var_40 = 0x7FFFFFFF;
+
+ short nSector = sprite[nSprite].sectnum;
+ short var_28 = sprite[nSprite].ang;
+
+ short nAng = (sprite[nSprite].ang - 512) & kAngleMask;
+
+ for (int i = 0; i < 5; i++)
+ {
+ short hitsect, hitwall, hitsprite;
+ int hitx, hity, hitz;
+
+ hitscan(x, y, z, nSector, Sin(nAng + 512), Sin(nAng), 0, &hitsect, &hitwall, &hitsprite, &hitx, &hity, &hitz, CLIPMASK1);
+
+ if (hitwall > -1)
+ {
+ int ebx = klabs(hitx - x);
+ int eax = klabs(hity - y);
+
+ ebx += eax;
+
+ if (ebx < var_40)
+ {
+ var_40 = ebx;
+ var_28 = nAng;
+ }
+ }
+
+ nAng += 256;
+ nAng &= kAngleMask;
+ }
+
+ sprite[nSprite].ang = var_28;
+
+ LionList[nLion].nAction = 6;
+ sprite[nSprite].xvel = (Sin(sprite[nSprite].ang + 512)) - (Sin(sprite[nSprite].ang + 512) >> 3);
+ sprite[nSprite].yvel = (Sin(sprite[nSprite].ang)) - (Sin(sprite[nSprite].ang) >> 3);
+ D3PlayFX(StaticSound[kSound24], nSprite);
+ }
+
+ return;
+ }
+
+ case 6:
+ {
+ if (nVal & 0x30000)
+ {
+ LionList[nLion].nAction = 2;
+ LionList[nLion]._b = 0;
+ return;
+ }
+
+ if ((nVal & 0xC000) == 0x8000)
+ {
+ LionList[nLion].nAction = 7;
+ sprite[nSprite].ang = (GetWallNormal(nVal & 0x3FFF) + 1024) & kAngleMask;
+ LionList[nLion]._g = RandomSize(4);
+ return;
+ }
+ else if ((nVal & 0xC000) == 0xC000)
+ {
+ if ((nVal & 0x3FFF) == nTarget)
+ {
+ int nAng = getangle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+ if (AngleDiff(sprite[nSprite].ang, nAng) < 64)
+ {
+ LionList[nLion].nAction = 3;
+ LionList[nLion]._b = 0;
+ }
+ }
+ else
+ {
+ // loc_378FA:
+ sprite[nSprite].ang = (sprite[nSprite].ang + 256) & kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 1;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 1;
+ }
+ }
+
+ return;
+ }
+
+ case 7:
+ {
+ LionList[nLion]._g--;
+
+ if (LionList[nLion]._g <= 0)
+ {
+ LionList[nLion]._g = 0;
+ if (nTarget > -1)
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+ }
+ else
+ {
+ sprite[nSprite].ang = (RandomSize(9) + (sprite[nSprite].ang + 768)) & kAngleMask;
+ }
+
+ sprite[nSprite].zvel = -1000;
+
+ LionList[nLion].nAction = 6;
+ sprite[nSprite].xvel = (Sin(sprite[nSprite].ang + 512)) - (Sin(sprite[nSprite].ang + 512) >> 3);
+ sprite[nSprite].yvel = (Sin(sprite[nSprite].ang)) - (Sin(sprite[nSprite].ang) >> 3);
+ D3PlayFX(StaticSound[kSound24], nSprite);
+ }
+
+ return;
+ }
+
+ case 8:
+ {
+ if (var_18)
+ {
+ LionList[nLion].nAction = 2;
+ LionList[nLion]._b = 0;
+ sprite[nSprite].cstat |= 0x8000;
+ }
+ return;
+ }
+
+ case 9:
+ {
+ if (var_18)
+ {
+ LionList[nLion]._b = 0;
+ LionList[nLion].nAction = 2;
+ sprite[nSprite].cstat |= 0x101;
+ }
+ return;
+ }
+
+ case 10:
+ case 11:
+ {
+ if (var_18)
+ {
+ runlist_SubRunRec(sprite[nSprite].owner);
+ runlist_SubRunRec(MoveHook[nLion]);
+ sprite[nSprite].cstat = 0x8000;
+ }
+ return;
+ }
+ }
+
+ // loc_379AD: ?
+ if (nAction != 1 && nTarget != -1)
+ {
+ if (!(sprite[nTarget].cstat & 0x101))
+ {
+ LionList[nLion].nAction = 1;
+ LionList[nLion]._b = 0;
+ LionList[nLion]._g = 100;
+ LionList[nLion].nTarget = -1;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ }
+ }
+
+ return;
+ }
+ }
+}
diff --git a/source/exhumed/src/lion.h b/source/exhumed/src/lion.h
new file mode 100644
index 000000000..9cac93f55
--- /dev/null
+++ b/source/exhumed/src/lion.h
@@ -0,0 +1,9 @@
+
+#ifndef __lion_h__
+#define __lion_h__
+
+void InitLion();
+int BuildLion(short nSprite, int x, int y, int z, short nSector, short nAngle);
+void FuncLion(int, int, int);
+
+#endif
diff --git a/source/exhumed/src/main.cpp b/source/exhumed/src/main.cpp
new file mode 100644
index 000000000..2610f1c8f
--- /dev/null
+++ b/source/exhumed/src/main.cpp
@@ -0,0 +1,29 @@
+
+#include "exhumed.h"
+
+extern "C" {
+#ifndef __WATCOMC__
+#include "build.h"
+#include "osd.h"
+#include "baselayer.h"
+#endif
+
+void faketimerhandler(void)
+{
+}
+
+#ifdef __WATCOMC__
+void main(int argc, char *argv[])
+{
+ ExhumedMain(argc, argv); // main function in exhumed.cpp
+}
+#else
+int app_main(int argc, char *argv[])
+{
+ wm_setapptitle("Exhumed/PowerSlave PC RE");
+ ExhumedMain(argc, argv); // main function in exhumed.cpp
+ return 0;
+}
+#endif
+
+}
diff --git a/source/exhumed/src/map.cpp b/source/exhumed/src/map.cpp
new file mode 100644
index 000000000..314e93c99
--- /dev/null
+++ b/source/exhumed/src/map.cpp
@@ -0,0 +1,279 @@
+
+#include "typedefs.h"
+#include
+#include "player.h"
+#include "init.h"
+#include "engine.h"
+#include "exhumed.h"
+
+short bShowTowers = kTrue; //kFalse; REVERT to kFalse
+long ldMapZoom;
+long lMapZoom;
+
+void MarkSectorSeen(short nSector);
+
+
+void InitMap()
+{
+ memset(show2dsector, 0, sizeof(show2dsector));
+ memset(show2dwall, 0, sizeof(show2dwall));
+ memset(show2dsprite, 0, sizeof(show2dsprite));
+
+ ldMapZoom = 64;
+ lMapZoom = 1000;
+}
+
+void GrabMap()
+{
+ for (int i = 0; i < numsectors; i++) {
+ MarkSectorSeen(i);
+ }
+}
+
+void MarkSectorSeen(short nSector)
+{
+ if (!((1 << (nSector & 7)) & show2dsector[nSector >> 3]))
+ {
+ show2dsector[nSector >> 3] |= 1 << (nSector & 7);
+
+ short startwall = sector[nSector].wallptr;
+ short nWalls = sector[nSector].wallnum;
+ short endwall = startwall + nWalls;
+
+ while (startwall <= endwall)
+ {
+ show2dwall[startwall >> 3] = (1 << (startwall & 7)) | show2dwall[startwall >> 3];
+ startwall++;
+ }
+ }
+}
+
+void drawoverheadmap(long cposx, long cposy, long czoom, short cang)
+{
+#ifndef __WATCOMC__ // FIXME - Won't compile on Watcom
+ long xvect = sintable[(2048 - cang) & 2047] * czoom;
+ long yvect = sintable[(1536 - cang) & 2047] * czoom;
+ long xvect2 = mulscale(xvect, yxaspect, 16);
+ long yvect2 = mulscale(yvect, yxaspect, 16);
+
+ // draw player position arrow
+ drawline256(xdim << 11, (ydim << 11) - 20480, xdim << 11, (ydim << 11) + 20480, 24);
+ drawline256((xdim << 11) - 20480, ydim << 11, xdim << 11, (ydim << 11) - 20480, 24);
+ drawline256((xdim << 11) + 20480, ydim << 11, xdim << 11, (ydim << 11) - 20480, 24);
+
+ short nPlayerSprite = PlayerList[nLocalPlayer].nSprite;
+
+ int nPlayerZ = sprite[nPlayerSprite].z;
+
+ for (int nSector = 0; nSector < numsectors; nSector++)
+ {
+ short startwall = sector[nSector].wallptr;
+ short nWalls = sector[nSector].wallnum;
+ short endwall = startwall + nWalls - 1;
+
+ int nCeilZ = sector[nSector].ceilingz;
+ int nFloorZ = sector[nSector].floorz;
+
+ int nZVal = nFloorZ - nPlayerZ;
+ if (nZVal < 0) {
+ nZVal = -nZVal;
+ }
+
+ int var_10 = nZVal >> 13;
+ if (var_10 > 12) {
+ var_10 = 12;
+ }
+
+ var_10 = 111 - var_10;
+
+ int startwallB = startwall;
+
+ for (int nWall = startwall; nWall <= endwall; nWall++)
+ {
+ short nextwall = wall[nWall].nextwall;
+
+ if (nextwall >= 0)
+ {
+ if (show2dwall[nWall >> 3] & (1 << (nWall & 7)))
+ {
+ if (nextwall <= nWall || (show2dwall[nextwall >> 3] & (1 << (nextwall & 7))) <= 0)
+ {
+ if (nCeilZ != sector[wall[nWall].nextsector].ceilingz ||
+ nFloorZ != sector[wall[nWall].nextsector].floorz ||
+ ((wall[nextwall].cstat | wall[nWall].cstat) & 0x30))
+ {
+ long ox = wall[nWall].x - cposx;
+ long oy = wall[nWall].y - cposy;
+
+ long x1 = mulscale(ox, xvect, 16) - mulscale(oy, yvect, 16);
+ long y1 = mulscale(oy, xvect2, 16) + mulscale(ox, yvect2, 16);
+
+ int nWall2 = wall[nWall].point2;
+ ox = wall[nWall2].x - cposx;
+ oy = wall[nWall2].y - cposy;
+ long x2 = mulscale(ox, xvect, 16) - mulscale(oy, yvect, 16);
+ long y2 = mulscale(oy, xvect2, 16) + mulscale(ox, yvect2, 16);
+
+ drawline256(x1 + (xdim << 11), y1 + (ydim << 11), x2 + (xdim << 11), y2 + (ydim << 11), var_10);
+
+ /*
+ drawline256(
+ ((unsigned __int64)(v4 * (signed __int64)v12) >> 16)
+ - ((unsigned __int64)(v5 * (signed __int64)v13) >> 16)
+ + (xdim << 11),
+ ((unsigned __int64)(v42 * (signed __int64)v12) >> 16)
+ + ((unsigned __int64)(v43 * (signed __int64)v13) >> 16)
+ + (ydim << 11),
+ (build_xdim << 11)
+ + ((unsigned __int64)(v4 * (signed __int64)(*v14 - v31)) >> 16)
+ - ((unsigned __int64)(v5 * (signed __int64)(v14[1] - v30)) >> 16),
+ ydim << 11)
+ + ((unsigned __int64)(v43 * (signed __int64)(v14[1] - v30)) >> 16)
+ + ((unsigned __int64)(v42 * (signed __int64)(*v14 - v31)) >> 16),
+ v48);
+ */
+ }
+ }
+ }
+ }
+ }
+ }
+
+// int var_4C = 0;
+// int var_48 = 0;
+
+ for (int nSector = 0; nSector < numsectors; nSector++)
+ {
+ int startwall = sector[nSector].wallptr;
+ int nWalls = sector[nSector].wallnum;
+ int endwall = startwall + nWalls - 1;
+
+ int nFloorZ = sector[nSector].floorz;
+
+ int nVal = nFloorZ - nPlayerZ;
+ if (nVal < 0) {
+ nVal = -nVal;
+ }
+
+ int var_14 = nVal >> 13;
+
+ if (var_14 <= 15)
+ {
+ var_14 = 111 - var_14;
+
+ for (int nWall = startwall; nWall <= endwall; nWall++)
+ {
+ if (wall[nWall].nextwall < 0)
+ {
+ if (show2dwall[nWall >> 3] & (1 << (nWall & 7)))
+ {
+ if (tilesizx[wall[nWall].picnum] && tilesizy[wall[nWall].picnum])
+ {
+ long ox = wall[nWall].x - cposx;
+ long oy = wall[nWall].y - cposy;
+ long x1 = mulscale(ox, xvect, 16) - mulscale(oy, yvect, 16);
+ long y1 = mulscale(oy, xvect2, 16) + mulscale(ox, yvect2, 16);
+
+ int nWall2 = wall[nWall].point2;
+ ox = wall[nWall2].x - cposx;
+ oy = wall[nWall2].y - cposy;
+ long x2 = mulscale(ox, xvect, 16) - mulscale(oy, yvect, 16);
+ long y2 = mulscale(oy, xvect2, 16) + mulscale(ox, yvect2, 16);
+
+ drawline256(x1 + (xdim << 11), y1 + (ydim << 11), x2 + (xdim << 11), y2 + (ydim << 11), 24);
+
+/*
+
+ v19 = *v17 - v31;
+ v20 = v17[1] - v30;
+ v21 = &wall[8 * *((_WORD *)v17 + 4)];
+
+ build_drawline256(
+ (build_xdim << 11)
+ + ((unsigned __int64)(v4 * (signed __int64)v19) >> 16)
+ - ((unsigned __int64)(v5 * (signed __int64)v20) >> 16),
+ (build_ydim << 11)
+ + ((unsigned __int64)(v42 * (signed __int64)v19) >> 16)
+ + ((unsigned __int64)(v43 * (signed __int64)v20) >> 16),
+ (build_xdim << 11)
+ + ((unsigned __int64)(v4 * (signed __int64)(*v21 - v31)) >> 16)
+ - ((unsigned __int64)(v5 * (signed __int64)(v21[1] - v30)) >> 16),
+ (build_ydim << 11)
+ + ((unsigned __int64)(v42 * (signed __int64)(*v21 - v31)) >> 16)
+ + ((unsigned __int64)(v43 * (signed __int64)(v21[1] - v30)) >> 16),
+ v46);
+*/
+ }
+ }
+ }
+ }
+
+ if (bShowTowers)
+ {
+ for (int nSprite = headspritestat[406]; nSprite != -1; nSprite = nextspritestat[nSprite])
+ {
+ long ox = sprite[nSprite].x - cposx; // var_64
+ long oy = sprite[nSprite].y - cposx; // var_68
+
+ // int var_58 = mulscale(var_64, xvect, 16) - mulscale(var_68, yvect, 16);
+ long x1 = mulscale(ox, xvect, 16) - mulscale(oy, yvect, 16);
+ long y1 = mulscale(oy, xvect2, 16) + mulscale(ox, yvect2, 16);
+
+ //int var_58 = mulscale(var_64, xvect, 16) - mulscale(var_68, yvect, 16);
+ //int esi = mulscale(var_68, xvect2, 16) + mulscale(var_65, yvect2, 16)
+
+ //v25 = ((unsigned __int64)(v4 * (signed __int64)ox) >> 16)
+ // - ((unsigned __int64)(v5 * (signed __int64)oy) >> 16);
+
+ //v26 = ((unsigned __int64)(v42 * (signed __int64)ox) >> 16)
+ // + ((unsigned __int64)(v43 * (signed __int64)oy) >> 16);
+
+ //v27 = v26 + 2048;
+ //v28 = v26 + 2048 + (ydim << 11);
+ //v26 -= 2048;
+
+ // v25 is x1
+ // v26 is y1
+ // v27 is y1 + 2048
+ // v28 is y1 + 2048 + (ydim << 1);
+
+ drawline256(
+ x1 - 2048 + (xdim << 11),
+ y1 - 2048 + (ydim << 11),
+ x1 - 2048 + (xdim << 11),
+ y1 + 2048 + (ydim << 1),
+ 170);
+
+ drawline256(
+ x1 + (xdim << 11),
+ y1 + (ydim << 11),
+ x1 + (xdim << 11),
+ y1 + 2048 + (ydim << 11),
+ 170);
+
+ drawline256(
+ x1 + 2048 + (xdim << 11),
+ y1 + (ydim << 11),
+ x1 + 2048 + (xdim << 11),
+ y1 + 2048 + (ydim << 11),
+ 170);
+ }
+ }
+ }
+ }
+#endif
+}
+
+void UpdateMap()
+{
+ if (sector[initsect].ceilingpal != 3 || (nPlayerTorch[nLocalPlayer] != 0)) {
+ MarkSectorSeen(initsect);
+ }
+}
+
+void DrawMap()
+{
+ if (!nFreeze) {
+ drawoverheadmap(initx, inity, lMapZoom, inita);
+ }
+}
diff --git a/source/exhumed/src/map.h b/source/exhumed/src/map.h
new file mode 100644
index 000000000..2e118a4cc
--- /dev/null
+++ b/source/exhumed/src/map.h
@@ -0,0 +1,16 @@
+
+#ifndef __map_h__
+#define __map_h__
+
+#include "typedefs.h"
+
+extern short bShowTowers;
+extern long ldMapZoom;
+extern long lMapZoom;
+
+void InitMap();
+void GrabMap();
+void UpdateMap();
+void DrawMap();
+
+#endif
diff --git a/source/exhumed/src/menu.cpp b/source/exhumed/src/menu.cpp
new file mode 100644
index 000000000..982ba0c0e
--- /dev/null
+++ b/source/exhumed/src/menu.cpp
@@ -0,0 +1,2356 @@
+
+#define _USE_32BIT_TIME_T 1
+
+#include "exhumed.h"
+#include "typedefs.h"
+#include "player.h"
+#include "sequence.h"
+#include "menu.h"
+#include "names.h"
+#include "engine.h"
+#include "types.h"
+#include "keyboard.h"
+#include "status.h"
+#include "random.h"
+#include "sound.h"
+#include "names.h"
+#include "init.h"
+#include "input.h"
+#include "gun.h"
+#include "view.h"
+#include "object.h"
+#include "light.h"
+#include "cd.h"
+#include "cdaudio.h"
+#include
+#include
+
+#include
+
+#ifdef __WATCOMC__
+#include
+#endif
+
+#define kMaxSaveSlots 5
+#define kMaxSaveSlotChars 25
+
+GameStat GameStats;
+
+short nCinemaSeen[30];
+
+// this might be static within the DoPlasma function?
+uchar plasmaBuffer[25600];
+
+uchar energytile[4356] = {0};
+
+uchar cinemapal[768];
+short nLeft[50] = {0};
+int line;
+
+short SavePosition = -1;
+
+BYTE *cur;
+BYTE *dest;
+
+unsigned int nSmokeBottom;
+unsigned int nSmokeRight;
+unsigned int nSmokeTop;
+unsigned int nSmokeLeft;
+
+unsigned int nRandom = 0x41C6167E;
+int dword_9AB57 = 0x1F;
+short word_9AB5B = 0;
+
+int keytimer = 0;
+
+int plasma_A[5] = {0};
+int plasma_B[5] = {0};
+int plasma_C[5] = {0};
+
+short nMenuKeys[] = { sc_N, sc_L, sc_M, sc_V, sc_Q, sc_None }; // select a menu item using the keys. 'N' for New Gane, 'V' for voume etc. 'M' picks Training for some reason...
+
+int zoomsize = 0;
+
+void menu_ResetKeyTimer();
+
+enum {
+ kMenuNewGame = 0,
+ kMenuLoadGame,
+ kMenuTraining,
+ kMenuVolume,
+ kMenuQuitGame,
+ kMenuMaxItems
+};
+
+
+void ClearCinemaSeen()
+{
+ memset(nCinemaSeen, 0, sizeof(nCinemaSeen));
+}
+
+unsigned int menu_RandomBit2()
+{
+ unsigned int result = nRandom & 1;
+
+ if ( --dword_9AB57 > 0 )
+ {
+ nRandom = (result << 31) | (nRandom >> 1);
+ }
+ else
+ {
+ dword_9AB57 = 31;
+ nRandom ^= nRandom >> 4;
+ }
+ return result;
+}
+
+int menu_RandomLong2()
+{
+ int randLong = 0;
+
+ for (int i = 0; i < 32; i++)
+ {
+ int val = menu_RandomBit2();
+ randLong *= 2;
+ randLong |= val;
+ }
+
+ return randLong;
+}
+
+void InitEnergyTile()
+{
+ memset(energytile, 96, sizeof(energytile));
+}
+
+void DoEnergyTile()
+{
+ loadtile(kEnergy1);
+ loadtile(kEnergy2);
+
+ nButtonColor += nButtonColor < 0 ? 8 : 0;
+
+ uchar *ptr1 = (waloff[kEnergy1] + 1984);
+ uchar *ptr2 = (waloff[kEnergy1] + 2048);
+
+ short nColor = nButtonColor + 161;
+
+ int i, j;
+
+ for (i = 0; i < 32; i++)
+ {
+ memset(ptr1, nColor, 64);
+ memset(ptr2, nColor, 64);
+
+ ptr1 -= 64;
+ ptr2 += 64;
+
+ nColor++;
+
+ if (nColor >= 168) {
+ nColor = 160;
+ }
+ }
+
+ if (nSmokeSparks)
+ {
+ uchar *c = &energytile[67]; // TODO - checkme
+ uchar *ptrW = waloff[kEnergy2];
+
+ for (i = 0; i < 64; i++)
+ {
+ for (j = 0; j < 64; j++)
+ {
+ if (*c != 96)
+ {
+ if (*c <= 158) {
+ *ptrW = 96;
+ }
+ else {
+ *ptrW = (*c) - 1;
+ }
+ //continue;
+ }
+ else
+ {
+ if (menu_RandomBit2()) {
+ *ptrW = *c;
+ c++;
+ ptrW++;
+ continue;
+ }
+
+ char al = *(c + 1);
+ char ah = *(c - 1);
+
+ if (al <= ah) {
+ al = ah;
+ }
+
+ char cl = al;
+ al = *(c - 66);
+
+ if (cl <= al) {
+ cl = al;
+ }
+
+ al = *(c + 66);
+ if (cl <= al) {
+ cl = al;
+ }
+
+ al = *(c + 66);
+ if (cl <= al) {
+ cl = al;
+ }
+
+ al = *(c + 66);
+ if (cl <= al) {
+ cl = al;
+ }
+
+ al = *(c - 65);
+ if (cl <= al) {
+ cl = al;
+ }
+
+ al = *(c - 67);
+ if (cl > al) {
+ al = cl;
+ }
+
+ if (al <= 159) {
+ *ptrW = 96;
+ //continue;
+ }
+ else
+ {
+ if (!menu_RandomBit2())
+ {
+ cl--;
+ }
+
+ *ptrW = cl;
+ }
+ }
+
+ c++;
+ ptrW++;
+ }
+
+ c += 2;
+ }
+
+ c = &energytile[67]; // TODO - checkme
+ ptrW = waloff[kEnergy2];
+
+ for (i = 0; i < 64; i++)
+ {
+ memcpy(c, ptrW, 64);
+ c += 66;
+ ptrW += 64;
+ }
+
+ ptrW = waloff[kEnergy2];
+
+ for (i = 0; i < 4096; i++)
+ {
+ if (*ptrW == 96) {
+ *ptrW = 255; // -1?
+ }
+
+ ptrW ++;
+ }
+
+ word_9AB5B--;
+ if (word_9AB5B <= 0)
+ {
+ int randSize = (RandomSize(5) & 0x1F) + 16;
+ int randSize2 = (RandomSize(5) & 0x1F) + 16;
+
+ int val = randSize << 5;
+ val += randSize;
+ val *= 2;
+ val += randSize2;
+
+ energytile[val] = 195;
+ word_9AB5B = 1;
+ }
+ }
+}
+
+char lockbyte4092 = 0;
+
+//int TILE_4092 = kTile4092;
+int nPlasmaTile = kTile4092;
+
+#define kPlasmaWidth 320
+#define kPlasmaHeight 80
+
+void menu_DoPlasma()
+{
+ if (!lockbyte4092)
+ {
+ lockbyte4092 = 1;
+ allocache((long*)&waloff[kTile4092], kPlasmaWidth * kPlasmaHeight, &lockbyte4092);
+ memset(waloff[kTile4092], 96, 25600);
+
+ tilesizx[kTile4092] = kPlasmaWidth;
+ tilesizy[kTile4092] = kPlasmaHeight;
+
+ waloff[kTile4093] = plasmaBuffer;
+ memset(plasmaBuffer, 96, sizeof(plasmaBuffer));
+
+ nSmokeLeft = 160 - tilesizx[kExhumedLogo] / 2;
+ nSmokeRight = nSmokeLeft + tilesizx[kExhumedLogo];
+
+ tilesizx[kTile4093] = kPlasmaWidth;
+ tilesizy[kTile4093] = kPlasmaHeight;
+
+ nSmokeTop = 40 - tilesizy[kExhumedLogo] / 2;
+ nSmokeBottom = 40 - tilesizy[kExhumedLogo] / 2 + tilesizy[kExhumedLogo] - 1;
+
+ ulong t = time(0) << 16;
+ ulong t2 = time(0) | t;
+
+ // t2 is 64bits on visual studio, but would have been 32bit on WATCOM... just going to cast here
+ nRandom = t2;
+
+ for (int i = 0; i < 5; i++)
+ {
+ int logoWidth = tilesizx[kExhumedLogo];
+#if 1
+ plasma_C[i] = (nSmokeLeft + rand() % logoWidth) << 16;
+ plasma_B[i] = (menu_RandomLong2() % 327680) + 0x10000;
+#else
+ int r = rand();
+ long rand2 = menu_RandomLong2();
+
+ __asm {
+ mov ebx, i
+ mov ecx, logoWidth
+ mov eax, r
+ mov edx, eax
+ sar edx, 31
+ idiv ecx
+
+ add edx, nSmokeLeft
+ shl edx, 16
+ mov ecx, 327680
+ mov plasma_C[ebx * 4], edx
+ xor edx, edx
+ mov eax, rand2
+// call menu_RandomLong2
+ div ecx
+ add edx, 10000h
+ mov plasma_B[ebx * 4], edx
+ };
+#endif
+
+ if (menu_RandomBit2()) {
+ plasma_B[i] = -plasma_B[i];
+ }
+
+ plasma_A[i] = menu_RandomBit2();
+ }
+ }
+
+ clearview(overscanindex);
+
+ BYTE *r_ebx = waloff[nPlasmaTile] + 81;
+ BYTE *r_edx = waloff[nPlasmaTile ^ 1] + 81; // flip between value of 4092 and 4093 with xor
+
+ for (int x = 0; x < kPlasmaWidth - 2; x++)
+// for (int x = 1; x < 318; x++)
+ {
+// for (int y = 1; y < 79; y++)
+ for (int y = 0; y < kPlasmaHeight - 2; y++)
+ {
+ uchar al = *r_edx;
+
+ if (al != 96)
+ {
+ if (al > 158) {
+ *r_ebx = al - 1;
+ }
+ else {
+ *r_ebx = 96;
+ }
+ }
+ else
+ {
+ if (menu_RandomBit2()) {
+ *r_ebx = *r_edx;
+ }
+ else
+ {
+ uchar al = *(r_edx + 1);
+ uchar cl = *(r_edx - 1);
+
+ if (al <= cl) {
+ al = cl;
+ }
+
+ cl = al;
+ al = *(r_edx - 80);
+ if (cl <= al) {
+ cl = al;
+ }
+
+ al = *(r_edx + 80);
+ if (cl <= al) {
+ cl = al;
+ }
+
+ al = *(r_edx + 80);
+ if (cl <= al) {
+ cl = al;
+ }
+
+ al = *(r_edx + 80);
+ if (cl <= al) {
+ cl = al;
+ }
+
+ al = *(r_edx - 79);
+ if (cl > al) {
+ al = cl;
+ }
+
+ cl = *(r_edx - 81);
+ if (al <= cl) {
+ al = cl;
+ }
+
+ cl = al;
+
+ if (al <= 159) {
+ *r_ebx = 96;
+ }
+ else
+ {
+ if (!menu_RandomBit2()) {
+ cl--;
+ }
+
+ *r_ebx = cl;
+ }
+ }
+ }
+
+ // before restarting inner loop
+ r_edx++;
+ r_ebx++;
+ }
+
+ // before restarting outer loop
+ r_edx += 2;
+ r_ebx += 2;
+ }
+
+ loadtile(kExhumedLogo);
+
+ for (int j = 0; j < 5; j++)
+ {
+ int pB = plasma_B[j];
+ int pC = plasma_C[j];
+
+ BYTE *ptr3 = (waloff[kExhumedLogo] + ((pC >> 16) - nSmokeLeft) * tilesizy[kExhumedLogo]);
+
+ plasma_C[j] += plasma_B[j];
+
+ if (pB > 0 && (plasma_C[j] >> 16) >= nSmokeRight || pB < 0 && (plasma_C[j] >> 16) <= nSmokeLeft)
+ {
+ int esi = plasma_A[j];
+ plasma_B[j] = -plasma_B[j];
+ plasma_A[j] = esi == 0;
+ }
+
+ unsigned int nSmokeOffset = 0;
+
+ if (plasma_A[j])
+ {
+ nSmokeOffset = nSmokeTop;
+
+ while (nSmokeOffset < nSmokeBottom)
+ {
+ uchar al = *ptr3;
+ if (al != 255 && al != 96) {
+ break;
+ }
+
+ nSmokeOffset++;
+ ptr3++;
+ }
+ }
+ else
+ {
+ nSmokeOffset = nSmokeBottom;
+
+ ptr3 += tilesizy[kExhumedLogo] - 1;
+
+ while (nSmokeOffset > nSmokeTop)
+ {
+ uchar al = *ptr3;
+ if (al != 255 && al != 96) {
+ break;
+ }
+
+ nSmokeOffset--;
+ ptr3--;
+ }
+ }
+
+ BYTE *v28 = 80 * (plasma_C[j] >> 16) + waloff[nPlasmaTile];
+ v28[nSmokeOffset] = 175;
+ }
+
+ overwritesprite(0, 0, nPlasmaTile, 0, 2, kPalNormal);
+ overwritesprite(160, 40, kExhumedLogo, 0, 3, kPalNormal);
+
+ // flip between tile 4092 and 4093
+ if (nPlasmaTile == kTile4092) {
+ nPlasmaTile = kTile4093;
+ }
+ else if (nPlasmaTile == kTile4093) {
+ nPlasmaTile = kTile4092;
+ }
+
+ // draw the fire urn/lamp thingies
+ int dword_9AB5F = ((totalclock - ((totalclock >> 31) + 16 * (totalclock >> 31))) >> 4) & 3;
+
+ overwritesprite(50, 150, kTile3512 + dword_9AB5F, 0, 3, kPalNormal);
+ overwritesprite(270, 150, kTile3512 + ((dword_9AB5F + 2) & 3), 0, 3, kPalNormal);
+
+ // TEMP
+ int time = totalclock + 4;
+ while (totalclock < time) {
+ handleevents();
+ }
+}
+
+
+uchar MapDataArray_A[] = { 0, 50, 10, 20, 0, 45, 236, 20, 5, 0, 246, 10, 30, 236, 0, 20, 0, 0, 0, 0 };
+
+struct TILEFRAMEDEF
+{
+ short nTile;
+ short xOffs;
+ short yOffs;
+};
+
+// 22 bytes
+struct MapNamePlaque
+{
+ short xPos;
+ short yPos;
+ TILEFRAMEDEF tiles[2];
+ TILEFRAMEDEF text;
+};
+
+MapNamePlaque mapNamePlaques[] = {
+ { 100, 170, 3376, 0, 0, 3377, 0, 0, 3411, 18, 6 },
+ { 230, 10, 3378, 0, 0, 3379, 0, 0, 3414, 18, 6 }, // DENDUR (level 2)
+ { 180, 125, 3380, 0, 0, 3381, 0, 0, 3417, 18, 6 }, // Kalabash
+ { 10, 95, 3382, 0, 0, 3383, 0, 0, 3420, 18, 6 },
+ { 210, 160, 3384, 0, 0, 3385, 0, 0, 3423, 18, 6 },
+ { 10, 110, 3371, 0, 0, 3386, 0, 0, 3426, 18, 6 },
+ { 10, 50, 3387, 0, 0, 3388, 0, 0, 3429, 18, 6 },
+ { 140, 0, 3389, 0, 0, 3390, 0, 0, 3432, 18, 6 },
+ { 30, 20, 3391, 0, 0, 3392, 0, 0, 3435, 18, 6 },
+ { 200, 150, 3409, 0, 0, 3410, 0, 0, 3418, 20, 4 },
+ { 145, 170, 3393, 0, 0, 3394, 0, 0, 3438, 18, 6 },
+ { 80, 80, 3395, 0, 0, 3396, 0, 0, 3441, 18, 6 },
+ { 15, 0, 3397, 0, 0, 3398, 0, 0, 3444, 18, 5 },
+ { 220, 35, 3399, 0, 0, 3400, 0, 0, 3447, 18, 6 },
+ { 190, 40, 3401, 0, 0, 3402, 0, 0, 3450, 18, 6 },
+ { 20, 130, 3403, 0, 0, 3404, 0, 0, 3453, 19, 6 },
+ { 220, 160, 3405, 0, 0, 3406, 0, 0, 3456, 18, 6 },
+ { 20, 10, 3407, 0, 0, 3408, 0, 0, 3459, 18, 6 },
+ { 200, 10, 3412, 0, 0, 3413, 0, 0, 3419, 18, 5 },
+ { 20, 10, 3415, 0, 0, 3416, 0, 0, 3421, 19, 4 }
+};
+
+// 3 different types of fire, each with 4 frames
+TILEFRAMEDEF FireTiles[3][4] = {
+ {{ 3484,0,3 },{ 3485,0,0 },{ 3486,0,3 },{ 3487,0,0 }},
+ {{ 3488,1,0 },{ 3489,1,0 },{ 3490,0,1 },{ 3491,1,1 }},
+ {{ 3492,1,2 },{ 3493,1,0 },{ 3494,1,2 },{ 3495,1,0 }}
+};
+
+struct Fire
+{
+ short nFireType;
+ short xPos;
+ short yPos;
+};
+
+// 20 bytes
+struct MapFire
+{
+ short nFires;
+ Fire fires[3];
+};
+
+/*
+ level 1 - 3 fires
+ level 2 - 3 fires
+ level 3 - 1 fire
+
+*/
+
+MapFire MapLevelFires[] = {
+ 3, {{0, 107, 95}, {1, 58, 140}, {2, 28, 38}},
+ 3, {{2, 240, 0}, {0, 237, 32}, {1, 200, 30}},
+ 2, {{2, 250, 57}, {0, 250, 43}, {2, 200, 70}},
+ 2, {{1, 82, 59}, {2, 84, 16}, {0, 10, 95}},
+ 2, {{2, 237, 50}, {1, 215, 42}, {1, 210, 50}},
+ 3, {{0, 40, 7}, {1, 75, 6}, {2, 100, 10}},
+ 3, {{0, 58, 61}, {1, 85, 80}, {2, 111, 63}},
+ 3, {{0, 260, 65}, {1, 228, 0}, {2, 259, 15}},
+ 2, {{0, 81, 38}, {2, 58, 38}, {2, 30, 20}},
+ 3, {{0, 259, 49}, {1, 248, 76}, {2, 290, 65}},
+ 3, {{2, 227, 66}, {0, 224, 98}, {1, 277, 30}},
+ 2, {{0, 100, 10}, {2, 48, 76}, {2, 80, 80}},
+ 3, {{0, 17, 2}, {1, 29, 49}, {2, 53, 28}},
+ 3, {{0, 266, 42}, {1, 283, 99}, {2, 243, 108}},
+ 2, {{0, 238, 19}, {2, 240, 92}, {2, 190, 40}},
+ 2, {{0, 27, 0}, {1, 70, 40}, {0, 20, 130}},
+ 3, {{0, 275, 65}, {1, 235, 8}, {2, 274, 6}},
+ 3, {{0, 75, 45}, {1, 152, 105}, {2, 24, 68}},
+ 3, {{0, 290, 25}, {1, 225, 63}, {2, 260, 110}},
+ 0, {{1, 20, 10}, {1, 20, 10}, {1, 20, 10}}
+};
+
+int menu_DrawTheMap(int nLevel, int nLevelNew, int nLevelBest)
+{
+ int i;
+ int x = 0;
+ int var_2C = 0;
+ int var_38 = 0;
+ int bFadeDone = kFalse;
+
+ slong startTime = totalclock;
+
+ ClearAllKeys();
+ UnMaskStatus();
+ setview(0, 0, nScreenWidth - 1, nScreenHeight - 1);
+
+ // 0-offset the level numbers
+ nLevel--;
+ nLevelNew--;
+ nLevelBest--;
+
+ if (nLevel > kMap20) { // max levels
+ return -1;
+ }
+
+ if (nLevelNew > kMap20) {
+ return -1;
+ }
+
+ if (nLevel < 0) {
+ nLevel = 0;
+ }
+
+ if (nLevelNew < 0) {
+ nLevelNew = nLevel;
+ }
+
+ int y1 = MapDataArray_A[nLevel] + (200 * (nLevel / 2));
+ int y2 = MapDataArray_A[nLevelNew] + (200 * (nLevelNew / 2));
+
+ if (y1 < y2) {
+ var_2C = 2;
+ }
+
+ if (y1 > y2) {
+ var_2C = -2;
+ }
+
+ while (var_38 < 12)
+ {
+ handleevents();
+
+ if ((totalclock - startTime) / kTimerTicks)
+ {
+ var_38++;
+ startTime = totalclock;
+ }
+
+ int var_3C = totalclock;
+
+ int tileY = y1;
+
+ // Draw the background screens
+ for (i = 0; i < 10; i++)
+ {
+ overwritesprite(x, tileY, kTile3353 + i, 0, 2, kPalNormal);
+ tileY -= 200;
+ }
+
+ // for each level - drawing the 'level completed' on-fire smoke markers
+ for (i = 0; i < kMap20; i++)
+ {
+ handleevents();
+
+ int screenY = (i >> 1) * -200;
+
+ if (nLevelBest >= i) // check if the player has finished this level
+ {
+ for (int j = 0; j < MapLevelFires[i].nFires; j++)
+ {
+ int nFireFrame = ((totalclock >> 4) & 3);
+ assert(nFireFrame >= 0 && nFireFrame < 4);
+
+ int nFireType = MapLevelFires[i].fires[j].nFireType;
+ assert(nFireType >= 0 && nFireType < 3);
+
+ int nTile = FireTiles[nFireType][nFireFrame].nTile;
+ int smokeX = MapLevelFires[i].fires[j].xPos + FireTiles[nFireType][nFireFrame].xOffs;
+ int smokeY = MapLevelFires[i].fires[j].yPos + FireTiles[nFireType][nFireFrame].yOffs + y1 + screenY;
+
+ overwritesprite(smokeX, smokeY, nTile, 0, 2, kPalNormal);
+ }
+ }
+
+ int t = (((totalclock & 16) >> 4));
+
+ int nTile = mapNamePlaques[i].tiles[t].nTile;
+
+ int nameX = mapNamePlaques[i].xPos + mapNamePlaques[i].tiles[t].xOffs;
+ int nameY = mapNamePlaques[i].yPos + mapNamePlaques[i].tiles[t].yOffs + y1 + screenY;
+
+ // Draw level name plaque
+ overwritesprite(nameX, nameY, nTile, 0, 2, kPalNormal);
+
+ schar shade = 96;
+
+ if (nLevelNew == i)
+ {
+ shade = (Sin(16 * totalclock) + 31) >> 8;
+ }
+ else if (nLevelBest >= i)
+ {
+ shade = 31;
+ }
+
+ int textY = mapNamePlaques[i].yPos + mapNamePlaques[i].text.yOffs + y1 + screenY;
+ int textX = mapNamePlaques[i].xPos + mapNamePlaques[i].text.xOffs;
+ nTile = mapNamePlaques[i].text.nTile;
+
+ // draw the text, alternating between red and black
+ overwritesprite(textX, textY, nTile, shade, 2, kPalNormal);
+ }
+
+ nextpage();
+ if (!bFadeDone)
+ {
+ bFadeDone = kTrue;
+ FadeIn();
+ var_3C = totalclock;
+ }
+
+ if (y1 == y2)
+ {
+ if (KB_KeyDown[sc_UpArrow])
+ {
+ KB_KeyDown[sc_UpArrow] = 0;
+
+ if (nLevelNew <= nLevelBest)
+ {
+ nLevelNew++;
+
+ y2 = MapDataArray_A[nLevelNew] + (200 * (nLevelNew / 2));
+
+ if (y1 <= y2) {
+ var_2C = 2;
+ }
+ else {
+ var_2C = -2;
+ }
+
+ var_38 = 0;
+ }
+ }
+
+ if (KB_KeyDown[sc_DownArrow])
+ {
+ KB_KeyDown[sc_DownArrow] = 0;
+
+ if (nLevelNew > 0)
+ {
+ nLevelNew--;
+
+ y2 = MapDataArray_A[nLevelNew] + (200 * (nLevelNew / 2));
+
+ if (y1 <= y2) {
+ var_2C = 2;
+ }
+ else {
+ var_2C = -2;
+ }
+
+ var_38 = 0;
+ }
+ }
+
+ if (KB_KeyDown[sc_Escape] || KB_KeyDown[sc_Space] || KB_KeyDown[sc_Return])
+ {
+ KB_KeyDown[sc_Escape] = 0;
+ KB_KeyDown[sc_Return] = 0;
+ KB_KeyDown[sc_Space] = 0;
+ return nLevelNew + 1;
+ }
+ }
+ else
+ {
+ y1 += var_2C * ((totalclock - var_3C) / 2);
+
+ if (KB_KeyDown[sc_Escape] || KB_KeyDown[sc_Space] || KB_KeyDown[sc_Return])
+ {
+ if (var_2C < 8) {
+ var_2C *= 2;
+ }
+
+ KB_KeyDown[sc_Escape] = 0;
+ KB_KeyDown[sc_Return] = 0;
+ KB_KeyDown[sc_Space] = 0;
+ }
+
+ if (y1 > y2 && var_2C > 0) {
+ y1 = y2;
+ }
+
+ if (y1 < y2 && var_2C < 0) {
+ y1 = y2;
+ }
+
+ var_38 = 0;
+ }
+ }
+
+ MySetView(nViewLeft, nViewTop, nViewRight, nViewBottom);
+ return nLevelNew + 1;
+}
+
+void menu_AdjustVolume()
+{
+ int nOption = 1;
+ int var_8 = 0;
+
+ while (1)
+ {
+ handleevents();
+
+ menu_DoPlasma();
+
+ overwritesprite(80, 50, kMenuMusicTile, (Sin(totalclock << 4) >> 9) * (nOption == 0), 2, kPalNormal);
+ overwritesprite(55, 75, kMenuBlankTitleTile, 0, 2, kPalNormal);
+
+ seq_DrawGunSequence(
+ SeqOffsets[kSeqSlider], // eax
+ gMusicVolume % 3, // pick one of 3 frames?
+ (gMusicVolume >> 1) - 93, // ebx. must be x???
+ -22,
+ 0,
+ 0);
+
+ overwritesprite(80, 110, kMenuSoundFxTile, (Sin(totalclock << 4) >> 9) * (nOption == 1), 2, kPalNormal);
+ overwritesprite(55, 135, kMenuBlankTitleTile, 0, 2, kPalNormal);
+
+ seq_DrawGunSequence(
+ SeqOffsets[kSeqSlider],
+ gFXVolume % 3,
+ (gFXVolume / 2) - 93,
+ 38,
+ 0,
+ 0);
+
+ int y = (60 * nOption) + 38;
+
+ overwritesprite(60, y, kMenuCursorTile, 0, 2, kPalNormal);
+ overwritesprite(206, y, kMenuCursorTile, 0, 10, kPalNormal);
+
+ nextpage();
+
+ if (KB_KeyDown[sc_Escape] || KB_KeyDown[sc_Return] || KB_KeyDown[sc_Space])
+ {
+ PlayLocalSound(StaticSound[kSound33], 0);
+ KB_KeyDown[sc_Escape] = 0;
+ KB_KeyDown[sc_Space] = 0;
+ KB_KeyDown[sc_Return] = 0;
+ return;
+ }
+
+ if (KB_KeyDown[sc_UpArrow])
+ {
+ if (nOption > 0)
+ {
+ nOption--;
+ PlayLocalSound(StaticSound[kSound35], 0);
+ }
+
+ KB_KeyDown[sc_UpArrow] = 0;
+ }
+
+ if (KB_KeyDown[sc_DownArrow])
+ {
+ if (nOption < 1)
+ {
+ nOption++;
+ PlayLocalSound(StaticSound[kSound35], 0);
+ }
+
+ KB_KeyDown[sc_DownArrow] = 0;
+ }
+
+ if (totalclock <= var_8) {
+ continue;
+ }
+
+ var_8 = totalclock + 5;
+
+ if (KB_KeyDown[sc_LeftArrow])
+ {
+ switch (nOption)
+ {
+ case 0:
+ {
+ if (gMusicVolume > 3) {
+ gMusicVolume -= 4;
+ }
+
+// TODO SetMusicVolume();
+// TODO setCDaudiovolume(gMusicVolume);
+ continue;
+ }
+
+ case 1:
+ {
+ if (gFXVolume > 3) {
+ gFXVolume -= 4;
+ }
+
+ if (LocalSoundPlaying()) {
+ UpdateLocalSound();
+ }
+ else {
+ PlayLocalSound(StaticSound[kSound23], 0);
+ }
+ continue;
+ }
+ }
+ }
+
+ if (KB_KeyDown[sc_RightArrow])
+ {
+ switch (nOption)
+ {
+ case 0:
+ {
+ if (gMusicVolume < 252) {
+ gMusicVolume += 4;
+ }
+
+// TODO SetMusicVolume();
+// TODO setCDaudiovolume(gMusicVolume);
+ continue;
+ }
+
+ case 1:
+ {
+ if (gFXVolume < 252) {
+ gFXVolume += 4;
+ }
+
+ if (LocalSoundPlaying()) {
+ UpdateLocalSound();
+ }
+ else {
+ PlayLocalSound(StaticSound[kSound23], 0);
+ }
+ continue;
+ }
+ }
+ }
+
+ if (GetLocalSound() != 23) {
+ continue;
+ }
+ else {
+ StopLocalSound();
+ }
+ }
+}
+
+int menu_NewGameMenu()
+{
+ const char endMark = 0xF;
+ char nameList[5][25];
+ int nNameLen = sizeof(nameList);
+
+ int nNameOffset = 0; // char index into slot name string
+
+ int nPages = numpages;
+
+ int arg_3E = tilesizx[kMenuBlankTitleTile] - 10;
+
+ int nSlot = 0;
+
+ FILE *fp = fopen("savgamea.sav", "rb");
+ if (fp == NULL)
+ {
+ memset(nameList, 0, nNameLen);
+ memset(&GameStats, 0, sizeof(GameStat));
+
+ fp = fopen("savgamea.sav", "wb+");
+ if (fp != NULL)
+ {
+ fwrite(nameList, nNameLen, 1, fp);
+ fwrite(&GameStats, 75, 1, fp); //fwrite(&GameStats, 75, 5, fp); // CHECKME! the size
+ fwrite(&endMark, sizeof(endMark), 1, fp);
+
+ fclose(fp);
+ }
+ }
+ else
+ {
+ int nRead = fread(nameList, 1, nNameLen, fp);
+ if (nRead != nNameLen)
+ {
+ memset(nameList, 0, nNameLen);
+ }
+
+ fclose(fp);
+ }
+
+ // while (1)
+ {
+ ClearAllKeys();
+
+ while (1)
+ {
+ handleevents();
+ menu_DoPlasma();
+
+ int y = (tilesizy[kMenuBlankTitleTile] - (tilesizy[kMenuBlankTitleTile] / 2) / 2) + 65;
+ rotatesprite(160 << 16, y << 16, 0x10000, 0, kMenuNewGameTile, 0, 0, 2, 0, 0, nScreenWidth, nScreenHeight);
+
+ int edi = 0;
+
+ int arg_4A = 90;
+ int arg_4E = 98;
+
+ // Loop #3
+ for (int i = 0; i < 5; i++)
+ {
+ // CHECKME
+ schar shade = ((Sin(totalclock << 4) >> 9) * (i == nSlot)) + ((i != nSlot) * 31);
+
+ overwritesprite(55, arg_4A, kMenuBlankTitleTile, shade, 2, kPalNormal);
+ myprintext(63, arg_4E, nameList[i], 0);
+
+ arg_4E += 22;
+ arg_4A += 22;
+
+ edi++;
+ }
+
+ edi = nSlot * 22;
+
+ // draw selection markers
+ overwritesprite(35, edi + 78, kMenuCursorTile, 0, 2, kPalNormal);
+ overwritesprite(233, edi + 78, kMenuCursorTile, 0, 10, kPalNormal);
+ nextpage();
+
+ nPages--;
+ if (nPages > 0) {
+ continue;
+ }
+
+ if (KB_KeyDown[sc_Escape])
+ {
+ PlayLocalSound(StaticSound[kSound33], 0);
+ KB_KeyDown[sc_Escape] = 0;
+ return -1;
+ }
+
+ if (KB_KeyDown[sc_UpArrow])
+ {
+ PlayLocalSound(StaticSound[kSound35], 0);
+ if (nSlot <= 0) {
+ nSlot = 4;
+ }
+ else {
+ nSlot--;
+ }
+
+ KB_KeyDown[sc_UpArrow] = 0;
+ ClearAllKeys();
+ continue;
+ }
+
+ if (KB_KeyDown[sc_DownArrow])
+ {
+ PlayLocalSound(StaticSound[kSound35], 0);
+ if (nSlot >= 4) {
+ nSlot = 0;
+ }
+ else {
+ nSlot++;
+ }
+
+ KB_KeyDown[sc_DownArrow] = 0;
+ ClearAllKeys();
+ continue;
+ }
+
+ if (KB_KeyDown[sc_Return] || KB_KeyWaiting())
+ {
+ break;
+ }
+ }
+ }
+
+ PlayLocalSound(StaticSound[kSound33], 0);
+ if (KB_KeyDown[sc_Return]) {
+ ClearAllKeys();
+ }
+
+ char *pName = nameList[nSlot];
+ int nNameLength = strlen(pName);
+
+ memset(pName, 0, nNameLength);
+
+ menu_DoPlasma();
+ overwritesprite(55, (nSlot * 22) + 90, kMenuBlankTitleTile, 0, 2, kPalNormal);
+
+ int arg_5A = 90;
+ int arg_52 = 98;
+
+ for (int i = 0; i < 5; i++)
+ {
+ overwritesprite(55, arg_5A, kMenuBlankTitleTile, (i != nSlot) * 31, 2, kPalNormal);
+ myprintext(63, arg_52, nameList[i], 0);
+
+ arg_52 += 22;
+ arg_5A += 22;
+ }
+
+ int x = 35;
+ int y = (nSlot * 22) + 78;
+
+ while (1)
+ {
+ handleevents();
+
+ overwritesprite(x, y, kMenuCursorTile, 0, 2, kPalNormal);
+ overwritesprite(233, y, kMenuCursorTile, 0, 10, kPalNormal);
+ nextpage();
+
+ char ch = 0;
+
+ while (KB_KeyWaiting())
+ {
+ handleevents();
+
+ ch = KB_GetCh();
+ if (!ch) {
+ KB_GetCh();
+ continue;
+ }
+ }
+
+ if (ch == asc_Enter)
+ {
+ // loc_39ACA:
+
+ nameList[nSlot][nNameOffset] = 0;
+
+ PlayLocalSound(StaticSound[kSound33], 0);
+ KB_KeyDown[sc_Return] = 0;
+
+ if (nameList[nSlot][0] == 0) {
+ return -1;
+ }
+
+ if (nNameLength) // does the save slot already exist?
+ {
+ menu_DoPlasma();
+ if (Query(2, 4, "Overwrite existing game?", "Y/N", 'Y', 13, 'N', 27) >= 2) {
+ return -1;
+ }
+ }
+
+ FILE *fp = fopen("savgamea.sav", "rb+");
+ if (fp == NULL) {
+ return -1;
+ }
+
+ memset(&GameStats, 0, sizeof(GameStat));
+ GameStats.nWeapons = 1;
+ GameStats.nMap = 1;
+
+ fwrite(nameList, sizeof(nameList), 1, fp);
+ fseek(fp, sizeof(nameList), SEEK_SET);
+ fseek(fp, nSlot * sizeof(GameStat), SEEK_CUR);
+ fwrite(&GameStats, sizeof(GameStat), 1, fp);
+ fclose(fp);
+ return nSlot;
+ }
+ else
+ {
+ // Enter wasn't pressed
+ PlayLocalSound(4, 0); // ??
+
+ if (ch == asc_BackSpace)
+ {
+ nameList[nSlot][nNameOffset] = 0;
+
+ if (nNameOffset > 0) {
+ nNameOffset--;
+ }
+
+ nameList[nSlot][nNameOffset] = 0;
+ }
+ else if (ch == asc_Escape)
+ {
+ PlayLocalSound(StaticSound[kSound33], 0);
+ KB_ClearKeysDown();
+ KB_FlushKeyboardQueue();
+ KB_KeyDown[sc_Escape] = 0;
+ return -1;
+ }
+ else
+ {
+ // check if a slot name is being typed
+ if ((ch >= '0' && ch <= '9')
+ || (ch >= 'A' && ch <= 'Z')
+ || (ch >= 'a' && ch <= 'z')
+ || (ch == ' '))
+ {
+ ch = toupper(ch);
+ if (nNameOffset < 24) // n chars per slot name
+ {
+ nameList[nSlot][nNameOffset] = ch;
+ nNameOffset++;
+ nameList[nSlot][nNameOffset] = '\0'; // null terminate in the new offset
+
+ int nLen = MyGetStringWidth(nameList[nSlot]);
+ if (nLen > arg_3E)
+ {
+ nNameOffset--;
+ nameList[nSlot][nNameOffset] = '\0';
+ }
+ }
+ }
+ }
+
+ // loc_399FD:
+ menu_DoPlasma();
+
+ int arg_5E = (totalclock / 30) & 1;
+
+ int y = 90;
+ int arg_42 = 98;
+
+ for (int i = 0; i < 5; i++)
+ {
+ overwritesprite(55, y, kMenuBlankTitleTile, (i != nSlot) * 31, 2, kPalNormal);
+ int nTextWidth = myprintext(63, arg_42, nameList[i], 0);
+
+ // flash a full-stop to show the current typing position
+ if (arg_5E != 0 && nSlot == i)
+ {
+ myprintext(nTextWidth, arg_42, ".", 0);
+ }
+
+ arg_42 += 22;
+ y += 22;
+ }
+ }
+ }
+}
+
+int menu_LoadGameMenu()
+{
+ char nameList[5][25];
+
+ int nSlot = 0;
+
+ FILE *fp = fopen("savgamea.sav", "rb");
+ if (fp == NULL)
+ {
+ memset(nameList, 0, sizeof(nameList));
+ }
+ else
+ {
+ fread(nameList, sizeof(nameList), 1, fp);
+ fclose(fp);
+ }
+
+ while (1)
+ {
+ menu_DoPlasma();
+
+ handleevents();
+
+ overwritesprite(80, 65, kMenuLoadGameTile, 0, 2, kPalNormal);
+
+ int spriteY = 90;
+ int textY = 98;
+
+ for (int i = 0; i < kMaxSaveSlots; i++)
+ {
+ // TODO - shade flashing
+ overwritesprite(55, spriteY, kMenuBlankTitleTile, 0, 2, kPalNormal);
+
+ myprintext(63, textY, nameList[i], 0);
+ textY += 22;
+ spriteY += 22;
+ }
+
+ int y = (nSlot * 22) + 78;
+
+ overwritesprite(35, y, kMenuCursorTile, 0, 2, kPalNormal);
+ overwritesprite(233, y, kMenuCursorTile, 0, 10, kPalNormal);
+ nextpage();
+
+ if (KB_KeyDown[sc_Escape])
+ {
+ PlayLocalSound(StaticSound[kSound33], 0);
+ KB_KeyDown[sc_Escape] = 0;
+ return -1;
+ }
+
+ if (KB_KeyDown[sc_UpArrow])
+ {
+ PlayLocalSound(StaticSound[kSound35], 0);
+ if (nSlot > 0) {
+ nSlot--;
+ }
+ else {
+ nSlot = kMaxSaveSlots - 1;
+ }
+
+ KB_KeyDown[sc_UpArrow] = 0;
+ }
+
+ if (KB_KeyDown[sc_DownArrow]) // checkme - is 0x5b in disassembly
+ {
+ PlayLocalSound(StaticSound[kSound35], 0);
+ if (nSlot < kMaxSaveSlots - 1) {
+ nSlot++;
+ }
+ else {
+ nSlot = 0;
+ }
+
+ KB_KeyDown[sc_DownArrow] = 0;
+ }
+
+ if (!KB_KeyDown[sc_Return]) {
+ continue;
+ }
+
+ PlayLocalSound(StaticSound[kSound33], 0);
+ KB_KeyDown[sc_Return] = 0;
+ KB_ClearKeysDown();
+ KB_FlushKeyboardQueue();
+
+ if (nameList[nSlot][0] != '\0')
+ {
+ PlayLocalSound(StaticSound[33], 0);
+ return nSlot;
+ }
+
+ PlayLocalSound(4, 0);
+ }
+}
+
+void menu_ResetKeyTimer()
+{
+ keytimer = totalclock + 2400;
+}
+
+void menu_GameLoad2(FILE *fp)
+{
+ fread(&GameStats, sizeof(GameStats), 1, fp);
+
+ nPlayerWeapons[nLocalPlayer] = GameStats.nWeapons;
+
+ PlayerList[nLocalPlayer].nCurrentWeapon = GameStats.nCurrentWeapon;
+ nPlayerClip[nLocalPlayer] = GameStats.clip;
+
+ int nPistolBullets = PlayerList[nLocalPlayer].nAmmo[kWeaponPistol];
+ if (nPistolBullets >= 6) {
+ nPistolBullets = 6;
+ }
+
+ nPistolClip[nLocalPlayer] = nPistolBullets;
+
+ memcpy(&PlayerList[nLocalPlayer], &GameStats.player, sizeof(Player));
+
+ nPlayerItem[nLocalPlayer] = GameStats.items;
+ nPlayerLives[nLocalPlayer] = GameStats.nLives;
+
+ SetPlayerItem(nLocalPlayer, nPlayerItem[nLocalPlayer]);
+ CheckClip(nLocalPlayer);
+}
+
+short menu_GameLoad(int nSlot)
+{
+ memset(&GameStats, 0, sizeof(GameStats));
+
+ FILE *fp = fopen("savegamea.sav", "rb");
+ if (fp == NULL) {
+ return 0;
+ }
+
+ fseek(fp, 125, SEEK_SET);
+ fseek(fp, nSlot * sizeof(GameStats), SEEK_CUR);
+
+ menu_GameLoad2(fp);
+ fclose(fp);
+
+ return GameStats.nMap;
+}
+
+void menu_GameSave2(FILE *fp)
+{
+ memset(&GameStats, 0, sizeof(GameStats));
+
+ GameStats.nMap = (uchar)levelnew;
+ GameStats.nWeapons = nPlayerWeapons[nLocalPlayer];
+ GameStats.nCurrentWeapon = PlayerList[nLocalPlayer].nCurrentWeapon;
+ GameStats.clip = nPlayerClip[nLocalPlayer];
+ GameStats.items = nPlayerItem[nLocalPlayer];
+ GameStats.nLives = nPlayerLives[nLocalPlayer];
+
+ memcpy(&GameStats.player, &PlayerList[nLocalPlayer], sizeof(GameStats.player));
+
+ fwrite(&GameStats, sizeof(GameStats), 1, fp);
+}
+
+void menu_GameSave(int nSaveSlot)
+{
+ if (nSaveSlot < 0) {
+ return;
+ }
+
+ FILE *fp = fopen("savgamea.sav", "rb+");
+ if (fp != NULL)
+ {
+ fseek(fp, 125, SEEK_SET); // skip save slot names
+ fseek(fp, sizeof(GameStat) * nSaveSlot, SEEK_CUR);
+ menu_GameSave2(fp);
+ fclose(fp);
+ }
+}
+
+void menu_ResetZoom()
+{
+ zoomsize = 0;
+ PlayLocalSound(StaticSound[kSound62], 0);
+}
+
+int menu_Menu(int nVal)
+{
+ GrabPalette();
+
+ int var_1C = 0;
+
+ setview(0, 0, nScreenWidth - 1, nScreenHeight - 1);
+
+ KB_KeyDown[sc_Escape] = 0;
+
+ StopAllSounds();
+ StopLocalSound();
+
+ menu_ResetKeyTimer();
+
+ KB_FlushKeyboardQueue();
+ KB_ClearKeysDown();
+
+ menu_ResetZoom();
+
+ short ptr[5];
+ memset(ptr, 1, sizeof(ptr));
+
+ // disable new game and load game if in multiplayer?
+ if (nNetPlayerCount)
+ {
+ ptr[1] = 0;
+ ptr[0] = 0;
+ }
+
+ // denote which menu item we've currently got selected
+ int nMenu = 0;
+
+ while (1)
+ {
+ handleevents();
+
+ // skip any disabled menu items so we're selecting the first active one
+ while (!ptr[nMenu])
+ {
+ nMenu++;
+ if (nMenu == 5) {
+ nMenu = 0;
+ }
+ }
+
+ // handle the menu zoom-in
+ if (zoomsize < 0x10000)
+ {
+ zoomsize += 4096;
+ if (zoomsize >= 0x10000) {
+ zoomsize = 0x10000;
+ }
+ }
+
+ // menu idle timer
+ if (!nVal && totalclock > keytimer) {
+ return 9;
+ }
+
+ // loc_39F54:
+ menu_DoPlasma();
+
+ int y = 65 - tilesizy[kMenuNewGameTile] / 2;
+
+ // YELLOW loop - Draw the 5 menu options (NEW GAME, TRAINING etc)
+ for (int j = 0; j < 5; j++)
+ {
+ schar shade;
+
+ if (nMenu == j) { // currently selected menu item
+ shade = Sin(totalclock << 4) >> 9;
+ }
+ else if (ptr[j]) {
+ shade = 0;
+ }
+ else {
+ shade = 25;
+ }
+
+ picanm[j + kMenuNewGameTile] &= 0xFF0000FF;
+ rotatesprite(160 << 16, (y + tilesizy[j + kMenuNewGameTile]) << 16, zoomsize, 0, kMenuNewGameTile + j, shade, 0, 2, 0, 0, nScreenWidth, nScreenHeight);
+
+ y += 22;
+ }
+
+ // tilesizx is 51
+ // tilesizy is 33
+
+ int markerY = (22 * nMenu) + 53;
+ overwritesprite(62, markerY, kMenuCursorTile, 0, 2, kPalNormal);
+ overwritesprite(62 + 146, markerY, kMenuCursorTile, 0, 10, kPalNormal);
+
+ nextpage();
+
+ int l = 0; // edi
+
+ // ORANGE loop
+ for (l = 0; ; l++)
+ {
+ int nKey = nMenuKeys[l];
+ if (!nKey) {
+ break;
+ }
+
+ if (KB_KeyDown[nKey])
+ {
+ goto LABEL_21; // TEMP
+ }
+ }
+
+ // loc_3A0A7
+ while (KB_KeyDown[sc_Escape])
+ {
+ handleevents();
+
+ PlayLocalSound(StaticSound[kSound33], 0);
+ KB_KeyDown[sc_Escape] = 0;
+
+ if (nVal)
+ {
+ StopAllSounds();
+ PlayLocalSound(StaticSound[kSound33], 0);
+ MySetView(nViewLeft, nViewTop, nViewRight, nViewBottom);
+ return -1;
+ }
+
+ l = 4;
+LABEL_21:
+
+ menu_ResetKeyTimer();
+
+ if (l != nMenu)
+ {
+ PlayLocalSound(StaticSound[kSound35], 0);
+ KB_KeyDown[nMenuKeys[l]] = 0;
+ nMenu = l;
+ }
+ }
+
+ if (KB_KeyDown[sc_Space] || KB_KeyDown[sc_Return])
+ {
+ var_1C = 1;
+ }
+ else if (var_1C)
+ {
+ var_1C = 0;
+
+ PlayLocalSound(StaticSound[kSound33], 0);
+
+ switch (nMenu) // TODO - change var name?
+ {
+ case kMenuNewGame:
+ {
+ if (nTotalPlayers > 1) {
+ menu_ResetZoom();
+ menu_ResetKeyTimer();
+ break;
+ }
+
+ SavePosition = menu_NewGameMenu();
+ if (SavePosition == -1) {
+ menu_ResetZoom();
+ menu_ResetKeyTimer();
+ break;
+ }
+
+ FadeOut(1);
+ StopAllSounds();
+
+ StopAllSounds();
+ PlayLocalSound(StaticSound[kSound33], 0);
+ MySetView(nViewLeft, nViewTop, nViewRight, nViewBottom);
+ return 1;
+ }
+
+ case kMenuLoadGame:
+ {
+ if (nTotalPlayers > 1) {
+ menu_ResetZoom();
+ menu_ResetKeyTimer();
+ break;
+ }
+
+ SavePosition = menu_LoadGameMenu();
+
+ StopAllSounds();
+
+ StopAllSounds();
+ PlayLocalSound(StaticSound[kSound33], 0);
+ MySetView(nViewLeft, nViewTop, nViewRight, nViewBottom);
+ return 2;
+ }
+
+ case kMenuTraining:
+ {
+ if (nTotalPlayers > 1) {
+ menu_ResetZoom();
+ menu_ResetKeyTimer();
+ break;
+ }
+
+ StopAllSounds();
+ PlayLocalSound(StaticSound[kSound33], 0);
+ MySetView(nViewLeft, nViewTop, nViewRight, nViewBottom);
+ return 3;
+ }
+
+ case kMenuVolume:
+ {
+ menu_AdjustVolume();
+ menu_ResetZoom();
+ menu_ResetKeyTimer();
+ break;
+ }
+
+ case kMenuQuitGame:
+ {
+ StopAllSounds();
+ StopAllSounds();
+ PlayLocalSound(StaticSound[kSound33], 0);
+ MySetView(nViewLeft, nViewTop, nViewRight, nViewBottom);
+ return 0;
+ }
+
+ default:
+ menu_ResetZoom();
+ menu_ResetKeyTimer();
+ break;
+ }
+ }
+
+ if (KB_KeyDown[sc_UpArrow])
+ {
+ PlayLocalSound(StaticSound[kSound35], 0);
+ if (nMenu <= 0) {
+ nMenu = 4;
+ }
+ else {
+ nMenu--;
+ }
+
+ KB_KeyDown[sc_UpArrow] = 0;
+ menu_ResetKeyTimer();
+ }
+
+ if (KB_KeyDown[sc_DownArrow]) // FIXME - is this down arrow? value is '5B' in disassembly
+ {
+ PlayLocalSound(StaticSound[kSound35], 0);
+ if (nMenu >= 4) {
+ nMenu = 0;
+ }
+ else {
+ nMenu++;
+ }
+
+ KB_KeyDown[sc_DownArrow] = 0;
+ menu_ResetKeyTimer();
+ }
+
+ // TODO - change to #defines
+ if (KB_KeyDown[0x5c]) {
+ KB_KeyDown[0x5c] = 0;
+ }
+
+ if (KB_KeyDown[0x5d]) {
+ KB_KeyDown[0x5d] = 0;
+ }
+ }
+
+ return 0;// todo
+}
+
+#define kMaxCinemaPals 16
+char *cinpalfname[kMaxCinemaPals] = {
+ "3454.pal",
+ "3452.pal",
+ "3449.pal",
+ "3445.pal",
+ "set.pal",
+ "3448.pal",
+ "3446.pal",
+ "hsc1.pal",
+ "2972.pal",
+ "2973.pal",
+ "2974.pal",
+ "2975.pal",
+ "2976.pal",
+ "heli.pal",
+ "2978.pal",
+ "terror.pal"
+};
+
+int linecount;
+int nextclock;
+short nHeight;
+short nCrawlY;
+short cinematile;
+
+
+// TODO - moveme
+int LoadCinemaPalette(int nPal)
+{
+ nPal--;
+
+ if (nPal < 0 || nPal >= kMaxCinemaPals) {
+ return -2;
+ }
+
+ // original code strcpy'd into a buffer first...
+
+ int hFile = kopen4load(cinpalfname[nPal], 1);
+ if (hFile < 0) {
+ return -2;
+ }
+
+ kread(hFile, cinemapal, sizeof(cinemapal));
+ kclose(hFile);
+
+ return nPal;
+}
+
+int IncrementCinemaFadeIn()
+{
+ dest = cinemapal;
+ cur = curpal;
+
+ int ebx = 0;
+
+ for (int i = 0; i < 768; i++)
+ {
+ ebx++;
+
+ if (*cur < *dest)
+ {
+ (*cur)++;
+ }
+ else if (*cur == *dest)
+ {
+ ebx--;
+ }
+ else
+ {
+ (*cur)--;
+ }
+
+ cur++;
+ dest++;
+ }
+
+ MySetPalette(curpal);
+ return ebx;
+}
+
+void CinemaFadeIn()
+{
+ BlackOut();
+
+ while (1)
+ {
+ int val = IncrementCinemaFadeIn();
+ WaitTicks(2);
+
+ if (val <= 0) {
+ break;
+ }
+ }
+}
+
+void ComputeCinemaText(int nLine)
+{
+ linecount = 0;
+
+ while (1)
+ {
+ if (!strcmp(gString[linecount + nLine], "END")) {
+ break;
+ }
+
+ int nWidth = MyGetStringWidth(gString[linecount + nLine]);
+ nLeft[linecount] = 160 - nWidth / 2;
+
+ linecount++;
+ }
+
+ nCrawlY = 199;
+ nHeight = linecount * 10;
+
+ ClearAllKeys();
+}
+
+void ReadyCinemaText(ushort nVal)
+{
+ line = FindGString("CINEMAS");
+ if (line < 0) {
+ return;
+ }
+
+ while (nVal)
+ {
+ while (strcmp(gString[line], "END")) {
+ line++;
+ }
+
+ line++;
+ nVal--;
+ }
+
+ ComputeCinemaText(line);
+}
+
+BOOL AdvanceCinemaText()
+{
+ int var_1C = nCDTrackLength;
+
+ if (nHeight + nCrawlY > 0 || nCDTrackLength && nCDTrackLength > 0)
+ {
+ nextclock = totalclock + 14;
+
+ if ((nHeight + nCrawlY > 0) > 0)
+ {
+ short y = nCrawlY;
+ int edi = 0;
+
+ while (edi < linecount && y <= 199)
+ {
+ if (y >= -10) {
+ myprintext(nLeft[edi], y, gString[line + edi], 0);
+ }
+
+ edi++;
+ y += 10;
+ }
+
+ nCrawlY--;
+ }
+
+ while (1)
+ {
+ handleevents();
+
+ if (KB_KeyDown[sc_Escape] || KB_KeyDown[sc_Return] || KB_KeyDown[sc_Space]) {
+ break;
+ }
+
+ if (var_1C || nCDTrackLength)
+ {
+ if (nextclock <= totalclock) {
+ return TRUE;
+ }
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+void DoCinemaText(short nVal)
+{
+ ReadyCinemaText(nVal);
+
+ while (1)
+ {
+ overwritesprite(0, 0, cinematile, 0, 2, kPalNormal);
+
+ BOOL bContinue = AdvanceCinemaText();
+
+ WaitVBL();
+ nextpage();
+
+ if (!bContinue) {
+ return;
+ }
+ }
+}
+
+void GoToTheCinema(int nVal)
+{
+ UnMaskStatus();
+
+ switch (nVal - 1)
+ {
+ default:
+ return;
+
+ case 0:
+ {
+ LoadCinemaPalette(1);
+ cinematile = 3454;
+ break;
+ }
+
+ case 1:
+ {
+ LoadCinemaPalette(2);
+ cinematile = 3452;
+ break;
+ }
+
+ case 2:
+ {
+ LoadCinemaPalette(3);
+ cinematile = 3449;
+ break;
+ }
+
+ case 3:
+ {
+ LoadCinemaPalette(4);
+ cinematile = 3445;
+ break;
+ }
+
+ case 4:
+ {
+ LoadCinemaPalette(5);
+ cinematile = 3451;
+ break;
+ }
+
+ case 5:
+ {
+ LoadCinemaPalette(6);
+ cinematile = 3448;
+ break;
+ }
+
+ case 6:
+ {
+ LoadCinemaPalette(7);
+ cinematile = 3446;
+ break;
+ }
+ }
+
+ FadeOut(FALSE);
+ StopAllSounds();
+ NoClip();
+
+ overwritesprite(0, 0, 764, 100, 2, kPalNormal);
+ nextpage();
+
+// int386(16, (const union REGS *)&val, (union REGS *)&val)
+
+ overwritesprite(0, 0, cinematile, 0, 2, kPalNormal);
+ nextpage();
+
+ CinemaFadeIn();
+ ClearAllKeys();
+
+ int ebx = -1;
+ int edx = -1;
+
+ switch (nVal - 1)
+ {
+ default:
+ WaitAnyKey(10);
+ break;
+
+ case 0:
+ ebx = 4;
+ edx = ebx;
+ break;
+
+ case 1:
+ ebx = 0;
+ break;
+
+ case 2:
+ ebx = 2;
+ edx = ebx;
+ break;
+
+ case 3:
+ ebx = 7;
+ break;
+
+ case 4:
+ ebx = 3;
+ edx = ebx;
+ break;
+
+ case 5:
+ ebx = 8;
+ edx = ebx;
+ break;
+
+ case 6:
+ ebx = 6;
+ edx = ebx;
+ break;
+ }
+
+ if (ebx != -1)
+ {
+ if (edx != -1)
+ {
+ if (CDplaying()) {
+ fadecdaudio();
+ }
+
+ playCDtrack(edx + 2); // , 1);
+ }
+
+ DoCinemaText(ebx);
+ }
+
+ FadeOut(TRUE);
+
+ overwritesprite(0, 0, 764, 100, 2, kPalNormal);
+ nextpage();
+
+ MySetPalette(kenpal);
+ GrabPalette();
+ Clip();
+}
+
+
+short nBeforeScene[] = { 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+
+void CheckBeforeScene(int nLevel)
+{
+ if (nLevel == kMap20)
+ {
+ DoLastLevelCinema();
+ return;
+ }
+
+ if (nBeforeScene[nLevel])
+ {
+ if (!nCinemaSeen[nLevel])
+ {
+ GoToTheCinema(nLevel);
+ nCinemaSeen[nLevel] = 1;
+ }
+ }
+}
+
+int showmap(short nLevel, short nLevelNew, short nLevelBest)
+{
+ FadeOut(0);
+ EraseScreen(overscanindex);
+ GrabPalette();
+ BlackOut();
+
+ if (nLevelNew != 11) {
+ CheckBeforeScene(nLevelNew);
+ }
+
+ int selectedLevel = menu_DrawTheMap(nLevel, nLevelNew, nLevelBest);
+ if (selectedLevel == 11) {
+ CheckBeforeScene(selectedLevel);
+ }
+
+ return selectedLevel;
+}
+
+void DoAfterCinemaScene(int nLevel)
+{
+ short word_9ABD5[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 7, 0, 0, 0, 0, 6 };
+
+ if (word_9ABD5[nLevel]) {
+ GoToTheCinema(word_9ABD5[nLevel]);
+ }
+}
+
+void DoFailedFinalScene()
+{
+ setview(0, 0, nScreenWidth - 1, nScreenHeight - 1);
+
+ if (CDplaying()) {
+ fadecdaudio();
+ }
+
+ playCDtrack(9);
+ FadeToWhite();
+
+// TODO GoToTheCinema(word_9ABFF);
+}
+
+int FindGString(const char *str)
+{
+ int i = 0;
+
+ while (1)
+ {
+ if (!strcmp(gString[i], str))
+ return i + 1;
+
+ if (!strcmp(gString[i], "EOF"))
+ break;
+
+ i++;
+ }
+
+ return -1;
+}
+
+BOOL CheckForEscape()
+{
+ if (!KB_KeyWaiting() || (KB_GetCh() != 27)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void DoStatic(int a, int b)
+{
+ RandomLong(); // nothing done with the result of this?
+
+ loadtile(kTileLoboLaptop);
+
+ int v2 = 160 - a / 2;
+ int v4 = 81 - b / 2;
+
+ int var_18 = v2 + a;
+ int v5 = v4 + b;
+
+ BYTE *pTile = (waloff[kTileLoboLaptop] + (200 * v2)) + v4;
+
+ while (v2 < var_18)
+ {
+ BYTE *pStart = pTile;
+ pTile += 200;
+
+ int v7 = v4;
+
+ while (v7 < v5)
+ {
+ *pStart = RandomBit() * 16;
+
+ v7++;
+ pStart++;
+ }
+ v2++;
+ }
+
+ overwritesprite(0, 0, kTileLoboLaptop, 0, 2, kPalNormal);
+ nextpage();
+}
+
+void DoLastLevelCinema()
+{
+ FadeOut(0);
+ UnMaskStatus();
+
+ setview(0, 0, nScreenWidth - 1, nScreenHeight - 1);
+
+ EraseScreen(-1);
+ RestorePalette();
+
+ int nString = FindGString("LASTLEVEL");
+
+ PlayLocalSound(StaticSound[kSound75], 0);
+
+ loadtile(kTileLoboLaptop);
+
+ memcpy(waloff[kTileLoboLaptop], waloff[kTileLoboLaptop], tilesizx[kTileLoboLaptop] * tilesizy[kTileLoboLaptop]);
+
+ int var_24 = 16;
+ int var_28 = 12;
+
+ int nEndTime = totalclock + 240;
+
+ while (KB_KeyWaiting()) {
+ KB_Getch();
+ }
+
+ while (nEndTime > totalclock)
+ {
+ handleevents();
+
+ if (var_24 >= 116)
+ {
+ if (var_28 < 192)
+ var_28 += 20;
+ }
+ else
+ {
+ var_24 += 20;
+ }
+
+ DoStatic(var_28, var_24);
+ }
+
+// loadtilelockmode = 1;
+ loadtile(kTileLoboLaptop);
+// loadtilelockmode = 0;
+
+ // loc_3AD75
+
+ do
+ {
+ handleevents();
+LABEL_11:
+ if (strlen(gString[nString]) == 0)
+ break;
+
+ int esi = nString;
+
+ loadtile(kTileLoboLaptop);
+
+ while (strlen(gString[esi]) != 0)
+ esi++;
+
+ int ebp = esi;
+
+ ebp -= nString;
+ ebp = 81 - (ebp <<= 2);
+
+ int var_1C = esi - nString;
+
+ // loc_3ADD7
+ while (1)
+ {
+ handleevents();
+
+ if (strlen(gString[nString]) == 0)
+ break;
+
+ int xPos = 70;
+
+ char *nChar = gString[nString];
+
+ nString++;
+
+ while (*nChar)
+ {
+ handleevents();
+
+ if (*nChar != ' ') {
+ PlayLocalSound(StaticSound[kSound71], 0);
+ }
+
+ xPos += CopyCharToBitmap(*nChar, kTileLoboLaptop, xPos, ebp);
+ nChar++;
+
+ overwritesprite(0, 0, kTileLoboLaptop, 0, 2, kPalNormal);
+ nextpage();
+
+ WaitVBL();
+ if (CheckForEscape())
+ goto LABEL_28;
+ }
+
+ ebp += 8;
+ }
+
+ nString++;
+
+ KB_FlushKeyboardQueue();
+ KB_ClearKeysDown();
+
+ int v11 = kTimerTicks * (var_1C + 2) + totalclock;
+
+ do
+ {
+ handleevents();
+
+ if (v11 <= totalclock)
+ goto LABEL_11;
+ } while (!KB_KeyWaiting());
+ }
+ while (KB_Getch() != 27);
+
+LABEL_28:
+ PlayLocalSound(StaticSound[kSound75], 0);
+
+ while (1)
+ {
+ handleevents();
+
+ DoStatic(var_28, var_24);
+
+ if (var_28 > 20) {
+ var_28 -= 20;
+ continue;
+ }
+
+ if (var_24 > 20) {
+ var_24 -= 20;
+ continue;
+ }
+
+ break;
+ }
+
+ EraseScreen(-1);
+ loadtile(kTileLoboLaptop);
+ FadeOut(0);
+ MySetView(nViewLeft, nViewTop, nViewRight, nViewBottom);
+ MaskStatus();
+}
diff --git a/source/exhumed/src/menu.h b/source/exhumed/src/menu.h
new file mode 100644
index 000000000..17e7aa4a5
--- /dev/null
+++ b/source/exhumed/src/menu.h
@@ -0,0 +1,60 @@
+
+#ifndef __menu_h__
+#define __menu_h__
+
+#include "player.h"
+#include "typedefs.h"
+#include
+
+#pragma pack(1)
+// should be 75 bytes
+struct GameStat
+{
+ uchar nMap;
+ short nWeapons;
+ short nCurrentWeapon;
+ short clip;
+ short items;
+
+ Player player;
+
+ short nLives;
+};
+#pragma pack()
+
+extern GameStat GameStats;
+
+extern unsigned char cinemapal[];
+
+extern short SavePosition;
+
+int showmap(short nLevel, short nLevelNew, short nLevelBest);
+
+void ClearCinemaSeen();
+void menu_DoPlasma();
+int menu_Menu(int val);
+void menu_AdjustVolume();
+short menu_GameLoad(int nSlot);
+void menu_GameLoad2(FILE *fp);
+void menu_GameSave2(FILE *fp);
+void menu_GameSave(int nSaveSlot);
+
+int menu_DrawTheMap(int nLevel, int param_B, int param_C);
+
+void DoEnergyTile();
+
+int LoadCinemaPalette(int nPal);
+
+void CinemaFadeIn();
+
+void ReadyCinemaText(ushort nVal);
+BOOL AdvanceCinemaText();
+
+void DoFailedFinalScene();
+
+void DoLastLevelCinema();
+void DoAfterCinemaScene(int nLevel);
+
+void InitEnergyTile();
+
+#endif
diff --git a/source/exhumed/src/mono.cpp b/source/exhumed/src/mono.cpp
new file mode 100644
index 000000000..ddd75c354
--- /dev/null
+++ b/source/exhumed/src/mono.cpp
@@ -0,0 +1,53 @@
+
+/*
+Name: MonoClear_
+address = 0001:0001CF5A
+module index = 24
+kind: (code)
+Name: MonoInUse_
+address = 0001:0001CF8A
+module index = 24
+kind: (code)
+Name: MonoOpen_
+address = 0001:0001CF8A
+module index = 24
+kind: (code)
+Name: MonoClose_
+address = 0001:0001CF8D
+module index = 24
+kind: (code)
+Name: MonoOut_
+address = 0001:0001CFAA
+module index = 24
+kind: (code)
+Name: CACopy_
+address = 0001:0001D1C0
+module index = 24
+kind: (static pubdef) (code)
+Name: CAFill_
+address = 0001:0001D1CD
+module index = 24
+kind: (static pubdef) (code)
+Name: MonoQuery_
+address = 0001:0001D1E6
+module index = 24
+kind: (code)
+Name: _rowCur
+address = 0003:000073D8
+module index = 24
+kind: (data)
+Name: _colCur
+address = 0003:000073DC
+module index = 24
+kind: (data)
+Name: _fMonoOpen
+address = 0003:000073E0
+module index = 24
+kind: (data)
+
+
+*/
+#include "mono.h"
+
+int rowCur = 0;
+int colCur = 0;
diff --git a/source/exhumed/src/mono.h b/source/exhumed/src/mono.h
new file mode 100644
index 000000000..97cdc4da9
--- /dev/null
+++ b/source/exhumed/src/mono.h
@@ -0,0 +1,7 @@
+
+#ifndef __mono_h__
+#define __mono_h__
+
+
+
+#endif
diff --git a/source/exhumed/src/move.cpp b/source/exhumed/src/move.cpp
new file mode 100644
index 000000000..c58a7bfb3
--- /dev/null
+++ b/source/exhumed/src/move.cpp
@@ -0,0 +1,1519 @@
+
+#include "engine.h"
+#include "exhumed.h"
+#include "move.h"
+#include "init.h"
+#include "lighting.h"
+#include "bubbles.h"
+#include "object.h"
+#include "player.h"
+#include "view.h"
+#include "status.h"
+#include "runlist.h"
+#include "items.h"
+#include "sound.h"
+#include "trigdat.h"
+#include "anims.h"
+#include "random.h"
+#include "bullet.h"
+#include
+#include
+#ifndef __WATCOMC__
+//#include
+#else
+#include
+//#include
+#endif
+
+short NearSector[kMaxSectors] = { 0 };
+
+short nPushBlocks;
+
+// TODO - moveme?
+short overridesect;
+short NearCount = -1;
+
+short nBodySprite[50];
+
+long hihit, sprceiling, sprfloor, lohit;
+
+#define kMaxPushBlocks 100
+#define kMaxChunks 75
+
+// think this belongs in init.c?
+BlockInfo sBlockInfo[kMaxPushBlocks];
+
+short nChunkSprite[kMaxChunks];
+
+
+signed int lsqrt(int a1)
+{
+ int v1; // edx@1
+ int v2; // ebx@1
+ signed int result; // eax@1
+
+ v1 = a1;
+ v2 = a1 - 0x40000000;
+ result = 0;
+ if (v2 >= 0)
+ {
+ result = 0x8000;
+ v1 = v2;
+ }
+ if (v1 - ((result << 15) + 0x10000000) >= 0)
+ {
+ v1 -= (result << 15) + 0x10000000;
+ result += 0x4000;
+ }
+ if (v1 - ((result << 14) + 0x4000000) >= 0)
+ {
+ v1 -= (result << 14) + 0x4000000;
+ result += 0x2000;
+ }
+ if (v1 - ((result << 13) + 0x1000000) >= 0)
+ {
+ v1 -= (result << 13) + 0x1000000;
+ result += 4096;
+ }
+ if (v1 - ((result << 12) + 0x400000) >= 0)
+ {
+ v1 -= (result << 12) + 0x400000;
+ result += 2048;
+ }
+ if (v1 - ((result << 11) + 0x100000) >= 0)
+ {
+ v1 -= (result << 11) + 0x100000;
+ result += 1024;
+ }
+ if (v1 - ((result << 10) + 0x40000) >= 0)
+ {
+ v1 -= (result << 10) + 0x40000;
+ result += 512;
+ }
+ if (v1 - ((result << 9) + 0x10000) >= 0)
+ {
+ v1 -= (result << 9) + 0x10000;
+ result += 256;
+ }
+ if (v1 - ((result << 8) + 0x4000) >= 0)
+ {
+ v1 -= (result << 8) + 0x4000;
+ result += 128;
+ }
+ if (v1 - ((result << 7) + 4096) >= 0)
+ {
+ v1 -= (result << 7) + 4096;
+ result += 64;
+ }
+ if (v1 - ((result << 6) + 1024) >= 0)
+ {
+ v1 -= (result << 6) + 1024;
+ result += 32;
+ }
+ if (v1 - (32 * result + 256) >= 0)
+ {
+ v1 -= 32 * result + 256;
+ result += 16;
+ }
+ if (v1 - (16 * result + 64) >= 0)
+ {
+ v1 -= 16 * result + 64;
+ result += 8;
+ }
+ if (v1 - (8 * result + 16) >= 0)
+ {
+ v1 -= 8 * result + 16;
+ result += 4;
+ }
+ if (v1 - (4 * result + 4) >= 0)
+ {
+ v1 -= 4 * result + 4;
+ result += 2;
+ }
+ if (v1 - (2 * result + 1) >= 0)
+ ++result;
+ return result;
+}
+
+void MoveThings()
+{
+ UndoFlashes();
+ DoLights();
+
+ short the_freeze = nFreeze;
+
+ if (nFreeze)
+ {
+ if (nFreeze == 1 || nFreeze == 2) {
+ DoSpiritHead();
+ }
+ }
+ else
+ {
+ runlist_ExecObjects();
+ runlist_CleanRunRecs();
+ }
+
+ MoveStatus();
+ DoBubbleMachines();
+ DoDrips();
+ DoMovingSects();
+ DoRegenerates();
+
+ if (levelnum == kMap20)
+ {
+ DoFinale();
+ if (lCountDown < 1800 && nDronePitch < 2400 && !lFinaleStart)
+ {
+ nDronePitch += 64;
+ BendAmbientSound();
+ }
+ }
+}
+
+void ResetMoveFifo()
+{
+ localclock = totalclock;
+ movefifoend = 0;
+ movefifopos = 0;
+}
+
+// not used
+void clipwall()
+{
+
+}
+
+void BuildNear(int x, int y, int walldist, int nSector)
+{
+ NearSector[0] = nSector;
+ NearCount = 1;
+
+ int i = 0;
+
+ while (i < NearCount)
+ {
+ short nSector = NearSector[i];
+
+ short nWall = sector[nSector].wallptr;
+ short nWallCount = sector[nSector].wallnum;
+
+ while (1)
+ {
+ nWallCount--;
+ if (nWallCount < 0)
+ {
+ i++;
+ break;
+ }
+
+ short nNextSector = wall[nWall].nextsector;
+
+ if (nNextSector >= 0)
+ {
+ int j = 0;
+ for (; j < NearCount; j++)
+ {
+ // loc_14F4D:
+ if (nNextSector == NearSector[j])
+ break;
+ }
+
+ if (j >= NearCount)
+ {
+ if (clipinsidebox(x, y, nWall, walldist))
+ {
+ NearSector[NearCount] = wall[nWall].nextsector;
+ NearCount++;
+ }
+ }
+ }
+
+ nWall++;
+ }
+ }
+}
+
+int BelowNear(short nSprite)
+{
+ short nSector = sprite[nSprite].sectnum;
+ int z = sprite[nSprite].z;
+
+ int var_24, z2;
+
+ if ((lohit & 0xC000) == 0xC000)
+ {
+ var_24 = lohit & 0xC000;
+ z2 = sprite[lohit & 0x3FFF].z;
+ }
+ else
+ {
+ var_24 = 0x20000;
+ z2 = sector[nSector].floorz + SectDepth[nSector];
+
+ if (NearCount > 0)
+ {
+ short edx;
+
+ for (int i = 0; i < NearCount; i++)
+ {
+ int nSect2 = NearSector[i];
+
+ while (nSect2 >= 0)
+ {
+ edx = nSect2;
+ nSect2 = SectBelow[nSect2];
+ }
+
+ int ecx = sector[edx].floorz + SectDepth[edx];
+ int eax = ecx - z;
+
+ if (eax < 0 && eax >= -5120)
+ {
+ z2 = ecx;
+ nSector = edx;
+ }
+ }
+ }
+ }
+
+ if (z2 < sprite[nSprite].z)
+ {
+ sprite[nSprite].z = z2;
+ overridesect = nSector;
+ sprite[nSprite].zvel = 0;
+
+ bTouchFloor = kTrue;
+
+ return var_24;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int movespritez(short nSprite, int z, int height, long flordist, int clipdist)
+{
+ short nSector = sprite[nSprite].sectnum;
+ assert(nSector >= 0 && nSector < kMaxSectors);
+
+ overridesect = nSector;
+ int edi = nSector;
+
+ // backup cstat
+ ushort cstat = sprite[nSprite].cstat;
+
+ sprite[nSprite].cstat &= 0xFFFE;
+
+ int nRet = 0;
+
+ if (SectFlag[nSector] & kSectUnderwater) {
+ z >>= 1;
+ }
+
+ int spriteZ = sprite[nSprite].z;
+ int floorZ = sector[nSector].floorz;
+
+ int ebp = spriteZ + z;
+ int eax = sector[nSector].ceilingz + (height >> 1);
+
+ if ((SectFlag[nSector] & kSectUnderwater) && ebp < eax) {
+ ebp = eax;
+ }
+
+ // loc_151E7:
+ while (1)
+ {
+ if (ebp <= sector[sprite[nSprite].sectnum].floorz || SectBelow[sprite[nSprite].sectnum] < 0)
+ break;
+
+ edi = SectBelow[sprite[nSprite].sectnum];
+
+ mychangespritesect(nSprite, edi);
+ }
+
+ if (edi == nSector)
+ {
+ while (1)
+ {
+ if ((ebp >= sector[sprite[nSprite].sectnum].ceilingz) || (SectAbove[sprite[nSprite].sectnum] < 0))
+ break;
+
+ edi = SectAbove[sprite[nSprite].sectnum];
+
+ mychangespritesect(nSprite, edi);
+ }
+ }
+ else
+ {
+ sprite[nSprite].z = ebp;
+
+ if (SectFlag[edi] & kSectUnderwater)
+ {
+ if (nSprite == PlayerList[nLocalPlayer].nSprite) {
+ D3PlayFX(StaticSound[kSound2], nSprite);
+ }
+
+ if (sprite[nSprite].statnum <= 107) {
+ sprite[nSprite].hitag = 0;
+ }
+ }
+ }
+
+ // This function will keep the player from falling off cliffs when you're too close to the edge.
+ // This function finds the highest and lowest z coordinates that your clipping BOX can get to.
+ getzrange(sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z - 256, sprite[nSprite].sectnum,
+ &sprceiling, &hihit, &sprfloor, &lohit, 128, CLIPMASK0);
+
+ long mySprfloor = sprfloor;
+
+ if ((lohit & 0xC000) != 0xC000) {
+ mySprfloor += SectDepth[sprite[nSprite].sectnum];
+ }
+
+ if (ebp > mySprfloor)
+ {
+ if (z > 0)
+ {
+ bTouchFloor = kTrue;
+
+ if ((lohit & 0xC000) != 0xC000)
+ {
+ // Path B
+ if (SectBelow[sprite[nSprite].sectnum] == -1)
+ {
+ nRet |= 0x20000;
+
+ short nSectDamage = SectDamage[sprite[nSprite].sectnum];
+
+ if (nSectDamage != 0)
+ {
+ if (sprite[nSprite].hitag < 15)
+ {
+ IgniteSprite(nSprite);
+ sprite[nSprite].hitag = 20;
+ }
+#if 1
+ short dx = nSectDamage;
+ dx >>= 2;
+ int eax = dx;
+ int edx = eax;
+ edx >>= 2;
+ eax -= edx;
+
+ int outval;
+
+ __asm
+ {
+ mov dx, nSectDamage
+ sar dx, 2
+ movsx eax, dx
+ mov edx, eax
+ sar edx, 2; // >> 4
+ sub eax, edx
+ //mov edx, eax
+ movsx edx, ax
+ mov outval, edx
+ }
+#endif
+
+ short nDamageVal = (nSectDamage / 4) - (nSectDamage / 8);
+ if (nDamageVal) {
+ runlist_DamageEnemy(nSprite, -1, nDamageVal);
+ }
+ }
+
+ sprite[nSprite].zvel = 0;
+ }
+ }
+ else
+ {
+ // Path A
+ short nFloorSprite = lohit & 0x3FFF;
+
+ if (sprite[nSprite].statnum != 100 || !sprite[nFloorSprite].statnum || sprite[nFloorSprite].statnum >= 100)
+ {
+ short nStat = sprite[nFloorSprite].statnum;
+ if (!nStat || nStat > 199)
+ {
+ nRet |= 0x20000;
+ }
+ else
+ {
+ nRet |= lohit;
+ }
+
+ sprite[nSprite].zvel = 0;
+ }
+ else
+ {
+ if (z >> 9)
+ {
+ runlist_DamageEnemy((lohit & 0x3FFF), nSprite, (z >> 9) * 2);
+ }
+
+ sprite[nSprite].zvel = -z;
+ }
+ }
+ }
+
+ // loc_1543B:
+ ebp = mySprfloor;
+ sprite[nSprite].z = mySprfloor;
+ }
+ else
+ {
+ if ((ebp - height) < sprceiling && ((hihit & 0xC000) == 0xC000 || SectAbove[sprite[nSprite].sectnum] == -1))
+ {
+ ebp = sprceiling + height;
+ nRet |= 0x10000;
+ }
+ }
+
+ if (spriteZ <= floorZ && ebp > floorZ)
+ {
+ if ((SectDepth[nSector] != 0) || (edi != nSector && (SectFlag[edi] & kSectUnderwater)))
+ {
+ assert(nSector >= 0 && nSector < kMaxSectors);
+ BuildSplash(nSprite, nSector);
+ }
+ }
+
+ sprite[nSprite].cstat = cstat; // restore cstat
+ sprite[nSprite].z = ebp;
+
+ if (sprite[nSprite].statnum == 100)
+ {
+ BuildNear(sprite[nSprite].x, sprite[nSprite].y, clipdist + (clipdist / 2), sprite[nSprite].sectnum);
+ nRet |= BelowNear(nSprite);
+ }
+
+ return nRet;
+}
+
+int GetSpriteHeight(int nSprite)
+{
+ return tilesizy[sprite[nSprite].picnum] * sprite[nSprite].yrepeat * 4;
+}
+
+// TODO - where is ceildist used?
+int movesprite(short nSprite, long dx, long dy, long dz, long ceildist, long flordist, unsigned long clipmask)
+{
+ bTouchFloor = kFalse;
+
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ int z = sprite[nSprite].z;
+
+ int nSpriteHeight = GetSpriteHeight(nSprite);
+
+ int nClipDist = sprite[nSprite].clipdist << 2;
+
+ short nSector = sprite[nSprite].sectnum;
+ assert(nSector >= 0 && nSector < kMaxSectors);
+
+ int floorZ = sector[nSector].floorz;
+
+ int nRet = 0;
+
+ if ((SectFlag[nSector] & kSectUnderwater) || (floorZ < z))
+ {
+ dx >>= 1;
+ dy >>= 1;
+ }
+
+ short nSprite2 = nSprite;
+
+ nRet |= movespritez(nSprite, dz, nSpriteHeight, flordist, nClipDist);
+
+ nSector = sprite[nSprite].sectnum; // modified in movespritez so re-grab this variable
+
+ if (sprite[nSprite].statnum == 100)
+ {
+ short nPlayer = GetPlayerFromSprite(nSprite2);
+
+ long varA = 0;
+ long varB = 0;
+
+ CheckSectorFloor(overridesect, sprite[nSprite].z, &varB, &varA);
+
+ if (varB || varA)
+ {
+ nXDamage[nPlayer] = varB;
+ nYDamage[nPlayer] = varA;
+ }
+
+ dx += nXDamage[nPlayer];
+ dy += nYDamage[nPlayer];
+ }
+ else
+ {
+ CheckSectorFloor(overridesect, sprite[nSprite].z, &dx, &dy);
+ }
+
+ /*
+ The game masks off the top 16 bits of the return value.
+ */
+ nRet |= clipmove(&sprite[nSprite].x, &sprite[nSprite].y, &sprite[nSprite].z, &nSector, dx, dy, nClipDist, nSpriteHeight, flordist, clipmask) & 0xFFFF;
+
+ if ((nSector != sprite[nSprite].sectnum) && nSector >= 0)
+ {
+ if (nRet & 0x20000) {
+ dz = 0;
+ }
+
+ if ((sector[nSector].floorz - z) < (dz + flordist))
+ {
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ }
+ else
+ {
+ mychangespritesect(nSprite, nSector);
+
+ if (sprite[nSprite].pal < 5 && !sprite[nSprite].hitag)
+ {
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ }
+ }
+ }
+
+ return nRet;
+}
+
+// OK
+void Gravity(short nSprite)
+{
+ short nSector = sprite[nSprite].sectnum;
+
+ if (SectFlag[nSector] & kSectUnderwater)
+ {
+ if (sprite[nSprite].statnum != 100)
+ {
+ if (sprite[nSprite].zvel <= 1024)
+ {
+ if (sprite[nSprite].zvel < 2048) {
+ sprite[nSprite].zvel += 512;
+ }
+ }
+ else
+ {
+ sprite[nSprite].zvel -= 64;
+ }
+ }
+ else
+ {
+ if (sprite[nSprite].zvel > 0)
+ {
+ sprite[nSprite].zvel -= 64;
+ if (sprite[nSprite].zvel < 0) {
+ sprite[nSprite].zvel = 0;
+ }
+ }
+ else if (sprite[nSprite].zvel < 0)
+ {
+ sprite[nSprite].zvel += 64;
+ if (sprite[nSprite].zvel > 0) {
+ sprite[nSprite].zvel = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ sprite[nSprite].zvel += 512;
+ if (sprite[nSprite].zvel > 16384) {
+ sprite[nSprite].zvel = 16384;
+ }
+ }
+}
+
+int MoveCreature(short nSprite)
+{
+ return movesprite(nSprite, sprite[nSprite].xvel << 8, sprite[nSprite].yvel << 8, sprite[nSprite].zvel, 15360, -5120, CLIPMASK0);
+}
+
+int MoveCreatureWithCaution(int nSprite)
+{
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ int z = sprite[nSprite].z;
+ short nSectorPre = sprite[nSprite].sectnum;
+
+ int ecx = MoveCreature(nSprite);
+
+ short nSector = sprite[nSprite].sectnum;
+
+ if (nSector != nSectorPre)
+ {
+ int zDiff = sector[nSectorPre].floorz - sector[nSector].floorz;
+ if (zDiff < 0) {
+ zDiff = -zDiff;
+ }
+
+ if (zDiff > 15360 || (SectFlag[nSector] & kSectUnderwater) || (SectBelow[nSector] > -1 && SectFlag[SectBelow[nSector]]) || SectDamage[nSector])
+ {
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+
+ mychangespritesect(nSprite, nSectorPre);
+
+ sprite[nSprite].ang = (sprite[nSprite].ang + 256) & kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
+ return 0;
+ }
+ }
+
+ return ecx;
+}
+
+int GetAngleToSprite(int nSprite1, int nSprite2)
+{
+ if (nSprite1 < 0 || nSprite2 < 0)
+ return -1;
+
+ return GetMyAngle(sprite[nSprite2].x - sprite[nSprite1].x, sprite[nSprite2].y - sprite[nSprite1].y);
+}
+
+int PlotCourseToSprite(int nSprite1, int nSprite2)
+{
+ if (nSprite1 < 0 || nSprite2 < 0)
+ return -1;
+
+ int x = sprite[nSprite2].x - sprite[nSprite1].x;
+ int y = sprite[nSprite2].y - sprite[nSprite1].y;
+
+ sprite[nSprite1].ang = GetMyAngle(x, y);
+
+ return ksqrt(y * y + x * x);
+}
+
+int FindPlayer(int nSprite, int nVal)
+{
+ int var_18 = 0;
+ if (nSprite >= 0)
+ var_18 = 1;
+
+ if (nSprite < 0)
+ nSprite = -nSprite;
+
+ if (nVal < 0)
+ nVal = 100;
+
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ short nSector = sprite[nSprite].sectnum;
+
+ int z = sprite[nSprite].z - GetSpriteHeight(nSprite);
+
+ nVal <<= 8;
+
+ short nPlayerSprite;
+ int i = 0;
+
+ while (1)
+ {
+ if (i >= nTotalPlayers)
+ return -1;
+
+ nPlayerSprite = PlayerList[i].nSprite;
+
+ if ((sprite[nPlayerSprite].cstat & 0x101) && (!(sprite[nPlayerSprite].cstat & 0x8000)))
+ {
+ int v9 = sprite[nPlayerSprite].x - x;
+ if (v9 < 0) {
+ v9 = -v9;
+ }
+
+ int v10 = sprite[nPlayerSprite].y - y;
+
+ if (v9 < nVal)
+ {
+ if (v10 < 0) {
+ v10 = -v10;
+ }
+
+ if (v10 < nVal && cansee(sprite[nPlayerSprite].x, sprite[nPlayerSprite].y, sprite[nPlayerSprite].z - 7680, sprite[nPlayerSprite].sectnum, x, y, z, nSector))
+ {
+ break;
+ }
+ }
+ }
+
+ i++;
+ }
+
+ if (var_18) {
+ PlotCourseToSprite(nSprite, nPlayerSprite);
+ }
+
+ return nPlayerSprite;
+}
+
+void CheckSectorFloor(short nSector, int z, long *a, long *b)
+{
+ short nSpeed = SectSpeed[nSector];
+
+ if (!nSpeed) {
+ return;
+ }
+
+ short nFlag = SectFlag[nSector];
+ short nAng = nFlag & kAngleMask;
+
+ if (z >= sector[nSector].floorz)
+ {
+ *a += (Sin(nAng + 512) << 3) * nSpeed;
+ *b += (sintable[nAng] << 3) * nSpeed;
+ }
+ else if (nFlag & 0x800)
+ {
+ *a += (Sin(nAng + 512) << 4) * nSpeed;
+ *b += (sintable[nAng] << 4) * nSpeed;
+ }
+}
+
+int GetUpAngle(short nSprite1, int nVal, short nSprite2, int ecx)
+{
+ int x = sprite[nSprite2].x - sprite[nSprite1].x;
+ int y = sprite[nSprite2].y - sprite[nSprite1].y;
+
+ int ebx = (sprite[nSprite2].z + ecx) - (sprite[nSprite1].z + nVal);
+ int edx = (sprite[nSprite2].z + ecx) - (sprite[nSprite1].z + nVal);
+
+ ebx >>= 4;
+ edx >>= 8;
+
+ ebx = -ebx;
+
+ ebx -= edx;
+
+ int nSqrt = lsqrt(x * x + y * y);
+
+ return GetMyAngle(nSqrt, ebx);
+}
+
+void InitPushBlocks()
+{
+ nPushBlocks = 0;
+}
+
+int GrabPushBlock()
+{
+ if (nPushBlocks >= kMaxPushBlocks) {
+ return -1;
+ }
+
+ return nPushBlocks++;
+}
+
+void CreatePushBlock(int nSector)
+{
+ int nBlock = GrabPushBlock();
+ int i;
+
+ int startwall = sector[nSector].wallptr;
+ int nWalls = sector[nSector].wallnum;
+
+ int ecx = 0;
+ int ebx = 0;
+
+ for (i = 0; i < nWalls; i++)
+ {
+ ecx += wall[startwall + i].x;
+ ebx += wall[startwall + i].y;
+ }
+
+ int avgx = ecx / nWalls;
+ int avgy = ebx / nWalls;
+
+ sBlockInfo[nBlock].x = avgx;
+ sBlockInfo[nBlock].y = avgy;
+
+ int nSprite = insertsprite(nSector, 0);
+
+ sBlockInfo[nBlock].nSprite = nSprite;
+
+ sprite[nSprite].x = avgx;
+ sprite[nSprite].y = avgy;
+ sprite[nSprite].z = sector[nSector].floorz - 256;
+ sprite[nSprite].cstat = 0x8000;
+
+ int var_28 = 0;
+
+ for (i = 0; i < nWalls; i++)
+ {
+ int x = avgx - wall[startwall + i].x;
+ int y = avgy - wall[startwall + i].y;
+
+ int nSqrt = ksqrt(x * x + y * y);
+ if (nSqrt > var_28) {
+ var_28 = nSqrt;
+ }
+ }
+
+ sBlockInfo[nBlock].field_8 = var_28;
+
+ sprite[nSprite].clipdist = (var_28 & 0xFF) << 2;
+ sector[nSector].extra = nBlock;
+}
+
+void MoveSector(short nSector, int nAngle, int *nXVel, int *nYVel)
+{
+ int i;
+
+ if (nSector == -1) {
+ return;
+ }
+
+ long nXVect, nYVect;
+
+ if (nAngle < 0)
+ {
+ nXVect = *nXVel;
+ nYVect = *nYVel;
+ nAngle = GetMyAngle(nXVect, nYVect);
+ }
+ else
+ {
+ nXVect = Sin(nAngle + 512) << 6;
+ nYVect = Sin(nAngle) << 6;
+ }
+
+ short nBlock = sector[nSector].extra;
+ short nSectFlag = SectFlag[nSector];
+
+ SECTOR *pSector = §or[nSector];
+ int nFloorZ = sector[nSector].floorz;
+ int startwall = sector[nSector].wallptr;
+ int nWalls = sector[nSector].wallnum;
+
+ WALL *pStartWall = &wall[startwall];
+ short nNextSector = wall[startwall].nextsector;
+
+ BlockInfo *pBlockInfo = &sBlockInfo[nBlock];
+
+ long x = sBlockInfo[nBlock].x;
+ long x_b = sBlockInfo[nBlock].x;
+
+ long y = sBlockInfo[nBlock].y;
+ long y_b = sBlockInfo[nBlock].y;
+
+ short nSectorB = nSector;
+
+ int nZVal;
+ long z;
+
+ int bUnderwater = nSectFlag & kSectUnderwater;
+
+ if (nSectFlag & kSectUnderwater)
+ {
+ nZVal = sector[nSector].ceilingz;
+ z = sector[nNextSector].ceilingz + 256;
+
+ sector[nSector].ceilingz = sector[nNextSector].ceilingz;
+ }
+ else
+ {
+ nZVal = sector[nSector].floorz;
+ z = sector[nNextSector].floorz - 256;
+
+ sector[nSector].floorz = sector[nNextSector].floorz;
+ }
+
+ clipmove(&x, &y, &z, &nSectorB, nXVect, nYVect, pBlockInfo->field_8, 0, 0, CLIPMASK1);
+
+ int yvect = y - y_b;
+ int xvect = x - x_b;
+
+ if (nSectorB != nNextSector && nSectorB != nSector)
+ {
+ yvect = 0;
+ xvect = 0;
+ }
+ else
+ {
+ if (!bUnderwater)
+ {
+ z = nZVal;
+ x = x_b;
+ y = y_b;
+
+ clipmove(&x, &y, &z, &nSectorB, nXVect, nYVect, pBlockInfo->field_8, 0, 0, CLIPMASK1);
+
+ int ebx = x;
+ int ecx = x_b;
+ int edx = y;
+ int eax = xvect;
+ int esi = y_b;
+
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ ebx -= ecx;
+ ecx = eax;
+ eax = ebx;
+ edx -= esi;
+
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ if (ecx > eax)
+ {
+ xvect = ebx;
+ }
+
+ eax = yvect;
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ ebx = eax;
+ eax = edx;
+
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ if (ebx > eax) {
+ yvect = edx;
+ }
+ }
+ }
+
+ // GREEN
+ if (yvect || xvect)
+ {
+ for (i = headspritesect[nSector]; i != -1; i = nextspritesect[i])
+ {
+ if (sprite[i].statnum < 99)
+ {
+ sprite[i].x += xvect;
+ sprite[i].y += yvect;
+ }
+ else
+ {
+ z = sprite[i].z;
+
+ if ((nSectFlag & kSectUnderwater) || z != nZVal || sprite[i].cstat & 0x8000)
+ {
+ x = sprite[i].x;
+ y = sprite[i].y;
+ nSectorB = nSector;
+
+ clipmove(&x, &y, &z, &nSectorB, -xvect, -yvect, 4 * sprite[i].clipdist, 0, 0, CLIPMASK0);
+
+ if (nSectorB >= 0 && nSectorB < kMaxSectors && nSectorB != nSector) {
+ mychangespritesect(i, nSectorB);
+ }
+ }
+ }
+ }
+
+ //int var_1C = nAngle & kAngleMask;
+ int var_38 = yvect << 14;
+ int var_58 = xvect << 14;
+
+ for (i = headspritesect[nNextSector]; i != -1; i = nextspritesect[i])
+ {
+ if (sprite[i].statnum >= 99)
+ {
+ x = sprite[i].x;
+ y = sprite[i].y;
+ z = sprite[i].z;
+ nSectorB = nNextSector;
+
+ clipmove(&x, &y, &z, &nSectorB,
+ -xvect - (Sin(nAngle + 512) * (4 * sprite[i].clipdist)),
+ -yvect - (Sin(nAngle) * (4 * sprite[i].clipdist)),
+ 4 * sprite[i].clipdist, 0, 0, CLIPMASK0);
+
+
+ if (nSectorB != nNextSector && (nSectorB == nSector || nNextSector == nSector))
+ {
+ if (nSectorB != nSector || nFloorZ >= sprite[i].z)
+ {
+ if (nSectorB >= 0 && nSectorB < kMaxSectors) {
+ mychangespritesect(i, nSectorB);
+ }
+ }
+ else
+ {
+ movesprite(i,
+ (xvect << 14) + Sin(nAngle + 512) * sprite[i].clipdist,
+ (yvect << 14) + Sin(nAngle) * sprite[i].clipdist,
+ 0, 0, 0, CLIPMASK0);
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < nWalls; i++)
+ {
+ dragpoint(startwall, xvect + pStartWall->x, yvect + pStartWall->y);
+ pStartWall++;
+ startwall++;
+ }
+
+ pBlockInfo->x += xvect;
+ pBlockInfo->y += yvect;
+ }
+ else {
+ int gasd = 123;
+ }
+
+ // loc_163DD
+ xvect <<= 14;
+ yvect <<= 14;
+
+ if (!(nSectFlag & kSectUnderwater))
+ {
+ for (i = headspritesect[nSector]; i != -1; i = nextspritesect[i])
+ {
+ if (sprite[i].statnum >= 99 && nZVal == sprite[i].z && !(sprite[i].cstat & 0x8000))
+ {
+ nSectorB = nSector;
+ clipmove(&sprite[i].x, &sprite[i].y, &sprite[i].z, &nSectorB, xvect, yvect, 4 * sprite[i].clipdist, 5120, -5120, CLIPMASK0);
+ }
+ }
+ }
+
+ if (nSectFlag & kSectUnderwater) {
+ pSector->ceilingz = nZVal;
+ }
+ else {
+ pSector->floorz = nZVal;
+ }
+
+ *nXVel = xvect;
+ *nYVel = yvect;
+}
+
+void SetQuake(short nSprite, int nVal)
+{
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+
+ for (int i = 0; i < nTotalPlayers; i++)
+ {
+ int nPlayerSprite = PlayerList[i].nSprite;
+
+ int nSqrt = ksqrt(((sprite[nPlayerSprite].x - x) >> 8) * ((sprite[nPlayerSprite].x - x) >> 8) + ((sprite[nPlayerSprite].y - y) >> 8)
+ * ((sprite[nPlayerSprite].y - y) >> 8));
+
+ int eax = nVal * 256;
+
+ if (nSqrt)
+ {
+ eax = eax / nSqrt;
+
+ if (eax >= 256)
+ {
+ if (eax > 3840) {
+ eax = 3840;
+ }
+ }
+ else
+ {
+ eax = 0;
+ }
+ }
+
+ if (eax > nQuake[i]) {
+ nQuake[i] = eax;
+ }
+ }
+}
+
+int AngleChase(int nSprite, int nSprite2, int ebx, int ecx, int push1)
+{
+ int nClipType = sprite[nSprite].statnum != 107;
+
+ /* bjd - need to handle cliptype to clipmask change that occured in later build engine version */
+ if (nClipType == 1) {
+ nClipType = CLIPMASK1;
+ }
+ else {
+ nClipType = CLIPMASK0;
+ }
+
+ short nAngle;
+
+ if (nSprite2 < 0)
+ {
+ sprite[nSprite].zvel = 0;
+ nAngle = sprite[nSprite].ang;
+ }
+ else
+ {
+ int nHeight = tilesizy[sprite[nSprite2].picnum] * sprite[nSprite2].yrepeat * 2;
+
+ int nMyAngle = GetMyAngle(sprite[nSprite2].x - sprite[nSprite].x, sprite[nSprite2].y - sprite[nSprite].y);
+
+ int nSqrt = ksqrt(
+ (sprite[nSprite2].y - sprite[nSprite].y)
+ *
+ (sprite[nSprite2].y - sprite[nSprite].y)
+ +
+ (sprite[nSprite2].x - sprite[nSprite].x)
+ *
+ (sprite[nSprite2].x - sprite[nSprite].x)
+ );
+
+ int var_18 = GetMyAngle(nSqrt, ((sprite[nSprite2].z - nHeight) - sprite[nSprite].z) >> 8);
+
+ int edx = nMyAngle;
+
+ int nAngDelta = AngleDelta(sprite[nSprite].ang, nMyAngle, 1024);
+ int nAngDelta2 = nAngDelta;
+
+ if (nAngDelta2 < 0)
+ nAngDelta2 = -nAngDelta2;
+
+ if (nAngDelta2 > 63)
+ {
+ nAngDelta2 = nAngDelta;
+ nAngDelta2 >>= 6;
+
+ edx = ebx;
+
+ if (nAngDelta2 < 0)
+ nAngDelta2 = -nAngDelta2;
+
+ ebx /= nAngDelta2;
+
+ if (ebx < 5)
+ ebx = 5;
+ }
+
+ int nAngDeltaC = nAngDelta;
+
+ if (nAngDeltaC < 0)
+ nAngDeltaC = -nAngDeltaC;
+
+ if (nAngDeltaC > push1)
+ {
+ if (nAngDelta >= 0)
+ nAngDelta = push1;
+ else
+ nAngDelta = -push1;
+ }
+
+ int nAngDeltaD = AngleDelta(sprite[nSprite].zvel, var_18, 24);
+ nAngle = (nAngDelta + sprite[nSprite].ang) & kAngleMask;
+
+ // TODO - CHECKME int ebx = 24;
+
+ sprite[nSprite].zvel = (sprite[nSprite].zvel + nAngDeltaD) & kAngleMask;
+ }
+
+ sprite[nSprite].ang = nAngle;
+
+ int eax = Sin(sprite[nSprite].zvel + 512);
+ int edx = (nAngle + 512) & kAngleMask;
+
+ if (eax < 0)
+ eax = -eax;
+
+ // rename this var. CHECKME
+ int x = ((sintable[edx] * ebx) >> 14) * eax;
+
+ int ceildist = x >> 8;
+
+ int y = ((Sin(nAngle) * ebx) >> 14) * eax;
+
+ int nVal = y >> 8;
+
+ int z = Sin(sprite[nSprite].zvel) * ksqrt((nVal * nVal) + (ceildist * ceildist));
+
+ return movesprite(nSprite, x >> 2, y >> 2, (z >> 13) + (Sin(ecx) >> 5), 0, 0, nClipType);
+}
+
+int GetWallNormal(short nWall)
+{
+ nWall &= 0x1FFF;
+
+ int nWall2 = wall[nWall].point2;
+
+ int nAngle = GetMyAngle(wall[nWall2].x - wall[nWall].x, wall[nWall2].y - wall[nWall].y);
+ return (nAngle + 512) & kAngleMask;
+}
+
+void WheresMyMouth(int nPlayer, int *x, int *y, int *z, short *sectnum)
+{
+ int nSprite = PlayerList[nPlayer].nSprite;
+
+ *x = sprite[nSprite].x;
+ *y = sprite[nSprite].y;
+
+ int height = GetSpriteHeight(nSprite) / 2;
+
+ *z = sprite[nSprite].z - height;
+ *sectnum = sprite[nSprite].sectnum;
+
+ clipmove((long*)x, (long*)y, (long*)z, sectnum,
+ Sin(sprite[nSprite].ang + 512) << 7,
+ Sin(sprite[nSprite].ang) << 7,
+ 5120, 1280, 1280, CLIPMASK1);
+}
+
+void InitChunks()
+{
+ nCurChunkNum = 0;
+ memset(nChunkSprite, -1, sizeof(nChunkSprite));
+ memset(nBodyGunSprite, -1, sizeof(nBodyGunSprite));
+ memset(nBodySprite, -1, sizeof(nBodySprite));
+ nCurBodyNum = 0;
+ nCurBodyGunNum = 0;
+ nBodyTotal = 0;
+ nChunkTotal = 0;
+}
+
+int GrabBodyGunSprite()
+{
+ int nSprite = nBodyGunSprite[nCurBodyGunNum];
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(0, 899);
+ nBodyGunSprite[nCurBodyGunNum] = nSprite;
+
+ sprite[nSprite].lotag = -1;
+ sprite[nSprite].owner = -1;
+ }
+ else
+ {
+ int nAnim = sprite[nSprite].owner;
+
+ if (nAnim != -1) {
+ DestroyAnim(nAnim);
+ }
+
+ sprite[nSprite].lotag = -1;
+ sprite[nSprite].owner = -1;
+ }
+
+ nCurBodyGunNum++;
+ if (nCurBodyGunNum >= 50) { // TODO - enum/define
+ nCurBodyGunNum = 0;
+ }
+
+ sprite[nSprite].cstat = 0;
+
+ return nSprite;
+}
+
+int GrabBody()
+{
+ int nSprite;
+
+ do
+ {
+ nSprite = nBodySprite[nCurBodyNum];
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(0, 899);
+ nBodySprite[nCurBodyNum] = nSprite;
+ sprite[nSprite].cstat = 0x8000;
+ }
+
+ nCurBodyNum++;
+ if (nCurBodyNum >= 50) {
+ nCurBodyNum = 0;
+ }
+ }
+ while (sprite[nSprite].cstat & 0x101);
+
+ if (nBodyTotal < 50) {
+ nBodyTotal++;
+ }
+
+ sprite[nSprite].cstat = 0;
+ return nSprite;
+}
+
+int GrabChunkSprite()
+{
+ int nSprite = nChunkSprite[nCurChunkNum];
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(0, 899);
+ nChunkSprite[nCurChunkNum] = nSprite;
+ }
+ else if (sprite[nSprite].statnum)
+ {
+// TODO MonoOut("too many chunks being used at once!\n");
+ return -1;
+ }
+
+ changespritestat(nSprite, 899);
+
+ nCurChunkNum++;
+ if (nCurChunkNum >= kMaxChunks)
+ nCurChunkNum = 0;
+
+ if (nChunkTotal < kMaxChunks)
+ nChunkTotal++;
+
+ sprite[nSprite].cstat = 0x80;
+
+ return nSprite;
+}
+
+int BuildCreatureChunk(int nVal, int nPic)
+{
+ int var_14;
+
+ int nSprite = GrabChunkSprite();
+
+ if (nSprite == -1) {
+ return -1;
+ }
+
+ if (nVal & 0x4000)
+ {
+ nVal &= 0x3FFF;
+ var_14 = 1;
+ }
+ else
+ {
+ var_14 = 0;
+ }
+
+ nVal &= 0xFFFF;
+
+ sprite[nSprite].x = sprite[nVal].x;
+ sprite[nSprite].y = sprite[nVal].y;
+ sprite[nSprite].z = sprite[nVal].z;
+
+ mychangespritesect(nSprite, sprite[nVal].sectnum);
+
+ sprite[nSprite].cstat = 0x80;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].pal = 0;
+
+ sprite[nSprite].xvel = (RandomSize(5) - 16) << 7;
+ sprite[nSprite].yvel = (RandomSize(5) - 16) << 7;
+ sprite[nSprite].zvel = (-(RandomSize(8) + 512)) << 3;
+
+ if (var_14)
+ {
+ sprite[nSprite].xvel *= 4;
+ sprite[nSprite].yvel *= 4;
+ sprite[nSprite].zvel *= 2;
+ }
+
+ sprite[nSprite].xrepeat = 64;
+ sprite[nSprite].yrepeat = 64;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].picnum = nPic;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].clipdist = 40;
+
+// GrabTimeSlot(3);
+
+ sprite[nSprite].extra = -1;
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nSprite | 0xD0000);
+ sprite[nSprite].hitag = runlist_AddRunRec(NewRun, nSprite | 0xD0000);
+
+ return nSprite | 0xD0000;
+}
+
+void FuncCreatureChunk(int a, int, int nRun)
+{
+ int nSprite = RunData[nRun].nVal;
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ int nMessage = a & 0x7F0000;
+
+ if (nMessage != 0x20000)
+ return;
+
+ Gravity(nSprite);
+
+ int nSector = sprite[nSprite].sectnum;
+ sprite[nSprite].pal = sector[nSector].ceilingpal;
+
+ int nVal = movesprite(nSprite, sprite[nSprite].xvel << 10, sprite[nSprite].yvel << 10, sprite[nSprite].zvel, 2560, -2560, CLIPMASK1);
+
+ if (sprite[nSprite].z >= sector[nSector].floorz)
+ {
+ // re-grab this variable as it may have changed in movesprite(). Note the check above is against the value *before* movesprite so don't change it.
+ nSector = sprite[nSprite].sectnum;
+
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].z = sector[nSector].floorz;
+ }
+ else
+ {
+ if (!nVal)
+ return;
+
+ short nAngle;
+
+ if (nVal & 0x20000)
+ {
+ sprite[nSprite].cstat = 0x8000;
+ }
+ else
+ {
+ if ((nVal & 0x3C000) == 0x10000)
+ {
+ sprite[nSprite].xvel >>= 1;
+ sprite[nSprite].yvel >>= 1;
+ sprite[nSprite].zvel = -sprite[nSprite].zvel;
+ return;
+ }
+ else if ((nVal & 0x3C000) == 0xC000)
+ {
+ nAngle = sprite[nVal & 0x3FFF].ang;
+ }
+ else if ((nVal & 0x3C000) == 0x8000)
+ {
+ nAngle = GetWallNormal(nVal & 0x3FFF);
+ }
+ else
+ {
+ return;
+ }
+
+ // loc_16E0C
+ int nSqrt = lsqrt(((sprite[nSprite].yvel >> 10) * (sprite[nSprite].yvel >> 10)
+ + (sprite[nSprite].xvel >> 10) * (sprite[nSprite].xvel >> 10)) >> 8);
+
+ sprite[nSprite].xvel = Sin(nAngle + 512) * (nSqrt >> 1);
+ sprite[nSprite].yvel = Sin(nAngle) * (nSqrt >> 1);
+ return;
+ }
+ }
+
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+ runlist_SubRunRec(sprite[nSprite].hitag);
+
+ changespritestat(nSprite, 0);
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].lotag = 0;
+}
+
+short UpdateEnemy(short *nEnemy)
+{
+ if (*nEnemy >= 0)
+ {
+ if (!(sprite[*nEnemy].cstat & 0x101)) {
+ *nEnemy = -1;
+ }
+ }
+
+ return *nEnemy;
+}
diff --git a/source/exhumed/src/move.h b/source/exhumed/src/move.h
new file mode 100644
index 000000000..058691513
--- /dev/null
+++ b/source/exhumed/src/move.h
@@ -0,0 +1,60 @@
+
+#ifndef __move_h__
+#define __move_h__
+
+// 16 bytes
+struct BlockInfo
+{
+ int x;
+ int y;
+ int field_8;
+ short nSprite;
+};
+extern BlockInfo sBlockInfo[];
+
+extern long hihit;
+extern short nChunkSprite[];
+
+signed int lsqrt(int a1);
+void MoveThings();
+void ResetMoveFifo();
+void InitChunks();
+void InitPushBlocks();
+void Gravity(short nSprite);
+short UpdateEnemy(short *nEnemy);
+int MoveCreature(short nSprite);
+int MoveCreatureWithCaution(int nSprite);
+void WheresMyMouth(int nPlayer, int *x, int *y, int *z, short *sectnum);
+
+int GetSpriteHeight(int nSprite);
+
+int GrabBody();
+
+int GrabBodyGunSprite();
+void CreatePushBlock(int nSector);
+
+void FuncCreatureChunk(int a, int, int nRun);
+
+int FindPlayer(int nSprite, int nVal);
+
+int BuildCreatureChunk(int nVal, int nPic);
+
+void BuildNear(int x, int y, int walldist, int nSector);
+int BelowNear(short nSprite);
+
+int PlotCourseToSprite(int nSprite1, int nSprite2);
+
+void CheckSectorFloor(short nSector, int z, long *a, long *b);
+
+int GetAngleToSprite(int nSprite1, int nSprite2);
+
+int GetWallNormal(short nWall);
+
+int GetUpAngle(short nSprite1, int nVal, short nSprite2, int ecx);
+void MoveSector(short nSector, int nAngle, int *nXVel, int *nYVel);
+
+int AngleChase(int nSprite, int nSprite2, int ebx, int ecx, int push1);
+
+void SetQuake(short nSprite, int nVal);
+
+#endif
diff --git a/source/exhumed/src/movie.cpp b/source/exhumed/src/movie.cpp
new file mode 100644
index 000000000..2eeb60d90
--- /dev/null
+++ b/source/exhumed/src/movie.cpp
@@ -0,0 +1,210 @@
+
+#include "engine.h"
+#include "exhumed.h"
+#include "names.h"
+#include "movie.h"
+#include "cdrom.h"
+#include "light.h"
+#include
+#include
+#include "baselayer.h"
+#include "typedefs.h"
+#include "keyboard.h"
+
+enum {
+ kFramePalette = 0,
+ kFrameSound,
+ kFrameImage,
+ kFrameDone
+};
+
+uchar lh[32] = { 0 };
+char streambuf[2205];
+char byte_1C6DF5[2205];
+
+static BYTE* CurFrame = NULL;
+
+
+int serve_sample()
+{
+// if (!SoundCardActive()) {
+// return 1;
+// }
+
+ return 0;
+}
+
+int ReadFrame(FILE *fp)
+{
+ static int nFrame = 0;
+ DebugOut("Reading frame %d...\n", nFrame);
+ nFrame++;
+
+ uchar nType;
+ uchar var_1C;
+ int nSize;
+ ushort yOffset;
+ uchar xOffset;
+ uchar nPixels;
+ uchar palette[768];
+
+ while (1)
+ {
+ if (fread(&nType, 1, sizeof(nType), fp) == 0) {
+ return 0;
+ }
+
+ fread(&nSize, sizeof(nSize), 1, fp);
+
+ nType--;
+ if (nType > 3) {
+ continue;
+ }
+
+ switch (nType)
+ {
+ case kFramePalette:
+ {
+ fread(palette, sizeof(palette[0]), sizeof(palette) / sizeof(palette[0]), fp);
+ fread(&var_1C, sizeof(var_1C), 1, fp);
+
+ MySetPalette(palette);
+
+ memset(CurFrame, overscanindex, 4); //sizeof(CurFrame));
+ continue;
+ }
+ case kFrameSound:
+ {
+ DebugOut("Reading sound block size %d...\n", nSize);
+ // TODO - just skip for now
+ fseek(fp, nSize, SEEK_CUR);
+ continue;
+ }
+ case kFrameImage:
+ {
+ DebugOut("Reading image block size %d...\n", nSize);
+ if (nSize == 0) {
+ continue;
+ }
+
+ BYTE *pFrame = CurFrame;
+
+ int nRead = fread(&yOffset, 1, sizeof(yOffset), fp);
+ nSize -= nRead;
+
+ pFrame += yOffset * 200; // row position
+
+ while (nSize > 0)
+ {
+ fread(&xOffset, sizeof(xOffset), 1, fp);
+ fread(&nPixels, sizeof(nPixels), 1, fp);
+ nSize -= 2;
+
+ pFrame += xOffset;
+
+ if (nPixels)
+ {
+ int nRead = fread(pFrame, 1, nPixels, fp);
+ pFrame += nRead;
+ nSize -= nRead;
+ }
+ }
+
+ break;
+ }
+ case kFrameDone:
+ {
+ return 1;
+ break;
+ }
+ }
+ }
+}
+
+void PlayMovie(const char *fileName)
+{
+ char buffer[256];
+
+ int bDoFade = 1;
+
+ if (bNoCDCheck)
+ {
+ sprintf(buffer, "C:\\PS\\%s", fileName);
+ }
+ else
+ {
+ char driveLetter = GetCDDriveLetter();
+ if (!driveLetter) {
+ driveLetter = 'C';
+ }
+ sprintf(buffer, "%c:%s", driveLetter, fileName);
+ }
+
+ tileLoad(kMovieTile);
+ CurFrame = (BYTE*)waloff[kMovieTile];
+
+ FILE *fp = fopen(buffer, "rb");
+ if (fp == NULL)
+ {
+ DebugOut("Can't open movie file '%s' on CD-ROM\n", buffer);
+ fp = fopen(fileName, "rb");
+ if (fp == NULL)
+ {
+ DebugOut("Can't open movie file on hard drive\n");
+ return;
+ }
+ }
+
+ fread(lh, sizeof(lh), 1, fp);
+ memset(streambuf, 0, sizeof(streambuf));
+ memset(byte_1C6DF5, 0, sizeof(byte_1C6DF5));
+
+ // sound stuff
+
+ // clear keys
+ KB_FlushKeyboardQueue();
+ KB_ClearKeysDown();
+
+ if (bDoFade) {
+ StartFadeIn();
+ }
+
+ int angle = 1536;
+ int z = 0;
+
+ if (ReadFrame(fp))
+ {
+ while (!KB_KeyWaiting())
+ {
+ handleevents();
+
+ if (z < 65536) { // Zoom - normal zoom is 65536.
+ z += 2048;
+ }
+ if (angle != 0) {
+ angle += 16;
+ if (angle == 2048) {
+ angle = 0;
+ }
+ }
+
+ rotatesprite(160 << 16, 100 << 16, z, angle, kMovieTile, 0, 1, 2, 0, 0, nScreenHeight - 1, nScreenWidth - 1);
+
+ if (bDoFade) {
+ bDoFade = DoFadeIn();
+ }
+
+ videoNextPage();
+
+ if (ReadFrame(fp) == 0) {
+ break;
+ }
+ }
+ }
+
+ if (KB_KeyWaiting()) {
+ KB_GetCh();
+ }
+
+ fclose(fp);
+}
diff --git a/source/exhumed/src/movie.h b/source/exhumed/src/movie.h
new file mode 100644
index 000000000..ebd99a012
--- /dev/null
+++ b/source/exhumed/src/movie.h
@@ -0,0 +1,7 @@
+
+#ifndef __movie_h__
+#define __movie_h__
+
+void PlayMovie(const char *fileName);
+
+#endif
diff --git a/source/exhumed/src/mummy.cpp b/source/exhumed/src/mummy.cpp
new file mode 100644
index 000000000..823168a48
--- /dev/null
+++ b/source/exhumed/src/mummy.cpp
@@ -0,0 +1,514 @@
+
+#include "mummy.h"
+#include "sequence.h"
+#include "move.h"
+#include "map.h"
+#include "sound.h"
+#include "exhumed.h"
+#include "random.h"
+#include "trigdat.h"
+#include "bullet.h"
+#include "items.h"
+#include
+#include "engine.h"
+
+short nMummies = -1;
+
+struct Mummy
+{
+ short nHealth;
+ short B;
+ short nAction;
+ short nSprite;
+ short nTarget;
+ short F;
+ short G;
+ short H;
+};
+
+Mummy MummyList[kMaxMummies];
+
+static actionSeq ActionSeq[] = {
+ {8, 0},
+ {0, 0},
+ {16, 0},
+ {24, 0},
+ {32, 1},
+ {40, 1},
+ {48, 1},
+ {50, 0}
+};
+
+// done
+void InitMummy()
+{
+ nMummies = 0;
+}
+
+// done
+int BuildMummy(int nSprite, int x, int y, int z, int nSector, int nAngle)
+{
+ if (nMummies >= kMaxMummies) {
+ return -1;
+ }
+
+ short nMummy = nMummies++;
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(nSector, 102);
+ }
+ else
+ {
+ x = sprite[nSprite].x;
+ y = sprite[nSprite].y;
+ z = sprite[nSprite].z;
+ nAngle = sprite[nSprite].ang;
+
+ changespritestat(nSprite, 102);
+ }
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].clipdist = 32;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].xrepeat = 42;
+ sprite[nSprite].yrepeat = 42;
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].extra = -1;
+
+// GrabTimeSlot(3);
+
+ MummyList[nMummy].nAction = 0;
+ MummyList[nMummy].nHealth = 640;
+ MummyList[nMummy].B = 0;
+ MummyList[nMummy].nSprite = nSprite;
+ MummyList[nMummy].nTarget = -1;
+ MummyList[nMummy].F = nMummy;
+ MummyList[nMummy].G = 0;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nMummy | 0xE0000);
+
+ MummyList[nMummy].H = runlist_AddRunRec(NewRun, nMummy | 0xE0000);
+
+ nCreaturesLeft++;
+
+ return (nMummy | 0xE0000);
+}
+
+// done
+void CheckMummyRevive(short nMummy)
+{
+ short nSprite = MummyList[nMummy].nSprite;
+
+ for (int i = 0; i < nMummies; i++)
+ {
+ if (i != nMummy)
+ {
+ short nSprite2 = MummyList[i].nSprite;
+ if (sprite[nSprite2].statnum != 102) {
+ continue;
+ }
+
+ if (MummyList[i].nAction != 5) {
+ continue;
+ }
+
+ int x = sprite[nSprite2].x - sprite[nSprite].x;
+ if (x < 0) {
+ x = -x;
+ }
+
+ x = x >> 8;
+
+ int y = sprite[nSprite2].y - sprite[nSprite].y;
+ if (y < 0) {
+ y = -y;
+ }
+
+ y = y >> 8;
+
+ if (x <= 20 && y <= 20)
+ {
+ int bCanSee = cansee(sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z - 8192, sprite[nSprite].sectnum,
+ sprite[nSprite2].x, sprite[nSprite2].y, sprite[nSprite2].z - 8192, sprite[nSprite2].sectnum);
+
+ if (bCanSee)
+ {
+ sprite[nSprite2].cstat = 0;
+ MummyList[i].nAction = 6;
+ MummyList[i].B = 0;
+ }
+ }
+ }
+ }
+}
+
+void FuncMummy(int a, int nDamage, int nRun)
+{
+ short nMummy = RunData[nRun].nVal;
+ assert(nMummy >= 0 && nMummy < kMaxMummies);
+
+ short nTarget = UpdateEnemy(&MummyList[nMummy].nTarget);
+
+ short nSprite = MummyList[nMummy].nSprite;
+ short nAction = MummyList[nMummy].nAction;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x20000:
+ {
+ Gravity(nSprite);
+
+ int nSeq = SeqOffsets[kSeqMummy] + ActionSeq[nAction].a;
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, MummyList[nMummy].B);
+
+ short nFrame = SeqBase[nSeq] + MummyList[nMummy].B;
+ short nFrameFlag = FrameFlag[nFrame];
+
+ seq_MoveSequence(nSprite, nSeq, MummyList[nMummy].B);
+
+ short ecx = 0;
+
+ MummyList[nMummy].B++;
+ if (MummyList[nMummy].B >= SeqSize[nSeq])
+ {
+ MummyList[nMummy].B = 0;
+
+ ecx = 1;
+ }
+
+ if (nTarget != -1 && nAction < 4)
+ {
+ if (!sprite[nTarget].cstat && nAction)
+ {
+ MummyList[nMummy].nAction = 0;
+ MummyList[nMummy].B = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ }
+ }
+
+ int nMov = MoveCreatureWithCaution(nSprite);
+
+ if (nAction > 7)
+ return;
+
+ switch (nAction)
+ {
+ case 0:
+ {
+ if ((MummyList[nMummy].F & 31) == (totalmoves & 31))
+ {
+ sprite[nSprite].cstat = 0x101;
+ if (nTarget < 0)
+ {
+ int nPlayerSprite = FindPlayer(nSprite, 100);
+ if (nPlayerSprite >= 0)
+ {
+ D3PlayFX(StaticSound[kSound7], nSprite);
+ MummyList[nMummy].B = 0;
+ MummyList[nMummy].nTarget = nPlayerSprite;
+ MummyList[nMummy].nAction = 1;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
+ MummyList[nMummy].G = 90;
+ }
+ }
+ }
+ return;
+ }
+
+ case 1:
+ {
+ if (MummyList[nMummy].G > 0)
+ {
+ MummyList[nMummy].G--;
+ }
+
+ if ((MummyList[nMummy].F & 31) == (totalmoves & 31))
+ {
+ sprite[nSprite].cstat = 0x101;
+
+ PlotCourseToSprite(nSprite, nTarget);
+
+ if (MummyList[nMummy].nAction == 1)
+ {
+ if (RandomBit())
+ {
+ int nTargetHeight = GetSpriteHeight(nTarget);
+ int nSpriteHeight = GetSpriteHeight(nSprite);
+
+ if (cansee(sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z - nSpriteHeight, sprite[nSprite].sectnum, sprite[nTarget].x, sprite[nTarget].y, sprite[nTarget].z - nTargetHeight, sprite[nTarget].sectnum))
+ {
+ MummyList[nMummy].nAction = 3;
+ MummyList[nMummy].B = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ return;
+ }
+ }
+ }
+
+ if (!MummyList[nMummy].B)
+ {
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 1;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 1;
+ }
+
+ if (sprite[nSprite].xvel || sprite[nSprite].yvel)
+ {
+ if (sprite[nSprite].xvel > 0)
+ {
+ sprite[nSprite].xvel -= 1024;
+ if (sprite[nSprite].xvel < 0) {
+ sprite[nSprite].xvel = 0;
+ }
+ }
+ else if (sprite[nSprite].xvel < 0)
+ {
+ sprite[nSprite].xvel += 1024;
+ if (sprite[nSprite].xvel > 0) {
+ sprite[nSprite].xvel = 0;
+ }
+ }
+
+ if (sprite[nSprite].yvel > 0)
+ {
+ sprite[nSprite].yvel -= 1024;
+ if (sprite[nSprite].yvel < 0) {
+ sprite[nSprite].yvel = 0;
+ }
+ }
+ else if (sprite[nSprite].yvel < 0)
+ {
+ sprite[nSprite].yvel += 1024;
+ if (sprite[nSprite].yvel > 0) {
+ sprite[nSprite].yvel = 0;
+ }
+ }
+ }
+
+ if (nMov)
+ {
+ switch (nMov & 0xC000)
+ {
+ case 0x8000:
+ {
+ sprite[nSprite].ang = (sprite[nSprite].ang + ((RandomWord() & 0x3FF) + 1024)) & kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
+ return;
+ }
+
+ case 0xC000:
+ {
+ if ((nMov & 0x3FFF) == nTarget)
+ {
+ int nAngle = getangle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+ if (AngleDiff(sprite[nSprite].ang, nAngle) < 64)
+ {
+ MummyList[nMummy].nAction = 2;
+ MummyList[nMummy].B = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ }
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+
+ case 2:
+ {
+ if (nTarget == -1)
+ {
+ MummyList[nMummy].nAction = 0;
+ MummyList[nMummy].B = 0;
+ }
+ else
+ {
+ if (PlotCourseToSprite(nSprite, nTarget) >= 1024)
+ {
+ MummyList[nMummy].nAction = 1;
+ MummyList[nMummy].B = 0;
+ }
+ else if (nFrameFlag & 0x80)
+ {
+ runlist_DamageEnemy(nTarget, nSprite, 5);
+ }
+ }
+ return;
+ }
+
+ case 3:
+ {
+ if (ecx)
+ {
+ MummyList[nMummy].B = 0;
+ MummyList[nMummy].nAction = 0;
+ MummyList[nMummy].G = 100;
+ MummyList[nMummy].nTarget = -1;
+ return;
+ }
+ else if (nFrameFlag & 0x80)
+ {
+ SetQuake(nSprite, 100);
+
+ // low 16 bits of returned var contains the sprite index, the high 16 the bullet number
+ int nBullet = BuildBullet(nSprite, 9, 0, 0, 0x0FFFFC400, sprite[nSprite].ang, nTarget + 10000, 1);
+ CheckMummyRevive(nMummy);
+
+ if (nBullet > -1)
+ {
+ if (!RandomSize(3))
+ {
+ short a = nBullet >> 16;
+ short b = nBullet & 0xFFFF;
+
+ // FIXME CHECKME - nBullet & 0xFFFF can be -1. Original code doesn't handle this??
+
+ SetBulletEnemy(nBullet >> 16, nTarget); // isolate the bullet number (shift off the sprite index)
+ sprite[nBullet & 0xFFFF].pal = 5;
+ }
+ }
+ }
+ return;
+ }
+
+ case 4:
+ {
+ if (ecx)
+ {
+ MummyList[nMummy].B = 0;
+ MummyList[nMummy].nAction = 5;
+ }
+ return;
+ }
+
+ case 5:
+ {
+ MummyList[nMummy].B = 0;
+ return;
+ }
+
+ case 6:
+ {
+ if (ecx)
+ {
+ MummyList[nMummy].nAction = 0;
+ sprite[nSprite].cstat = 0x101;
+ MummyList[nMummy].nHealth = 300;
+ MummyList[nMummy].nTarget = -1;
+ nCreaturesLeft++;
+ }
+ return;
+ }
+
+ case 7:
+ {
+ if (nMov & 0x20000)
+ {
+ sprite[nSprite].xvel >>= 1;
+ sprite[nSprite].yvel >>= 1;
+ }
+
+ if (ecx)
+ {
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ MummyList[nMummy].nAction = 0;
+ MummyList[nMummy].B = 0;
+ sprite[nSprite].cstat = 0x101;
+ MummyList[nMummy].nTarget = -1;
+ }
+
+ return;
+ }
+ }
+
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, SeqOffsets[kSeqMummy] + ActionSeq[nAction].a, MummyList[nMummy].B, ActionSeq[nAction].b);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ if (MummyList[nMummy].nHealth <= 0)
+ return;
+
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ // fall through to 0x80000
+ }
+ case 0x80000:
+ {
+ if (nDamage <= 0)
+ return;
+
+ if (MummyList[nMummy].nHealth <= 0) {
+ return;
+ }
+
+ MummyList[nMummy].nHealth -= nDamage;
+
+ if (MummyList[nMummy].nHealth <= 0)
+ {
+ MummyList[nMummy].nHealth = 0;
+ sprite[nSprite].cstat &= 0xFEFE;
+ nCreaturesLeft--;
+
+ DropMagic(nSprite);
+
+ MummyList[nMummy].B = 0;
+ MummyList[nMummy].nAction = 4;
+
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].z = sector[sprite[nSprite].sectnum].floorz;
+ }
+ else
+ {
+ if (!RandomSize(2))
+ {
+ MummyList[nMummy].nAction = 7;
+ MummyList[nMummy].B = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ }
+ }
+
+ return;
+ }
+
+ default:
+ {
+ DebugOut("unknown msg %d for Mummy\n", a & 0x7F0000);
+ break;
+ }
+ }
+}
diff --git a/source/exhumed/src/mummy.h b/source/exhumed/src/mummy.h
new file mode 100644
index 000000000..637a52278
--- /dev/null
+++ b/source/exhumed/src/mummy.h
@@ -0,0 +1,14 @@
+
+#ifndef __mummy_h__
+#define __mummy_h__
+
+#include "runlist.h"
+
+#define kMaxMummies 150
+
+void InitMummy();
+int BuildMummy(int val, int x, int y, int z, int nSector, int angle);
+
+void FuncMummy(int nSector, int edx, int nRun);
+
+#endif
diff --git a/source/exhumed/src/names.h b/source/exhumed/src/names.h
new file mode 100644
index 000000000..242e49a99
--- /dev/null
+++ b/source/exhumed/src/names.h
@@ -0,0 +1,6150 @@
+
+#ifndef __names_h__
+#define __names_h__
+
+#define kTile0 0
+#define kTile1 1
+#define kTile2 2
+#define kTile3 3
+#define kTile4 4
+#define kTile5 5
+#define kTile6 6
+#define kTile7 7
+#define kTile8 8
+#define kTile9 9
+#define kTile10 10
+#define kTile11 11
+#define kTile12 12
+#define kTile13 13
+#define kTile14 14
+#define kTile15 15
+#define kTile16 16
+#define kTile17 17
+#define kTile18 18
+#define kTile19 19
+#define kTile20 20
+#define kTile21 21
+#define kTile22 22
+#define kTile23 23
+#define kTile24 24
+#define kTile25 25
+#define kTile26 26
+#define kTile27 27
+#define kTile28 28
+#define kTile29 29
+#define kTile30 30
+#define kTile31 31
+#define kTile32 32
+#define kTile33 33
+#define kTile34 34
+#define kTile35 35
+#define kTile36 36
+#define kTile37 37
+#define kTile38 38
+#define kTile39 39
+#define kTile40 40
+#define kTile41 41
+#define kTile42 42
+#define kTile43 43
+#define kTile44 44
+#define kTile45 45
+#define kTile46 46
+#define kTile47 47
+#define kTile48 48
+#define kTile49 49
+#define kTile50 50
+#define kTile51 51
+#define kTile52 52
+#define kTile53 53
+#define kTile54 54
+#define kTile55 55
+#define kTile56 56
+#define kTile57 57
+#define kTile58 58
+#define kTile59 59
+#define kTile60 60
+#define kTile61 61
+#define kTile62 62
+#define kTile63 63
+#define kTile64 64
+#define kTile65 65
+#define kTile66 66
+#define kTile67 67
+#define kTile68 68
+#define kTile69 69
+#define kTile70 70
+#define kTile71 71
+#define kTile72 72
+#define kTile73 73
+#define kTile74 74
+#define kTile75 75
+#define kTile76 76
+#define kTile77 77
+#define kTile78 78
+#define kTile79 79
+#define kTile80 80
+#define kTile81 81
+#define kTile82 82
+#define kTile83 83
+#define kTile84 84
+#define kTile85 85
+#define kTile86 86
+#define kTile87 87
+#define kTile88 88
+#define kTile89 89
+#define kTile90 90
+#define kTile91 91
+#define kTile92 92
+#define kTile93 93
+#define kTile94 94
+#define kTile95 95
+#define kTile96 96
+#define kTile97 97
+#define kTile98 98
+#define kTile99 99
+#define kTile100 100
+#define kTile101 101
+#define kTile102 102
+#define kTile103 103
+#define kTile104 104
+#define kTile105 105
+#define kTile106 106
+#define kTile107 107
+#define kTile108 108
+#define kTile109 109
+#define kTile110 110
+#define kTile111 111
+#define kTile112 112
+#define kTile113 113
+#define kTile114 114
+#define kTile115 115
+#define kTile116 116
+#define kTile117 117
+#define kTile118 118
+#define kTile119 119
+#define kTile120 120
+#define kTile121 121
+#define kTile122 122
+#define kTile123 123
+#define kTile124 124
+#define kTile125 125
+#define kTile126 126
+#define kTile127 127
+#define kTile128 128
+#define kTile129 129
+#define kTile130 130
+#define kTile131 131
+#define kTile132 132
+#define kTile133 133
+#define kTile134 134
+#define kTile135 135
+#define kTile136 136
+#define kTile137 137
+#define kTile138 138
+#define kTile139 139
+#define kTile140 140
+#define kTile141 141
+#define kTile142 142
+#define kTile143 143
+#define kTile144 144
+#define kTile145 145
+#define kTile146 146
+#define kTile147 147
+#define kTile148 148
+#define kTile149 149
+#define kTile150 150
+#define kTile151 151
+#define kTile152 152
+#define kTile153 153
+#define kTile154 154
+#define kTile155 155
+#define kTile156 156
+#define kTile157 157
+#define kTile158 158
+#define kTile159 159
+#define kTile160 160
+#define kTile161 161
+#define kTile162 162
+#define kTile163 163
+#define kTile164 164
+#define kTile165 165
+#define kTile166 166
+#define kTile167 167
+#define kTile168 168
+#define kTile169 169
+#define kTile170 170
+#define kTile171 171
+#define kTile172 172
+#define kTile173 173
+#define kTile174 174
+#define kTile175 175
+#define kTile176 176
+#define kTile177 177
+#define kTile178 178
+#define kTile179 179
+#define kTile180 180
+#define kTile181 181
+#define kTile182 182
+#define kTile183 183
+#define kTile184 184
+#define kTile185 185
+#define kTile186 186
+#define kTile187 187
+#define kTile188 188
+#define kTile189 189
+#define kTile190 190
+#define kTile191 191
+#define kTile192 192
+#define kTile193 193
+#define kTile194 194
+#define kTile195 195
+#define kTile196 196
+#define kTile197 197
+#define kTile198 198
+#define kTile199 199
+#define kTile200 200
+#define kTile201 201
+#define kTile202 202
+#define kTile203 203
+#define kTile204 204
+#define kTile205 205
+#define kTile206 206
+#define kTile207 207
+#define kTile208 208
+#define kTile209 209
+#define kTile210 210
+#define kTile211 211
+#define kTile212 212
+#define kTile213 213
+#define kTile214 214
+#define kTile215 215
+#define kTile216 216
+#define kTile217 217
+#define kTile218 218
+#define kTile219 219
+#define kTile220 220
+#define kTile221 221
+#define kTile222 222
+#define kTile223 223
+#define kTile224 224
+#define kTile225 225
+#define kTile226 226
+#define kTile227 227
+#define kTile228 228
+#define kTile229 229
+#define kTile230 230
+#define kTile231 231
+#define kTile232 232
+#define kTile233 233
+#define kTile234 234
+#define kTile235 235
+#define kTile236 236
+#define kTile237 237
+#define kTile238 238
+#define kTile239 239
+#define kTile240 240
+#define kTile241 241
+#define kTile242 242
+#define kTile243 243
+#define kTile244 244
+#define kTile245 245
+#define kTile246 246
+#define kTile247 247
+#define kTile248 248
+#define kTile249 249
+#define kTile250 250
+#define kTile251 251
+#define kTile252 252
+#define kTile253 253
+#define kTile254 254
+#define kTile255 255
+#define kTile256 256
+#define kTile257 257
+#define kTile258 258
+#define kTile259 259
+#define kTile260 260
+#define kTile261 261
+#define kTile262 262
+#define kTile263 263
+#define kTile264 264
+#define kTile265 265
+#define kTile266 266
+#define kTile267 267
+#define kTile268 268
+#define kTile269 269
+#define kTile270 270
+#define kTile271 271
+#define kTile272 272
+#define kTile273 273
+#define kTile274 274
+#define kTile275 275
+#define kTile276 276
+#define kTile277 277
+#define kTile278 278
+#define kTile279 279
+#define kTile280 280
+#define kTile281 281
+#define kTile282 282
+#define kTile283 283
+#define kTile284 284
+#define kTile285 285
+#define kTile286 286
+#define kTile287 287
+#define kTile288 288
+#define kTile289 289
+#define kTile290 290
+#define kTile291 291
+#define kTile292 292
+#define kTile293 293
+#define kTile294 294
+#define kTile295 295
+#define kTile296 296
+#define kTile297 297
+#define kTile298 298
+#define kTile299 299
+#define kTile300 300
+#define kTile301 301
+#define kTile302 302
+#define kTile303 303
+#define kTile304 304
+#define kTile305 305
+#define kTile306 306
+#define kTile307 307
+#define kTile308 308
+#define kTile309 309
+#define kTile310 310
+#define kTile311 311
+#define kTile312 312
+#define kTile313 313
+#define kTile314 314
+#define kTile315 315
+#define kTile316 316
+#define kTile317 317
+#define kTile318 318
+#define kTile319 319
+#define kTile320 320
+#define kTile321 321
+#define kTile322 322
+#define kTile323 323
+#define kTile324 324
+#define kTile325 325
+#define kTile326 326
+#define kTile327 327
+#define kTile328 328
+#define kTile329 329
+#define kTile330 330
+#define kTile331 331
+#define kTile332 332
+#define kTile333 333
+#define kTile334 334
+#define kTile335 335
+#define kTile336 336
+#define kTile337 337
+#define kTile338 338
+#define kTile339 339
+#define kTile340 340
+#define kTile341 341
+#define kTile342 342
+#define kTile343 343
+#define kTile344 344
+#define kTile345 345
+#define kTile346 346
+#define kTile347 347
+#define kTile348 348
+#define kTile349 349
+#define kTile350 350
+#define kTile351 351
+#define kTile352 352
+#define kTile353 353
+#define kTile354 354
+#define kTile355 355
+#define kTile356 356
+#define kTile357 357
+#define kTile358 358
+#define kTile359 359
+#define kTile360 360
+#define kTile361 361
+#define kTile362 362
+#define kTile363 363
+#define kTile364 364
+#define kTile365 365
+#define kTile366 366
+#define kTile367 367
+#define kTile368 368
+#define kTile369 369
+#define kTile370 370
+#define kTile371 371
+#define kTile372 372
+#define kTile373 373
+#define kTile374 374
+#define kTile375 375
+#define kTile376 376
+#define kTile377 377
+#define kTile378 378
+#define kTile379 379
+#define kTile380 380
+#define kTile381 381
+#define kTile382 382
+#define kTile383 383
+#define kTile384 384
+#define kTile385 385
+#define kTile386 386
+#define kTile387 387
+#define kTile388 388
+#define kTile389 389
+#define kTile390 390
+#define kTile391 391
+#define kTile392 392
+#define kTile393 393
+#define kTile394 394
+#define kTile395 395
+#define kTile396 396
+#define kTile397 397
+#define kTile398 398
+#define kTile399 399
+#define kTile400 400
+#define kTile401 401
+#define kTile402 402
+#define kTile403 403
+#define kTile404 404
+#define kTile405 405
+#define kTile406 406
+#define kTile407 407
+#define kTile408 408
+#define kTile409 409
+#define kTile410 410
+#define kTile411 411
+#define kTile412 412
+#define kTile413 413
+#define kTile414 414
+#define kTile415 415
+#define kTile416 416
+#define kTile417 417
+#define kTile418 418
+#define kTile419 419
+#define kTile420 420
+#define kTile421 421
+#define kTile422 422
+#define kTile423 423
+#define kTile424 424
+#define kTile425 425
+#define kTile426 426
+#define kTile427 427
+#define kTile428 428
+#define kTile429 429
+#define kTile430 430
+#define kTile431 431
+#define kTile432 432
+#define kTile433 433
+#define kTile434 434
+#define kTile435 435
+#define kTile436 436
+#define kTile437 437
+#define kTile438 438
+#define kTile439 439
+#define kTile440 440
+#define kTile441 441
+#define kTile442 442
+#define kTile443 443
+#define kTile444 444
+#define kTile445 445
+#define kTile446 446
+#define kTile447 447
+#define kTile448 448
+#define kTile449 449
+#define kTile450 450
+#define kTile451 451
+#define kTile452 452
+#define kTile453 453
+#define kTile454 454
+#define kTile455 455
+#define kTile456 456
+#define kTile457 457
+#define kTile458 458
+#define kTile459 459
+#define kTile460 460
+#define kTile461 461
+#define kTile462 462
+#define kTile463 463
+#define kTile464 464
+#define kTile465 465
+#define kTile466 466
+#define kTile467 467
+#define kTile468 468
+#define kTile469 469
+#define kTile470 470
+#define kTile471 471
+#define kTile472 472
+#define kTile473 473
+#define kTile474 474
+#define kTile475 475
+#define kTile476 476
+#define kTile477 477
+#define kTile478 478
+#define kTile479 479
+#define kTile480 480
+#define kTile481 481
+#define kTile482 482
+#define kTile483 483
+#define kTile484 484
+#define kTile485 485
+#define kTile486 486
+#define kTile487 487
+#define kTile488 488
+#define kTile489 489
+#define kTile490 490
+#define kTile491 491
+#define kTile492 492
+#define kTile493 493
+#define kTile494 494
+#define kTile495 495
+#define kTile496 496
+#define kTile497 497
+#define kTile498 498
+#define kTile499 499
+#define kTile500 500
+#define kTile501 501
+#define kTile502 502
+#define kTile503 503
+#define kTile504 504
+#define kTile505 505
+#define kTile506 506
+#define kTile507 507
+#define kTile508 508
+#define kTile509 509
+#define kTile510 510
+#define kTile511 511
+#define kTile512 512
+#define kTile513 513
+#define kTile514 514
+#define kTile515 515
+#define kTile516 516
+#define kTile517 517
+#define kTile518 518
+#define kTile519 519
+#define kTile520 520
+#define kTile521 521
+#define kTile522 522
+#define kTile523 523
+#define kTile524 524
+#define kTile525 525
+#define kTile526 526
+#define kTile527 527
+#define kTile528 528
+#define kTile529 529
+#define kTile530 530
+#define kTile531 531
+#define kTile532 532
+#define kTile533 533
+#define kTile534 534
+#define kTile535 535
+#define kTile536 536
+#define kTile537 537
+#define kTile538 538
+#define kTile539 539
+#define kTile540 540
+#define kTile541 541
+#define kTile542 542
+#define kTile543 543
+#define kTile544 544
+#define kTile545 545
+#define kTile546 546
+#define kTile547 547
+#define kTile548 548
+#define kTile549 549
+#define kTile550 550
+#define kTile551 551
+#define kTile552 552
+#define kTile553 553
+#define kTile554 554
+#define kTile555 555
+#define kTile556 556
+#define kTile557 557
+#define kTile558 558
+#define kTile559 559
+#define kTile560 560
+#define kTile561 561
+#define kTile562 562
+#define kTile563 563
+#define kTile564 564
+#define kTile565 565
+#define kTile566 566
+#define kTile567 567
+#define kTile568 568
+#define kTile569 569
+#define kTile570 570
+#define kTile571 571
+#define kTile572 572
+#define kTile573 573
+#define kTile574 574
+#define kTile575 575
+#define kTile576 576
+#define kTile577 577
+#define kTile578 578
+#define kTile579 579
+#define kTile580 580
+#define kTile581 581
+#define kTile582 582
+#define kTile583 583
+#define kTile584 584
+#define kTile585 585
+#define kTile586 586
+#define kTile587 587
+#define kTile588 588
+#define kTile589 589
+#define kTileRamsesGold 590
+#define kTileRamsesWorkTile 591
+#define kTileRamsesNormal 592
+#define kTile593 593
+#define kTile594 594
+#define kTile595 595
+#define kTile596 596
+#define kTile597 597
+#define kTile598 598
+#define kTile599 599
+#define kTile600 600
+#define kTile601 601
+#define kTile602 602
+#define kTile603 603
+#define kTile604 604
+#define kTile605 605
+#define kTile606 606
+#define kTile607 607
+#define kTile608 608
+#define kTile609 609
+#define kTile610 610
+#define kTile611 611
+#define kTile612 612
+#define kTile613 613
+#define kTile614 614
+#define kTile615 615
+#define kTile616 616
+#define kTile617 617
+#define kTile618 618
+#define kTile619 619
+#define kTile620 620
+#define kTile621 621
+#define kTile622 622
+#define kTile623 623
+#define kTile624 624
+#define kTile625 625
+#define kTile626 626
+#define kTile627 627
+#define kTile628 628
+#define kTile629 629
+#define kTile630 630
+#define kTile631 631
+#define kTile632 632
+#define kTile633 633
+#define kTile634 634
+#define kTile635 635
+#define kTile636 636
+#define kTile637 637
+#define kTile638 638
+#define kTile639 639
+#define kTile640 640
+#define kTile641 641
+#define kTile642 642
+#define kTile643 643
+#define kTile644 644
+#define kTile645 645
+#define kTile646 646
+#define kTile647 647
+#define kTile648 648
+#define kTile649 649
+#define kTile650 650
+#define kTile651 651
+#define kTile652 652
+#define kTile653 653
+#define kTile654 654
+#define kTile655 655
+#define kTile656 656
+#define kTile657 657
+#define kTile658 658
+#define kTile659 659
+#define kTile660 660
+#define kTile661 661
+#define kTile662 662
+#define kTile663 663
+#define kTile664 664
+#define kTile665 665
+#define kTile666 666
+#define kTile667 667
+#define kTile668 668
+#define kTile669 669
+#define kTile670 670
+#define kTile671 671
+#define kTile672 672
+#define kTile673 673
+#define kTile674 674
+#define kTile675 675
+#define kTile676 676
+#define kTile677 677
+#define kTile678 678
+#define kTile679 679
+#define kTile680 680
+#define kTile681 681
+#define kTile682 682
+#define kTile683 683
+#define kTile684 684
+#define kTile685 685
+#define kTile686 686
+#define kTile687 687
+#define kTile688 688
+#define kTile689 689
+#define kTile690 690
+#define kTile691 691
+#define kTile692 692
+#define kTile693 693
+#define kTile694 694
+#define kTile695 695
+#define kTile696 696
+#define kTile697 697
+#define kTile698 698
+#define kTile699 699
+#define kTile700 700
+#define kTile701 701
+#define kTile702 702
+#define kTile703 703
+#define kTile704 704
+#define kTile705 705
+#define kTile706 706
+#define kTile707 707
+#define kTile708 708
+#define kTile709 709
+#define kTile710 710
+#define kTile711 711
+#define kTile712 712
+#define kTile713 713
+#define kTile714 714
+#define kTile715 715
+#define kTile716 716
+#define kTile717 717
+#define kTile718 718
+#define kTile719 719
+#define kTile720 720
+#define kTile721 721
+#define kTile722 722
+#define kTile723 723
+#define kTile724 724
+#define kTile725 725
+#define kTile726 726
+#define kTile727 727
+#define kTile728 728
+#define kTile729 729
+#define kTile730 730
+#define kTile731 731
+#define kTile732 732
+#define kTile733 733
+#define kTile734 734
+#define kTile735 735
+#define kTile736 736
+#define kTile737 737
+#define kTile738 738
+#define kTile739 739
+#define kTile740 740
+#define kTile741 741
+#define kTile742 742
+#define kTile743 743
+#define kTile744 744
+#define kTile745 745
+#define kTile746 746
+#define kTile747 747
+#define kTile748 748
+#define kTile749 749
+#define kTile750 750
+#define kTile751 751
+#define kTile752 752
+#define kTile753 753
+#define kTile754 754
+#define kTile755 755
+#define kTile756 756
+#define kTile757 757
+#define kTile758 758
+#define kTile759 759
+#define kTile760 760
+#define kTile761 761
+#define kTile762 762
+#define kTile763 763
+#define kMovieTile 764
+#define kTile765 765
+#define kTile766 766
+#define kTile767 767
+#define kTile768 768
+#define kTile769 769
+#define kTile770 770
+#define kTile771 771
+#define kTile772 772
+#define kTile773 773
+#define kTile774 774
+#define kTile775 775
+#define kTile776 776
+#define kTile777 777
+#define kTile778 778
+#define kTile779 779
+#define kTile780 780
+#define kTile781 781
+#define kTile782 782
+#define kTile783 783
+#define kTile784 784
+#define kTile785 785
+#define kTile786 786
+#define kTile787 787
+#define kTile788 788
+#define kTile789 789
+#define kTile790 790
+#define kTile791 791
+#define kTile792 792
+#define kTile793 793
+#define kTile794 794
+#define kTile795 795
+#define kTile796 796
+#define kTile797 797
+#define kTile798 798
+#define kTile799 799
+#define kTile800 800
+#define kTile801 801
+#define kTile802 802
+#define kTile803 803
+#define kTile804 804
+#define kTile805 805
+#define kTile806 806
+#define kTile807 807
+#define kTile808 808
+#define kTile809 809
+#define kTile810 810
+#define kTile811 811
+#define kTile812 812
+#define kTile813 813
+#define kTile814 814
+#define kTile815 815
+#define kTile816 816
+#define kTile817 817
+#define kTile818 818
+#define kTile819 819
+#define kTile820 820
+#define kTile821 821
+#define kTile822 822
+#define kTile823 823
+#define kTile824 824
+#define kTile825 825
+#define kTile826 826
+#define kTile827 827
+#define kTile828 828
+#define kTile829 829
+#define kTile830 830
+#define kTile831 831
+#define kTile832 832
+#define kTile833 833
+#define kTile834 834
+#define kTile835 835
+#define kTile836 836
+#define kTile837 837
+#define kTile838 838
+#define kTile839 839
+#define kTile840 840
+#define kTile841 841
+#define kTile842 842
+#define kTile843 843
+#define kTile844 844
+#define kTile845 845
+#define kTile846 846
+#define kTile847 847
+#define kTile848 848
+#define kTile849 849
+#define kTile850 850
+#define kTile851 851
+#define kTile852 852
+#define kTile853 853
+#define kTile854 854
+#define kTile855 855
+#define kTile856 856
+#define kTile857 857
+#define kTile858 858
+#define kTile859 859
+#define kTile860 860
+#define kTile861 861
+#define kTile862 862
+#define kTile863 863
+#define kTile864 864
+#define kTile865 865
+#define kTile866 866
+#define kTile867 867
+#define kTile868 868
+#define kTile869 869
+#define kTile870 870
+#define kTile871 871
+#define kTile872 872
+#define kTile873 873
+#define kTile874 874
+#define kTile875 875
+#define kTile876 876
+#define kTile877 877
+#define kTile878 878
+#define kTile879 879
+#define kTile880 880
+#define kTile881 881
+#define kTile882 882
+#define kTile883 883
+#define kTile884 884
+#define kTile885 885
+#define kTile886 886
+#define kTile887 887
+#define kTile888 888
+#define kTile889 889
+#define kTile890 890
+#define kTile891 891
+#define kTile892 892
+#define kTile893 893
+#define kTile894 894
+#define kTile895 895
+#define kTile896 896
+#define kTile897 897
+#define kTile898 898
+#define kTile899 899
+#define kTile900 900
+#define kTile901 901
+#define kTile902 902
+#define kTile903 903
+#define kTile904 904
+#define kTile905 905
+#define kTile906 906
+#define kTile907 907
+#define kTile908 908
+#define kTile909 909
+#define kTile910 910
+#define kTile911 911
+#define kTile912 912
+#define kTile913 913
+#define kTile914 914
+#define kTile915 915
+#define kTile916 916
+#define kTile917 917
+#define kTile918 918
+#define kTile919 919
+#define kTile920 920
+#define kTile921 921
+#define kTile922 922
+#define kTile923 923
+#define kTile924 924
+#define kTile925 925
+#define kTile926 926
+#define kTile927 927
+#define kTile928 928
+#define kTile929 929
+#define kTile930 930
+#define kTile931 931
+#define kTile932 932
+#define kTile933 933
+#define kTile934 934
+#define kTile935 935
+#define kTile936 936
+#define kTile937 937
+#define kTile938 938
+#define kTile939 939
+#define kTile940 940
+#define kTile941 941
+#define kTile942 942
+#define kTile943 943
+#define kTile944 944
+#define kTile945 945
+#define kTile946 946
+#define kTile947 947
+#define kTile948 948
+#define kTile949 949
+#define kTile950 950
+#define kTile951 951
+#define kTile952 952
+#define kTile953 953
+#define kTile954 954
+#define kTile955 955
+#define kTile956 956
+#define kTile957 957
+#define kTile958 958
+#define kTile959 959
+#define kTile960 960
+#define kTile961 961
+#define kTile962 962
+#define kTile963 963
+#define kTile964 964
+#define kTile965 965
+#define kTile966 966
+#define kTile967 967
+#define kTile968 968
+#define kTile969 969
+#define kTile970 970
+#define kTile971 971
+#define kTile972 972
+#define kTile973 973
+#define kTile974 974
+#define kTile975 975
+#define kTile976 976
+#define kTile977 977
+#define kTile978 978
+#define kTile979 979
+#define kTile980 980
+#define kTile981 981
+#define kTile982 982
+#define kTile983 983
+#define kTile984 984
+#define kTile985 985
+#define kTile986 986
+#define kTile987 987
+#define kTile988 988
+#define kTile989 989
+#define kTile990 990
+#define kTile991 991
+#define kTile992 992
+#define kTile993 993
+#define kTile994 994
+#define kTile995 995
+#define kTile996 996
+#define kTile997 997
+#define kTile998 998
+#define kTile999 999
+#define kTile1000 1000
+#define kTile1001 1001
+#define kTile1002 1002
+#define kTile1003 1003
+#define kTile1004 1004
+#define kTile1005 1005
+#define kTile1006 1006
+#define kTile1007 1007
+#define kTile1008 1008
+#define kTile1009 1009
+#define kTile1010 1010
+#define kTile1011 1011
+#define kTile1012 1012
+#define kTile1013 1013
+#define kTile1014 1014
+#define kTile1015 1015
+#define kTile1016 1016
+#define kTile1017 1017
+#define kTile1018 1018
+#define kTile1019 1019
+#define kTile1020 1020
+#define kTile1021 1021
+#define kTile1022 1022
+#define kTile1023 1023
+#define kTile1024 1024
+#define kTile1025 1025
+#define kTile1026 1026
+#define kTile1027 1027
+#define kTile1028 1028
+#define kTile1029 1029
+#define kTile1030 1030
+#define kTile1031 1031
+#define kTile1032 1032
+#define kTile1033 1033
+#define kTile1034 1034
+#define kTile1035 1035
+#define kTile1036 1036
+#define kTile1037 1037
+#define kTile1038 1038
+#define kTile1039 1039
+#define kTile1040 1040
+#define kTile1041 1041
+#define kTile1042 1042
+#define kTile1043 1043
+#define kTile1044 1044
+#define kTile1045 1045
+#define kTile1046 1046
+#define kTile1047 1047
+#define kTile1048 1048
+#define kTile1049 1049
+#define kTile1050 1050
+#define kTile1051 1051
+#define kTile1052 1052
+#define kTile1053 1053
+#define kTile1054 1054
+#define kTile1055 1055
+#define kTile1056 1056
+#define kTile1057 1057
+#define kTile1058 1058
+#define kTile1059 1059
+#define kTile1060 1060
+#define kTile1061 1061
+#define kTile1062 1062
+#define kTile1063 1063
+#define kTile1064 1064
+#define kTile1065 1065
+#define kTile1066 1066
+#define kTile1067 1067
+#define kTile1068 1068
+#define kTile1069 1069
+#define kTile1070 1070
+#define kTile1071 1071
+#define kTile1072 1072
+#define kTile1073 1073
+#define kTile1074 1074
+#define kTile1075 1075
+#define kTile1076 1076
+#define kTile1077 1077
+#define kTile1078 1078
+#define kTile1079 1079
+#define kTile1080 1080
+#define kTile1081 1081
+#define kTile1082 1082
+#define kTile1083 1083
+#define kTile1084 1084
+#define kTile1085 1085
+#define kTile1086 1086
+#define kTile1087 1087
+#define kTile1088 1088
+#define kTile1089 1089
+#define kTile1090 1090
+#define kTile1091 1091
+#define kTile1092 1092
+#define kTile1093 1093
+#define kTile1094 1094
+#define kTile1095 1095
+#define kTile1096 1096
+#define kTile1097 1097
+#define kTile1098 1098
+#define kTile1099 1099
+#define kTile1100 1100
+#define kTile1101 1101
+#define kTile1102 1102
+#define kTile1103 1103
+#define kTile1104 1104
+#define kTile1105 1105
+#define kTile1106 1106
+#define kTile1107 1107
+#define kTile1108 1108
+#define kTile1109 1109
+#define kTile1110 1110
+#define kTile1111 1111
+#define kTile1112 1112
+#define kTile1113 1113
+#define kTile1114 1114
+#define kTile1115 1115
+#define kTile1116 1116
+#define kTile1117 1117
+#define kTile1118 1118
+#define kTile1119 1119
+#define kTile1120 1120
+#define kTile1121 1121
+#define kTile1122 1122
+#define kTile1123 1123
+#define kTile1124 1124
+#define kTile1125 1125
+#define kTile1126 1126
+#define kTile1127 1127
+#define kTile1128 1128
+#define kTile1129 1129
+#define kTile1130 1130
+#define kTile1131 1131
+#define kTile1132 1132
+#define kTile1133 1133
+#define kTile1134 1134
+#define kTile1135 1135
+#define kTile1136 1136
+#define kTile1137 1137
+#define kTile1138 1138
+#define kTile1139 1139
+#define kTile1140 1140
+#define kTile1141 1141
+#define kTile1142 1142
+#define kTile1143 1143
+#define kTile1144 1144
+#define kTile1145 1145
+#define kTile1146 1146
+#define kTile1147 1147
+#define kTile1148 1148
+#define kTile1149 1149
+#define kTile1150 1150
+#define kTile1151 1151
+#define kTile1152 1152
+#define kTile1153 1153
+#define kTile1154 1154
+#define kTile1155 1155
+#define kTile1156 1156
+#define kTile1157 1157
+#define kTile1158 1158
+#define kTile1159 1159
+#define kTile1160 1160
+#define kTile1161 1161
+#define kTile1162 1162
+#define kTile1163 1163
+#define kTile1164 1164
+#define kTile1165 1165
+#define kTile1166 1166
+#define kTile1167 1167
+#define kTile1168 1168
+#define kTile1169 1169
+#define kTile1170 1170
+#define kTile1171 1171
+#define kTile1172 1172
+#define kTile1173 1173
+#define kTile1174 1174
+#define kTile1175 1175
+#define kTile1176 1176
+#define kTile1177 1177
+#define kTile1178 1178
+#define kTile1179 1179
+#define kTile1180 1180
+#define kTile1181 1181
+#define kTile1182 1182
+#define kTile1183 1183
+#define kTile1184 1184
+#define kTile1185 1185
+#define kTile1186 1186
+#define kTile1187 1187
+#define kTile1188 1188
+#define kTile1189 1189
+#define kTile1190 1190
+#define kTile1191 1191
+#define kTile1192 1192
+#define kTile1193 1193
+#define kTile1194 1194
+#define kTile1195 1195
+#define kTile1196 1196
+#define kTile1197 1197
+#define kTile1198 1198
+#define kTile1199 1199
+#define kTile1200 1200
+#define kTile1201 1201
+#define kTile1202 1202
+#define kTile1203 1203
+#define kTile1204 1204
+#define kTile1205 1205
+#define kTile1206 1206
+#define kTile1207 1207
+#define kTile1208 1208
+#define kTile1209 1209
+#define kTile1210 1210
+#define kTile1211 1211
+#define kTile1212 1212
+#define kTile1213 1213
+#define kTile1214 1214
+#define kTile1215 1215
+#define kTile1216 1216
+#define kTile1217 1217
+#define kTile1218 1218
+#define kTile1219 1219
+#define kTile1220 1220
+#define kTile1221 1221
+#define kTile1222 1222
+#define kTile1223 1223
+#define kTile1224 1224
+#define kTile1225 1225
+#define kTile1226 1226
+#define kTile1227 1227
+#define kTile1228 1228
+#define kTile1229 1229
+#define kTile1230 1230
+#define kTile1231 1231
+#define kTile1232 1232
+#define kTile1233 1233
+#define kTile1234 1234
+#define kTile1235 1235
+#define kTile1236 1236
+#define kTile1237 1237
+#define kTile1238 1238
+#define kTile1239 1239
+#define kTile1240 1240
+#define kTile1241 1241
+#define kTile1242 1242
+#define kTile1243 1243
+#define kTile1244 1244
+#define kTile1245 1245
+#define kTile1246 1246
+#define kTile1247 1247
+#define kTile1248 1248
+#define kTile1249 1249
+#define kTile1250 1250
+#define kTile1251 1251
+#define kTile1252 1252
+#define kTile1253 1253
+#define kTile1254 1254
+#define kTile1255 1255
+#define kTile1256 1256
+#define kTile1257 1257
+#define kTile1258 1258
+#define kTile1259 1259
+#define kTile1260 1260
+#define kTile1261 1261
+#define kTile1262 1262
+#define kTile1263 1263
+#define kTile1264 1264
+#define kTile1265 1265
+#define kTile1266 1266
+#define kTile1267 1267
+#define kTile1268 1268
+#define kTile1269 1269
+#define kTile1270 1270
+#define kTile1271 1271
+#define kTile1272 1272
+#define kTile1273 1273
+#define kTile1274 1274
+#define kTile1275 1275
+#define kTile1276 1276
+#define kTile1277 1277
+#define kTile1278 1278
+#define kTile1279 1279
+#define kTile1280 1280
+#define kTile1281 1281
+#define kTile1282 1282
+#define kTile1283 1283
+#define kTile1284 1284
+#define kTile1285 1285
+#define kTile1286 1286
+#define kTile1287 1287
+#define kTile1288 1288
+#define kTile1289 1289
+#define kTile1290 1290
+#define kTile1291 1291
+#define kTile1292 1292
+#define kTile1293 1293
+#define kTile1294 1294
+#define kTile1295 1295
+#define kTile1296 1296
+#define kTile1297 1297
+#define kTile1298 1298
+#define kTile1299 1299
+#define kTile1300 1300
+#define kTile1301 1301
+#define kTile1302 1302
+#define kTile1303 1303
+#define kTile1304 1304
+#define kTile1305 1305
+#define kTile1306 1306
+#define kTile1307 1307
+#define kTile1308 1308
+#define kTile1309 1309
+#define kTile1310 1310
+#define kTile1311 1311
+#define kTile1312 1312
+#define kTile1313 1313
+#define kTile1314 1314
+#define kTile1315 1315
+#define kTile1316 1316
+#define kTile1317 1317
+#define kTile1318 1318
+#define kTile1319 1319
+#define kTile1320 1320
+#define kTile1321 1321
+#define kTile1322 1322
+#define kTile1323 1323
+#define kTile1324 1324
+#define kTile1325 1325
+#define kTile1326 1326
+#define kTile1327 1327
+#define kTile1328 1328
+#define kTile1329 1329
+#define kTile1330 1330
+#define kTile1331 1331
+#define kTile1332 1332
+#define kTile1333 1333
+#define kTile1334 1334
+#define kTile1335 1335
+#define kTile1336 1336
+#define kTile1337 1337
+#define kTile1338 1338
+#define kTile1339 1339
+#define kTile1340 1340
+#define kTile1341 1341
+#define kTile1342 1342
+#define kTile1343 1343
+#define kTile1344 1344
+#define kTile1345 1345
+#define kTile1346 1346
+#define kTile1347 1347
+#define kTile1348 1348
+#define kTile1349 1349
+#define kTile1350 1350
+#define kTile1351 1351
+#define kTile1352 1352
+#define kTile1353 1353
+#define kTile1354 1354
+#define kTile1355 1355
+#define kTile1356 1356
+#define kTile1357 1357
+#define kTile1358 1358
+#define kTile1359 1359
+#define kTile1360 1360
+#define kTile1361 1361
+#define kTile1362 1362
+#define kTile1363 1363
+#define kTile1364 1364
+#define kTile1365 1365
+#define kTile1366 1366
+#define kTile1367 1367
+#define kTile1368 1368
+#define kTile1369 1369
+#define kTile1370 1370
+#define kTile1371 1371
+#define kTile1372 1372
+#define kTile1373 1373
+#define kTile1374 1374
+#define kTile1375 1375
+#define kTile1376 1376
+#define kTile1377 1377
+#define kTile1378 1378
+#define kTile1379 1379
+#define kTile1380 1380
+#define kTile1381 1381
+#define kTile1382 1382
+#define kTile1383 1383
+#define kTile1384 1384
+#define kTile1385 1385
+#define kTile1386 1386
+#define kTile1387 1387
+#define kTile1388 1388
+#define kTile1389 1389
+#define kTile1390 1390
+#define kTile1391 1391
+#define kTile1392 1392
+#define kTile1393 1393
+#define kTile1394 1394
+#define kTile1395 1395
+#define kTile1396 1396
+#define kTile1397 1397
+#define kTile1398 1398
+#define kTile1399 1399
+#define kTile1400 1400
+#define kTile1401 1401
+#define kTile1402 1402
+#define kTile1403 1403
+#define kTile1404 1404
+#define kTile1405 1405
+#define kTile1406 1406
+#define kTile1407 1407
+#define kTile1408 1408
+#define kTile1409 1409
+#define kTile1410 1410
+#define kTile1411 1411
+#define kTile1412 1412
+#define kTile1413 1413
+#define kTile1414 1414
+#define kTile1415 1415
+#define kTile1416 1416
+#define kTile1417 1417
+#define kTile1418 1418
+#define kTile1419 1419
+#define kTile1420 1420
+#define kTile1421 1421
+#define kTile1422 1422
+#define kTile1423 1423
+#define kTile1424 1424
+#define kTile1425 1425
+#define kTile1426 1426
+#define kTile1427 1427
+#define kTile1428 1428
+#define kTile1429 1429
+#define kTile1430 1430
+#define kTile1431 1431
+#define kTile1432 1432
+#define kTile1433 1433
+#define kTile1434 1434
+#define kTile1435 1435
+#define kTile1436 1436
+#define kTile1437 1437
+#define kTile1438 1438
+#define kTile1439 1439
+#define kTile1440 1440
+#define kTile1441 1441
+#define kTile1442 1442
+#define kTile1443 1443
+#define kTile1444 1444
+#define kTile1445 1445
+#define kTile1446 1446
+#define kTile1447 1447
+#define kTile1448 1448
+#define kTile1449 1449
+#define kTile1450 1450
+#define kTile1451 1451
+#define kTile1452 1452
+#define kTile1453 1453
+#define kTile1454 1454
+#define kTile1455 1455
+#define kTile1456 1456
+#define kTile1457 1457
+#define kTile1458 1458
+#define kTile1459 1459
+#define kTile1460 1460
+#define kTile1461 1461
+#define kTile1462 1462
+#define kTile1463 1463
+#define kTile1464 1464
+#define kTile1465 1465
+#define kTile1466 1466
+#define kTile1467 1467
+#define kTile1468 1468
+#define kTile1469 1469
+#define kTile1470 1470
+#define kTile1471 1471
+#define kTile1472 1472
+#define kTile1473 1473
+#define kTile1474 1474
+#define kTile1475 1475
+#define kTile1476 1476
+#define kTile1477 1477
+#define kTile1478 1478
+#define kTile1479 1479
+#define kTile1480 1480
+#define kTile1481 1481
+#define kTile1482 1482
+#define kTile1483 1483
+#define kTile1484 1484
+#define kTile1485 1485
+#define kTile1486 1486
+#define kTile1487 1487
+#define kTile1488 1488
+#define kTile1489 1489
+#define kTile1490 1490
+#define kTile1491 1491
+#define kTile1492 1492
+#define kTile1493 1493
+#define kTile1494 1494
+#define kTile1495 1495
+#define kTile1496 1496
+#define kTile1497 1497
+#define kTile1498 1498
+#define kTile1499 1499
+#define kTile1500 1500
+#define kTile1501 1501
+#define kTile1502 1502
+#define kTile1503 1503
+#define kTile1504 1504
+#define kTile1505 1505
+#define kTile1506 1506
+#define kTile1507 1507
+#define kTile1508 1508
+#define kTile1509 1509
+#define kTile1510 1510
+#define kTile1511 1511
+#define kTile1512 1512
+#define kTile1513 1513
+#define kTile1514 1514
+#define kTile1515 1515
+#define kTile1516 1516
+#define kTile1517 1517
+#define kTile1518 1518
+#define kTile1519 1519
+#define kTile1520 1520
+#define kTile1521 1521
+#define kTile1522 1522
+#define kTile1523 1523
+#define kTile1524 1524
+#define kTile1525 1525
+#define kTile1526 1526
+#define kTile1527 1527
+#define kTile1528 1528
+#define kTile1529 1529
+#define kTile1530 1530
+#define kTile1531 1531
+#define kTile1532 1532
+#define kTile1533 1533
+#define kTile1534 1534
+#define kTile1535 1535
+#define kTile1536 1536
+#define kTile1537 1537
+#define kTile1538 1538
+#define kTile1539 1539
+#define kTile1540 1540
+#define kTile1541 1541
+#define kTile1542 1542
+#define kTile1543 1543
+#define kTile1544 1544
+#define kTile1545 1545
+#define kTile1546 1546
+#define kTile1547 1547
+#define kTile1548 1548
+#define kTile1549 1549
+#define kTile1550 1550
+#define kTile1551 1551
+#define kTile1552 1552
+#define kTile1553 1553
+#define kTile1554 1554
+#define kTile1555 1555
+#define kTile1556 1556
+#define kTile1557 1557
+#define kTile1558 1558
+#define kTile1559 1559
+#define kTile1560 1560
+#define kTile1561 1561
+#define kTile1562 1562
+#define kTile1563 1563
+#define kTile1564 1564
+#define kTile1565 1565
+#define kTile1566 1566
+#define kTile1567 1567
+#define kTile1568 1568
+#define kTile1569 1569
+#define kTile1570 1570
+#define kTile1571 1571
+#define kTile1572 1572
+#define kTile1573 1573
+#define kTile1574 1574
+#define kTile1575 1575
+#define kTile1576 1576
+#define kTile1577 1577
+#define kTile1578 1578
+#define kTile1579 1579
+#define kTile1580 1580
+#define kTile1581 1581
+#define kTile1582 1582
+#define kTile1583 1583
+#define kTile1584 1584
+#define kTile1585 1585
+#define kTile1586 1586
+#define kTile1587 1587
+#define kTile1588 1588
+#define kTile1589 1589
+#define kTile1590 1590
+#define kTile1591 1591
+#define kTile1592 1592
+#define kTile1593 1593
+#define kTile1594 1594
+#define kTile1595 1595
+#define kTile1596 1596
+#define kTile1597 1597
+#define kTile1598 1598
+#define kTile1599 1599
+#define kTile1600 1600
+#define kTile1601 1601
+#define kTile1602 1602
+#define kTile1603 1603
+#define kTile1604 1604
+#define kTile1605 1605
+#define kTile1606 1606
+#define kTile1607 1607
+#define kTile1608 1608
+#define kTile1609 1609
+#define kTile1610 1610
+#define kTile1611 1611
+#define kTile1612 1612
+#define kTile1613 1613
+#define kTile1614 1614
+#define kTile1615 1615
+#define kTile1616 1616
+#define kTile1617 1617
+#define kTile1618 1618
+#define kTile1619 1619
+#define kTile1620 1620
+#define kTile1621 1621
+#define kTile1622 1622
+#define kTile1623 1623
+#define kTile1624 1624
+#define kTile1625 1625
+#define kTile1626 1626
+#define kTile1627 1627
+#define kTile1628 1628
+#define kTile1629 1629
+#define kTile1630 1630
+#define kTile1631 1631
+#define kTile1632 1632
+#define kTile1633 1633
+#define kTile1634 1634
+#define kTile1635 1635
+#define kTile1636 1636
+#define kTile1637 1637
+#define kTile1638 1638
+#define kTile1639 1639
+#define kTile1640 1640
+#define kTile1641 1641
+#define kTile1642 1642
+#define kTile1643 1643
+#define kTile1644 1644
+#define kTile1645 1645
+#define kTile1646 1646
+#define kTile1647 1647
+#define kTile1648 1648
+#define kTile1649 1649
+#define kTile1650 1650
+#define kTile1651 1651
+#define kTile1652 1652
+#define kTile1653 1653
+#define kTile1654 1654
+#define kTile1655 1655
+#define kTile1656 1656
+#define kTile1657 1657
+#define kTile1658 1658
+#define kTile1659 1659
+#define kTile1660 1660
+#define kTile1661 1661
+#define kTile1662 1662
+#define kTile1663 1663
+#define kTile1664 1664
+#define kTile1665 1665
+#define kTile1666 1666
+#define kTile1667 1667
+#define kTile1668 1668
+#define kTile1669 1669
+#define kTile1670 1670
+#define kTile1671 1671
+#define kTile1672 1672
+#define kTile1673 1673
+#define kTile1674 1674
+#define kTile1675 1675
+#define kTile1676 1676
+#define kTile1677 1677
+#define kTile1678 1678
+#define kTile1679 1679
+#define kTile1680 1680
+#define kTile1681 1681
+#define kTile1682 1682
+#define kTile1683 1683
+#define kTile1684 1684
+#define kTile1685 1685
+#define kTile1686 1686
+#define kTile1687 1687
+#define kTile1688 1688
+#define kTile1689 1689
+#define kTile1690 1690
+#define kTile1691 1691
+#define kTile1692 1692
+#define kTile1693 1693
+#define kTile1694 1694
+#define kTile1695 1695
+#define kTile1696 1696
+#define kTile1697 1697
+#define kTile1698 1698
+#define kTile1699 1699
+#define kTile1700 1700
+#define kTile1701 1701
+#define kTile1702 1702
+#define kTile1703 1703
+#define kTile1704 1704
+#define kTile1705 1705
+#define kTile1706 1706
+#define kTile1707 1707
+#define kTile1708 1708
+#define kTile1709 1709
+#define kTile1710 1710
+#define kTile1711 1711
+#define kTile1712 1712
+#define kTile1713 1713
+#define kTile1714 1714
+#define kTile1715 1715
+#define kTile1716 1716
+#define kTile1717 1717
+#define kTile1718 1718
+#define kTile1719 1719
+#define kTile1720 1720
+#define kTile1721 1721
+#define kTile1722 1722
+#define kTile1723 1723
+#define kTile1724 1724
+#define kTile1725 1725
+#define kTile1726 1726
+#define kTile1727 1727
+#define kTile1728 1728
+#define kTile1729 1729
+#define kTile1730 1730
+#define kTile1731 1731
+#define kTile1732 1732
+#define kTile1733 1733
+#define kTile1734 1734
+#define kTile1735 1735
+#define kTile1736 1736
+#define kTile1737 1737
+#define kTile1738 1738
+#define kTile1739 1739
+#define kTile1740 1740
+#define kTile1741 1741
+#define kTile1742 1742
+#define kTile1743 1743
+#define kTile1744 1744
+#define kTile1745 1745
+#define kTile1746 1746
+#define kTile1747 1747
+#define kTile1748 1748
+#define kTile1749 1749
+#define kTile1750 1750
+#define kTile1751 1751
+#define kTile1752 1752
+#define kTile1753 1753
+#define kTile1754 1754
+#define kTile1755 1755
+#define kTile1756 1756
+#define kTile1757 1757
+#define kTile1758 1758
+#define kTile1759 1759
+#define kTile1760 1760
+#define kTile1761 1761
+#define kTile1762 1762
+#define kTile1763 1763
+#define kTile1764 1764
+#define kTile1765 1765
+#define kTile1766 1766
+#define kTile1767 1767
+#define kTile1768 1768
+#define kTile1769 1769
+#define kTile1770 1770
+#define kTile1771 1771
+#define kTile1772 1772
+#define kTile1773 1773
+#define kTile1774 1774
+#define kTile1775 1775
+#define kTile1776 1776
+#define kTile1777 1777
+#define kTile1778 1778
+#define kTile1779 1779
+#define kTile1780 1780
+#define kTile1781 1781
+#define kTile1782 1782
+#define kTile1783 1783
+#define kTile1784 1784
+#define kTile1785 1785
+#define kTile1786 1786
+#define kTile1787 1787
+#define kTile1788 1788
+#define kTile1789 1789
+#define kTile1790 1790
+#define kTile1791 1791
+#define kTile1792 1792
+#define kTile1793 1793
+#define kTile1794 1794
+#define kTile1795 1795
+#define kTile1796 1796
+#define kTile1797 1797
+#define kTile1798 1798
+#define kTile1799 1799
+#define kTile1800 1800
+#define kTile1801 1801
+#define kTile1802 1802
+#define kTile1803 1803
+#define kTile1804 1804
+#define kTile1805 1805
+#define kTile1806 1806
+#define kTile1807 1807
+#define kTile1808 1808
+#define kTile1809 1809
+#define kTile1810 1810
+#define kTile1811 1811
+#define kTile1812 1812
+#define kTile1813 1813
+#define kTile1814 1814
+#define kTile1815 1815
+#define kTile1816 1816
+#define kTile1817 1817
+#define kTile1818 1818
+#define kTile1819 1819
+#define kTile1820 1820
+#define kTile1821 1821
+#define kTile1822 1822
+#define kTile1823 1823
+#define kTile1824 1824
+#define kTile1825 1825
+#define kTile1826 1826
+#define kTile1827 1827
+#define kTile1828 1828
+#define kTile1829 1829
+#define kTile1830 1830
+#define kTile1831 1831
+#define kTile1832 1832
+#define kTile1833 1833
+#define kTile1834 1834
+#define kTile1835 1835
+#define kTile1836 1836
+#define kTile1837 1837
+#define kTile1838 1838
+#define kTile1839 1839
+#define kTile1840 1840
+#define kTile1841 1841
+#define kTile1842 1842
+#define kTile1843 1843
+#define kTile1844 1844
+#define kTile1845 1845
+#define kTile1846 1846
+#define kTile1847 1847
+#define kTile1848 1848
+#define kTile1849 1849
+#define kTile1850 1850
+#define kTile1851 1851
+#define kTile1852 1852
+#define kTile1853 1853
+#define kTile1854 1854
+#define kTile1855 1855
+#define kTile1856 1856
+#define kTile1857 1857
+#define kTile1858 1858
+#define kTile1859 1859
+#define kTile1860 1860
+#define kTile1861 1861
+#define kTile1862 1862
+#define kTile1863 1863
+#define kTile1864 1864
+#define kTile1865 1865
+#define kTile1866 1866
+#define kTile1867 1867
+#define kTile1868 1868
+#define kTile1869 1869
+#define kTile1870 1870
+#define kTile1871 1871
+#define kTile1872 1872
+#define kTile1873 1873
+#define kTile1874 1874
+#define kTile1875 1875
+#define kTile1876 1876
+#define kTile1877 1877
+#define kTile1878 1878
+#define kTile1879 1879
+#define kTile1880 1880
+#define kTile1881 1881
+#define kTile1882 1882
+#define kTile1883 1883
+#define kTile1884 1884
+#define kTile1885 1885
+#define kTile1886 1886
+#define kTile1887 1887
+#define kTile1888 1888
+#define kTile1889 1889
+#define kTile1890 1890
+#define kTile1891 1891
+#define kTile1892 1892
+#define kTile1893 1893
+#define kTile1894 1894
+#define kTile1895 1895
+#define kTile1896 1896
+#define kTile1897 1897
+#define kTile1898 1898
+#define kTile1899 1899
+#define kTile1900 1900
+#define kTile1901 1901
+#define kTile1902 1902
+#define kTile1903 1903
+#define kTile1904 1904
+#define kTile1905 1905
+#define kTile1906 1906
+#define kTile1907 1907
+#define kTile1908 1908
+#define kTile1909 1909
+#define kTile1910 1910
+#define kTile1911 1911
+#define kTile1912 1912
+#define kTile1913 1913
+#define kTile1914 1914
+#define kTile1915 1915
+#define kTile1916 1916
+#define kTile1917 1917
+#define kTile1918 1918
+#define kTile1919 1919
+#define kTile1920 1920
+#define kTile1921 1921
+#define kTile1922 1922
+#define kTile1923 1923
+#define kTile1924 1924
+#define kTile1925 1925
+#define kTile1926 1926
+#define kTile1927 1927
+#define kTile1928 1928
+#define kTile1929 1929
+#define kTile1930 1930
+#define kTile1931 1931
+#define kTile1932 1932
+#define kTile1933 1933
+#define kTile1934 1934
+#define kTile1935 1935
+#define kTile1936 1936
+#define kTile1937 1937
+#define kTile1938 1938
+#define kTile1939 1939
+#define kTile1940 1940
+#define kTile1941 1941
+#define kTile1942 1942
+#define kTile1943 1943
+#define kTile1944 1944
+#define kTile1945 1945
+#define kTile1946 1946
+#define kTile1947 1947
+#define kTile1948 1948
+#define kTile1949 1949
+#define kTile1950 1950
+#define kTile1951 1951
+#define kTile1952 1952
+#define kTile1953 1953
+#define kTile1954 1954
+#define kTile1955 1955
+#define kTile1956 1956
+#define kTile1957 1957
+#define kTile1958 1958
+#define kTile1959 1959
+#define kTile1960 1960
+#define kTile1961 1961
+#define kTile1962 1962
+#define kTile1963 1963
+#define kTile1964 1964
+#define kTile1965 1965
+#define kTile1966 1966
+#define kTile1967 1967
+#define kTile1968 1968
+#define kTile1969 1969
+#define kTile1970 1970
+#define kTile1971 1971
+#define kTile1972 1972
+#define kTile1973 1973
+#define kTile1974 1974
+#define kTile1975 1975
+#define kTile1976 1976
+#define kTile1977 1977
+#define kTile1978 1978
+#define kTile1979 1979
+#define kTile1980 1980
+#define kTile1981 1981
+#define kTile1982 1982
+#define kTile1983 1983
+#define kTile1984 1984
+#define kTile1985 1985
+#define kTile1986 1986
+#define kTile1987 1987
+#define kTile1988 1988
+#define kTile1989 1989
+#define kTile1990 1990
+#define kTile1991 1991
+#define kTile1992 1992
+#define kTile1993 1993
+#define kTile1994 1994
+#define kTile1995 1995
+#define kTile1996 1996
+#define kTile1997 1997
+#define kTile1998 1998
+#define kTile1999 1999
+#define kTile2000 2000
+#define kTile2001 2001
+#define kTile2002 2002
+#define kTile2003 2003
+#define kTile2004 2004
+#define kTile2005 2005
+#define kTile2006 2006
+#define kTile2007 2007
+#define kTile2008 2008
+#define kTile2009 2009
+#define kTile2010 2010
+#define kTile2011 2011
+#define kTile2012 2012
+#define kTile2013 2013
+#define kTile2014 2014
+#define kTile2015 2015
+#define kTile2016 2016
+#define kTile2017 2017
+#define kTile2018 2018
+#define kTile2019 2019
+#define kTile2020 2020
+#define kTile2021 2021
+#define kTile2022 2022
+#define kTile2023 2023
+#define kTile2024 2024
+#define kTile2025 2025
+#define kTile2026 2026
+#define kTile2027 2027
+#define kTile2028 2028
+#define kTile2029 2029
+#define kTile2030 2030
+#define kTile2031 2031
+#define kTile2032 2032
+#define kTile2033 2033
+#define kTile2034 2034
+#define kTile2035 2035
+#define kTile2036 2036
+#define kTile2037 2037
+#define kTile2038 2038
+#define kTile2039 2039
+#define kTile2040 2040
+#define kTile2041 2041
+#define kTile2042 2042
+#define kTile2043 2043
+#define kTile2044 2044
+#define kTile2045 2045
+#define kTile2046 2046
+#define kTile2047 2047
+#define kTile2048 2048
+#define kTile2049 2049
+#define kTile2050 2050
+#define kTile2051 2051
+#define kTile2052 2052
+#define kTile2053 2053
+#define kTile2054 2054
+#define kTile2055 2055
+#define kTile2056 2056
+#define kTile2057 2057
+#define kTile2058 2058
+#define kTile2059 2059
+#define kTile2060 2060
+#define kTile2061 2061
+#define kTile2062 2062
+#define kTile2063 2063
+#define kTile2064 2064
+#define kTile2065 2065
+#define kTile2066 2066
+#define kTile2067 2067
+#define kTile2068 2068
+#define kTile2069 2069
+#define kTile2070 2070
+#define kTile2071 2071
+#define kTile2072 2072
+#define kTile2073 2073
+#define kTile2074 2074
+#define kTile2075 2075
+#define kTile2076 2076
+#define kTile2077 2077
+#define kTile2078 2078
+#define kTile2079 2079
+#define kTile2080 2080
+#define kTile2081 2081
+#define kTile2082 2082
+#define kTile2083 2083
+#define kTile2084 2084
+#define kTile2085 2085
+#define kTile2086 2086
+#define kTile2087 2087
+#define kTile2088 2088
+#define kTile2089 2089
+#define kTile2090 2090
+#define kTile2091 2091
+#define kTile2092 2092
+#define kTile2093 2093
+#define kTile2094 2094
+#define kTile2095 2095
+#define kTile2096 2096
+#define kTile2097 2097
+#define kTile2098 2098
+#define kTile2099 2099
+#define kTile2100 2100
+#define kTile2101 2101
+#define kTile2102 2102
+#define kTile2103 2103
+#define kTile2104 2104
+#define kTile2105 2105
+#define kTile2106 2106
+#define kTile2107 2107
+#define kTile2108 2108
+#define kTile2109 2109
+#define kTile2110 2110
+#define kTile2111 2111
+#define kTile2112 2112
+#define kTile2113 2113
+#define kTile2114 2114
+#define kTile2115 2115
+#define kTile2116 2116
+#define kTile2117 2117
+#define kTile2118 2118
+#define kTile2119 2119
+#define kTile2120 2120
+#define kTile2121 2121
+#define kTile2122 2122
+#define kTile2123 2123
+#define kTile2124 2124
+#define kTile2125 2125
+#define kTile2126 2126
+#define kTile2127 2127
+#define kTile2128 2128
+#define kTile2129 2129
+#define kTile2130 2130
+#define kTile2131 2131
+#define kTile2132 2132
+#define kTile2133 2133
+#define kTile2134 2134
+#define kTile2135 2135
+#define kTile2136 2136
+#define kTile2137 2137
+#define kTile2138 2138
+#define kTile2139 2139
+#define kTile2140 2140
+#define kTile2141 2141
+#define kTile2142 2142
+#define kTile2143 2143
+#define kTile2144 2144
+#define kTile2145 2145
+#define kTile2146 2146
+#define kTile2147 2147
+#define kTile2148 2148
+#define kTile2149 2149
+#define kTile2150 2150
+#define kTile2151 2151
+#define kTile2152 2152
+#define kTile2153 2153
+#define kTile2154 2154
+#define kTile2155 2155
+#define kTile2156 2156
+#define kTile2157 2157
+#define kTile2158 2158
+#define kTile2159 2159
+#define kTile2160 2160
+#define kTile2161 2161
+#define kTile2162 2162
+#define kTile2163 2163
+#define kTile2164 2164
+#define kTile2165 2165
+#define kTile2166 2166
+#define kTile2167 2167
+#define kTile2168 2168
+#define kTile2169 2169
+#define kTile2170 2170
+#define kTile2171 2171
+#define kTile2172 2172
+#define kTile2173 2173
+#define kTile2174 2174
+#define kTile2175 2175
+#define kTile2176 2176
+#define kTile2177 2177
+#define kTile2178 2178
+#define kTile2179 2179
+#define kTile2180 2180
+#define kTile2181 2181
+#define kTile2182 2182
+#define kTile2183 2183
+#define kTile2184 2184
+#define kTile2185 2185
+#define kTile2186 2186
+#define kTile2187 2187
+#define kTile2188 2188
+#define kTile2189 2189
+#define kTile2190 2190
+#define kTile2191 2191
+#define kTile2192 2192
+#define kTile2193 2193
+#define kTile2194 2194
+#define kTile2195 2195
+#define kTile2196 2196
+#define kTile2197 2197
+#define kTile2198 2198
+#define kTile2199 2199
+#define kTile2200 2200
+#define kTile2201 2201
+#define kTile2202 2202
+#define kTile2203 2203
+#define kTile2204 2204
+#define kTile2205 2205
+#define kTile2206 2206
+#define kTile2207 2207
+#define kTile2208 2208
+#define kTile2209 2209
+#define kTile2210 2210
+#define kTile2211 2211
+#define kTile2212 2212
+#define kTile2213 2213
+#define kTile2214 2214
+#define kTile2215 2215
+#define kTile2216 2216
+#define kTile2217 2217
+#define kTile2218 2218
+#define kTile2219 2219
+#define kTile2220 2220
+#define kTile2221 2221
+#define kTile2222 2222
+#define kTile2223 2223
+#define kTile2224 2224
+#define kTile2225 2225
+#define kTile2226 2226
+#define kTile2227 2227
+#define kTile2228 2228
+#define kTile2229 2229
+#define kTile2230 2230
+#define kTile2231 2231
+#define kTile2232 2232
+#define kTile2233 2233
+#define kTile2234 2234
+#define kTile2235 2235
+#define kTile2236 2236
+#define kTile2237 2237
+#define kTile2238 2238
+#define kTile2239 2239
+#define kTile2240 2240
+#define kTile2241 2241
+#define kTile2242 2242
+#define kTile2243 2243
+#define kTile2244 2244
+#define kTile2245 2245
+#define kTile2246 2246
+#define kTile2247 2247
+#define kTile2248 2248
+#define kTile2249 2249
+#define kTile2250 2250
+#define kTile2251 2251
+#define kTile2252 2252
+#define kTile2253 2253
+#define kTile2254 2254
+#define kTile2255 2255
+#define kTile2256 2256
+#define kTile2257 2257
+#define kTile2258 2258
+#define kTile2259 2259
+#define kTile2260 2260
+#define kTile2261 2261
+#define kTile2262 2262
+#define kTile2263 2263
+#define kTile2264 2264
+#define kTile2265 2265
+#define kTile2266 2266
+#define kTile2267 2267
+#define kTile2268 2268
+#define kTile2269 2269
+#define kTile2270 2270
+#define kTile2271 2271
+#define kTile2272 2272
+#define kTile2273 2273
+#define kTile2274 2274
+#define kTile2275 2275
+#define kTile2276 2276
+#define kTile2277 2277
+#define kTile2278 2278
+#define kTile2279 2279
+#define kTile2280 2280
+#define kTile2281 2281
+#define kTile2282 2282
+#define kTile2283 2283
+#define kTile2284 2284
+#define kTile2285 2285
+#define kTile2286 2286
+#define kTile2287 2287
+#define kTile2288 2288
+#define kTile2289 2289
+#define kTile2290 2290
+#define kTile2291 2291
+#define kTile2292 2292
+#define kTile2293 2293
+#define kTile2294 2294
+#define kTile2295 2295
+#define kTile2296 2296
+#define kTile2297 2297
+#define kTile2298 2298
+#define kTile2299 2299
+#define kTile2300 2300
+#define kTile2301 2301
+#define kTile2302 2302
+#define kTile2303 2303
+#define kTile2304 2304
+#define kTile2305 2305
+#define kTile2306 2306
+#define kTile2307 2307
+#define kTile2308 2308
+#define kTile2309 2309
+#define kTile2310 2310
+#define kTile2311 2311
+#define kTile2312 2312
+#define kTile2313 2313
+#define kTile2314 2314
+#define kTile2315 2315
+#define kTile2316 2316
+#define kTile2317 2317
+#define kTile2318 2318
+#define kTile2319 2319
+#define kTile2320 2320
+#define kTile2321 2321
+#define kTile2322 2322
+#define kTile2323 2323
+#define kTile2324 2324
+#define kTile2325 2325
+#define kTile2326 2326
+#define kTile2327 2327
+#define kTile2328 2328
+#define kTile2329 2329
+#define kTile2330 2330
+#define kTile2331 2331
+#define kTile2332 2332
+#define kTile2333 2333
+#define kTile2334 2334
+#define kTile2335 2335
+#define kTile2336 2336
+#define kTile2337 2337
+#define kTile2338 2338
+#define kTile2339 2339
+#define kTile2340 2340
+#define kTile2341 2341
+#define kTile2342 2342
+#define kTile2343 2343
+#define kTile2344 2344
+#define kTile2345 2345
+#define kTile2346 2346
+#define kTile2347 2347
+#define kTile2348 2348
+#define kTile2349 2349
+#define kTile2350 2350
+#define kTile2351 2351
+#define kTile2352 2352
+#define kTile2353 2353
+#define kTile2354 2354
+#define kTile2355 2355
+#define kTile2356 2356
+#define kTile2357 2357
+#define kTile2358 2358
+#define kTile2359 2359
+#define kTile2360 2360
+#define kTile2361 2361
+#define kTile2362 2362
+#define kTile2363 2363
+#define kTile2364 2364
+#define kTile2365 2365
+#define kTile2366 2366
+#define kTile2367 2367
+#define kTile2368 2368
+#define kTile2369 2369
+#define kTile2370 2370
+#define kTile2371 2371
+#define kTile2372 2372
+#define kTile2373 2373
+#define kTile2374 2374
+#define kTile2375 2375
+#define kTile2376 2376
+#define kTile2377 2377
+#define kTile2378 2378
+#define kTile2379 2379
+#define kTile2380 2380
+#define kTile2381 2381
+#define kTile2382 2382
+#define kTile2383 2383
+#define kTile2384 2384
+#define kTile2385 2385
+#define kTile2386 2386
+#define kTile2387 2387
+#define kTile2388 2388
+#define kTile2389 2389
+#define kTile2390 2390
+#define kTile2391 2391
+#define kTile2392 2392
+#define kTile2393 2393
+#define kTile2394 2394
+#define kTile2395 2395
+#define kTile2396 2396
+#define kTile2397 2397
+#define kTile2398 2398
+#define kTile2399 2399
+#define kTile2400 2400
+#define kTile2401 2401
+#define kTile2402 2402
+#define kTile2403 2403
+#define kTile2404 2404
+#define kTile2405 2405
+#define kTile2406 2406
+#define kTile2407 2407
+#define kTile2408 2408
+#define kTile2409 2409
+#define kTile2410 2410
+#define kTile2411 2411
+#define kTile2412 2412
+#define kTile2413 2413
+#define kTile2414 2414
+#define kTile2415 2415
+#define kTile2416 2416
+#define kTile2417 2417
+#define kTile2418 2418
+#define kTile2419 2419
+#define kTile2420 2420
+#define kTile2421 2421
+#define kTile2422 2422
+#define kTile2423 2423
+#define kTile2424 2424
+#define kTile2425 2425
+#define kTile2426 2426
+#define kTile2427 2427
+#define kTile2428 2428
+#define kTile2429 2429
+#define kTile2430 2430
+#define kTile2431 2431
+#define kTile2432 2432
+#define kTile2433 2433
+#define kTile2434 2434
+#define kTile2435 2435
+#define kTile2436 2436
+#define kTile2437 2437
+#define kTile2438 2438
+#define kTile2439 2439
+#define kTile2440 2440
+#define kTile2441 2441
+#define kTile2442 2442
+#define kTile2443 2443
+#define kTile2444 2444
+#define kTile2445 2445
+#define kTile2446 2446
+#define kTile2447 2447
+#define kTile2448 2448
+#define kTile2449 2449
+#define kTile2450 2450
+#define kTile2451 2451
+#define kTile2452 2452
+#define kTile2453 2453
+#define kTile2454 2454
+#define kTile2455 2455
+#define kTile2456 2456
+#define kTile2457 2457
+#define kTile2458 2458
+#define kTile2459 2459
+#define kTile2460 2460
+#define kTile2461 2461
+#define kTile2462 2462
+#define kTile2463 2463
+#define kTile2464 2464
+#define kTile2465 2465
+#define kTile2466 2466
+#define kTile2467 2467
+#define kTile2468 2468
+#define kTile2469 2469
+#define kTile2470 2470
+#define kTile2471 2471
+#define kTile2472 2472
+#define kTile2473 2473
+#define kTile2474 2474
+#define kTile2475 2475
+#define kTile2476 2476
+#define kTile2477 2477
+#define kTile2478 2478
+#define kTile2479 2479
+#define kTile2480 2480
+#define kTile2481 2481
+#define kTile2482 2482
+#define kTile2483 2483
+#define kTile2484 2484
+#define kTile2485 2485
+#define kTile2486 2486
+#define kTile2487 2487
+#define kTile2488 2488
+#define kTile2489 2489
+#define kTile2490 2490
+#define kTile2491 2491
+#define kTile2492 2492
+#define kTile2493 2493
+#define kTile2494 2494
+#define kTile2495 2495
+#define kTile2496 2496
+#define kTile2497 2497
+#define kTile2498 2498
+#define kTile2499 2499
+#define kTile2500 2500
+#define kTile2501 2501
+#define kTile2502 2502
+#define kTile2503 2503
+#define kTile2504 2504
+#define kTile2505 2505
+#define kTile2506 2506
+#define kTile2507 2507
+#define kTile2508 2508
+#define kTile2509 2509
+#define kTile2510 2510
+#define kTile2511 2511
+#define kTile2512 2512
+#define kTile2513 2513
+#define kTile2514 2514
+#define kTile2515 2515
+#define kTile2516 2516
+#define kTile2517 2517
+#define kTile2518 2518
+#define kTile2519 2519
+#define kTile2520 2520
+#define kTile2521 2521
+#define kTile2522 2522
+#define kTile2523 2523
+#define kTile2524 2524
+#define kTile2525 2525
+#define kTile2526 2526
+#define kTile2527 2527
+#define kTile2528 2528
+#define kTile2529 2529
+#define kTile2530 2530
+#define kTile2531 2531
+#define kTile2532 2532
+#define kTile2533 2533
+#define kTile2534 2534
+#define kTile2535 2535
+#define kTile2536 2536
+#define kTile2537 2537
+#define kTile2538 2538
+#define kTile2539 2539
+#define kTile2540 2540
+#define kTile2541 2541
+#define kTile2542 2542
+#define kTile2543 2543
+#define kTile2544 2544
+#define kTile2545 2545
+#define kTile2546 2546
+#define kTile2547 2547
+#define kTile2548 2548
+#define kTile2549 2549
+#define kTile2550 2550
+#define kTile2551 2551
+#define kTile2552 2552
+#define kTile2553 2553
+#define kTile2554 2554
+#define kTile2555 2555
+#define kTile2556 2556
+#define kTile2557 2557
+#define kTile2558 2558
+#define kTile2559 2559
+#define kTile2560 2560
+#define kTile2561 2561
+#define kTile2562 2562
+#define kTile2563 2563
+#define kTile2564 2564
+#define kTile2565 2565
+#define kTile2566 2566
+#define kTile2567 2567
+#define kTile2568 2568
+#define kTile2569 2569
+#define kTile2570 2570
+#define kTile2571 2571
+#define kTile2572 2572
+#define kTile2573 2573
+#define kTile2574 2574
+#define kTile2575 2575
+#define kTile2576 2576
+#define kTile2577 2577
+#define kTile2578 2578
+#define kTile2579 2579
+#define kTile2580 2580
+#define kTile2581 2581
+#define kTile2582 2582
+#define kTile2583 2583
+#define kTile2584 2584
+#define kTile2585 2585
+#define kTile2586 2586
+#define kTile2587 2587
+#define kTile2588 2588
+#define kTile2589 2589
+#define kTile2590 2590
+#define kTile2591 2591
+#define kTile2592 2592
+#define kTile2593 2593
+#define kTile2594 2594
+#define kTile2595 2595
+#define kTile2596 2596
+#define kTile2597 2597
+#define kTile2598 2598
+#define kTile2599 2599
+#define kTile2600 2600
+#define kTile2601 2601
+#define kTile2602 2602
+#define kTile2603 2603
+#define kTile2604 2604
+#define kTile2605 2605
+#define kTile2606 2606
+#define kTile2607 2607
+#define kTile2608 2608
+#define kTile2609 2609
+#define kTile2610 2610
+#define kTile2611 2611
+#define kTile2612 2612
+#define kTile2613 2613
+#define kTile2614 2614
+#define kTile2615 2615
+#define kTile2616 2616
+#define kTile2617 2617
+#define kTile2618 2618
+#define kTile2619 2619
+#define kTile2620 2620
+#define kTile2621 2621
+#define kTile2622 2622
+#define kTile2623 2623
+#define kTile2624 2624
+#define kTile2625 2625
+#define kTile2626 2626
+#define kTile2627 2627
+#define kTile2628 2628
+#define kTile2629 2629
+#define kTile2630 2630
+#define kTile2631 2631
+#define kTile2632 2632
+#define kTile2633 2633
+#define kTile2634 2634
+#define kTile2635 2635
+#define kTile2636 2636
+#define kTile2637 2637
+#define kTile2638 2638
+#define kTile2639 2639
+#define kTile2640 2640
+#define kTile2641 2641
+#define kTile2642 2642
+#define kTile2643 2643
+#define kTile2644 2644
+#define kTile2645 2645
+#define kTile2646 2646
+#define kTile2647 2647
+#define kTile2648 2648
+#define kTile2649 2649
+#define kTile2650 2650
+#define kTile2651 2651
+#define kTile2652 2652
+#define kTile2653 2653
+#define kTile2654 2654
+#define kTile2655 2655
+#define kTile2656 2656
+#define kTile2657 2657
+#define kTile2658 2658
+#define kTile2659 2659
+#define kTile2660 2660
+#define kTile2661 2661
+#define kTile2662 2662
+#define kTile2663 2663
+#define kTile2664 2664
+#define kTile2665 2665
+#define kTile2666 2666
+#define kTile2667 2667
+#define kTile2668 2668
+#define kTile2669 2669
+#define kTile2670 2670
+#define kTile2671 2671
+#define kTile2672 2672
+#define kTile2673 2673
+#define kTile2674 2674
+#define kTile2675 2675
+#define kTile2676 2676
+#define kTile2677 2677
+#define kTile2678 2678
+#define kTile2679 2679
+#define kTile2680 2680
+#define kTile2681 2681
+#define kTile2682 2682
+#define kTile2683 2683
+#define kTile2684 2684
+#define kTile2685 2685
+#define kTile2686 2686
+#define kTile2687 2687
+#define kTile2688 2688
+#define kTile2689 2689
+#define kTile2690 2690
+#define kTile2691 2691
+#define kTile2692 2692
+#define kTile2693 2693
+#define kTile2694 2694
+#define kTile2695 2695
+#define kTile2696 2696
+#define kTile2697 2697
+#define kTile2698 2698
+#define kTile2699 2699
+#define kTile2700 2700
+#define kTile2701 2701
+#define kTile2702 2702
+#define kTile2703 2703
+#define kTile2704 2704
+#define kTile2705 2705
+#define kTile2706 2706
+#define kTile2707 2707
+#define kTile2708 2708
+#define kTile2709 2709
+#define kTile2710 2710
+#define kTile2711 2711
+#define kTile2712 2712
+#define kTile2713 2713
+#define kTile2714 2714
+#define kTile2715 2715
+#define kTile2716 2716
+#define kTile2717 2717
+#define kTile2718 2718
+#define kTile2719 2719
+#define kTile2720 2720
+#define kTile2721 2721
+#define kTile2722 2722
+#define kTile2723 2723
+#define kTile2724 2724
+#define kTile2725 2725
+#define kTile2726 2726
+#define kTile2727 2727
+#define kTile2728 2728
+#define kTile2729 2729
+#define kTile2730 2730
+#define kTile2731 2731
+#define kTile2732 2732
+#define kTile2733 2733
+#define kTile2734 2734
+#define kTile2735 2735
+#define kTile2736 2736
+#define kTile2737 2737
+#define kTile2738 2738
+#define kTile2739 2739
+#define kTile2740 2740
+#define kTile2741 2741
+#define kTile2742 2742
+#define kTile2743 2743
+#define kTile2744 2744
+#define kTile2745 2745
+#define kTile2746 2746
+#define kTile2747 2747
+#define kTile2748 2748
+#define kTile2749 2749
+#define kTile2750 2750
+#define kTile2751 2751
+#define kTile2752 2752
+#define kTile2753 2753
+#define kTile2754 2754
+#define kTile2755 2755
+#define kTile2756 2756
+#define kTile2757 2757
+#define kTile2758 2758
+#define kTile2759 2759
+#define kTile2760 2760
+#define kTile2761 2761
+#define kTile2762 2762
+#define kTile2763 2763
+#define kTile2764 2764
+#define kTile2765 2765
+#define kTile2766 2766
+#define kTile2767 2767
+#define kTile2768 2768
+#define kTile2769 2769
+#define kTile2770 2770
+#define kTile2771 2771
+#define kTile2772 2772
+#define kTile2773 2773
+#define kTile2774 2774
+#define kTile2775 2775
+#define kTile2776 2776
+#define kTile2777 2777
+#define kTile2778 2778
+#define kTile2779 2779
+#define kTile2780 2780
+#define kTile2781 2781
+#define kTile2782 2782
+#define kTile2783 2783
+#define kTile2784 2784
+#define kTile2785 2785
+#define kTile2786 2786
+#define kTile2787 2787
+#define kTile2788 2788
+#define kTile2789 2789
+#define kTile2790 2790
+#define kTile2791 2791
+#define kTile2792 2792
+#define kTile2793 2793
+#define kTile2794 2794
+#define kTile2795 2795
+#define kTile2796 2796
+#define kTile2797 2797
+#define kTile2798 2798
+#define kTile2799 2799
+#define kTile2800 2800
+#define kTile2801 2801
+#define kTile2802 2802
+#define kTile2803 2803
+#define kTile2804 2804
+#define kTile2805 2805
+#define kTile2806 2806
+#define kTile2807 2807
+#define kTile2808 2808
+#define kTile2809 2809
+#define kTile2810 2810
+#define kTile2811 2811
+#define kTile2812 2812
+#define kTile2813 2813
+#define kTile2814 2814
+#define kTile2815 2815
+#define kTile2816 2816
+#define kTile2817 2817
+#define kTile2818 2818
+#define kTile2819 2819
+#define kTile2820 2820
+#define kTile2821 2821
+#define kTile2822 2822
+#define kTile2823 2823
+#define kTile2824 2824
+#define kTile2825 2825
+#define kTile2826 2826
+#define kTile2827 2827
+#define kTile2828 2828
+#define kTile2829 2829
+#define kTile2830 2830
+#define kTile2831 2831
+#define kTile2832 2832
+#define kTile2833 2833
+#define kTile2834 2834
+#define kTile2835 2835
+#define kTile2836 2836
+#define kTile2837 2837
+#define kTile2838 2838
+#define kTile2839 2839
+#define kTile2840 2840
+#define kTile2841 2841
+#define kTile2842 2842
+#define kTile2843 2843
+#define kTile2844 2844
+#define kTile2845 2845
+#define kTile2846 2846
+#define kTile2847 2847
+#define kTile2848 2848
+#define kTile2849 2849
+#define kTile2850 2850
+#define kTile2851 2851
+#define kTile2852 2852
+#define kTile2853 2853
+#define kTile2854 2854
+#define kTile2855 2855
+#define kTile2856 2856
+#define kTile2857 2857
+#define kTile2858 2858
+#define kTile2859 2859
+#define kTile2860 2860
+#define kTile2861 2861
+#define kTile2862 2862
+#define kTile2863 2863
+#define kTile2864 2864
+#define kTile2865 2865
+#define kTile2866 2866
+#define kTile2867 2867
+#define kTile2868 2868
+#define kTile2869 2869
+#define kTile2870 2870
+#define kTile2871 2871
+#define kTile2872 2872
+#define kTile2873 2873
+#define kTile2874 2874
+#define kTile2875 2875
+#define kTile2876 2876
+#define kTile2877 2877
+#define kTile2878 2878
+#define kTile2879 2879
+#define kTile2880 2880
+#define kTile2881 2881
+#define kTile2882 2882
+#define kTile2883 2883
+#define kTile2884 2884
+#define kTile2885 2885
+#define kTile2886 2886
+#define kTile2887 2887
+#define kTile2888 2888
+#define kTile2889 2889
+#define kTile2890 2890
+#define kTile2891 2891
+#define kTile2892 2892
+#define kTile2893 2893
+#define kTile2894 2894
+#define kTile2895 2895
+#define kTile2896 2896
+#define kTile2897 2897
+#define kTile2898 2898
+#define kTile2899 2899
+#define kTile2900 2900
+#define kTile2901 2901
+#define kTile2902 2902
+#define kTile2903 2903
+#define kTile2904 2904
+#define kTile2905 2905
+#define kTile2906 2906
+#define kTile2907 2907
+#define kTile2908 2908
+#define kTile2909 2909
+#define kTile2910 2910
+#define kTile2911 2911
+#define kTile2912 2912
+#define kTile2913 2913
+#define kTile2914 2914
+#define kTile2915 2915
+#define kTile2916 2916
+#define kTile2917 2917
+#define kTile2918 2918
+#define kTile2919 2919
+#define kTile2920 2920
+#define kTile2921 2921
+#define kTile2922 2922
+#define kTile2923 2923
+#define kTile2924 2924
+#define kTile2925 2925
+#define kTile2926 2926
+#define kTile2927 2927
+#define kTile2928 2928
+#define kTile2929 2929
+#define kTile2930 2930
+#define kTile2931 2931
+#define kTile2932 2932
+#define kTile2933 2933
+#define kTile2934 2934
+#define kTile2935 2935
+#define kTile2936 2936
+#define kTile2937 2937
+#define kTile2938 2938
+#define kTile2939 2939
+#define kTile2940 2940
+#define kTile2941 2941
+#define kTile2942 2942
+#define kTile2943 2943
+#define kTile2944 2944
+#define kTile2945 2945
+#define kTile2946 2946
+#define kTile2947 2947
+#define kTile2948 2948
+#define kTile2949 2949
+#define kTile2950 2950
+#define kTile2951 2951
+#define kTile2952 2952
+#define kTile2953 2953
+#define kTile2954 2954
+#define kTile2955 2955
+#define kTile2956 2956
+#define kTile2957 2957
+#define kTile2958 2958
+#define kTile2959 2959
+#define kTile2960 2960
+#define kTile2961 2961
+#define kTile2962 2962
+#define kTile2963 2963
+#define kTile2964 2964
+#define kTile2965 2965
+#define kTile2966 2966
+#define kTile2967 2967
+#define kTile2968 2968
+#define kTile2969 2969
+#define kTile2970 2970
+#define kTile2971 2971
+#define kTile2972 2972
+#define kTile2973 2973
+#define kTile2974 2974
+#define kTile2975 2975
+#define kTile2976 2976
+#define kTile2977 2977
+#define kTile2978 2978
+#define kTile2979 2979
+#define kTile2980 2980
+#define kTile2981 2981
+#define kTile2982 2982
+#define kTile2983 2983
+#define kTile2984 2984
+#define kTile2985 2985
+#define kTile2986 2986
+#define kTile2987 2987
+#define kTile2988 2988
+#define kTile2989 2989
+#define kTile2990 2990
+#define kTile2991 2991
+#define kTile2992 2992
+#define kTile2993 2993
+#define kTile2994 2994
+#define kTile2995 2995
+#define kTile2996 2996
+#define kTile2997 2997
+#define kTile2998 2998
+#define kTile2999 2999
+#define kTile3000 3000
+#define kTile3001 3001
+#define kTile3002 3002
+#define kTile3003 3003
+#define kTile3004 3004
+#define kTile3005 3005
+#define kTile3006 3006
+#define kTile3007 3007
+#define kTile3008 3008
+#define kTile3009 3009
+#define kTile3010 3010
+#define kTile3011 3011
+#define kTile3012 3012
+#define kTile3013 3013
+#define kTile3014 3014
+#define kTile3015 3015
+#define kTile3016 3016
+#define kTile3017 3017
+#define kTile3018 3018
+#define kTile3019 3019
+#define kTile3020 3020
+#define kTile3021 3021
+#define kTile3022 3022
+#define kTile3023 3023
+#define kTile3024 3024
+#define kTile3025 3025
+#define kTile3026 3026
+#define kTile3027 3027
+#define kTile3028 3028
+#define kTile3029 3029
+#define kTile3030 3030
+#define kTile3031 3031
+#define kTile3032 3032
+#define kTile3033 3033
+#define kTile3034 3034
+#define kTile3035 3035
+#define kTile3036 3036
+#define kTile3037 3037
+#define kTile3038 3038
+#define kTile3039 3039
+#define kTile3040 3040
+#define kTile3041 3041
+#define kTile3042 3042
+#define kTile3043 3043
+#define kTile3044 3044
+#define kTile3045 3045
+#define kTile3046 3046
+#define kTile3047 3047
+#define kTile3048 3048
+#define kTile3049 3049
+#define kTile3050 3050
+#define kTile3051 3051
+#define kTile3052 3052
+#define kTile3053 3053
+#define kTile3054 3054
+#define kTile3055 3055
+#define kTile3056 3056
+#define kTile3057 3057
+#define kTile3058 3058
+#define kTile3059 3059
+#define kTile3060 3060
+#define kTile3061 3061
+#define kTile3062 3062
+#define kTile3063 3063
+#define kTile3064 3064
+#define kTile3065 3065
+#define kTile3066 3066
+#define kTile3067 3067
+#define kTile3068 3068
+#define kTile3069 3069
+#define kTile3070 3070
+#define kTile3071 3071
+#define kTile3072 3072
+#define kTile3073 3073
+#define kTile3074 3074
+#define kTile3075 3075
+#define kTile3076 3076
+#define kTile3077 3077
+#define kTile3078 3078
+#define kTile3079 3079
+#define kTile3080 3080
+#define kTile3081 3081
+#define kTile3082 3082
+#define kTile3083 3083
+#define kTile3084 3084
+#define kTile3085 3085
+#define kTile3086 3086
+#define kTile3087 3087
+#define kTile3088 3088
+#define kTile3089 3089
+#define kTile3090 3090
+#define kTile3091 3091
+#define kTile3092 3092
+#define kTile3093 3093
+#define kTile3094 3094
+#define kTile3095 3095
+#define kTile3096 3096
+#define kTile3097 3097
+#define kTile3098 3098
+#define kTile3099 3099
+#define kTile3100 3100
+#define kTile3101 3101
+#define kTile3102 3102
+#define kTile3103 3103
+#define kTile3104 3104
+#define kTile3105 3105
+#define kTile3106 3106
+#define kTile3107 3107
+#define kTile3108 3108
+#define kTile3109 3109
+#define kTile3110 3110
+#define kTile3111 3111
+#define kTile3112 3112
+#define kTile3113 3113
+#define kTile3114 3114
+#define kTile3115 3115
+#define kTile3116 3116
+#define kTile3117 3117
+#define kTile3118 3118
+#define kTile3119 3119
+#define kTile3120 3120
+#define kTile3121 3121
+#define kTile3122 3122
+#define kTile3123 3123
+#define kTile3124 3124
+#define kTile3125 3125
+#define kTile3126 3126
+#define kTile3127 3127
+#define kTile3128 3128
+#define kTile3129 3129
+#define kTile3130 3130
+#define kTile3131 3131
+#define kTile3132 3132
+#define kTile3133 3133
+#define kTile3134 3134
+#define kTile3135 3135
+#define kTile3136 3136
+#define kTile3137 3137
+#define kTile3138 3138
+#define kTile3139 3139
+#define kTile3140 3140
+#define kTile3141 3141
+#define kTile3142 3142
+#define kTile3143 3143
+#define kTile3144 3144
+#define kTile3145 3145
+#define kTile3146 3146
+#define kTile3147 3147
+#define kTile3148 3148
+#define kTile3149 3149
+#define kTile3150 3150
+#define kTile3151 3151
+#define kTile3152 3152
+#define kTile3153 3153
+#define kTile3154 3154
+#define kTile3155 3155
+#define kTile3156 3156
+#define kTile3157 3157
+#define kTile3158 3158
+#define kTile3159 3159
+#define kTile3160 3160
+#define kTile3161 3161
+#define kTile3162 3162
+#define kTile3163 3163
+#define kTile3164 3164
+#define kTile3165 3165
+#define kTile3166 3166
+#define kTile3167 3167
+#define kTile3168 3168
+#define kTile3169 3169
+#define kTile3170 3170
+#define kTile3171 3171
+#define kTile3172 3172
+#define kTile3173 3173
+#define kTile3174 3174
+#define kTile3175 3175
+#define kTile3176 3176
+#define kTile3177 3177
+#define kTile3178 3178
+#define kTile3179 3179
+#define kTile3180 3180
+#define kTile3181 3181
+#define kTile3182 3182
+#define kTile3183 3183
+#define kTile3184 3184
+#define kTile3185 3185
+#define kTile3186 3186
+#define kTile3187 3187
+#define kTile3188 3188
+#define kTile3189 3189
+#define kTile3190 3190
+#define kTile3191 3191
+#define kTile3192 3192
+#define kTile3193 3193
+#define kTile3194 3194
+#define kTile3195 3195
+#define kTile3196 3196
+#define kTile3197 3197
+#define kTile3198 3198
+#define kTile3199 3199
+#define kTile3200 3200
+#define kTile3201 3201
+#define kTile3202 3202
+#define kTile3203 3203
+#define kTile3204 3204
+#define kTile3205 3205
+#define kTile3206 3206
+#define kTile3207 3207
+#define kTile3208 3208
+#define kTile3209 3209
+#define kTile3210 3210
+#define kTile3211 3211
+#define kTile3212 3212
+#define kTile3213 3213
+#define kTile3214 3214
+#define kTile3215 3215
+#define kTile3216 3216
+#define kTile3217 3217
+#define kTile3218 3218
+#define kTile3219 3219
+#define kTile3220 3220
+#define kTile3221 3221
+#define kTile3222 3222
+#define kTile3223 3223
+#define kTile3224 3224
+#define kTile3225 3225
+#define kTile3226 3226
+#define kTile3227 3227
+#define kTile3228 3228
+#define kTile3229 3229
+#define kTile3230 3230
+#define kTile3231 3231
+#define kTile3232 3232
+#define kTile3233 3233
+#define kTile3234 3234
+#define kTile3235 3235
+#define kTile3236 3236
+#define kTile3237 3237
+#define kTile3238 3238
+#define kTile3239 3239
+#define kTile3240 3240
+#define kTile3241 3241
+#define kTile3242 3242
+#define kTile3243 3243
+#define kTile3244 3244
+#define kTile3245 3245
+#define kTile3246 3246
+#define kTile3247 3247
+#define kTile3248 3248
+#define kTile3249 3249
+#define kTile3250 3250
+#define kTile3251 3251
+#define kTile3252 3252
+#define kTile3253 3253
+#define kTile3254 3254
+#define kTile3255 3255
+#define kTile3256 3256
+#define kTile3257 3257
+#define kTile3258 3258
+#define kTile3259 3259
+#define kTile3260 3260
+#define kTile3261 3261
+#define kTile3262 3262
+#define kTile3263 3263
+#define kTile3264 3264
+#define kTile3265 3265
+#define kTile3266 3266
+#define kTile3267 3267
+#define kTile3268 3268
+#define kTile3269 3269
+#define kTile3270 3270
+#define kTile3271 3271
+#define kTile3272 3272
+#define kTile3273 3273
+#define kTile3274 3274
+#define kTile3275 3275
+#define kTile3276 3276
+#define kTile3277 3277
+#define kTile3278 3278
+#define kTile3279 3279
+#define kTile3280 3280
+#define kTile3281 3281
+#define kTile3282 3282
+#define kTile3283 3283
+#define kTile3284 3284
+#define kTile3285 3285
+#define kTile3286 3286
+#define kTile3287 3287
+#define kTile3288 3288
+#define kTile3289 3289
+#define kTile3290 3290
+#define kTile3291 3291
+#define kTile3292 3292
+#define kTile3293 3293
+#define kTile3294 3294
+#define kTile3295 3295
+#define kTile3296 3296
+#define kTile3297 3297
+#define kTile3298 3298
+#define kTile3299 3299
+#define kTile3300 3300
+#define kTile3301 3301
+#define kTile3302 3302
+#define kTile3303 3303
+#define kTile3304 3304
+#define kTile3305 3305
+#define kTile3306 3306
+#define kTile3307 3307
+#define kTile3308 3308
+#define kTile3309 3309
+#define kTile3310 3310
+#define kTile3311 3311
+#define kTile3312 3312
+#define kTile3313 3313
+#define kTile3314 3314
+#define kTile3315 3315
+#define kTile3316 3316
+#define kTile3317 3317
+#define kTile3318 3318
+#define kTile3319 3319
+#define kTile3320 3320
+#define kTile3321 3321
+#define kTile3322 3322
+#define kTile3323 3323
+#define kTile3324 3324
+#define kTile3325 3325
+#define kTile3326 3326
+#define kTile3327 3327
+#define kTile3328 3328
+#define kTile3329 3329
+#define kTile3330 3330
+#define kTile3331 3331
+#define kTile3332 3332
+#define kTile3333 3333
+#define kTile3334 3334
+#define kTile3335 3335
+#define kTile3336 3336
+#define kTile3337 3337
+#define kTile3338 3338
+#define kTile3339 3339
+#define kTile3340 3340
+#define kTile3341 3341
+#define kTile3342 3342
+#define kTile3343 3343
+#define kTile3344 3344
+#define kTile3345 3345
+#define kTile3346 3346
+#define kTile3347 3347
+#define kTile3348 3348
+#define kTile3349 3349
+#define kTile3350 3350
+#define kTile3351 3351
+#define kTile3352 3352
+#define kTile3353 3353
+#define kTile3354 3354
+#define kTile3355 3355
+#define kTile3356 3356
+#define kTile3357 3357
+#define kTile3358 3358
+#define kTile3359 3359
+#define kTile3360 3360
+#define kTile3361 3361
+#define kTile3362 3362
+#define kTile3363 3363 // sky
+#define kTile3364 3364 // sky
+#define kTile3365 3365 // sky
+#define kTile3366 3366 // sky
+#define kTile3367 3367 // sky
+#define kPublisherLogo 3368
+#define kTile3369 3369
+#define kTile3370 3370
+#define kTile3371 3371
+#define kTile3372 3372
+#define kTile3373 3373
+#define kTile3374 3374
+#define kTile3375 3375
+#define kTile3376 3376
+#define kTile3377 3377
+#define kTile3378 3378
+#define kTile3379 3379
+#define kTile3380 3380
+#define kTile3381 3381
+#define kTile3382 3382
+#define kTile3383 3383
+#define kTile3384 3384
+#define kTile3385 3385
+#define kTile3386 3386
+#define kTile3387 3387
+#define kTile3388 3388
+#define kTile3389 3389
+#define kTile3390 3390
+#define kTile3391 3391
+#define kTile3392 3392
+#define kTile3393 3393
+#define kTile3394 3394
+#define kTile3395 3395
+#define kTile3396 3396
+#define kTile3397 3397
+#define kTile3398 3398
+#define kTile3399 3399
+#define kTile3400 3400
+#define kTile3401 3401
+#define kTile3402 3402
+#define kTile3403 3403
+#define kTile3404 3404
+#define kTile3405 3405
+#define kTile3406 3406
+#define kTile3407 3407
+#define kTile3408 3408
+#define kTile3409 3409
+#define kTile3410 3410
+#define kTile3411 3411
+#define kTile3412 3412
+#define kTile3413 3413
+#define kTile3414 3414
+#define kTile3415 3415
+#define kTile3416 3416
+#define kTile3417 3417
+#define kTile3418 3418
+#define kTile3419 3419
+#define kTile3420 3420
+#define kTile3421 3421
+#define kTile3422 3422
+#define kTile3423 3423
+#define kTile3424 3424
+#define kTile3425 3425
+#define kTile3426 3426
+#define kTile3427 3427
+#define kTile3428 3428
+#define kTile3429 3429
+#define kTile3430 3430
+#define kTile3431 3431
+#define kTile3432 3432
+#define kTile3433 3433
+#define kTile3434 3434
+#define kTile3435 3435
+#define kTile3436 3436
+#define kSkullJaw 3437
+#define kTile3438 3438
+#define kTile3439 3439
+#define kTile3440 3440
+#define kTile3441 3441
+#define kTile3442 3442
+#define kTile3443 3443
+#define kTile3444 3444
+#define kTile3445 3445
+#define kTile3446 3446
+#define kTile3447 3447
+#define kTile3448 3448
+#define kTile3449 3449
+#define kTile3450 3450
+#define kTile3451 3451
+#define kTile3452 3452
+#define kTile3453 3453
+#define kTile3454 3454
+#define kTile3455 3455
+#define kTile3456 3456
+#define kTile3457 3457
+#define kTile3458 3458
+#define kTile3459 3459
+#define kMenuNewGameTile 3460
+#define kMenuLoadGameTile 3461
+#define kTile3462 3462
+#define kTile3463 3463
+#define kTile3464 3464
+#define kMenuMusicTile 3465
+#define kMenuSoundFxTile 3466
+#define kTile3467 3467
+#define kMenuCursorTile 3468
+#define kMenuBlankTitleTile 3469
+#define kTile3470 3470
+#define kTile3471 3471
+#define kTile3472 3472
+#define kTile3473 3473
+#define kTile3474 3474
+#define kTile3475 3475
+#define kTile3476 3476
+#define kTile3477 3477
+#define kTile3478 3478
+#define kTile3479 3479
+#define kTile3480 3480
+#define kTile3481 3481
+#define kTile3482 3482
+#define kTile3483 3483
+#define kTile3484 3484
+#define kTile3485 3485
+#define kTile3486 3486
+#define kTile3487 3487
+#define kTile3488 3488
+#define kTile3489 3489
+#define kTile3490 3490
+#define kTile3491 3491
+#define kTile3492 3492
+#define kTile3493 3493
+#define kTile3494 3494
+#define kTile3495 3495
+#define kTile3496 3496
+#define kTile3497 3497
+#define kTile3498 3498
+#define kTile3499 3499
+#define kTile3500 3500
+#define kTile3501 3501
+#define kTile3502 3502
+#define kTile3503 3503
+#define kTile3504 3504
+#define kTile3505 3505
+#define kTile3506 3506
+#define kTile3507 3507
+#define kTile3508 3508
+#define kTile3509 3509
+#define kTile3510 3510
+#define kTile3511 3511
+#define kTile3512 3512
+#define kTile3513 3513
+#define kTile3514 3514
+#define kTile3515 3515
+#define kTile3516 3516
+#define kTile3517 3517
+#define kTile3518 3518
+#define kTile3519 3519
+#define kTile3520 3520
+#define kTile3521 3521
+#define kTile3522 3522
+#define kTile3523 3523
+#define kTile3524 3524
+#define kTile3525 3525
+#define kTile3526 3526
+#define kTile3527 3527
+#define kTile3528 3528
+#define kTile3529 3529
+#define kTile3530 3530
+#define kTile3531 3531
+#define kTile3532 3532
+#define kTile3533 3533
+#define kTile3534 3534
+#define kTile3535 3535
+#define kTile3536 3536
+#define kTile3537 3537
+#define kTile3538 3538
+#define kTile3539 3539
+#define kTile3540 3540
+#define kTile3541 3541
+#define kTile3542 3542
+#define kTile3543 3543
+#define kTile3544 3544
+#define kTile3545 3545
+#define kTile3546 3546
+#define kTile3547 3547
+#define kTile3548 3548
+#define kTile3549 3549
+#define kTile3550 3550
+#define kTile3551 3551
+#define kTile3552 3552
+#define kTile3553 3553
+#define kTile3554 3554
+#define kTile3555 3555
+#define kTile3556 3556
+#define kTile3557 3557
+#define kTile3558 3558
+#define kTile3559 3559
+#define kTile3560 3560
+#define kTile3561 3561
+#define kTile3562 3562
+#define kTile3563 3563
+#define kTile3564 3564
+#define kTile3565 3565
+#define kTile3566 3566
+#define kTile3567 3567
+#define kTile3568 3568
+#define kTile3569 3569
+#define kTile3570 3570
+#define kTile3571 3571
+#define kTile3572 3572
+#define kTile3573 3573
+#define kTile3574 3574
+#define kTile3575 3575
+#define kTile3576 3576
+#define kTile3577 3577
+#define kTile3578 3578
+#define kTile3579 3579
+#define kTile3580 3580
+#define kTile3581 3581
+#define kSkullHead 3582
+#define kTile3583 3583
+#define kTile3584 3584
+#define kTile3585 3585
+#define kTile3586 3586
+#define kTile3587 3587
+#define kTile3588 3588
+#define kTile3589 3589
+#define kTile3590 3590
+#define kTile3591 3591
+#define kExhumedLogo 3592
+#define kTile3593 3593
+#define kTile3594 3594
+#define kTile3595 3595
+#define kTile3596 3596
+#define kTile3597 3597
+#define kTile3598 3598
+#define kTile3599 3599
+#define kTile3600 3600
+#define kTile3601 3601
+#define kTile3602 3602
+#define kTile3603 3603
+#define kEnergy1 3604
+#define kEnergy2 3605
+#define kTile3606 3606
+#define kTile3607 3607
+#define kTile3608 3608
+#define kTile3609 3609
+#define kTile3610 3610
+#define kTile3611 3611
+#define kTile3612 3612
+#define kTile3613 3613
+#define kTile3614 3614
+#define kTile3615 3615
+#define kTile3616 3616
+#define kTile3617 3617
+#define kTile3618 3618
+#define kTile3619 3619
+#define kTile3620 3620
+#define kTile3621 3621
+#define kTile3622 3622
+#define kTileLoboLaptop 3623
+#define kTile3624 3624
+#define kTile3625 3625
+#define kTile3626 3626
+#define kTile3627 3627
+#define kTile3628 3628
+#define kTile3629 3629
+#define kTile3630 3630
+#define kTile3631 3631
+#define kTile3632 3632
+#define kTile3633 3633
+#define kTile3634 3634
+#define kTile3635 3635
+#define kTile3636 3636
+#define kTile3637 3637
+#define kTile3638 3638
+#define kTile3639 3639
+#define kTile3640 3640
+#define kTile3641 3641
+#define kTile3642 3642
+#define kTile3643 3643
+#define kTile3644 3644
+#define kTile3645 3645
+#define kTile3646 3646
+#define kTile3647 3647
+#define kTile3648 3648
+#define kTile3649 3649
+#define kTile3650 3650
+#define kTile3651 3651
+#define kTile3652 3652
+#define kTile3653 3653
+#define kTile3654 3654
+#define kTile3655 3655
+#define kTile3656 3656
+#define kTile3657 3657
+#define kTile3658 3658
+#define kTile3659 3659
+#define kTile3660 3660
+#define kTile3661 3661
+#define kTile3662 3662
+#define kTile3663 3663
+#define kTile3664 3664
+#define kTile3665 3665
+#define kTile3666 3666
+#define kTile3667 3667
+#define kTile3668 3668
+#define kTile3669 3669
+#define kTile3670 3670
+#define kTile3671 3671
+#define kTile3672 3672
+#define kTile3673 3673
+#define kTile3674 3674
+#define kTile3675 3675
+#define kTile3676 3676
+#define kTile3677 3677
+#define kTile3678 3678
+#define kTile3679 3679
+#define kTile3680 3680
+#define kTile3681 3681
+#define kTile3682 3682
+#define kTile3683 3683
+#define kTile3684 3684
+#define kTile3685 3685
+#define kTile3686 3686
+#define kTile3687 3687
+#define kTile3688 3688
+#define kTile3689 3689
+#define kTile3690 3690
+#define kTile3691 3691
+#define kTile3692 3692
+#define kTile3693 3693
+#define kTile3694 3694
+#define kTile3695 3695
+#define kTile3696 3696
+#define kTile3697 3697
+#define kTile3698 3698
+#define kTile3699 3699
+#define kTile3700 3700
+#define kTile3701 3701
+#define kTile3702 3702
+#define kTile3703 3703
+#define kTile3704 3704
+#define kTile3705 3705
+#define kTile3706 3706
+#define kTile3707 3707
+#define kTile3708 3708
+#define kTile3709 3709
+#define kTile3710 3710
+#define kTile3711 3711
+#define kTile3712 3712
+#define kTile3713 3713
+#define kTile3714 3714
+#define kTile3715 3715
+#define kTile3716 3716
+#define kTile3717 3717
+#define kTile3718 3718
+#define kTile3719 3719
+#define kTile3720 3720
+#define kTile3721 3721
+#define kTile3722 3722
+#define kTile3723 3723
+#define kTile3724 3724
+#define kTile3725 3725
+#define kTile3726 3726
+#define kTile3727 3727
+#define kTile3728 3728
+#define kTile3729 3729
+#define kTile3730 3730
+#define kTile3731 3731
+#define kTile3732 3732
+#define kTile3733 3733
+#define kTile3734 3734
+#define kTile3735 3735
+#define kTile3736 3736
+#define kTile3737 3737
+#define kTile3738 3738
+#define kTile3739 3739
+#define kTile3740 3740
+#define kTile3741 3741
+#define kTile3742 3742
+#define kTile3743 3743
+#define kTile3744 3744
+#define kTile3745 3745
+#define kTile3746 3746
+#define kTile3747 3747
+#define kTile3748 3748
+#define kTile3749 3749
+#define kTile3750 3750
+#define kTile3751 3751
+#define kTile3752 3752
+#define kTile3753 3753
+#define kTile3754 3754
+#define kTile3755 3755
+#define kTile3756 3756
+#define kTile3757 3757
+#define kTile3758 3758
+#define kTile3759 3759
+#define kTile3760 3760
+#define kTile3761 3761
+#define kTile3762 3762
+#define kTile3763 3763
+#define kTile3764 3764
+#define kTile3765 3765
+#define kTile3766 3766
+#define kTile3767 3767
+#define kTile3768 3768
+#define kTile3769 3769
+#define kTile3770 3770
+#define kTile3771 3771
+#define kTile3772 3772
+#define kTile3773 3773
+#define kTile3774 3774
+#define kTile3775 3775
+#define kTile3776 3776
+#define kTile3777 3777
+#define kTile3778 3778
+#define kTile3779 3779
+#define kTile3780 3780
+#define kTile3781 3781
+#define kTile3782 3782
+#define kTile3783 3783
+#define kTile3784 3784
+#define kTile3785 3785
+#define kTile3786 3786
+#define kTile3787 3787
+#define kTile3788 3788
+#define kTile3789 3789
+#define kTile3790 3790
+#define kTile3791 3791
+#define kTile3792 3792
+#define kTile3793 3793
+#define kTile3794 3794
+#define kTile3795 3795
+#define kTile3796 3796
+#define kTile3797 3797
+#define kTile3798 3798
+#define kTile3799 3799
+#define kTile3800 3800
+#define kTile3801 3801
+#define kTile3802 3802
+#define kTile3803 3803
+#define kTile3804 3804
+#define kTile3805 3805
+#define kTile3806 3806
+#define kTile3807 3807
+#define kTile3808 3808
+#define kTile3809 3809
+#define kTile3810 3810
+#define kTile3811 3811
+#define kTile3812 3812
+#define kTile3813 3813
+#define kTile3814 3814
+#define kTile3815 3815
+#define kTile3816 3816
+#define kTile3817 3817
+#define kTile3818 3818
+#define kTile3819 3819
+#define kTile3820 3820
+#define kTile3821 3821
+#define kTile3822 3822
+#define kTile3823 3823
+#define kTile3824 3824
+#define kTile3825 3825
+#define kTile3826 3826
+#define kTile3827 3827
+#define kTile3828 3828
+#define kTile3829 3829
+#define kTile3830 3830
+#define kTile3831 3831
+#define kTile3832 3832
+#define kTile3833 3833
+#define kTile3834 3834
+#define kTile3835 3835
+#define kTile3836 3836
+#define kTile3837 3837
+#define kTile3838 3838
+#define kTile3839 3839
+#define kTile3840 3840
+#define kTile3841 3841
+#define kTile3842 3842
+#define kTile3843 3843
+#define kTile3844 3844
+#define kTile3845 3845
+#define kTile3846 3846
+#define kTile3847 3847
+#define kTile3848 3848
+#define kTile3849 3849
+#define kTile3850 3850
+#define kTile3851 3851
+#define kTile3852 3852
+#define kTile3853 3853
+#define kTile3854 3854
+#define kTile3855 3855
+#define kTile3856 3856
+#define kTile3857 3857
+#define kTile3858 3858
+#define kTile3859 3859
+#define kTile3860 3860
+#define kTile3861 3861
+#define kTile3862 3862
+#define kTile3863 3863
+#define kTile3864 3864
+#define kTile3865 3865
+#define kTile3866 3866
+#define kTile3867 3867
+#define kTile3868 3868
+#define kTile3869 3869
+#define kTile3870 3870
+#define kTile3871 3871
+#define kTile3872 3872
+#define kTile3873 3873
+#define kTile3874 3874
+#define kTile3875 3875
+#define kTile3876 3876
+#define kTile3877 3877
+#define kTile3878 3878
+#define kTile3879 3879
+#define kTile3880 3880
+#define kTile3881 3881
+#define kTile3882 3882
+#define kTile3883 3883
+#define kTile3884 3884
+#define kTile3885 3885
+#define kTile3886 3886
+#define kTile3887 3887
+#define kTile3888 3888
+#define kTile3889 3889
+#define kTile3890 3890
+#define kTile3891 3891
+#define kTile3892 3892
+#define kTile3893 3893
+#define kTile3894 3894
+#define kTile3895 3895
+#define kTile3896 3896
+#define kTile3897 3897
+#define kTile3898 3898
+#define kTile3899 3899
+#define kTile3900 3900
+#define kTile3901 3901
+#define kTile3902 3902
+#define kTile3903 3903
+#define kTile3904 3904
+#define kTile3905 3905
+#define kTile3906 3906
+#define kTile3907 3907
+#define kTile3908 3908
+#define kTile3909 3909
+#define kTile3910 3910
+#define kTile3911 3911
+#define kTile3912 3912
+#define kTile3913 3913
+#define kTile3914 3914
+#define kTile3915 3915
+#define kTile3916 3916
+#define kTile3917 3917
+#define kTile3918 3918
+#define kTile3919 3919
+#define kTile3920 3920
+#define kTile3921 3921
+#define kTile3922 3922
+#define kTile3923 3923
+#define kTile3924 3924
+#define kTile3925 3925
+#define kTile3926 3926
+#define kTile3927 3927
+#define kTile3928 3928
+#define kTile3929 3929
+#define kTile3930 3930
+#define kTile3931 3931
+#define kTile3932 3932
+#define kTile3933 3933
+#define kTile3934 3934
+#define kTile3935 3935
+#define kTile3936 3936
+#define kTile3937 3937
+#define kTile3938 3938
+#define kTile3939 3939
+#define kTile3940 3940
+#define kTile3941 3941
+#define kTile3942 3942
+#define kTile3943 3943
+#define kTile3944 3944
+#define kTile3945 3945
+#define kTile3946 3946
+#define kTile3947 3947
+#define kTile3948 3948
+#define kTile3949 3949
+#define kTile3950 3950
+#define kTile3951 3951
+#define kTile3952 3952
+#define kTile3953 3953
+#define kTile3954 3954
+#define kTile3955 3955
+#define kTile3956 3956
+#define kTile3957 3957
+#define kTile3958 3958
+#define kTile3959 3959
+#define kTile3960 3960
+#define kTile3961 3961
+#define kTile3962 3962
+#define kTile3963 3963
+#define kTile3964 3964
+#define kTile3965 3965
+#define kTile3966 3966
+#define kTile3967 3967
+#define kTile3968 3968
+#define kTile3969 3969
+#define kTile3970 3970
+#define kTile3971 3971
+#define kTile3972 3972
+#define kTile3973 3973
+#define kTile3974 3974
+#define kTile3975 3975
+#define kTile3976 3976
+#define kTile3977 3977
+#define kTile3978 3978
+#define kTile3979 3979
+#define kTile3980 3980
+#define kTile3981 3981
+#define kTile3982 3982
+#define kTile3983 3983
+#define kTile3984 3984
+#define kTile3985 3985
+#define kTile3986 3986
+#define kTile3987 3987
+#define kTile3988 3988
+#define kTile3989 3989
+#define kTile3990 3990
+#define kTile3991 3991
+#define kTile3992 3992
+#define kTile3993 3993
+#define kTile3994 3994
+#define kTile3995 3995
+#define kTile3996 3996
+#define kTile3997 3997
+#define kTile3998 3998
+#define kTile3999 3999
+#define kTile4000 4000
+#define kTile4001 4001
+#define kTile4002 4002
+#define kTile4003 4003
+#define kTile4004 4004
+#define kTile4005 4005
+#define kTile4006 4006
+#define kTile4007 4007
+#define kTile4008 4008
+#define kTile4009 4009
+#define kTile4010 4010
+#define kTile4011 4011
+#define kTile4012 4012
+#define kTile4013 4013
+#define kTile4014 4014
+#define kTile4015 4015
+#define kTile4016 4016
+#define kTile4017 4017
+#define kTile4018 4018
+#define kTile4019 4019
+#define kTile4020 4020
+#define kTile4021 4021
+#define kTile4022 4022
+#define kTile4023 4023
+#define kTile4024 4024
+#define kTile4025 4025
+#define kTile4026 4026
+#define kTile4027 4027
+#define kTile4028 4028
+#define kTile4029 4029
+#define kTile4030 4030
+#define kTile4031 4031
+#define kTile4032 4032
+#define kTile4033 4033
+#define kTile4034 4034
+#define kTile4035 4035
+#define kTile4036 4036
+#define kTile4037 4037
+#define kTile4038 4038
+#define kTile4039 4039
+#define kTile4040 4040
+#define kTile4041 4041
+#define kTile4042 4042
+#define kTile4043 4043
+#define kTile4044 4044
+#define kTile4045 4045
+#define kTile4046 4046
+#define kTile4047 4047
+#define kTile4048 4048
+#define kTile4049 4049
+#define kTile4050 4050
+#define kTile4051 4051
+#define kTile4052 4052
+#define kTile4053 4053
+#define kTile4054 4054
+#define kTile4055 4055
+#define kTile4056 4056
+#define kTile4057 4057
+#define kTile4058 4058
+#define kTile4059 4059
+#define kTile4060 4060
+#define kTile4061 4061
+#define kTile4062 4062
+#define kTile4063 4063
+#define kTile4064 4064
+#define kTile4065 4065
+#define kTile4066 4066
+#define kTile4067 4067
+#define kTile4068 4068
+#define kTile4069 4069
+#define kTile4070 4070
+#define kTile4071 4071
+#define kTile4072 4072
+#define kTile4073 4073
+#define kTile4074 4074
+#define kTile4075 4075
+#define kTile4076 4076
+#define kTile4077 4077
+#define kTile4078 4078
+#define kTile4079 4079
+#define kTile4080 4080
+#define kTile4081 4081
+#define kTile4082 4082
+#define kTile4083 4083
+#define kTile4084 4084
+#define kTile4085 4085
+#define kTile4086 4086
+#define kTile4087 4087
+#define kTile4088 4088
+#define kTile4089 4089
+#define kTile4090 4090
+#define kTile4091 4091
+#define kTile4092 4092
+#define kTile4093 4093
+#define kTile4094 4094
+#define kTile4095 4095
+#define kTile4096 4096
+#define kTile4097 4097
+#define kTile4098 4098
+#define kTile4099 4099
+#define kTile4100 4100
+#define kTile4101 4101
+#define kTile4102 4102
+#define kTile4103 4103
+#define kTile4104 4104
+#define kTile4105 4105
+#define kTile4106 4106
+#define kTile4107 4107
+#define kTile4108 4108
+#define kTile4109 4109
+#define kTile4110 4110
+#define kTile4111 4111
+#define kTile4112 4112
+#define kTile4113 4113
+#define kTile4114 4114
+#define kTile4115 4115
+#define kTile4116 4116
+#define kTile4117 4117
+#define kTile4118 4118
+#define kTile4119 4119
+#define kTile4120 4120
+#define kTile4121 4121
+#define kTile4122 4122
+#define kTile4123 4123
+#define kTile4124 4124
+#define kTile4125 4125
+#define kTile4126 4126
+#define kTile4127 4127
+#define kTile4128 4128
+#define kTile4129 4129
+#define kTile4130 4130
+#define kTile4131 4131
+#define kTile4132 4132
+#define kTile4133 4133
+#define kTile4134 4134
+#define kTile4135 4135
+#define kTile4136 4136
+#define kTile4137 4137
+#define kTile4138 4138
+#define kTile4139 4139
+#define kTile4140 4140
+#define kTile4141 4141
+#define kTile4142 4142
+#define kTile4143 4143
+#define kTile4144 4144
+#define kTile4145 4145
+#define kTile4146 4146
+#define kTile4147 4147
+#define kTile4148 4148
+#define kTile4149 4149
+#define kTile4150 4150
+#define kTile4151 4151
+#define kTile4152 4152
+#define kTile4153 4153
+#define kTile4154 4154
+#define kTile4155 4155
+#define kTile4156 4156
+#define kTile4157 4157
+#define kTile4158 4158
+#define kTile4159 4159
+#define kTile4160 4160
+#define kTile4161 4161
+#define kTile4162 4162
+#define kTile4163 4163
+#define kTile4164 4164
+#define kTile4165 4165
+#define kTile4166 4166
+#define kTile4167 4167
+#define kTile4168 4168
+#define kTile4169 4169
+#define kTile4170 4170
+#define kTile4171 4171
+#define kTile4172 4172
+#define kTile4173 4173
+#define kTile4174 4174
+#define kTile4175 4175
+#define kTile4176 4176
+#define kTile4177 4177
+#define kTile4178 4178
+#define kTile4179 4179
+#define kTile4180 4180
+#define kTile4181 4181
+#define kTile4182 4182
+#define kTile4183 4183
+#define kTile4184 4184
+#define kTile4185 4185
+#define kTile4186 4186
+#define kTile4187 4187
+#define kTile4188 4188
+#define kTile4189 4189
+#define kTile4190 4190
+#define kTile4191 4191
+#define kTile4192 4192
+#define kTile4193 4193
+#define kTile4194 4194
+#define kTile4195 4195
+#define kTile4196 4196
+#define kTile4197 4197
+#define kTile4198 4198
+#define kTile4199 4199
+#define kTile4200 4200
+#define kTile4201 4201
+#define kTile4202 4202
+#define kTile4203 4203
+#define kTile4204 4204
+#define kTile4205 4205
+#define kTile4206 4206
+#define kTile4207 4207
+#define kTile4208 4208
+#define kTile4209 4209
+#define kTile4210 4210
+#define kTile4211 4211
+#define kTile4212 4212
+#define kTile4213 4213
+#define kTile4214 4214
+#define kTile4215 4215
+#define kTile4216 4216
+#define kTile4217 4217
+#define kTile4218 4218
+#define kTile4219 4219
+#define kTile4220 4220
+#define kTile4221 4221
+#define kTile4222 4222
+#define kTile4223 4223
+#define kTile4224 4224
+#define kTile4225 4225
+#define kTile4226 4226
+#define kTile4227 4227
+#define kTile4228 4228
+#define kTile4229 4229
+#define kTile4230 4230
+#define kTile4231 4231
+#define kTile4232 4232
+#define kTile4233 4233
+#define kTile4234 4234
+#define kTile4235 4235
+#define kTile4236 4236
+#define kTile4237 4237
+#define kTile4238 4238
+#define kTile4239 4239
+#define kTile4240 4240
+#define kTile4241 4241
+#define kTile4242 4242
+#define kTile4243 4243
+#define kTile4244 4244
+#define kTile4245 4245
+#define kTile4246 4246
+#define kTile4247 4247
+#define kTile4248 4248
+#define kTile4249 4249
+#define kTile4250 4250
+#define kTile4251 4251
+#define kTile4252 4252
+#define kTile4253 4253
+#define kTile4254 4254
+#define kTile4255 4255
+#define kTile4256 4256
+#define kTile4257 4257
+#define kTile4258 4258
+#define kTile4259 4259
+#define kTile4260 4260
+#define kTile4261 4261
+#define kTile4262 4262
+#define kTile4263 4263
+#define kTile4264 4264
+#define kTile4265 4265
+#define kTile4266 4266
+#define kTile4267 4267
+#define kTile4268 4268
+#define kTile4269 4269
+#define kTile4270 4270
+#define kTile4271 4271
+#define kTile4272 4272
+#define kTile4273 4273
+#define kTile4274 4274
+#define kTile4275 4275
+#define kTile4276 4276
+#define kTile4277 4277
+#define kTile4278 4278
+#define kTile4279 4279
+#define kTile4280 4280
+#define kTile4281 4281
+#define kTile4282 4282
+#define kTile4283 4283
+#define kTile4284 4284
+#define kTile4285 4285
+#define kTile4286 4286
+#define kTile4287 4287
+#define kTile4288 4288
+#define kTile4289 4289
+#define kTile4290 4290
+#define kTile4291 4291
+#define kTile4292 4292
+#define kTile4293 4293
+#define kTile4294 4294
+#define kTile4295 4295
+#define kTile4296 4296
+#define kTile4297 4297
+#define kTile4298 4298
+#define kTile4299 4299
+#define kTile4300 4300
+#define kTile4301 4301
+#define kTile4302 4302
+#define kTile4303 4303
+#define kTile4304 4304
+#define kTile4305 4305
+#define kTile4306 4306
+#define kTile4307 4307
+#define kTile4308 4308
+#define kTile4309 4309
+#define kTile4310 4310
+#define kTile4311 4311
+#define kTile4312 4312
+#define kTile4313 4313
+#define kTile4314 4314
+#define kTile4315 4315
+#define kTile4316 4316
+#define kTile4317 4317
+#define kTile4318 4318
+#define kTile4319 4319
+#define kTile4320 4320
+#define kTile4321 4321
+#define kTile4322 4322
+#define kTile4323 4323
+#define kTile4324 4324
+#define kTile4325 4325
+#define kTile4326 4326
+#define kTile4327 4327
+#define kTile4328 4328
+#define kTile4329 4329
+#define kTile4330 4330
+#define kTile4331 4331
+#define kTile4332 4332
+#define kTile4333 4333
+#define kTile4334 4334
+#define kTile4335 4335
+#define kTile4336 4336
+#define kTile4337 4337
+#define kTile4338 4338
+#define kTile4339 4339
+#define kTile4340 4340
+#define kTile4341 4341
+#define kTile4342 4342
+#define kTile4343 4343
+#define kTile4344 4344
+#define kTile4345 4345
+#define kTile4346 4346
+#define kTile4347 4347
+#define kTile4348 4348
+#define kTile4349 4349
+#define kTile4350 4350
+#define kTile4351 4351
+#define kTile4352 4352
+#define kTile4353 4353
+#define kTile4354 4354
+#define kTile4355 4355
+#define kTile4356 4356
+#define kTile4357 4357
+#define kTile4358 4358
+#define kTile4359 4359
+#define kTile4360 4360
+#define kTile4361 4361
+#define kTile4362 4362
+#define kTile4363 4363
+#define kTile4364 4364
+#define kTile4365 4365
+#define kTile4366 4366
+#define kTile4367 4367
+#define kTile4368 4368
+#define kTile4369 4369
+#define kTile4370 4370
+#define kTile4371 4371
+#define kTile4372 4372
+#define kTile4373 4373
+#define kTile4374 4374
+#define kTile4375 4375
+#define kTile4376 4376
+#define kTile4377 4377
+#define kTile4378 4378
+#define kTile4379 4379
+#define kTile4380 4380
+#define kTile4381 4381
+#define kTile4382 4382
+#define kTile4383 4383
+#define kTile4384 4384
+#define kTile4385 4385
+#define kTile4386 4386
+#define kTile4387 4387
+#define kTile4388 4388
+#define kTile4389 4389
+#define kTile4390 4390
+#define kTile4391 4391
+#define kTile4392 4392
+#define kTile4393 4393
+#define kTile4394 4394
+#define kTile4395 4395
+#define kTile4396 4396
+#define kTile4397 4397
+#define kTile4398 4398
+#define kTile4399 4399
+#define kTile4400 4400
+#define kTile4401 4401
+#define kTile4402 4402
+#define kTile4403 4403
+#define kTile4404 4404
+#define kTile4405 4405
+#define kTile4406 4406
+#define kTile4407 4407
+#define kTile4408 4408
+#define kTile4409 4409
+#define kTile4410 4410
+#define kTile4411 4411
+#define kTile4412 4412
+#define kTile4413 4413
+#define kTile4414 4414
+#define kTile4415 4415
+#define kTile4416 4416
+#define kTile4417 4417
+#define kTile4418 4418
+#define kTile4419 4419
+#define kTile4420 4420
+#define kTile4421 4421
+#define kTile4422 4422
+#define kTile4423 4423
+#define kTile4424 4424
+#define kTile4425 4425
+#define kTile4426 4426
+#define kTile4427 4427
+#define kTile4428 4428
+#define kTile4429 4429
+#define kTile4430 4430
+#define kTile4431 4431
+#define kTile4432 4432
+#define kTile4433 4433
+#define kTile4434 4434
+#define kTile4435 4435
+#define kTile4436 4436
+#define kTile4437 4437
+#define kTile4438 4438
+#define kTile4439 4439
+#define kTile4440 4440
+#define kTile4441 4441
+#define kTile4442 4442
+#define kTile4443 4443
+#define kTile4444 4444
+#define kTile4445 4445
+#define kTile4446 4446
+#define kTile4447 4447
+#define kTile4448 4448
+#define kTile4449 4449
+#define kTile4450 4450
+#define kTile4451 4451
+#define kTile4452 4452
+#define kTile4453 4453
+#define kTile4454 4454
+#define kTile4455 4455
+#define kTile4456 4456
+#define kTile4457 4457
+#define kTile4458 4458
+#define kTile4459 4459
+#define kTile4460 4460
+#define kTile4461 4461
+#define kTile4462 4462
+#define kTile4463 4463
+#define kTile4464 4464
+#define kTile4465 4465
+#define kTile4466 4466
+#define kTile4467 4467
+#define kTile4468 4468
+#define kTile4469 4469
+#define kTile4470 4470
+#define kTile4471 4471
+#define kTile4472 4472
+#define kTile4473 4473
+#define kTile4474 4474
+#define kTile4475 4475
+#define kTile4476 4476
+#define kTile4477 4477
+#define kTile4478 4478
+#define kTile4479 4479
+#define kTile4480 4480
+#define kTile4481 4481
+#define kTile4482 4482
+#define kTile4483 4483
+#define kTile4484 4484
+#define kTile4485 4485
+#define kTile4486 4486
+#define kTile4487 4487
+#define kTile4488 4488
+#define kTile4489 4489
+#define kTile4490 4490
+#define kTile4491 4491
+#define kTile4492 4492
+#define kTile4493 4493
+#define kTile4494 4494
+#define kTile4495 4495
+#define kTile4496 4496
+#define kTile4497 4497
+#define kTile4498 4498
+#define kTile4499 4499
+#define kTile4500 4500
+#define kTile4501 4501
+#define kTile4502 4502
+#define kTile4503 4503
+#define kTile4504 4504
+#define kTile4505 4505
+#define kTile4506 4506
+#define kTile4507 4507
+#define kTile4508 4508
+#define kTile4509 4509
+#define kTile4510 4510
+#define kTile4511 4511
+#define kTile4512 4512
+#define kTile4513 4513
+#define kTile4514 4514
+#define kTile4515 4515
+#define kTile4516 4516
+#define kTile4517 4517
+#define kTile4518 4518
+#define kTile4519 4519
+#define kTile4520 4520
+#define kTile4521 4521
+#define kTile4522 4522
+#define kTile4523 4523
+#define kTile4524 4524
+#define kTile4525 4525
+#define kTile4526 4526
+#define kTile4527 4527
+#define kTile4528 4528
+#define kTile4529 4529
+#define kTile4530 4530
+#define kTile4531 4531
+#define kTile4532 4532
+#define kTile4533 4533
+#define kTile4534 4534
+#define kTile4535 4535
+#define kTile4536 4536
+#define kTile4537 4537
+#define kTile4538 4538
+#define kTile4539 4539
+#define kTile4540 4540
+#define kTile4541 4541
+#define kTile4542 4542
+#define kTile4543 4543
+#define kTile4544 4544
+#define kTile4545 4545
+#define kTile4546 4546
+#define kTile4547 4547
+#define kTile4548 4548
+#define kTile4549 4549
+#define kTile4550 4550
+#define kTile4551 4551
+#define kTile4552 4552
+#define kTile4553 4553
+#define kTile4554 4554
+#define kTile4555 4555
+#define kTile4556 4556
+#define kTile4557 4557
+#define kTile4558 4558
+#define kTile4559 4559
+#define kTile4560 4560
+#define kTile4561 4561
+#define kTile4562 4562
+#define kTile4563 4563
+#define kTile4564 4564
+#define kTile4565 4565
+#define kTile4566 4566
+#define kTile4567 4567
+#define kTile4568 4568
+#define kTile4569 4569
+#define kTile4570 4570
+#define kTile4571 4571
+#define kTile4572 4572
+#define kTile4573 4573
+#define kTile4574 4574
+#define kTile4575 4575
+#define kTile4576 4576
+#define kTile4577 4577
+#define kTile4578 4578
+#define kTile4579 4579
+#define kTile4580 4580
+#define kTile4581 4581
+#define kTile4582 4582
+#define kTile4583 4583
+#define kTile4584 4584
+#define kTile4585 4585
+#define kTile4586 4586
+#define kTile4587 4587
+#define kTile4588 4588
+#define kTile4589 4589
+#define kTile4590 4590
+#define kTile4591 4591
+#define kTile4592 4592
+#define kTile4593 4593
+#define kTile4594 4594
+#define kTile4595 4595
+#define kTile4596 4596
+#define kTile4597 4597
+#define kTile4598 4598
+#define kTile4599 4599
+#define kTile4600 4600
+#define kTile4601 4601
+#define kTile4602 4602
+#define kTile4603 4603
+#define kTile4604 4604
+#define kTile4605 4605
+#define kTile4606 4606
+#define kTile4607 4607
+#define kTile4608 4608
+#define kTile4609 4609
+#define kTile4610 4610
+#define kTile4611 4611
+#define kTile4612 4612
+#define kTile4613 4613
+#define kTile4614 4614
+#define kTile4615 4615
+#define kTile4616 4616
+#define kTile4617 4617
+#define kTile4618 4618
+#define kTile4619 4619
+#define kTile4620 4620
+#define kTile4621 4621
+#define kTile4622 4622
+#define kTile4623 4623
+#define kTile4624 4624
+#define kTile4625 4625
+#define kTile4626 4626
+#define kTile4627 4627
+#define kTile4628 4628
+#define kTile4629 4629
+#define kTile4630 4630
+#define kTile4631 4631
+#define kTile4632 4632
+#define kTile4633 4633
+#define kTile4634 4634
+#define kTile4635 4635
+#define kTile4636 4636
+#define kTile4637 4637
+#define kTile4638 4638
+#define kTile4639 4639
+#define kTile4640 4640
+#define kTile4641 4641
+#define kTile4642 4642
+#define kTile4643 4643
+#define kTile4644 4644
+#define kTile4645 4645
+#define kTile4646 4646
+#define kTile4647 4647
+#define kTile4648 4648
+#define kTile4649 4649
+#define kTile4650 4650
+#define kTile4651 4651
+#define kTile4652 4652
+#define kTile4653 4653
+#define kTile4654 4654
+#define kTile4655 4655
+#define kTile4656 4656
+#define kTile4657 4657
+#define kTile4658 4658
+#define kTile4659 4659
+#define kTile4660 4660
+#define kTile4661 4661
+#define kTile4662 4662
+#define kTile4663 4663
+#define kTile4664 4664
+#define kTile4665 4665
+#define kTile4666 4666
+#define kTile4667 4667
+#define kTile4668 4668
+#define kTile4669 4669
+#define kTile4670 4670
+#define kTile4671 4671
+#define kTile4672 4672
+#define kTile4673 4673
+#define kTile4674 4674
+#define kTile4675 4675
+#define kTile4676 4676
+#define kTile4677 4677
+#define kTile4678 4678
+#define kTile4679 4679
+#define kTile4680 4680
+#define kTile4681 4681
+#define kTile4682 4682
+#define kTile4683 4683
+#define kTile4684 4684
+#define kTile4685 4685
+#define kTile4686 4686
+#define kTile4687 4687
+#define kTile4688 4688
+#define kTile4689 4689
+#define kTile4690 4690
+#define kTile4691 4691
+#define kTile4692 4692
+#define kTile4693 4693
+#define kTile4694 4694
+#define kTile4695 4695
+#define kTile4696 4696
+#define kTile4697 4697
+#define kTile4698 4698
+#define kTile4699 4699
+#define kTile4700 4700
+#define kTile4701 4701
+#define kTile4702 4702
+#define kTile4703 4703
+#define kTile4704 4704
+#define kTile4705 4705
+#define kTile4706 4706
+#define kTile4707 4707
+#define kTile4708 4708
+#define kTile4709 4709
+#define kTile4710 4710
+#define kTile4711 4711
+#define kTile4712 4712
+#define kTile4713 4713
+#define kTile4714 4714
+#define kTile4715 4715
+#define kTile4716 4716
+#define kTile4717 4717
+#define kTile4718 4718
+#define kTile4719 4719
+#define kTile4720 4720
+#define kTile4721 4721
+#define kTile4722 4722
+#define kTile4723 4723
+#define kTile4724 4724
+#define kTile4725 4725
+#define kTile4726 4726
+#define kTile4727 4727
+#define kTile4728 4728
+#define kTile4729 4729
+#define kTile4730 4730
+#define kTile4731 4731
+#define kTile4732 4732
+#define kTile4733 4733
+#define kTile4734 4734
+#define kTile4735 4735
+#define kTile4736 4736
+#define kTile4737 4737
+#define kTile4738 4738
+#define kTile4739 4739
+#define kTile4740 4740
+#define kTile4741 4741
+#define kTile4742 4742
+#define kTile4743 4743
+#define kTile4744 4744
+#define kTile4745 4745
+#define kTile4746 4746
+#define kTile4747 4747
+#define kTile4748 4748
+#define kTile4749 4749
+#define kTile4750 4750
+#define kTile4751 4751
+#define kTile4752 4752
+#define kTile4753 4753
+#define kTile4754 4754
+#define kTile4755 4755
+#define kTile4756 4756
+#define kTile4757 4757
+#define kTile4758 4758
+#define kTile4759 4759
+#define kTile4760 4760
+#define kTile4761 4761
+#define kTile4762 4762
+#define kTile4763 4763
+#define kTile4764 4764
+#define kTile4765 4765
+#define kTile4766 4766
+#define kTile4767 4767
+#define kTile4768 4768
+#define kTile4769 4769
+#define kTile4770 4770
+#define kTile4771 4771
+#define kTile4772 4772
+#define kTile4773 4773
+#define kTile4774 4774
+#define kTile4775 4775
+#define kTile4776 4776
+#define kTile4777 4777
+#define kTile4778 4778
+#define kTile4779 4779
+#define kTile4780 4780
+#define kTile4781 4781
+#define kTile4782 4782
+#define kTile4783 4783
+#define kTile4784 4784
+#define kTile4785 4785
+#define kTile4786 4786
+#define kTile4787 4787
+#define kTile4788 4788
+#define kTile4789 4789
+#define kTile4790 4790
+#define kTile4791 4791
+#define kTile4792 4792
+#define kTile4793 4793
+#define kTile4794 4794
+#define kTile4795 4795
+#define kTile4796 4796
+#define kTile4797 4797
+#define kTile4798 4798
+#define kTile4799 4799
+#define kTile4800 4800
+#define kTile4801 4801
+#define kTile4802 4802
+#define kTile4803 4803
+#define kTile4804 4804
+#define kTile4805 4805
+#define kTile4806 4806
+#define kTile4807 4807
+#define kTile4808 4808
+#define kTile4809 4809
+#define kTile4810 4810
+#define kTile4811 4811
+#define kTile4812 4812
+#define kTile4813 4813
+#define kTile4814 4814
+#define kTile4815 4815
+#define kTile4816 4816
+#define kTile4817 4817
+#define kTile4818 4818
+#define kTile4819 4819
+#define kTile4820 4820
+#define kTile4821 4821
+#define kTile4822 4822
+#define kTile4823 4823
+#define kTile4824 4824
+#define kTile4825 4825
+#define kTile4826 4826
+#define kTile4827 4827
+#define kTile4828 4828
+#define kTile4829 4829
+#define kTile4830 4830
+#define kTile4831 4831
+#define kTile4832 4832
+#define kTile4833 4833
+#define kTile4834 4834
+#define kTile4835 4835
+#define kTile4836 4836
+#define kTile4837 4837
+#define kTile4838 4838
+#define kTile4839 4839
+#define kTile4840 4840
+#define kTile4841 4841
+#define kTile4842 4842
+#define kTile4843 4843
+#define kTile4844 4844
+#define kTile4845 4845
+#define kTile4846 4846
+#define kTile4847 4847
+#define kTile4848 4848
+#define kTile4849 4849
+#define kTile4850 4850
+#define kTile4851 4851
+#define kTile4852 4852
+#define kTile4853 4853
+#define kTile4854 4854
+#define kTile4855 4855
+#define kTile4856 4856
+#define kTile4857 4857
+#define kTile4858 4858
+#define kTile4859 4859
+#define kTile4860 4860
+#define kTile4861 4861
+#define kTile4862 4862
+#define kTile4863 4863
+#define kTile4864 4864
+#define kTile4865 4865
+#define kTile4866 4866
+#define kTile4867 4867
+#define kTile4868 4868
+#define kTile4869 4869
+#define kTile4870 4870
+#define kTile4871 4871
+#define kTile4872 4872
+#define kTile4873 4873
+#define kTile4874 4874
+#define kTile4875 4875
+#define kTile4876 4876
+#define kTile4877 4877
+#define kTile4878 4878
+#define kTile4879 4879
+#define kTile4880 4880
+#define kTile4881 4881
+#define kTile4882 4882
+#define kTile4883 4883
+#define kTile4884 4884
+#define kTile4885 4885
+#define kTile4886 4886
+#define kTile4887 4887
+#define kTile4888 4888
+#define kTile4889 4889
+#define kTile4890 4890
+#define kTile4891 4891
+#define kTile4892 4892
+#define kTile4893 4893
+#define kTile4894 4894
+#define kTile4895 4895
+#define kTile4896 4896
+#define kTile4897 4897
+#define kTile4898 4898
+#define kTile4899 4899
+#define kTile4900 4900
+#define kTile4901 4901
+#define kTile4902 4902
+#define kTile4903 4903
+#define kTile4904 4904
+#define kTile4905 4905
+#define kTile4906 4906
+#define kTile4907 4907
+#define kTile4908 4908
+#define kTile4909 4909
+#define kTile4910 4910
+#define kTile4911 4911
+#define kTile4912 4912
+#define kTile4913 4913
+#define kTile4914 4914
+#define kTile4915 4915
+#define kTile4916 4916
+#define kTile4917 4917
+#define kTile4918 4918
+#define kTile4919 4919
+#define kTile4920 4920
+#define kTile4921 4921
+#define kTile4922 4922
+#define kTile4923 4923
+#define kTile4924 4924
+#define kTile4925 4925
+#define kTile4926 4926
+#define kTile4927 4927
+#define kTile4928 4928
+#define kTile4929 4929
+#define kTile4930 4930
+#define kTile4931 4931
+#define kTile4932 4932
+#define kTile4933 4933
+#define kTile4934 4934
+#define kTile4935 4935
+#define kTile4936 4936
+#define kTile4937 4937
+#define kTile4938 4938
+#define kTile4939 4939
+#define kTile4940 4940
+#define kTile4941 4941
+#define kTile4942 4942
+#define kTile4943 4943
+#define kTile4944 4944
+#define kTile4945 4945
+#define kTile4946 4946
+#define kTile4947 4947
+#define kTile4948 4948
+#define kTile4949 4949
+#define kTile4950 4950
+#define kTile4951 4951
+#define kTile4952 4952
+#define kTile4953 4953
+#define kTile4954 4954
+#define kTile4955 4955
+#define kTile4956 4956
+#define kTile4957 4957
+#define kTile4958 4958
+#define kTile4959 4959
+#define kTile4960 4960
+#define kTile4961 4961
+#define kTile4962 4962
+#define kTile4963 4963
+#define kTile4964 4964
+#define kTile4965 4965
+#define kTile4966 4966
+#define kTile4967 4967
+#define kTile4968 4968
+#define kTile4969 4969
+#define kTile4970 4970
+#define kTile4971 4971
+#define kTile4972 4972
+#define kTile4973 4973
+#define kTile4974 4974
+#define kTile4975 4975
+#define kTile4976 4976
+#define kTile4977 4977
+#define kTile4978 4978
+#define kTile4979 4979
+#define kTile4980 4980
+#define kTile4981 4981
+#define kTile4982 4982
+#define kTile4983 4983
+#define kTile4984 4984
+#define kTile4985 4985
+#define kTile4986 4986
+#define kTile4987 4987
+#define kTile4988 4988
+#define kTile4989 4989
+#define kTile4990 4990
+#define kTile4991 4991
+#define kTile4992 4992
+#define kTile4993 4993
+#define kTile4994 4994
+#define kTile4995 4995
+#define kTile4996 4996
+#define kTile4997 4997
+#define kTile4998 4998
+#define kTile4999 4999
+#define kTile5000 5000
+#define kTile5001 5001
+#define kTile5002 5002
+#define kTile5003 5003
+#define kTile5004 5004
+#define kTile5005 5005
+#define kTile5006 5006
+#define kTile5007 5007
+#define kTile5008 5008
+#define kTile5009 5009
+#define kTile5010 5010
+#define kTile5011 5011
+#define kTile5012 5012
+#define kTile5013 5013
+#define kTile5014 5014
+#define kTile5015 5015
+#define kTile5016 5016
+#define kTile5017 5017
+#define kTile5018 5018
+#define kTile5019 5019
+#define kTile5020 5020
+#define kTile5021 5021
+#define kTile5022 5022
+#define kTile5023 5023
+#define kTile5024 5024
+#define kTile5025 5025
+#define kTile5026 5026
+#define kTile5027 5027
+#define kTile5028 5028
+#define kTile5029 5029
+#define kTile5030 5030
+#define kTile5031 5031
+#define kTile5032 5032
+#define kTile5033 5033
+#define kTile5034 5034
+#define kTile5035 5035
+#define kTile5036 5036
+#define kTile5037 5037
+#define kTile5038 5038
+#define kTile5039 5039
+#define kTile5040 5040
+#define kTile5041 5041
+#define kTile5042 5042
+#define kTile5043 5043
+#define kTile5044 5044
+#define kTile5045 5045
+#define kTile5046 5046
+#define kTile5047 5047
+#define kTile5048 5048
+#define kTile5049 5049
+#define kTile5050 5050
+#define kTile5051 5051
+#define kTile5052 5052
+#define kTile5053 5053
+#define kTile5054 5054
+#define kTile5055 5055
+#define kTile5056 5056
+#define kTile5057 5057
+#define kTile5058 5058
+#define kTile5059 5059
+#define kTile5060 5060
+#define kTile5061 5061
+#define kTile5062 5062
+#define kTile5063 5063
+#define kTile5064 5064
+#define kTile5065 5065
+#define kTile5066 5066
+#define kTile5067 5067
+#define kTile5068 5068
+#define kTile5069 5069
+#define kTile5070 5070
+#define kTile5071 5071
+#define kTile5072 5072
+#define kTile5073 5073
+#define kTile5074 5074
+#define kTile5075 5075
+#define kTile5076 5076
+#define kTile5077 5077
+#define kTile5078 5078
+#define kTile5079 5079
+#define kTile5080 5080
+#define kTile5081 5081
+#define kTile5082 5082
+#define kTile5083 5083
+#define kTile5084 5084
+#define kTile5085 5085
+#define kTile5086 5086
+#define kTile5087 5087
+#define kTile5088 5088
+#define kTile5089 5089
+#define kTile5090 5090
+#define kTile5091 5091
+#define kTile5092 5092
+#define kTile5093 5093
+#define kTile5094 5094
+#define kTile5095 5095
+#define kTile5096 5096
+#define kTile5097 5097
+#define kTile5098 5098
+#define kTile5099 5099
+#define kTile5100 5100
+#define kTile5101 5101
+#define kTile5102 5102
+#define kTile5103 5103
+#define kTile5104 5104
+#define kTile5105 5105
+#define kTile5106 5106
+#define kTile5107 5107
+#define kTile5108 5108
+#define kTile5109 5109
+#define kTile5110 5110
+#define kTile5111 5111
+#define kTile5112 5112
+#define kTile5113 5113
+#define kTile5114 5114
+#define kTile5115 5115
+#define kTile5116 5116
+#define kTile5117 5117
+#define kTile5118 5118
+#define kTile5119 5119
+#define kTile5120 5120
+#define kTile5121 5121
+#define kTile5122 5122
+#define kTile5123 5123
+#define kTile5124 5124
+#define kTile5125 5125
+#define kTile5126 5126
+#define kTile5127 5127
+#define kTile5128 5128
+#define kTile5129 5129
+#define kTile5130 5130
+#define kTile5131 5131
+#define kTile5132 5132
+#define kTile5133 5133
+#define kTile5134 5134
+#define kTile5135 5135
+#define kTile5136 5136
+#define kTile5137 5137
+#define kTile5138 5138
+#define kTile5139 5139
+#define kTile5140 5140
+#define kTile5141 5141
+#define kTile5142 5142
+#define kTile5143 5143
+#define kTile5144 5144
+#define kTile5145 5145
+#define kTile5146 5146
+#define kTile5147 5147
+#define kTile5148 5148
+#define kTile5149 5149
+#define kTile5150 5150
+#define kTile5151 5151
+#define kTile5152 5152
+#define kTile5153 5153
+#define kTile5154 5154
+#define kTile5155 5155
+#define kTile5156 5156
+#define kTile5157 5157
+#define kTile5158 5158
+#define kTile5159 5159
+#define kTile5160 5160
+#define kTile5161 5161
+#define kTile5162 5162
+#define kTile5163 5163
+#define kTile5164 5164
+#define kTile5165 5165
+#define kTile5166 5166
+#define kTile5167 5167
+#define kTile5168 5168
+#define kTile5169 5169
+#define kTile5170 5170
+#define kTile5171 5171
+#define kTile5172 5172
+#define kTile5173 5173
+#define kTile5174 5174
+#define kTile5175 5175
+#define kTile5176 5176
+#define kTile5177 5177
+#define kTile5178 5178
+#define kTile5179 5179
+#define kTile5180 5180
+#define kTile5181 5181
+#define kTile5182 5182
+#define kTile5183 5183
+#define kTile5184 5184
+#define kTile5185 5185
+#define kTile5186 5186
+#define kTile5187 5187
+#define kTile5188 5188
+#define kTile5189 5189
+#define kTile5190 5190
+#define kTile5191 5191
+#define kTile5192 5192
+#define kTile5193 5193
+#define kTile5194 5194
+#define kTile5195 5195
+#define kTile5196 5196
+#define kTile5197 5197
+#define kTile5198 5198
+#define kTile5199 5199
+#define kTile5200 5200
+#define kTile5201 5201
+#define kTile5202 5202
+#define kTile5203 5203
+#define kTile5204 5204
+#define kTile5205 5205
+#define kTile5206 5206
+#define kTile5207 5207
+#define kTile5208 5208
+#define kTile5209 5209
+#define kTile5210 5210
+#define kTile5211 5211
+#define kTile5212 5212
+#define kTile5213 5213
+#define kTile5214 5214
+#define kTile5215 5215
+#define kTile5216 5216
+#define kTile5217 5217
+#define kTile5218 5218
+#define kTile5219 5219
+#define kTile5220 5220
+#define kTile5221 5221
+#define kTile5222 5222
+#define kTile5223 5223
+#define kTile5224 5224
+#define kTile5225 5225
+#define kTile5226 5226
+#define kTile5227 5227
+#define kTile5228 5228
+#define kTile5229 5229
+#define kTile5230 5230
+#define kTile5231 5231
+#define kTile5232 5232
+#define kTile5233 5233
+#define kTile5234 5234
+#define kTile5235 5235
+#define kTile5236 5236
+#define kTile5237 5237
+#define kTile5238 5238
+#define kTile5239 5239
+#define kTile5240 5240
+#define kTile5241 5241
+#define kTile5242 5242
+#define kTile5243 5243
+#define kTile5244 5244
+#define kTile5245 5245
+#define kTile5246 5246
+#define kTile5247 5247
+#define kTile5248 5248
+#define kTile5249 5249
+#define kTile5250 5250
+#define kTile5251 5251
+#define kTile5252 5252
+#define kTile5253 5253
+#define kTile5254 5254
+#define kTile5255 5255
+#define kTile5256 5256
+#define kTile5257 5257
+#define kTile5258 5258
+#define kTile5259 5259
+#define kTile5260 5260
+#define kTile5261 5261
+#define kTile5262 5262
+#define kTile5263 5263
+#define kTile5264 5264
+#define kTile5265 5265
+#define kTile5266 5266
+#define kTile5267 5267
+#define kTile5268 5268
+#define kTile5269 5269
+#define kTile5270 5270
+#define kTile5271 5271
+#define kTile5272 5272
+#define kTile5273 5273
+#define kTile5274 5274
+#define kTile5275 5275
+#define kTile5276 5276
+#define kTile5277 5277
+#define kTile5278 5278
+#define kTile5279 5279
+#define kTile5280 5280
+#define kTile5281 5281
+#define kTile5282 5282
+#define kTile5283 5283
+#define kTile5284 5284
+#define kTile5285 5285
+#define kTile5286 5286
+#define kTile5287 5287
+#define kTile5288 5288
+#define kTile5289 5289
+#define kTile5290 5290
+#define kTile5291 5291
+#define kTile5292 5292
+#define kTile5293 5293
+#define kTile5294 5294
+#define kTile5295 5295
+#define kTile5296 5296
+#define kTile5297 5297
+#define kTile5298 5298
+#define kTile5299 5299
+#define kTile5300 5300
+#define kTile5301 5301
+#define kTile5302 5302
+#define kTile5303 5303
+#define kTile5304 5304
+#define kTile5305 5305
+#define kTile5306 5306
+#define kTile5307 5307
+#define kTile5308 5308
+#define kTile5309 5309
+#define kTile5310 5310
+#define kTile5311 5311
+#define kTile5312 5312
+#define kTile5313 5313
+#define kTile5314 5314
+#define kTile5315 5315
+#define kTile5316 5316
+#define kTile5317 5317
+#define kTile5318 5318
+#define kTile5319 5319
+#define kTile5320 5320
+#define kTile5321 5321
+#define kTile5322 5322
+#define kTile5323 5323
+#define kTile5324 5324
+#define kTile5325 5325
+#define kTile5326 5326
+#define kTile5327 5327
+#define kTile5328 5328
+#define kTile5329 5329
+#define kTile5330 5330
+#define kTile5331 5331
+#define kTile5332 5332
+#define kTile5333 5333
+#define kTile5334 5334
+#define kTile5335 5335
+#define kTile5336 5336
+#define kTile5337 5337
+#define kTile5338 5338
+#define kTile5339 5339
+#define kTile5340 5340
+#define kTile5341 5341
+#define kTile5342 5342
+#define kTile5343 5343
+#define kTile5344 5344
+#define kTile5345 5345
+#define kTile5346 5346
+#define kTile5347 5347
+#define kTile5348 5348
+#define kTile5349 5349
+#define kTile5350 5350
+#define kTile5351 5351
+#define kTile5352 5352
+#define kTile5353 5353
+#define kTile5354 5354
+#define kTile5355 5355
+#define kTile5356 5356
+#define kTile5357 5357
+#define kTile5358 5358
+#define kTile5359 5359
+#define kTile5360 5360
+#define kTile5361 5361
+#define kTile5362 5362
+#define kTile5363 5363
+#define kTile5364 5364
+#define kTile5365 5365
+#define kTile5366 5366
+#define kTile5367 5367
+#define kTile5368 5368
+#define kTile5369 5369
+#define kTile5370 5370
+#define kTile5371 5371
+#define kTile5372 5372
+#define kTile5373 5373
+#define kTile5374 5374
+#define kTile5375 5375
+#define kTile5376 5376
+#define kTile5377 5377
+#define kTile5378 5378
+#define kTile5379 5379
+#define kTile5380 5380
+#define kTile5381 5381
+#define kTile5382 5382
+#define kTile5383 5383
+#define kTile5384 5384
+#define kTile5385 5385
+#define kTile5386 5386
+#define kTile5387 5387
+#define kTile5388 5388
+#define kTile5389 5389
+#define kTile5390 5390
+#define kTile5391 5391
+#define kTile5392 5392
+#define kTile5393 5393
+#define kTile5394 5394
+#define kTile5395 5395
+#define kTile5396 5396
+#define kTile5397 5397
+#define kTile5398 5398
+#define kTile5399 5399
+#define kTile5400 5400
+#define kTile5401 5401
+#define kTile5402 5402
+#define kTile5403 5403
+#define kTile5404 5404
+#define kTile5405 5405
+#define kTile5406 5406
+#define kTile5407 5407
+#define kTile5408 5408
+#define kTile5409 5409
+#define kTile5410 5410
+#define kTile5411 5411
+#define kTile5412 5412
+#define kTile5413 5413
+#define kTile5414 5414
+#define kTile5415 5415
+#define kTile5416 5416
+#define kTile5417 5417
+#define kTile5418 5418
+#define kTile5419 5419
+#define kTile5420 5420
+#define kTile5421 5421
+#define kTile5422 5422
+#define kTile5423 5423
+#define kTile5424 5424
+#define kTile5425 5425
+#define kTile5426 5426
+#define kTile5427 5427
+#define kTile5428 5428
+#define kTile5429 5429
+#define kTile5430 5430
+#define kTile5431 5431
+#define kTile5432 5432
+#define kTile5433 5433
+#define kTile5434 5434
+#define kTile5435 5435
+#define kTile5436 5436
+#define kTile5437 5437
+#define kTile5438 5438
+#define kTile5439 5439
+#define kTile5440 5440
+#define kTile5441 5441
+#define kTile5442 5442
+#define kTile5443 5443
+#define kTile5444 5444
+#define kTile5445 5445
+#define kTile5446 5446
+#define kTile5447 5447
+#define kTile5448 5448
+#define kTile5449 5449
+#define kTile5450 5450
+#define kTile5451 5451
+#define kTile5452 5452
+#define kTile5453 5453
+#define kTile5454 5454
+#define kTile5455 5455
+#define kTile5456 5456
+#define kTile5457 5457
+#define kTile5458 5458
+#define kTile5459 5459
+#define kTile5460 5460
+#define kTile5461 5461
+#define kTile5462 5462
+#define kTile5463 5463
+#define kTile5464 5464
+#define kTile5465 5465
+#define kTile5466 5466
+#define kTile5467 5467
+#define kTile5468 5468
+#define kTile5469 5469
+#define kTile5470 5470
+#define kTile5471 5471
+#define kTile5472 5472
+#define kTile5473 5473
+#define kTile5474 5474
+#define kTile5475 5475
+#define kTile5476 5476
+#define kTile5477 5477
+#define kTile5478 5478
+#define kTile5479 5479
+#define kTile5480 5480
+#define kTile5481 5481
+#define kTile5482 5482
+#define kTile5483 5483
+#define kTile5484 5484
+#define kTile5485 5485
+#define kTile5486 5486
+#define kTile5487 5487
+#define kTile5488 5488
+#define kTile5489 5489
+#define kTile5490 5490
+#define kTile5491 5491
+#define kTile5492 5492
+#define kTile5493 5493
+#define kTile5494 5494
+#define kTile5495 5495
+#define kTile5496 5496
+#define kTile5497 5497
+#define kTile5498 5498
+#define kTile5499 5499
+#define kTile5500 5500
+#define kTile5501 5501
+#define kTile5502 5502
+#define kTile5503 5503
+#define kTile5504 5504
+#define kTile5505 5505
+#define kTile5506 5506
+#define kTile5507 5507
+#define kTile5508 5508
+#define kTile5509 5509
+#define kTile5510 5510
+#define kTile5511 5511
+#define kTile5512 5512
+#define kTile5513 5513
+#define kTile5514 5514
+#define kTile5515 5515
+#define kTile5516 5516
+#define kTile5517 5517
+#define kTile5518 5518
+#define kTile5519 5519
+#define kTile5520 5520
+#define kTile5521 5521
+#define kTile5522 5522
+#define kTile5523 5523
+#define kTile5524 5524
+#define kTile5525 5525
+#define kTile5526 5526
+#define kTile5527 5527
+#define kTile5528 5528
+#define kTile5529 5529
+#define kTile5530 5530
+#define kTile5531 5531
+#define kTile5532 5532
+#define kTile5533 5533
+#define kTile5534 5534
+#define kTile5535 5535
+#define kTile5536 5536
+#define kTile5537 5537
+#define kTile5538 5538
+#define kTile5539 5539
+#define kTile5540 5540
+#define kTile5541 5541
+#define kTile5542 5542
+#define kTile5543 5543
+#define kTile5544 5544
+#define kTile5545 5545
+#define kTile5546 5546
+#define kTile5547 5547
+#define kTile5548 5548
+#define kTile5549 5549
+#define kTile5550 5550
+#define kTile5551 5551
+#define kTile5552 5552
+#define kTile5553 5553
+#define kTile5554 5554
+#define kTile5555 5555
+#define kTile5556 5556
+#define kTile5557 5557
+#define kTile5558 5558
+#define kTile5559 5559
+#define kTile5560 5560
+#define kTile5561 5561
+#define kTile5562 5562
+#define kTile5563 5563
+#define kTile5564 5564
+#define kTile5565 5565
+#define kTile5566 5566
+#define kTile5567 5567
+#define kTile5568 5568
+#define kTile5569 5569
+#define kTile5570 5570
+#define kTile5571 5571
+#define kTile5572 5572
+#define kTile5573 5573
+#define kTile5574 5574
+#define kTile5575 5575
+#define kTile5576 5576
+#define kTile5577 5577
+#define kTile5578 5578
+#define kTile5579 5579
+#define kTile5580 5580
+#define kTile5581 5581
+#define kTile5582 5582
+#define kTile5583 5583
+#define kTile5584 5584
+#define kTile5585 5585
+#define kTile5586 5586
+#define kTile5587 5587
+#define kTile5588 5588
+#define kTile5589 5589
+#define kTile5590 5590
+#define kTile5591 5591
+#define kTile5592 5592
+#define kTile5593 5593
+#define kTile5594 5594
+#define kTile5595 5595
+#define kTile5596 5596
+#define kTile5597 5597
+#define kTile5598 5598
+#define kTile5599 5599
+#define kTile5600 5600
+#define kTile5601 5601
+#define kTile5602 5602
+#define kTile5603 5603
+#define kTile5604 5604
+#define kTile5605 5605
+#define kTile5606 5606
+#define kTile5607 5607
+#define kTile5608 5608
+#define kTile5609 5609
+#define kTile5610 5610
+#define kTile5611 5611
+#define kTile5612 5612
+#define kTile5613 5613
+#define kTile5614 5614
+#define kTile5615 5615
+#define kTile5616 5616
+#define kTile5617 5617
+#define kTile5618 5618
+#define kTile5619 5619
+#define kTile5620 5620
+#define kTile5621 5621
+#define kTile5622 5622
+#define kTile5623 5623
+#define kTile5624 5624
+#define kTile5625 5625
+#define kTile5626 5626
+#define kTile5627 5627
+#define kTile5628 5628
+#define kTile5629 5629
+#define kTile5630 5630
+#define kTile5631 5631
+#define kTile5632 5632
+#define kTile5633 5633
+#define kTile5634 5634
+#define kTile5635 5635
+#define kTile5636 5636
+#define kTile5637 5637
+#define kTile5638 5638
+#define kTile5639 5639
+#define kTile5640 5640
+#define kTile5641 5641
+#define kTile5642 5642
+#define kTile5643 5643
+#define kTile5644 5644
+#define kTile5645 5645
+#define kTile5646 5646
+#define kTile5647 5647
+#define kTile5648 5648
+#define kTile5649 5649
+#define kTile5650 5650
+#define kTile5651 5651
+#define kTile5652 5652
+#define kTile5653 5653
+#define kTile5654 5654
+#define kTile5655 5655
+#define kTile5656 5656
+#define kTile5657 5657
+#define kTile5658 5658
+#define kTile5659 5659
+#define kTile5660 5660
+#define kTile5661 5661
+#define kTile5662 5662
+#define kTile5663 5663
+#define kTile5664 5664
+#define kTile5665 5665
+#define kTile5666 5666
+#define kTile5667 5667
+#define kTile5668 5668
+#define kTile5669 5669
+#define kTile5670 5670
+#define kTile5671 5671
+#define kTile5672 5672
+#define kTile5673 5673
+#define kTile5674 5674
+#define kTile5675 5675
+#define kTile5676 5676
+#define kTile5677 5677
+#define kTile5678 5678
+#define kTile5679 5679
+#define kTile5680 5680
+#define kTile5681 5681
+#define kTile5682 5682
+#define kTile5683 5683
+#define kTile5684 5684
+#define kTile5685 5685
+#define kTile5686 5686
+#define kTile5687 5687
+#define kTile5688 5688
+#define kTile5689 5689
+#define kTile5690 5690
+#define kTile5691 5691
+#define kTile5692 5692
+#define kTile5693 5693
+#define kTile5694 5694
+#define kTile5695 5695
+#define kTile5696 5696
+#define kTile5697 5697
+#define kTile5698 5698
+#define kTile5699 5699
+#define kTile5700 5700
+#define kTile5701 5701
+#define kTile5702 5702
+#define kTile5703 5703
+#define kTile5704 5704
+#define kTile5705 5705
+#define kTile5706 5706
+#define kTile5707 5707
+#define kTile5708 5708
+#define kTile5709 5709
+#define kTile5710 5710
+#define kTile5711 5711
+#define kTile5712 5712
+#define kTile5713 5713
+#define kTile5714 5714
+#define kTile5715 5715
+#define kTile5716 5716
+#define kTile5717 5717
+#define kTile5718 5718
+#define kTile5719 5719
+#define kTile5720 5720
+#define kTile5721 5721
+#define kTile5722 5722
+#define kTile5723 5723
+#define kTile5724 5724
+#define kTile5725 5725
+#define kTile5726 5726
+#define kTile5727 5727
+#define kTile5728 5728
+#define kTile5729 5729
+#define kTile5730 5730
+#define kTile5731 5731
+#define kTile5732 5732
+#define kTile5733 5733
+#define kTile5734 5734
+#define kTile5735 5735
+#define kTile5736 5736
+#define kTile5737 5737
+#define kTile5738 5738
+#define kTile5739 5739
+#define kTile5740 5740
+#define kTile5741 5741
+#define kTile5742 5742
+#define kTile5743 5743
+#define kTile5744 5744
+#define kTile5745 5745
+#define kTile5746 5746
+#define kTile5747 5747
+#define kTile5748 5748
+#define kTile5749 5749
+#define kTile5750 5750
+#define kTile5751 5751
+#define kTile5752 5752
+#define kTile5753 5753
+#define kTile5754 5754
+#define kTile5755 5755
+#define kTile5756 5756
+#define kTile5757 5757
+#define kTile5758 5758
+#define kTile5759 5759
+#define kTile5760 5760
+#define kTile5761 5761
+#define kTile5762 5762
+#define kTile5763 5763
+#define kTile5764 5764
+#define kTile5765 5765
+#define kTile5766 5766
+#define kTile5767 5767
+#define kTile5768 5768
+#define kTile5769 5769
+#define kTile5770 5770
+#define kTile5771 5771
+#define kTile5772 5772
+#define kTile5773 5773
+#define kTile5774 5774
+#define kTile5775 5775
+#define kTile5776 5776
+#define kTile5777 5777
+#define kTile5778 5778
+#define kTile5779 5779
+#define kTile5780 5780
+#define kTile5781 5781
+#define kTile5782 5782
+#define kTile5783 5783
+#define kTile5784 5784
+#define kTile5785 5785
+#define kTile5786 5786
+#define kTile5787 5787
+#define kTile5788 5788
+#define kTile5789 5789
+#define kTile5790 5790
+#define kTile5791 5791
+#define kTile5792 5792
+#define kTile5793 5793
+#define kTile5794 5794
+#define kTile5795 5795
+#define kTile5796 5796
+#define kTile5797 5797
+#define kTile5798 5798
+#define kTile5799 5799
+#define kTile5800 5800
+#define kTile5801 5801
+#define kTile5802 5802
+#define kTile5803 5803
+#define kTile5804 5804
+#define kTile5805 5805
+#define kTile5806 5806
+#define kTile5807 5807
+#define kTile5808 5808
+#define kTile5809 5809
+#define kTile5810 5810
+#define kTile5811 5811
+#define kTile5812 5812
+#define kTile5813 5813
+#define kTile5814 5814
+#define kTile5815 5815
+#define kTile5816 5816
+#define kTile5817 5817
+#define kTile5818 5818
+#define kTile5819 5819
+#define kTile5820 5820
+#define kTile5821 5821
+#define kTile5822 5822
+#define kTile5823 5823
+#define kTile5824 5824
+#define kTile5825 5825
+#define kTile5826 5826
+#define kTile5827 5827
+#define kTile5828 5828
+#define kTile5829 5829
+#define kTile5830 5830
+#define kTile5831 5831
+#define kTile5832 5832
+#define kTile5833 5833
+#define kTile5834 5834
+#define kTile5835 5835
+#define kTile5836 5836
+#define kTile5837 5837
+#define kTile5838 5838
+#define kTile5839 5839
+#define kTile5840 5840
+#define kTile5841 5841
+#define kTile5842 5842
+#define kTile5843 5843
+#define kTile5844 5844
+#define kTile5845 5845
+#define kTile5846 5846
+#define kTile5847 5847
+#define kTile5848 5848
+#define kTile5849 5849
+#define kTile5850 5850
+#define kTile5851 5851
+#define kTile5852 5852
+#define kTile5853 5853
+#define kTile5854 5854
+#define kTile5855 5855
+#define kTile5856 5856
+#define kTile5857 5857
+#define kTile5858 5858
+#define kTile5859 5859
+#define kTile5860 5860
+#define kTile5861 5861
+#define kTile5862 5862
+#define kTile5863 5863
+#define kTile5864 5864
+#define kTile5865 5865
+#define kTile5866 5866
+#define kTile5867 5867
+#define kTile5868 5868
+#define kTile5869 5869
+#define kTile5870 5870
+#define kTile5871 5871
+#define kTile5872 5872
+#define kTile5873 5873
+#define kTile5874 5874
+#define kTile5875 5875
+#define kTile5876 5876
+#define kTile5877 5877
+#define kTile5878 5878
+#define kTile5879 5879
+#define kTile5880 5880
+#define kTile5881 5881
+#define kTile5882 5882
+#define kTile5883 5883
+#define kTile5884 5884
+#define kTile5885 5885
+#define kTile5886 5886
+#define kTile5887 5887
+#define kTile5888 5888
+#define kTile5889 5889
+#define kTile5890 5890
+#define kTile5891 5891
+#define kTile5892 5892
+#define kTile5893 5893
+#define kTile5894 5894
+#define kTile5895 5895
+#define kTile5896 5896
+#define kTile5897 5897
+#define kTile5898 5898
+#define kTile5899 5899
+#define kTile5900 5900
+#define kTile5901 5901
+#define kTile5902 5902
+#define kTile5903 5903
+#define kTile5904 5904
+#define kTile5905 5905
+#define kTile5906 5906
+#define kTile5907 5907
+#define kTile5908 5908
+#define kTile5909 5909
+#define kTile5910 5910
+#define kTile5911 5911
+#define kTile5912 5912
+#define kTile5913 5913
+#define kTile5914 5914
+#define kTile5915 5915
+#define kTile5916 5916
+#define kTile5917 5917
+#define kTile5918 5918
+#define kTile5919 5919
+#define kTile5920 5920
+#define kTile5921 5921
+#define kTile5922 5922
+#define kTile5923 5923
+#define kTile5924 5924
+#define kTile5925 5925
+#define kTile5926 5926
+#define kTile5927 5927
+#define kTile5928 5928
+#define kTile5929 5929
+#define kTile5930 5930
+#define kTile5931 5931
+#define kTile5932 5932
+#define kTile5933 5933
+#define kTile5934 5934
+#define kTile5935 5935
+#define kTile5936 5936
+#define kTile5937 5937
+#define kTile5938 5938
+#define kTile5939 5939
+#define kTile5940 5940
+#define kTile5941 5941
+#define kTile5942 5942
+#define kTile5943 5943
+#define kTile5944 5944
+#define kTile5945 5945
+#define kTile5946 5946
+#define kTile5947 5947
+#define kTile5948 5948
+#define kTile5949 5949
+#define kTile5950 5950
+#define kTile5951 5951
+#define kTile5952 5952
+#define kTile5953 5953
+#define kTile5954 5954
+#define kTile5955 5955
+#define kTile5956 5956
+#define kTile5957 5957
+#define kTile5958 5958
+#define kTile5959 5959
+#define kTile5960 5960
+#define kTile5961 5961
+#define kTile5962 5962
+#define kTile5963 5963
+#define kTile5964 5964
+#define kTile5965 5965
+#define kTile5966 5966
+#define kTile5967 5967
+#define kTile5968 5968
+#define kTile5969 5969
+#define kTile5970 5970
+#define kTile5971 5971
+#define kTile5972 5972
+#define kTile5973 5973
+#define kTile5974 5974
+#define kTile5975 5975
+#define kTile5976 5976
+#define kTile5977 5977
+#define kTile5978 5978
+#define kTile5979 5979
+#define kTile5980 5980
+#define kTile5981 5981
+#define kTile5982 5982
+#define kTile5983 5983
+#define kTile5984 5984
+#define kTile5985 5985
+#define kTile5986 5986
+#define kTile5987 5987
+#define kTile5988 5988
+#define kTile5989 5989
+#define kTile5990 5990
+#define kTile5991 5991
+#define kTile5992 5992
+#define kTile5993 5993
+#define kTile5994 5994
+#define kTile5995 5995
+#define kTile5996 5996
+#define kTile5997 5997
+#define kTile5998 5998
+#define kTile5999 5999
+#define kTile6000 6000
+#define kTile6001 6001
+#define kTile6002 6002
+#define kTile6003 6003
+#define kTile6004 6004
+#define kTile6005 6005
+#define kTile6006 6006
+#define kTile6007 6007
+#define kTile6008 6008
+#define kTile6009 6009
+#define kTile6010 6010
+#define kTile6011 6011
+#define kTile6012 6012
+#define kTile6013 6013
+#define kTile6014 6014
+#define kTile6015 6015
+#define kTile6016 6016
+#define kTile6017 6017
+#define kTile6018 6018
+#define kTile6019 6019
+#define kTile6020 6020
+#define kTile6021 6021
+#define kTile6022 6022
+#define kTile6023 6023
+#define kTile6024 6024
+#define kTile6025 6025
+#define kTile6026 6026
+#define kTile6027 6027
+#define kTile6028 6028
+#define kTile6029 6029
+#define kTile6030 6030
+#define kTile6031 6031
+#define kTile6032 6032
+#define kTile6033 6033
+#define kTile6034 6034
+#define kTile6035 6035
+#define kTile6036 6036
+#define kTile6037 6037
+#define kTile6038 6038
+#define kTile6039 6039
+#define kTile6040 6040
+#define kTile6041 6041
+#define kTile6042 6042
+#define kTile6043 6043
+#define kTile6044 6044
+#define kTile6045 6045
+#define kTile6046 6046
+#define kTile6047 6047
+#define kTile6048 6048
+#define kTile6049 6049
+#define kTile6050 6050
+#define kTile6051 6051
+#define kTile6052 6052
+#define kTile6053 6053
+#define kTile6054 6054
+#define kTile6055 6055
+#define kTile6056 6056
+#define kTile6057 6057
+#define kTile6058 6058
+#define kTile6059 6059
+#define kTile6060 6060
+#define kTile6061 6061
+#define kTile6062 6062
+#define kTile6063 6063
+#define kTile6064 6064
+#define kTile6065 6065
+#define kTile6066 6066
+#define kTile6067 6067
+#define kTile6068 6068
+#define kTile6069 6069
+#define kTile6070 6070
+#define kTile6071 6071
+#define kTile6072 6072
+#define kTile6073 6073
+#define kTile6074 6074
+#define kTile6075 6075
+#define kTile6076 6076
+#define kTile6077 6077
+#define kTile6078 6078
+#define kTile6079 6079
+#define kTile6080 6080
+#define kTile6081 6081
+#define kTile6082 6082
+#define kTile6083 6083
+#define kTile6084 6084
+#define kTile6085 6085
+#define kTile6086 6086
+#define kTile6087 6087
+#define kTile6088 6088
+#define kTile6089 6089
+#define kTile6090 6090
+#define kTile6091 6091
+#define kTile6092 6092
+#define kTile6093 6093
+#define kTile6094 6094
+#define kTile6095 6095
+#define kTile6096 6096
+#define kTile6097 6097
+#define kTile6098 6098
+#define kTile6099 6099
+#define kTile6100 6100
+#define kTile6101 6101
+#define kTile6102 6102
+#define kTile6103 6103
+#define kTile6104 6104
+#define kTile6105 6105
+#define kTile6106 6106
+#define kTile6107 6107
+#define kTile6108 6108
+#define kTile6109 6109
+#define kTile6110 6110
+#define kTile6111 6111
+#define kTile6112 6112
+#define kTile6113 6113
+#define kTile6114 6114
+#define kTile6115 6115
+#define kTile6116 6116
+#define kTile6117 6117
+#define kTile6118 6118
+#define kTile6119 6119
+#define kTile6120 6120
+#define kTile6121 6121
+#define kTile6122 6122
+#define kTile6123 6123
+#define kTile6124 6124
+#define kTile6125 6125
+#define kTile6126 6126
+#define kTile6127 6127
+#define kTile6128 6128
+#define kTile6129 6129
+#define kTile6130 6130
+#define kTile6131 6131
+#define kTile6132 6132
+#define kTile6133 6133
+#define kTile6134 6134
+#define kTile6135 6135
+#define kTile6136 6136
+#define kTile6137 6137
+#define kTile6138 6138
+#define kTile6139 6139
+#define kTile6140 6140
+#define kTile6141 6141
+#define kTile6142 6142
+#define kTile6143 6143
+
+#endif
\ No newline at end of file
diff --git a/source/exhumed/src/network.cpp b/source/exhumed/src/network.cpp
new file mode 100644
index 000000000..4ed21c01d
--- /dev/null
+++ b/source/exhumed/src/network.cpp
@@ -0,0 +1,41 @@
+
+// this is net.c in the original code
+
+#include "typedefs.h"
+#include "network.h"
+#include "serial.h"
+#include "input.h"
+
+short nNetMoveFrames = 0;
+
+
+void SendGoodbye()
+{
+ bSendBye = kTrue;
+ UpdateInputs();
+}
+
+void UpdateNetInputs()
+{
+
+}
+
+int InitNet(short nSocket, int nPlayers)
+{
+ return 0;
+}
+
+int InitSerial()
+{
+ return 1;
+}
+
+void AbortNetworkPlay()
+{
+
+}
+
+void UnInitNet()
+{
+
+}
diff --git a/source/exhumed/src/network.h b/source/exhumed/src/network.h
new file mode 100644
index 000000000..8b9a2ce74
--- /dev/null
+++ b/source/exhumed/src/network.h
@@ -0,0 +1,14 @@
+
+#ifndef __network_h__
+#define __network_h__
+
+extern short nNetMoveFrames;
+
+void SendGoodbye();
+void UpdateNetInputs();
+int InitNet(short nSocket, int nPlayers);
+int InitSerial();
+void AbortNetworkPlay();
+void UnInitNet();
+
+#endif
diff --git a/source/exhumed/src/object.cpp b/source/exhumed/src/object.cpp
new file mode 100644
index 000000000..f37f4ba0a
--- /dev/null
+++ b/source/exhumed/src/object.cpp
@@ -0,0 +1,2666 @@
+
+#include "engine.h"
+#include "object.h"
+#include "exhumed.h"
+#include "move.h"
+#include "random.h"
+#include "view.h"
+#include "sound.h"
+#include "init.h"
+#include "runlist.h"
+#include "names.h"
+#include "sequence.h"
+#include "lighting.h"
+#include "anims.h"
+#include "items.h"
+#include "player.h"
+#include "trigdat.h"
+#include "bullet.h"
+#include
+#include
+
+#define kMaxBobs 200
+#define kMaxDrips 50
+#define kMaxMoveSects 50
+#define kMaxObjects 128
+#define kMaxWallFace 4096
+#define kMaxSlideData 128
+#define kMaxPoints 1024
+#define kMaxTraps 40
+#define kMaxTrails 20
+#define kMaxTrailPoints 100
+
+
+static short ObjectSeq[] = {
+ 46, -1, 72, -1
+};
+
+static short ObjectStatnum[] = {
+ kStatExplodeTrigger, kStatExplodeTarget, 98, kStatDestructibleSprite
+};
+
+struct Trail
+{
+ short field_0;
+ short field_2;
+ short field_4;
+ short pad;
+};
+
+struct TrailPoint
+{
+ int x;
+ int y;
+};
+
+struct Bob
+{
+ short nSector;
+ char field_2;
+ char field_3;
+ int z;
+};
+
+struct Drip
+{
+ short nSprite;
+ short field_2;
+};
+
+// 56 bytes
+struct Elev
+{
+ short field_0;
+ short nChannel;
+ short nSector;
+ int field_6;
+ int field_A;
+ short nCountZOffsets; // count of items in zOffsets
+ short nCurZOffset;
+ int zOffsets[8]; // different Z offsets
+ short field_32;
+ short nSprite;
+ short field_36;
+};
+
+// 16 bytes
+struct MoveSect
+{
+ short nSector;
+ short nTrail;
+ short nTrailPoint;
+ short field_6;
+ short field_8; // nSector?
+ int field_10;
+ short field_14; // nChannel?
+};
+
+struct Object
+{
+ short field_0;
+ short nHealth;
+ short field_4;
+ short nSprite;
+ short field_8;
+ short field_10;
+ short field_12;
+};
+
+struct wallFace
+{
+ short nChannel;
+ short nWall;
+ short field_4;
+ short field_6[8];
+};
+
+// TODO - rename
+struct slideData2
+{
+ short nChannel;
+ short field_2;
+ short field_4;
+ short field_6;
+ short field_8;
+ uchar field_A[6]; // pad?
+};
+
+struct slideData
+{
+ int field_0;
+ int field_4;
+ int field_8;
+ int field_C;
+ int field_10;
+ int field_14;
+ int field_18;
+ int field_1C;
+ int field_20;
+ int field_24;
+ int field_28;
+ int field_2C;
+ int field_30;
+ int field_34;
+ int field_38;
+ int field_3C;
+};
+
+struct Point
+{
+ short field_0;
+ short field_2;
+ short field_4;
+ short field_6;
+ short field_8;
+ short field_A;
+ short field_C;
+ short field_E;
+};
+
+struct Trap
+{
+ short field_0;
+ short nSprite;
+ short nType;
+ short field_6;
+ short field_8;
+ short field_A;
+ short field_C;
+ short field_E;
+};
+
+Trap sTrap[kMaxTraps];
+
+Bob sBob[kMaxBobs];
+Trail sTrail[kMaxTrails];
+TrailPoint sTrailPoint[kMaxTrailPoints];
+Elev Elevator[kMaxElevs];
+Object ObjectList[kMaxObjects];
+MoveSect sMoveSect[kMaxMoveSects];
+slideData SlideData[kMaxSlideData];
+short sMoveDir[kMaxMoveSects];
+wallFace WallFace[kMaxWallFace];
+slideData2 SlideData2[kMaxSlideData];
+Point PointList[kMaxPoints];
+
+short nTrapInterval[kMaxTraps];
+
+short sBobID[kMaxBobs];
+
+short PointCount;
+short PointFree[kMaxPoints];
+
+short SlideCount = 0;
+short SlideFree[kMaxSlides];
+
+char nTrailPointVal[kMaxTrailPoints];
+short nTrailPointPrev[kMaxTrailPoints];
+short nTrailPointNext[kMaxTrailPoints];
+
+Drip sDrip[kMaxDrips];
+
+short ElevCount = -1;
+
+short WallFaceCount = -1;
+
+long lFinaleStart;
+
+short nTrailPoints;
+
+short nEnergyBlocks;
+short nMoveSects;
+short nFinaleStage;
+short nTrails;
+short nTraps;
+short nFinaleSpr;
+short ObjectCount;
+short nDrips;
+
+short nBobs = 0;
+short nDronePitch = 0;
+short nSmokeSparks = 0;
+
+// done
+void InitObjects()
+{
+ ObjectCount = 0;
+ nTraps = 0;
+ nDrips = 0;
+ nBobs = 0;
+ nTrails = 0;
+ nTrailPoints = 0;
+ nMoveSects = 0;
+
+ memset(sTrail, -1, sizeof(sTrail));
+
+ nEnergyBlocks = 0;
+ nDronePitch = 0;
+ nFinaleStage = 0;
+ lFinaleStart = 0;
+ nSmokeSparks = 0;
+}
+
+// done
+void InitElev()
+{
+ ElevCount = kMaxElevs;
+}
+
+// done
+int BuildWallSprite(int nSector)
+{
+ int nWall = sector[nSector].wallptr;
+
+ int x = wall[nWall].x;
+ int y = wall[nWall].y;
+
+ int x2 = wall[nWall + 1].x;
+ int y2 = wall[nWall + 1].y;
+
+ int nSprite = insertsprite(nSector, 401);
+
+ sprite[nSprite].x = (x + x2) / 2;
+ sprite[nSprite].y = (y + y2) / 2;
+ sprite[nSprite].z = (sector[nSector].floorz + sector[nSector].ceilingz) / 2;
+ sprite[nSprite].cstat = 0x8000;
+
+ return nSprite;
+}
+
+// done
+short FindWallSprites(short nSector)
+{
+ int var_24 = 0x7FFFFFFF;
+ int ecx = 0x7FFFFFFF;
+
+ int nWall = sector[nSector].wallptr;
+ int nWallCount = sector[nSector].wallnum;
+
+ int esi = 0x80000002;
+ int edi = 0x80000002;
+
+ int i;
+
+ for (i = 0; i < nWallCount; i++)
+ {
+ if (wall[nWall].x < var_24) {
+ var_24 = wall[nWall].x;
+ }
+
+ if (esi < wall[nWall].x) {
+ esi = wall[nWall].x;
+ }
+
+ if (ecx > wall[nWall].y) {
+ ecx = wall[nWall].y;
+ }
+
+ if (edi < wall[nWall].y) {
+ edi = wall[nWall].y;
+ }
+
+ nWall++;
+ }
+
+ ecx -= 5;
+ esi += 5;
+ edi += 5;
+ var_24 -= 5;
+
+ int nSprite = -1;
+
+ for (i = 0; i < kMaxSprites; i++)
+ {
+ if (sprite[i].lotag == 0)
+ {
+ if ((sprite[i].cstat & 0x50) == 80)
+ {
+ int var_28 = sprite[i].x;
+ int ebx = sprite[i].y;
+
+ if ((var_28 >= var_24) && (esi >= var_28) && (ebx >= ecx) && (ebx <= edi))
+ {
+ sprite[i].owner = nSprite;
+ nSprite = i;
+ }
+ }
+ }
+ }
+
+ if (nSprite < 0)
+ {
+ nSprite = insertsprite(nSector, 401);
+
+ sprite[nSprite].x = (var_24 + esi) / 2;
+ sprite[nSprite].y = (ecx + edi) / 2;
+ sprite[nSprite].z = sector[nSector].floorz;
+ sprite[nSprite].cstat = 0x8000;
+ sprite[nSprite].owner = -1;
+ sprite[nSprite].lotag = 0;
+ sprite[nSprite].hitag = 0;
+ }
+
+ return nSprite;
+}
+
+int BuildElevF(int nChannel, int nSector, int nWallSprite, int arg_4, int arg_5, int nCount, int zList ...)
+{
+ assert(ElevCount > 0);
+
+ if (ElevCount <= 0) {
+ return -1;
+ }
+
+ ElevCount--;
+
+ Elevator[ElevCount].field_0 = 2;
+ Elevator[ElevCount].field_6 = arg_4;
+ Elevator[ElevCount].field_32 = -1;
+ Elevator[ElevCount].field_A = arg_5;
+ Elevator[ElevCount].nChannel = nChannel;
+ Elevator[ElevCount].nSector = nSector;
+ Elevator[ElevCount].nCountZOffsets = 0;
+ Elevator[ElevCount].nCurZOffset = 0;
+ Elevator[ElevCount].field_36 = 0;
+
+ if (nWallSprite < 0) {
+ nWallSprite = BuildWallSprite(nSector);
+ }
+
+ Elevator[ElevCount].nSprite = nWallSprite;
+
+ int *pZVals = (int*)&zList;
+
+ while (1)
+ {
+ if (Elevator[ElevCount].nCountZOffsets >= nCount) {
+ return ElevCount;
+ }
+
+ int nVal = Elevator[ElevCount].nCountZOffsets;
+
+ Elevator[ElevCount].nCountZOffsets++;
+
+ Elevator[ElevCount].zOffsets[nVal] = *pZVals;
+ pZVals++;
+ }
+
+ return ElevCount;
+}
+
+int BuildElevC(int arg1, int nChannel, int nSector, int nWallSprite, int arg5, int arg6, int nCount, int zList ...)
+{
+ int edi = arg5;
+
+ assert(ElevCount > 0);
+ if (ElevCount <= 0) {
+ return -1;
+ }
+
+ ElevCount--;
+
+ Elevator[ElevCount].field_0 = arg1;
+
+ if (arg1 & 4)
+ {
+ edi = arg5 / 2;
+ }
+
+ Elevator[ElevCount].field_6 = edi;
+ Elevator[ElevCount].nCountZOffsets = 0;
+ Elevator[ElevCount].field_36 = 0;
+ Elevator[ElevCount].nCurZOffset = 0;
+ Elevator[ElevCount].field_A = arg6;
+ Elevator[ElevCount].field_32 = -1;
+ Elevator[ElevCount].nChannel = nChannel;
+ Elevator[ElevCount].nSector = nSector;
+
+ if (nWallSprite < 0) {
+ nWallSprite = BuildWallSprite(nSector);
+ }
+
+ Elevator[ElevCount].nSprite = nWallSprite;
+
+ int *pZVals = (int*)&zList;
+
+ while (1)
+ {
+ if (Elevator[ElevCount].nCountZOffsets >= nCount) {
+ return ElevCount;
+ }
+
+ int nVal = Elevator[ElevCount].nCountZOffsets;
+
+ Elevator[ElevCount].nCountZOffsets++;
+
+ Elevator[ElevCount].zOffsets[nVal] = *pZVals;
+ pZVals++;
+ }
+
+ return ElevCount;
+}
+
+// TODO - tidy me up
+// RENAME param A - not always Z
+// Confirmed 100% correct with original .exe
+int LongSeek(long *pZVal, int a2, int a3, int a4)
+{
+ int v4; // edx@1
+ int v5; // ebx@2
+
+ v4 = a2 - *pZVal;
+
+ if (v4 < 0)
+ {
+ v5 = -a3;
+ if (v5 > v4)
+ v4 = v5;
+ (*pZVal) += v4;
+ }
+
+ if (v4 > 0)
+ {
+ if (a4 < v4)
+ v4 = a4;
+ (*pZVal) += v4;
+ }
+
+ return v4;
+}
+
+// done
+int CheckSectorSprites(short nSector, int nVal)
+{
+ int b = 0;
+
+ if (nVal)
+ {
+ short nSprite = headspritesect[nSector];
+
+ int nZDiff = sector[nSector].floorz - sector[nSector].ceilingz;
+
+ while (nSprite != -1)
+ {
+ if ((sprite[nSprite].cstat & 0x101) && (nZDiff < GetSpriteHeight(nSprite)))
+ {
+ if (nVal != 1) {
+ return 1;
+ }
+
+ b = 1;
+
+ runlist_DamageEnemy(nSprite, -1, 5);
+
+ if (sprite[nSprite].statnum == 100 && PlayerList[GetPlayerFromSprite(nSprite)].nHealth <= 0)
+ {
+ /* TODO
+ PlayFXAtXYZ(StaticSound[kSoundJonFDie],
+ sprite[nSprite].x,
+ sprite[nSprite].y,
+ sprite[nSprite].z,
+ sprite[nSprite].sectnum | 0x40FF); // TODO - check last param??
+ */
+ }
+ }
+ nSprite = nextspritesect[nSprite];
+ }
+ }
+ else
+ {
+ for (int i = headspritesect[nSector]; i != -1; i = nextspritesect[i])
+ {
+ if (sprite[i].cstat & 0x101) {
+ return 1;
+ }
+ }
+ b = 0;
+ }
+
+ return b;
+}
+
+// done
+void MoveSectorSprites(int nSector, int z)
+{
+ int nSprite = headspritesect[nSector];
+
+ while (nSprite != -1)
+ {
+ if (sprite[nSprite].statnum != 200) {
+ sprite[nSprite].z += z;
+ }
+
+ nSprite = nextspritesect[nSprite];
+ }
+}
+
+void StartElevSound(short nSprite, int nVal)
+{
+ short nSound;
+
+ if (nVal & 2) {
+ nSound = nElevSound;
+ }
+ else {
+ nSound = nStoneSound;
+ }
+
+ D3PlayFX(StaticSound[nSound], nSprite);
+}
+
+void FuncElev(int a, int b, int nRun)
+{
+ short nElev = RunData[nRun].nVal;
+ assert(nElev >= 0 && nElev < kMaxElevs);
+
+ short nChannel = Elevator[nElev].nChannel;
+ short var_18 = Elevator[nElev].field_0;
+
+ RunChannel *pRunChannel = &sRunChannels[nChannel];
+
+ assert(nChannel >= 0 && nChannel < kMaxChannels);
+
+ int nMessage = a & 0x7F0000;
+
+ if (nMessage < 0x10000) {
+ return;
+ }
+
+// int var_24 = var_18 & 0x10; // floor based?
+
+ switch (nMessage)
+ {
+ default:
+ {
+ return;
+ }
+
+ case 0x10000:
+ {
+// short ax = var_18 & 8;
+ short dx = sRunChannels[nChannel].c;
+
+ int edi = 999; // FIXME CHECKME - this isn't default set to anything in the ASM that I can see - if ax is 0 and var_24 is 0, this will never be set to a known value otherwise!
+
+ if (var_18 & 0x8)
+ {
+ if (dx) {
+ edi = 1;
+ }
+ else {
+ edi = 0;
+ }
+ }
+ else
+ {
+ // loc_20D48:
+ if (var_18 & 0x10) // was var_24
+ {
+ if (Elevator[nElev].field_32 < 0)
+ {
+ Elevator[nElev].field_32 = runlist_AddRunRec(NewRun, RunData[nRun].nMoves);
+ StartElevSound(Elevator[nElev].nSprite, var_18);
+
+ edi = 1;
+ }
+ }
+ else
+ {
+ if (dx < 0) {
+ edi = 0;
+ }
+ else
+ {
+ if (dx == Elevator[nElev].nCurZOffset || dx >= Elevator[nElev].nCountZOffsets)
+ {
+ Elevator[nElev].field_36 = dx;
+ edi = 1;
+ }
+ else
+ {
+ Elevator[nElev].nCurZOffset = sRunChannels[nChannel].c;
+ edi = 1;
+ }
+ }
+ }
+ }
+
+ assert(edi != 999);
+
+ // loc_20DF9:
+ if (edi)
+ {
+ if (Elevator[nElev].field_32 < 0)
+ {
+ Elevator[nElev].field_32 = runlist_AddRunRec(NewRun, RunData[nRun].nMoves);
+
+ StartElevSound(Elevator[nElev].nSprite, var_18);
+ }
+ }
+ else
+ {
+ //loc_20E4E:
+ if (Elevator[nElev].field_32 >= 0)
+ {
+ runlist_SubRunRec(Elevator[nElev].field_32);
+ Elevator[nElev].field_32 = -1;
+ }
+ }
+
+ return;
+ }
+
+ case 0x20000:
+ {
+ short nSector = Elevator[nElev].nSector;
+ short di = Elevator[nElev].nSprite;
+
+ int ebp = 0; // initialise to *something*
+
+ if (var_18 & 0x2)
+ {
+ int nZOffset = Elevator[nElev].nCurZOffset;
+ int nZVal = Elevator[nElev].zOffsets[nZOffset];
+
+ short nSectorB = nSector;
+
+ int nVal = LongSeek(§or[nSector].floorz, nZVal, Elevator[nElev].field_6, Elevator[nElev].field_A);
+ ebp = nVal;
+
+ if (!nVal)
+ {
+ if (var_18 & 0x10)
+ {
+ Elevator[nElev].nCurZOffset ^= 1;
+ StartElevSound(di, var_18);
+ }
+ else
+ {
+ StopSpriteSound(di);
+ runlist_SubRunRec(nRun);
+ Elevator[nElev].field_32 = -1;
+ runlist_ReadyChannel(nChannel);
+
+ D3PlayFX(StaticSound[nStopSound], Elevator[nElev].nSprite);
+ }
+ }
+ else
+ {
+ assert(nSector == nSectorB);
+ MoveSectorSprites(nSector, nVal);
+
+ if (nVal < 0 && CheckSectorSprites(nSector, 2))
+ {
+ runlist_ChangeChannel(nChannel, sRunChannels[nChannel].c == 0);
+ return;
+ }
+ }
+ }
+ else
+ {
+ // loc_20FC3:
+ long ceilZ = sector[nSector].ceilingz;
+ SECTOR *var_28 = §or[nSector];
+
+ int nZOffset = Elevator[nElev].nCurZOffset;
+ int zVal = Elevator[nElev].zOffsets[nZOffset];
+
+ int nVal = LongSeek(&ceilZ, zVal, Elevator[nElev].field_6, Elevator[nElev].field_A);
+ ebp = nVal;
+
+ if (!nVal)
+ {
+ if (var_18 & 0x10)
+ {
+ Elevator[nElev].nCurZOffset ^= 1;
+
+ StartElevSound(Elevator[nElev].nSprite, var_18);
+ }
+ else
+ {
+ runlist_SubRunRec(nRun);
+ Elevator[nElev].field_32 = -1;
+ StopSpriteSound(Elevator[nElev].nSprite);
+ D3PlayFX(StaticSound[nStopSound], Elevator[nElev].nSprite);
+ runlist_ReadyChannel(nChannel);
+ }
+
+ return;
+ }
+ else if (nVal > 0)
+ {
+ if (ceilZ == zVal)
+ {
+ if (var_18 & 0x4) {
+ SetQuake(di, 30);
+ }
+
+// TODO PlayFXAtXYZ(StaticSound[kSound26], sprite[di].x, sprite[di].y, sprite[di].z, sprite[di].sectnum);
+ }
+
+ if (var_18 & 0x4)
+ {
+ if (CheckSectorSprites(nSector, 1)) {
+ return;
+ }
+ }
+ else
+ {
+ if (CheckSectorSprites(nSector, 0))
+ {
+ runlist_ChangeChannel(nChannel, sRunChannels[nChannel].c == 0);
+ return;
+ }
+ }
+ }
+
+ var_28->ceilingz = ceilZ;
+ }
+
+ // maybe this doesn't go here?
+ while (di != -1)
+ {
+ sprite[di].z += ebp;
+ di = sprite[di].owner;
+ }
+
+ return;
+ }
+ }
+}
+
+// done
+void InitWallFace()
+{
+ WallFaceCount = kMaxWallFace;
+}
+
+int BuildWallFace(short nChannel, short nWall, short nCount, int nPics ...)
+{
+ if (WallFaceCount <= 0) {
+ bail2dos("Too many wall faces!\n");
+ }
+
+ WallFaceCount--;
+
+ WallFace[WallFaceCount].field_4 = 0;
+ WallFace[WallFaceCount].nWall = nWall;
+ WallFace[WallFaceCount].nChannel = nChannel;
+
+ if (nCount > 8) {
+ nCount = 8;
+ }
+
+ int *pPicNums = (int*)&nPics;
+
+ while (WallFace[WallFaceCount].field_4 < nCount)
+ {
+ int i = WallFace[WallFaceCount].field_4;
+ WallFace[WallFaceCount].field_4++;
+
+ WallFace[WallFaceCount].field_6[i] = *pPicNums;
+ pPicNums++;
+ }
+
+ return WallFaceCount | 0x70000;
+}
+
+// Confirmed 100% correct with original .exe
+void FuncWallFace(int a, int b, int nRun)
+{
+ int nWallFace = RunData[nRun].nVal;
+ assert(nWallFace >= 0 && nWallFace < kMaxWallFace);
+
+ short nChannel = WallFace[nWallFace].nChannel;
+
+ if ((a & 0x7F0000) != 0x10000)
+ return;
+
+ short si = sRunChannels[nChannel].c;
+
+ if ((si <= WallFace[nWallFace].field_4) && (si >= 0))
+ {
+ wall[WallFace[nWallFace].nWall].picnum = WallFace[nWallFace].field_6[si];
+ }
+}
+
+// done
+void InitPoint()
+{
+ PointCount = 0;
+
+ for (int i = 0; i < kMaxPoints; i++) {
+ PointFree[i] = i;
+ }
+}
+
+// done
+int GrabPoint()
+{
+ return PointFree[PointCount++];
+}
+
+// done
+void InitSlide()
+{
+ SlideCount = kMaxSlides;
+
+ for (int i = 0; i < kMaxSlides; i++) {
+ SlideFree[i] = i;
+ }
+}
+
+int IdentifySector(int nVal)
+{
+ for (int i = 0; i < numsectors; i++)
+ {
+ for (int j = 0; ; j++)
+ {
+ if (j < sector[i].wallnum)
+ {
+ int nWall = sector[i].wallptr;
+ if (nWall + j == nVal)
+ return i;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ return -1;
+}
+
+int BuildSlide(int nChannel, int edx, int ebx, int ecx, int arg1, int arg2, int arg3)
+{
+ int var_1C = edx;
+ int ebp = ebx;
+ int nVal = ecx;
+
+ if (SlideCount <= 0) {
+ bail2dos("Too many slides!\n");
+ return -1;
+ }
+
+ SlideCount--;
+
+ int nSlide = SlideCount;
+
+ short nSector = IdentifySector(var_1C);
+
+ SlideData2[nSlide].field_4 = -1;
+ SlideData2[nSlide].nChannel = nChannel;
+ SlideData2[nSlide].field_2 = -1;
+
+ int nPoint = GrabPoint();
+
+ SlideData2[nSlide].field_2 = nPoint;
+
+ PointList[nPoint].field_E = -1;
+ PointList[nPoint].field_0 = nSector;
+
+ short startwall = sector[nSector].wallptr;
+ short endwall = startwall + sector[nSector].wallnum;
+
+ for (int nWall = startwall; nWall < endwall; nWall++)
+ {
+ short ax = SlideData2[nSlide].field_2;
+
+ if (ax >= 0)
+ {
+ while (ax >= 0)
+ {
+ if (wall[nWall].nextsector == PointList[ax].field_0) {
+ break;
+ }
+
+ ax = PointList[ax].field_E;
+ }
+ }
+ else
+ {
+ if (wall[nWall].nextsector >= 0)
+ {
+ nPoint = GrabPoint();
+
+ PointList[nPoint].field_E = SlideData2[nSlide].field_2;
+ PointList[nPoint].field_0 = wall[nWall].nextsector;
+
+ SlideData2[nSlide].field_2 = nPoint;
+ }
+ }
+ }
+
+ SlideData[nSlide].field_0 = var_1C;
+ SlideData[nSlide].field_8 = arg1;
+ SlideData[nSlide].field_C = arg2;
+ SlideData[nSlide].field_10 = wall[var_1C].x;
+ SlideData[nSlide].field_14 = wall[var_1C].y;
+
+ SlideData[nSlide].field_1C = wall[arg1].y;
+ SlideData[nSlide].field_18 = wall[arg1].x;
+
+ SlideData[nSlide].field_24 = wall[ebp].y;
+ SlideData[nSlide].field_20 = wall[ebp].x;
+
+ SlideData[nSlide].field_2C = wall[arg2].y;
+ SlideData[nSlide].field_28 = wall[arg2].x;
+
+ SlideData[nSlide].field_34 = wall[nVal].y;
+ SlideData[nSlide].field_4 = ebp;
+ SlideData[nSlide].field_30 = wall[nVal].x;
+ SlideData[nSlide].field_38 = wall[arg3].x;
+ SlideData[nSlide].field_3C = wall[arg3].y;
+
+ int nSprite = insertsprite(nSector, 899);
+
+ SlideData2[nSlide].field_6 = nSprite;
+ sprite[nSprite].cstat = 0x8000;
+ sprite[nSprite].x = wall[var_1C].x;
+ sprite[nSprite].y = wall[var_1C].y;
+ sprite[nSprite].z = sector[nSector].floorz;
+
+ SlideData2[nSlide].field_8 = 0;
+
+ return nSlide | 0x80000;
+}
+
+void FuncSlide(int a, int b, int c)
+{
+ int nSlide = RunData[c].nVal;
+ assert(nSlide >= 0 && nSlide < kMaxSlides);
+
+ short nChannel = SlideData2[nSlide].nChannel;
+
+ int nMessage = a & 0x7F0000;
+
+ int ebp = 0;
+
+ short cx = sRunChannels[nChannel].c;
+
+ switch (nMessage)
+ {
+ case 0x10000:
+ {
+ if (SlideData2[nSlide].field_4 >= 0)
+ {
+ runlist_SubRunRec(SlideData2[nSlide].field_4);
+ SlideData2[nSlide].field_4 = -1;
+ }
+
+ if (sRunChannels[nChannel].c && sRunChannels[nChannel].c != 1) {
+ return;
+ }
+
+ SlideData2[nSlide].field_4 = runlist_AddRunRec(NewRun, RunData[c].nMoves);
+
+ if (SlideData2[nSlide].field_8 != sRunChannels[nChannel].c)
+ {
+ D3PlayFX(StaticSound[kSound23], SlideData2[nSlide].field_6);
+ SlideData2[nSlide].field_8 = sRunChannels[nChannel].c;
+ }
+
+ return;
+ }
+
+ case 0x20000:
+ {
+ int clipmask = ebp + 1; // RENAME
+
+ if (cx == 1)
+ {
+ short nWall = SlideData[nSlide].field_4;
+ long x = wall[nWall].x;
+ long y = wall[nWall].y;
+
+ int nSeekA = LongSeek(&x, SlideData[nSlide].field_30, 20, 20);
+ int var_34 = nSeekA;
+ int var_20 = nSeekA;
+
+ int nSeekB = LongSeek(&y, SlideData[nSlide].field_34, 20, 20);
+ int var_2C = nSeekB;
+ int var_24 = nSeekB;
+
+ dragpoint(SlideData[nSlide].field_4, x, y);
+ movesprite(SlideData2[nSlide].field_6, var_34 << 14, var_2C << 14, 0, 0, 0, CLIPMASK1);
+
+ if (var_34 == 0)
+ {
+ if (var_2C == 0)
+ {
+ ebp = clipmask;
+ }
+ }
+
+ nWall = SlideData[nSlide].field_0;
+
+ y = wall[nWall].y + var_24;
+ x = wall[nWall].x + var_20;
+
+ dragpoint(SlideData[nSlide].field_0, x, y);
+
+ nWall = SlideData[nSlide].field_C;
+
+ x = wall[nWall].x;
+ y = wall[nWall].y;
+
+ int nSeekC = LongSeek(&x, SlideData[nSlide].field_38, 20, 20);
+ int var_30 = nSeekC;
+ var_20 = nSeekC;
+
+ int nSeekD = LongSeek(&y, SlideData[nSlide].field_3C, 20, 20);
+ int edi = nSeekD;
+ var_24 = nSeekD;
+
+ dragpoint(SlideData[nSlide].field_C, x, y);
+
+ if (var_30 == 0 && edi == 0) {
+ ebp++;
+ }
+
+ nWall = SlideData[nSlide].field_8;
+
+ x = wall[nWall].x + var_20;
+ y = wall[nWall].y + var_24;
+
+ dragpoint(SlideData[nSlide].field_8, x, y);
+ }
+ else if (cx == 0) // right branch
+ {
+ short nWall = SlideData[nSlide].field_0;
+ long x = wall[nWall].x;
+ long y = wall[nWall].y;
+
+ int nSeekA = LongSeek(&x, SlideData[nSlide].field_10, 20, 20);
+ int edi = nSeekA;
+ int var_1C = nSeekA;
+
+ int nSeekB = LongSeek(&y, SlideData[nSlide].field_14, 20, 20);
+ int ecx = nSeekB;
+ int var_28 = nSeekB;
+
+ dragpoint(SlideData[nSlide].field_0, x, y);
+
+ if (edi == 0 && ecx == 0) {
+ ebp = clipmask;
+ }
+
+ nWall = SlideData[nSlide].field_4;
+
+ y = wall[nWall].y + var_28;
+ x = wall[nWall].x + var_1C;
+
+ dragpoint(SlideData[nSlide].field_4, x, y);
+
+ nWall = SlideData[nSlide].field_8;
+
+ x = wall[nWall].x;
+ y = wall[nWall].y;
+
+ int nSeekC = LongSeek(&x, SlideData[nSlide].field_18, 20, 20);
+ edi = nSeekC;
+ var_1C = nSeekC;
+
+ int nSeekD = LongSeek(&y, SlideData[nSlide].field_1C, 20, 20);
+ ecx = nSeekD;
+ var_28 = nSeekD;
+
+ dragpoint(SlideData[nSlide].field_8, x, y);
+
+ if (edi == 0 && ecx == 0) {
+ ebp++;
+ }
+
+ nWall = SlideData[nSlide].field_C;
+
+ y = wall[nWall].y + var_28;
+ x = wall[nWall].x + var_1C;
+
+ dragpoint(SlideData[nSlide].field_C, x, y);
+ }
+
+ // loc_21A51:
+ if (ebp >= 2)
+ {
+ runlist_SubRunRec(SlideData2[nSlide].field_4);
+
+ SlideData2[nSlide].field_4 = -1;
+ D3PlayFX(StaticSound[nStopSound], SlideData2[nSlide].field_6);
+
+ runlist_ReadyChannel(nChannel);
+ }
+
+ return;
+ }
+ }
+}
+
+int BuildTrap(int nSprite, int edx, int ebx, int ecx)
+{
+ int var_14 = edx;
+ int var_18 = ebx;
+ int var_10 = ecx;
+
+ if (nTraps >= kMaxTraps) {
+ bail2dos("Too many traps!\n");
+ }
+
+ short nTrap = nTraps;
+ nTraps++;
+
+ changespritestat(nSprite, 0);
+
+ sprite[nSprite].cstat = 0x8000;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].extra = -1;
+
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].hitag = runlist_AddRunRec(NewRun, nTrap | 0x1F0000);
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nTrap | 0x1F0000);
+
+// GrabTimeSlot(3);
+
+ sTrap[nTrap].nSprite = nSprite;
+ sTrap[nTrap].nType = (var_14 == 0) + 14;
+ sTrap[nTrap].field_0 = -1;
+
+ nTrapInterval[nTrap] = 64 - (2 * var_10);
+ if (nTrapInterval[nTrap] < 5) {
+ nTrapInterval[nTrap] = 5;
+ }
+
+ sTrap[nTrap].field_C = 0;
+ sTrap[nTrap].field_A = 0;
+
+ if (var_18 == -1) {
+ return nTrap | 0x1F0000;
+ }
+
+ sTrap[nTrap].field_6 = -1;
+ sTrap[nTrap].field_8 = -1;
+
+ short nSector = sprite[nSprite].sectnum;
+ short nWall = sector[nSector].wallptr;
+
+ int i = 0;
+
+ while (1)
+ {
+ if (sector[nSector].wallnum >= i) {
+ return nTrap | 0x1F0000;
+ }
+
+ if (var_18 == wall[nWall].hitag)
+ {
+ if (sTrap[nTrap].field_6 != -1)
+ {
+ sTrap[nTrap].field_8 = nWall;
+ sTrap[nTrap].field_C = wall[nWall].picnum;
+ return nTrap | 0x1F0000;
+ }
+ else
+ {
+ sTrap[nTrap].field_6 = nWall;
+ sTrap[nTrap].field_A = wall[nWall].picnum;
+ }
+ }
+
+ ecx++;
+ nWall++;
+ }
+}
+
+void FuncTrap(int a, int b, int c)
+{
+ short nTrap = RunData[c].nVal;
+ short nSprite = sTrap[nTrap].nSprite;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x10000:
+ {
+ short nChannel = a & 0x3FFF;
+
+ if (sRunChannels[nChannel].c > 0)
+ {
+ sTrap[nTrap].field_0 = 12;
+ }
+ else
+ {
+ sTrap[nTrap].field_0 = -1;
+ }
+
+ return;
+ }
+
+ case 0x20000:
+ {
+ if (sTrap[nTrap].field_0 >= 0)
+ {
+ sTrap[nTrap].field_0--;
+ if (sTrap[nTrap].field_0 > 10) {
+ return;
+ }
+
+ short nType = sTrap[nTrap].nType;
+
+ if (sTrap[nTrap].field_0 == 0)
+ {
+ sTrap[nTrap].field_0 = nTrapInterval[nTrap];
+
+ if (nType == 14)
+ {
+ short nWall = sTrap[nTrap].field_6;
+ if (nWall > -1)
+ {
+ wall[nWall].picnum = sTrap[nTrap].field_A;
+ }
+
+ nWall = sTrap[nTrap].field_8;
+ if (nWall > -1)
+ {
+ wall[nWall].picnum = sTrap[nTrap].field_C;
+ }
+ }
+ }
+ else
+ {
+ // loc_21D92:
+ if (sTrap[nTrap].field_0 != 5) {
+ return;
+ }
+
+ int nBullet = BuildBullet(nSprite, nType, 0, 0, 0, sprite[nSprite].ang, 0, 1);
+ if (nType == 15)
+ {
+ sprite[nSprite].ang = Sin(sprite[nSprite].ang - 512);
+ D3PlayFX(StaticSound[kSound32], nSprite);
+ }
+ else
+ {
+ short nBulletSprite = nBullet & 0xFFFF; // isolate the sprite index (disregard top 16 bits)
+ sprite[nBulletSprite].clipdist = 50;
+
+ short nWall = sTrap[nTrap].field_6;
+ if (nWall > -1)
+ {
+ wall[nWall].picnum = sTrap[nTrap].field_A + 1;
+ }
+
+ nWall = sTrap[nTrap].field_8;
+ if (nWall > -1)
+ {
+ wall[nWall].picnum = sTrap[nTrap].field_C + 1;
+ }
+
+ D3PlayFX(StaticSound[kSound36], nSprite);
+ }
+ }
+ }
+
+ return;
+ }
+
+ case 0x30000:
+ case 0x90000:
+ case 0x80000:
+ case 0x0A0000:
+ return;
+
+ default:
+ DebugOut("unknown msg %d for trap\n", a & 0x7F0000);
+ return;
+ }
+}
+
+int BuildArrow(int nSprite, int nVal)
+{
+ return BuildTrap(nSprite, 0, -1, nVal);
+}
+
+int BuildFireBall(int nSprite, int a, int b)
+{
+ return BuildTrap(nSprite, 1, a, b);
+}
+
+// Confirmed 100% correct with original .exe
+int BuildSpark(int nSprite, int nVal)
+{
+ int var_14 = insertsprite(sprite[nSprite].sectnum, 0);
+
+ if (var_14 < 0) {
+ return -1;
+ }
+
+ assert(var_14 < kMaxSprites);
+
+ sprite[var_14].x = sprite[nSprite].x;
+ sprite[var_14].y = sprite[nSprite].y;
+ sprite[var_14].cstat = 0;
+ sprite[var_14].shade = -127;
+ sprite[var_14].pal = 1;
+ sprite[var_14].xrepeat = 50;
+ sprite[var_14].xoffset = 0;
+ sprite[var_14].yoffset = 0;
+ sprite[var_14].yrepeat = 50;
+
+ if (nVal >= 2)
+ {
+ sprite[var_14].picnum = kEnergy2;
+ nSmokeSparks++;
+
+ if (nVal == 3)
+ {
+ sprite[var_14].yrepeat = 120;
+ sprite[var_14].xrepeat = 120;
+ }
+ else
+ {
+ sprite[var_14].yrepeat = sprite[var_14].xrepeat + 15;
+ sprite[var_14].xrepeat = sprite[var_14].xrepeat + 15;
+ }
+ }
+ else
+ {
+ int nAngle = (sprite[nSprite].ang + 256) - RandomSize(9);
+
+ if (nVal)
+ {
+ sprite[var_14].xvel = Sin(nAngle + 512) >> 5;
+ sprite[var_14].yvel = Sin(nAngle) >> 5;
+ }
+ else
+ {
+ sprite[var_14].xvel = Sin(nAngle + 512) >> 6;
+ sprite[var_14].yvel = Sin(nAngle) >> 6;
+ }
+
+ sprite[var_14].zvel = -(RandomSize(4) << 7);
+ sprite[var_14].picnum = nVal + 985;
+ }
+
+ sprite[var_14].z = sprite[nSprite].z;
+ sprite[var_14].lotag = runlist_HeadRun() + 1;
+ sprite[var_14].clipdist = 1;
+ sprite[var_14].hitag = 0;
+
+// GrabTimeSlot(3);
+
+ sprite[var_14].extra = -1;
+ sprite[var_14].owner = runlist_AddRunRec(sprite[var_14].lotag - 1, var_14 | 0x260000);
+ sprite[var_14].hitag = runlist_AddRunRec(NewRun, var_14 | 0x260000);
+
+ return var_14;
+}
+
+void FuncSpark(int a, int b, int c)
+{
+ int nSprite = RunData[c].nVal;
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ int nMessage = a & 0x7F0000;
+
+ if (nMessage != 0x20000) {
+ return;
+ }
+
+ sprite[nSprite].shade += 3;
+ sprite[nSprite].xrepeat -= 2;
+
+ if (sprite[nSprite].xrepeat >= 4 && sprite[nSprite].shade <= 100)
+ {
+ sprite[nSprite].yrepeat -= 2;
+
+ if (sprite[nSprite].picnum == kTile986 && sprite[nSprite].xrepeat & 2)
+ {
+ BuildSpark(nSprite, 2);
+ }
+
+ if (sprite[nSprite].picnum >= kTile3000) {
+ return;
+ }
+
+ sprite[nSprite].zvel += 128;
+
+ int nMov = movesprite(nSprite, sprite[nSprite].xvel << 12, sprite[nSprite].yvel << 12, sprite[nSprite].zvel, 2560, -2560, CLIPMASK1);
+ if (!nMov) {
+ return;
+ }
+
+ if (sprite[nSprite].zvel <= 0) {
+ return;
+ }
+ }
+
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+
+ if (sprite[nSprite].picnum > kTile3000) {
+ nSmokeSparks--;
+ }
+
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+ runlist_SubRunRec(sprite[nSprite].hitag);
+ mydeletesprite(nSprite);
+}
+
+void DimLights()
+{
+ static short word_96786 = 0;
+
+ word_96786 = word_96786 == 0;
+ if (word_96786 == 0)
+ return;
+
+ for (int i = 0; i < numsectors; i++)
+ {
+ if (sector[i].ceilingshade < 100)
+ sector[i].ceilingshade++;
+
+ if (sector[i].floorshade < 100)
+ sector[i].floorshade++;
+
+ int nWall = sector[i].wallptr;
+
+ while (nWall < nWall + sector[i].wallnum)
+ {
+ if (wall[nWall].shade < 100)
+ wall[nWall].shade++;
+ }
+ }
+}
+
+void DoFinale()
+{
+ static int dword_96788 = 0;
+ static int dword_1542FC = 0;
+
+ if (!lFinaleStart)
+ return;
+
+ dword_96788++;
+
+ if (dword_96788 < 90)
+ {
+ if (!(dword_96788 & 2))
+ {
+ int nAng = RandomSize(11);
+ sprite[nFinaleSpr].ang = nAng;
+ BuildSpark(nFinaleSpr, 1);
+ }
+
+ if (!RandomSize(2))
+ {
+// TODO PlayFX2(StaticSound[kSound78] | 0x2000, nFinaleSpr);
+
+ for (int i = 0; i < nTotalPlayers; i++) {
+ nQuake[i] = 1280;
+ }
+ }
+ }
+ else
+ {
+ DimLights();
+
+ if (nDronePitch <= -2400)
+ {
+ if (nFinaleStage < 2)
+ {
+ if (nFinaleStage == 1)
+ {
+ StopLocalSound();
+ PlayLocalSound(StaticSound[kSound76], 0);
+ dword_1542FC = totalclock + 120;
+ ++nFinaleStage;
+ }
+ }
+ else if (nFinaleStage <= 2)
+ {
+ if (totalclock >= dword_1542FC)
+ {
+ PlayLocalSound(StaticSound[kSound77], 0);
+ nFinaleStage++;
+ dword_1542FC = totalclock + 360;
+ }
+ }
+ else if (nFinaleStage == 3 && totalclock >= dword_1542FC)
+ {
+ FinishLevel();
+ }
+ }
+ else
+ {
+ nDronePitch -= 128;
+ BendAmbientSound();
+ nFinaleStage = 1;
+ }
+ }
+}
+
+int BuildEnergyBlock(short nSector)
+{
+ short startwall = sector[nSector].wallptr;
+
+ int i = 0;
+ int x = 0;
+ int y = 0;
+
+ while (1)
+ {
+ if (i >= sector[nSector].wallnum) {
+ break;
+ }
+
+ x += wall[startwall + i].x;
+ y += wall[startwall + i].y;
+
+ wall[startwall + i].pal = 0;
+ wall[startwall + i].shade = 50;
+
+ i++;
+ }
+
+ int xAvg = x / 2;
+ int yAvg = y / 2;
+
+ int nSprite = insertsprite(nSector, 406);
+
+ short nextsector = wall[startwall].nextsector;
+
+ sprite[nSprite].x = xAvg;
+ sprite[nSprite].y = yAvg;
+
+ sector[nSector].extra = nSprite;
+
+// GrabTimeSlot(3);
+
+ sprite[nSprite].z = sector[nextsector].floorz;
+
+ // CHECKME - name of this variable?
+ int nRepeat = (sprite[nSprite].z - sector[nSector].floorz) >> 8;
+ if (nRepeat > 255) {
+ nRepeat = 255;
+ }
+
+ sprite[nSprite].xrepeat = nRepeat;
+ sprite[nSprite].cstat = 0x8000;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].extra = -1;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nSprite | 0x250000);
+
+ nEnergyBlocks++;
+
+ return nSprite | 0x250000;
+}
+
+// TODO - tidy
+void KillCreatures()
+{
+ signed int v0;
+ signed int v1;
+ int i;
+
+ v0 = 99;
+ v1 = 99;
+
+ while (1)
+ {
+ if (v0 != 100)
+ {
+ for (i = headspritestat[v1]; i != -1; i = nextspritestat[i])
+ {
+ runlist_DamageEnemy(i, -1, 1600);
+ }
+ }
+ ++v0;
+ ++v1;
+
+ if (v0 > 107) {
+ return;
+ }
+ }
+}
+
+void ExplodeEnergyBlock(int nSprite)
+{
+ short nSector = sprite[nSprite].sectnum;
+
+ short startwall = sector[nSector].wallptr;
+ short nWalls = sector[nSector].wallnum;
+
+ int i;
+
+ for (i = 0; i < nWalls; i++)
+ {
+ short nextwall = wall[startwall + i].nextwall;
+
+ if (wall[nextwall].pal >= 4) {
+ wall[nextwall].pal = 7;
+ }
+ else {
+ wall[nextwall].pal = 0;
+ }
+
+ wall[nextwall].shade = 50;
+ }
+
+ if (sector[nSector].floorpal >= 4) {
+ sector[nSector].floorpal = 7;
+ }
+ else {
+ sector[nSector].floorpal = 0;
+ }
+
+ sector[nSector].floorshade = 50;
+ sector[nSector].extra = -1;
+ sector[nSector].floorz = sprite[nSprite].z;
+
+ sprite[nSprite].z = (sprite[nSprite].z + sector[nSector].floorz) / 2;
+
+ BuildSpark(nSprite, 3);
+
+ sprite[nSprite].cstat = 0;
+ sprite[nSprite].xrepeat = 100;
+
+// TODO PlayFX2(StaticSound[kSound78], nSprite);
+
+ sprite[nSprite].xrepeat = 0;
+
+ nEnergyTowers--;
+
+ for (i = 0; i < 20; i++)
+ {
+ sprite[nSprite].ang = RandomSize(11);
+
+ BuildSpark(nSprite, 1);
+ }
+
+ TintPalette(16, 16, 16);
+
+ if (nEnergyTowers == 1)
+ {
+ runlist_ChangeChannel(nEnergyChan, nEnergyTowers);
+
+ StatusMessage(1000, "TAKE OUT THE CONTROL CENTER!");
+ }
+ else if (nEnergyTowers != 0)
+ {
+ StatusMessage(500, "%d TOWERS REMAINING", nEnergyTowers);
+ }
+ else
+ {
+ nFinaleSpr = nSprite;
+ lFinaleStart = totalclock;
+
+ if (!lFinaleStart) {
+ lFinaleStart = lFinaleStart + 1;
+ }
+
+ for (i = 0; i < numsectors; i++)
+ {
+ if (sector[i].ceilingpal == 1) {
+ sector[i].ceilingpal = 0;
+ }
+
+ if (sector[i].floorpal == 1) {
+ sector[i].floorpal = 0;
+ }
+
+ short startwall = sector[i].wallptr;
+ short endwall = startwall + sector[i].wallnum;
+
+ for (int nWall = startwall; nWall < endwall; nWall++)
+ {
+ if (wall[nWall].pal == 1) {
+ wall[nWall].pal = 0;
+ }
+ }
+ }
+
+ KillCreatures();
+ }
+
+ changespritestat(nSprite, 0);
+}
+
+void FuncEnergyBlock(int a, int b, int nRun)
+{
+ short nSprite = RunData[nRun].nVal;
+
+ int nDamage = b;
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x20000:
+ case 0x30000:
+ case 0x90000:
+ {
+ return;
+ }
+
+ case 0xA0000:
+ {
+ short nSector = sprite[nSprite].sectnum;
+
+ if (sector[nSector].extra == -1) {
+ return;
+ }
+
+ int nFloorZ = sector[nSector].floorz;
+
+ sector[nSector].floorz = sprite[nSprite].z;
+ sprite[nSprite].z -= 256;
+
+ nDamage = runlist_CheckRadialDamage(nSprite);
+
+ sector[nSector].floorz = nFloorZ;
+
+ sprite[nSprite].z += 256;
+
+ if (nDamage <= 0) {
+ return;
+ }
+
+ // fall through to case 0x80000
+ }
+
+ case 0x80000:
+ {
+ nDamage >>= 2;
+ if (nDamage <= 0) {
+ return;
+ }
+
+ if (nDamage < sprite[nSprite].xrepeat)
+ {
+ sprite[nSprite].xrepeat -= nDamage;
+
+ int nSprite2 = insertsprite(lasthitsect, 0);
+
+ sprite[nSprite2].ang = a & 0xFFFF;
+ sprite[nSprite2].x = lasthitx;
+ sprite[nSprite2].y = lasthity;
+ sprite[nSprite2].z = lasthitz;
+
+ BuildSpark(nSprite2, 0);
+ mydeletesprite(nSprite2);
+ }
+ else
+ {
+ sprite[nSprite].xrepeat = 0;
+
+ ExplodeEnergyBlock(nSprite);
+ }
+
+ return;
+ }
+ }
+}
+
+int BuildObject(short nSprite, int nOjectType, int nHitag)
+{
+ if (ObjectCount >= kMaxObjects) {
+ bail2dos("Too many objects!\n");
+ }
+
+ short nObject = ObjectCount;
+ ObjectCount++;
+
+ changespritestat(nSprite, ObjectStatnum[nOjectType]);
+
+ // 0x7FFD to ensure set as blocking ('B' and 'H') sprite and also disable translucency and set not invisible
+ sprite[nSprite].cstat = (sprite[nSprite].cstat | 0x101) & 0x7FFD;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].extra = -1;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nObject | 0x170000);
+
+// GrabTimeSlot(3);
+
+ if (sprite[nSprite].statnum == kStatDestructibleSprite) {
+ ObjectList[nObject].nHealth = 4;
+ }
+ else {
+ ObjectList[nObject].nHealth = 120;
+ }
+
+ ObjectList[nObject].nSprite = nSprite;
+ ObjectList[nObject].field_4 = runlist_AddRunRec(NewRun, nObject | 0x170000);
+
+ short nSeq = ObjectSeq[nOjectType];
+
+ if (nSeq <= -1)
+ {
+ ObjectList[nObject].field_0 = 0;
+ ObjectList[nObject].field_8 = -1;
+
+ if (sprite[nSprite].statnum == kStatDestructibleSprite) {
+ ObjectList[nObject].field_10 = -1;
+ }
+ else {
+ ObjectList[nObject].field_10 = -nHitag;
+ }
+ }
+ else
+ {
+ ObjectList[nObject].field_8 = SeqOffsets[nSeq];
+
+ if (!nOjectType) // if not Explosion Trigger (e.g. Exploding Fire Cauldron)
+ {
+ ObjectList[nObject].field_0 = RandomSize(4) % (SeqSize[nSeq] - 1);
+ }
+
+ int nSprite2 = insertsprite(sprite[nSprite].sectnum, 0);
+ ObjectList[nObject].field_10 = nSprite2;
+
+ sprite[nSprite2].cstat = 0x8000;
+ sprite[nSprite2].x = sprite[nSprite].x;
+ sprite[nSprite2].y = sprite[nSprite].y;
+ sprite[nSprite2].z = sprite[nSprite].z;
+ }
+
+ return nObject | 0x170000;
+}
+
+void ExplodeScreen(short nSprite)
+{
+ sprite[nSprite].z -= GetSpriteHeight(nSprite) / 2;
+
+ for (int i = 0; i < 30; i++) {
+ BuildSpark(nSprite, 0);
+ }
+
+ sprite[nSprite].cstat = 0x8000;
+// TODO PlayFX2(StaticSound[kSound78], nSprite);
+}
+
+void FuncObject(int a, int b, int nRun)
+{
+ short nObject = RunData[nRun].nVal;
+
+ short nSprite = ObjectList[nObject].nSprite;
+ short nStat = sprite[nSprite].statnum;
+ short bx = ObjectList[nObject].field_8;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Object\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0x30000:
+ return;
+
+ case 0x80000:
+ {
+ if (nStat >= 150 || ObjectList[nObject].nHealth <= 0) {
+ return;
+ }
+
+ if (nStat == 98)
+ {
+ D3PlayFX((StaticSound[kSound47] | 0x2000) | (RandomSize(2) << 9), nSprite);
+ return;
+ }
+
+ ObjectList[nObject].nHealth -= (short)b;
+ if (ObjectList[nObject].nHealth > 0) {
+ return;
+ }
+
+ if (nStat == kStatDestructibleSprite)
+ {
+ ExplodeScreen(nSprite);
+ }
+ else
+ {
+ ObjectList[nObject].nHealth = -(RandomSize(3) + 1);
+ }
+
+ return;
+ }
+
+ case 0x90000:
+ {
+ if (bx > -1)
+ {
+ seq_PlotSequence(a & 0xFFFF, bx, ObjectList[nObject].field_0, 1);
+ }
+ return;
+ }
+
+ case 0xA0000:
+ {
+ if (ObjectList[nObject].nHealth > 0 && sprite[nSprite].cstat & 0x101
+ && (nStat != kStatExplodeTarget
+ || sprite[nRadialSpr].statnum == 201
+ || nRadialBullet != 3 && nRadialBullet > -1
+ || sprite[nRadialSpr].statnum == kStatExplodeTrigger))
+ {
+ int nDamage = runlist_CheckRadialDamage(nSprite);
+ if (nDamage <= 0) {
+ return;
+ }
+
+ if (sprite[nSprite].statnum != kStat98) {
+ ObjectList[nObject].nHealth -= nDamage;
+ }
+
+ if (sprite[nSprite].statnum == kStatExplodeTarget)
+ {
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ }
+ else if (sprite[nSprite].statnum != kStat98)
+ {
+ sprite[nSprite].xvel >>= 1;
+ sprite[nSprite].yvel >>= 1;
+ sprite[nSprite].zvel >>= 1;
+ }
+
+ if (ObjectList[nObject].nHealth > 0) {
+ return;
+ }
+
+ if (sprite[nSprite].statnum == kStatExplodeTarget)
+ {
+ ObjectList[nObject].nHealth = -1;
+ short ax = ObjectList[nObject].field_10;
+
+ if (ax < 0 || ObjectList[ax].nHealth <= 0) {
+ return;
+ }
+
+ ObjectList[ax].nHealth = -1;
+ }
+ else if (sprite[nSprite].statnum == kStatDestructibleSprite)
+ {
+ ObjectList[nObject].nHealth = 0;
+
+ ExplodeScreen(nSprite);
+ }
+ else
+ {
+ ObjectList[nObject].nHealth = -(RandomSize(4) + 1);
+ }
+ }
+
+ return;
+ }
+
+ case 0x20000:
+ {
+ if (nStat == 97 || (!(sprite[nSprite].cstat & 0x101))) {
+ return;
+ }
+
+ if (nStat != kStatExplodeTarget) {
+ Gravity(nSprite);
+ }
+
+ // do animation
+ if (bx != -1)
+ {
+ ObjectList[nObject].field_0++;
+ if (ObjectList[nObject].field_0 >= SeqSize[bx]) {
+ ObjectList[nObject].field_0 = 0;
+ }
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(bx, ObjectList[nObject].field_0);
+ }
+
+ if (ObjectList[nObject].nHealth >= 0) {
+ goto FUNCOBJECT_GOTO;
+ }
+
+ ObjectList[nObject].nHealth++;
+
+ if (ObjectList[nObject].nHealth)
+ {
+FUNCOBJECT_GOTO:
+ if (nStat != kStatExplodeTarget)
+ {
+ int nMov = movesprite(nSprite, sprite[nSprite].xvel << 6, sprite[nSprite].yvel << 6, sprite[nSprite].zvel, 0, 0, CLIPMASK0);
+
+ if (sprite[nSprite].statnum == kStatExplodeTrigger) {
+ sprite[nSprite].pal = 1;
+ }
+
+ if (nMov & 0x20000)
+ {
+ sprite[nSprite].xvel -= sprite[nSprite].xvel >> 3;
+ sprite[nSprite].yvel -= sprite[nSprite].yvel >> 3;
+ }
+
+ if (((nMov & 0xC000) > 0x8000) && ((nMov & 0xC000) == 0xC000))
+ {
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+ }
+
+ return;
+ }
+ else
+ {
+ int var_18;
+
+ // red branch
+ if ((nStat == kStatExplodeTarget) || (sprite[nSprite].z < sector[sprite[nSprite].sectnum].floorz))
+ {
+ var_18 = 36;
+ }
+ else
+ {
+ var_18 = 34;
+ }
+
+ AddFlash(sprite[nSprite].sectnum, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, 128);
+ BuildAnim(-1, var_18, 0, sprite[nSprite].x, sprite[nSprite].y, sector[sprite[nSprite].sectnum].floorz, sprite[nSprite].sectnum, 240, 4);
+
+// int edi = nSprite | 0x4000;
+
+ if (nStat == kStatExplodeTrigger)
+ {
+ for (int i = 4; i < 8; i++) {
+ BuildCreatureChunk(nSprite | 0x4000, seq_GetSeqPicnum(kSeqFirePot, (i >> 2) + 1, 0));
+ }
+
+ runlist_RadialDamageEnemy(nSprite, 200, 20);
+ }
+ else if (nStat == kStatExplodeTarget)
+ {
+ for (int i = 0; i < 8; i++) {
+ BuildCreatureChunk(nSprite | 0x4000, seq_GetSeqPicnum(kSeqFirePot, (i >> 1) + 3, 0));
+ }
+ }
+
+ if (levelnum <= 20 || nStat != kStatExplodeTrigger)
+ {
+ runlist_SubRunRec(sprite[nSprite].owner);
+ runlist_SubRunRec(ObjectList[nObject].field_4);
+
+ assert(nSprite != 59);
+
+ mydeletesprite(nSprite);
+ return;
+ }
+ else
+ {
+ StartRegenerate(nSprite);
+ ObjectList[nObject].nHealth = 120;
+
+ sprite[nSprite].x = sprite[ObjectList[nObject].field_10].x;
+ sprite[nSprite].y = sprite[ObjectList[nObject].field_10].y;
+ sprite[nSprite].z = sprite[ObjectList[nObject].field_10].z;
+
+ mychangespritesect(nSprite, sprite[ObjectList[nObject].field_10].sectnum);
+ return;
+ }
+ }
+ }
+ }
+}
+
+void BuildDrip(int nSprite)
+{
+ if (nDrips >= kMaxDrips) {
+ bail2dos("Too many drips!\n");
+ }
+
+ sDrip[nDrips].nSprite = nSprite;
+ sDrip[nDrips].field_2 = RandomSize(8) + 90;
+
+ nDrips++;
+
+ sprite[nSprite].cstat = 0x8000u;
+}
+
+// Confirmed 100% correct with original .exe
+void DoDrips()
+{
+ int i;
+
+ for (i = 0; i < nDrips; i++)
+ {
+ sDrip[i].field_2--;
+ if (sDrip[i].field_2 <= 0)
+ {
+ short nSprite = sDrip[i].nSprite;
+
+ short nSeqOffset = SeqOffsets[kSeqDrips];
+
+ if (!(SectFlag[sprite[nSprite].sectnum] & kSectLava)) {
+ nSeqOffset++;
+ }
+
+ seq_MoveSequence(nSprite, nSeqOffset, RandomSize(2) % SeqSize[nSeqOffset]);
+
+ sDrip[i].field_2 = RandomSize(8) + 90;
+ }
+ }
+
+ for (i = 0; i < nBobs; i++)
+ {
+ sBob[i].field_2 += 4;
+
+ int edx = Sin(sBob[i].field_2 << 3) >> 4;
+ short nSector = sBob[i].nSector;
+
+ if (sBob[i].field_3)
+ {
+ sector[nSector].ceilingz = edx + sBob[i].z;
+ }
+ else
+ {
+ int nFloorZ = sector[nSector].floorz;
+
+ sector[nSector].floorz = edx + sBob[i].z;
+
+ MoveSectorSprites(nSector, sector[nSector].floorz - nFloorZ);
+ }
+ }
+}
+
+void SnapBobs(short nSectorA, short nSectorB)
+{
+ int ecx = -1;
+ int ebx = ecx;
+// int var_14 = nSector;
+// int edi = edx;
+
+ for (int i = 0; i < nBobs; i++)
+ {
+ int esi = sBob[i].nSector;
+
+ if (esi != nSectorA)
+ {
+ if (nSectorB != esi)
+ continue;
+
+ esi = ebx;
+ ecx = i;
+ }
+ else
+ {
+ esi = ecx;
+ ebx = i;
+ }
+
+ if (esi != -1) {
+ break;
+ }
+ }
+
+ if (ecx <= -1) {
+ return;
+ }
+
+ if (ebx <= -1) {
+ return;
+ }
+
+ sBob[ecx].field_2 = sBob[ebx].field_2;
+}
+
+void AddSectorBob(int nSector, int nHitag, int bx)
+{
+ if (nBobs >= kMaxBobs) {
+ bail2dos("Too many bobs!\n");
+ }
+
+ sBob[nBobs].field_3 = bx;
+
+ int z;
+
+ if (bx == 0) {
+ z = sector[nSector].floorz;
+ }
+ else {
+ z = sector[nSector].ceilingz;
+ }
+
+ sBob[nBobs].z = z;
+ sBob[nBobs].field_2 = nHitag << 4;
+ sBobID[nBobs] = nHitag;
+
+ sBob[nBobs].nSector = nSector;
+
+ SectFlag[nSector] |= 0x0010;
+
+ nBobs++;
+}
+
+// Confirmed 100% correct with original .exe
+int FindTrail(int nVal)
+{
+ for (int i = 0; i < nTrails; i++)
+ {
+ if (sTrail[i].field_2 == nVal)
+ return i;
+ }
+
+ sTrail[nTrails].field_2 = nVal;
+ sTrail[nTrails].field_0 = -1;
+
+ return nTrails++;
+}
+
+// ok ?
+void ProcessTrailSprite(int nSprite, int nLotag, int nHitag)
+{
+ if (nTrailPoints >= 100) {
+ bail2dos("Too many trail point sprites (900-949)... increase MAX_TRAILPOINTS\n");
+ }
+
+ short nPoint = nTrailPoints;
+ nTrailPoints++;
+
+ sTrailPoint[nPoint].x = sprite[nSprite].x;
+ sTrailPoint[nPoint].y = sprite[nSprite].y;
+
+ int nTrail = FindTrail(nHitag);
+
+ int var_14 = nLotag - 900;
+
+ nTrailPointVal[nPoint] = var_14;
+
+ int field0 = sTrail[nTrail].field_0;
+
+ if (field0 == -1)
+ {
+ sTrail[nTrail].field_0 = nPoint;
+ sTrail[nTrail].field_4 = nPoint;
+
+ nTrailPointNext[nTrail] = -1;
+ nTrailPointPrev[nTrail] = -1;
+ }
+ else
+ {
+ int ecx = -1;
+
+ while (field0 != -1)
+ {
+ if (nTrailPointVal[field0] > var_14)
+ {
+ nTrailPointPrev[nPoint] = nTrailPointPrev[field0];
+ nTrailPointPrev[field0] = nPoint;
+ nTrailPointNext[nPoint] = field0;
+
+ if (field0 == sTrail[nTrail].field_0) {
+ sTrail[nTrail].field_0 = nPoint;
+ }
+
+ break;
+ }
+
+ ecx = field0;
+ field0 = nTrailPointNext[field0];
+ }
+
+ if (field0 == -1)
+ {
+ nTrailPointNext[ecx] = nPoint;
+ nTrailPointPrev[nPoint] = ecx;
+ nTrailPointNext[nPoint] = -1;
+ sTrail[nTrail].field_4 = nPoint;
+ }
+ }
+
+ mydeletesprite(nSprite);
+}
+
+// ok?
+void AddMovingSector(int nSector, int edx, int ebx, int ecx)
+{
+ if (nMoveSects >= kMaxMoveSects) {
+ bail2dos("Too many moving sectors\n");
+ }
+
+ CreatePushBlock(nSector);
+
+ short nTrail = FindTrail(ebx);
+
+ sMoveDir[nMoveSects] = 1;
+
+ MoveSect *pMoveSect = &sMoveSect[nMoveSects];
+ nMoveSects++;
+
+ pMoveSect->nTrail = nTrail;
+ pMoveSect->nTrailPoint = -1;
+ pMoveSect->field_8 = -1;
+ pMoveSect->field_6 = ecx;
+ pMoveSect->field_10 = (edx / 1000) + 1;
+ pMoveSect->nSector = nSector;
+
+ if (ecx & 8)
+ {
+ pMoveSect->field_14 = runlist_AllocChannel(ebx % 1000);
+ }
+ else
+ {
+ pMoveSect->field_14 = -1;
+ }
+
+ sector[nSector].floorstat |= 0x40;
+}
+
+void DoMovingSects()
+{
+ for (int i = 0; i < nMoveSects; i++)
+ {
+ if (sMoveSect[i].nSector == -1) {
+ continue;
+ }
+
+ if (sMoveSect[i].field_14 != -1 && !sRunChannels[sMoveSect[i].field_14].c) {
+ continue;
+ }
+
+ short nSector = sMoveSect[i].nSector;
+ short nBlock = sector[nSector].extra;
+
+ BlockInfo *pBlockInfo = &sBlockInfo[nBlock];
+
+ if (sMoveSect[i].nTrailPoint == -1)
+ {
+ if (sMoveSect[i].field_6 & 0x20)
+ {
+ runlist_ChangeChannel(sMoveSect[i].field_14, 0);
+ }
+
+ short ax;
+
+ if (sMoveSect[i].field_6 & 0x10)
+ {
+ sMoveDir[i] = -sMoveDir[i];
+ if (sMoveDir[i] > 0)
+ {
+ ax = sTrail[sMoveSect[i].nTrail].field_0;
+ }
+ else
+ {
+ ax = sTrail[sMoveSect[i].nTrail].field_4;
+ }
+ }
+ else
+ {
+ ax = sTrail[sMoveSect[i].nTrail].field_0;
+ }
+
+ sMoveSect[i].nTrailPoint = ax;
+ }
+
+ short nTrail = sMoveSect[i].nTrailPoint;
+// TrailPoint *pTrail = &sTrailPoint[nTrail];
+
+ // loc_23872:
+ int nAngle = GetMyAngle(sTrailPoint[nTrail].x - pBlockInfo->x, sTrailPoint[nTrail].y - pBlockInfo->y);
+
+ int nXVel = (Sin(nAngle + 512) << 4) * sMoveSect[i].field_10;
+ int nYVel = (Sin(nAngle) << 4) * sMoveSect[i].field_10;
+
+ int ebx = (sTrailPoint[nTrail].x - pBlockInfo->x) << 14;
+
+ int eax = nXVel;
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ int edx = eax;
+ eax = ebx;
+
+ int ecx = (sTrailPoint[nTrail].y - pBlockInfo->y) << 14;
+
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ // loc_238EC:
+ if (edx <= eax)
+ {
+ eax = nYVel;
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ edx = eax;
+ eax = ecx;
+
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ if (edx > eax)
+ {
+ // loc_23908:
+ nYVel = ecx;
+ nXVel = ebx;
+
+ if (sMoveDir[i] > 0)
+ {
+ sMoveSect[i].nTrailPoint = nTrailPointNext[sMoveSect[i].nTrailPoint];
+ }
+ else
+ {
+ sMoveSect[i].nTrailPoint = nTrailPointPrev[sMoveSect[i].nTrailPoint];
+ }
+ }
+ }
+ else
+ {
+ // repeat of code from loc_23908
+ nYVel = ecx;
+ nXVel = ebx;
+
+ if (sMoveDir[i] > 0)
+ {
+ int thepoint = nTrailPointNext[sMoveSect[i].nTrailPoint];
+ sMoveSect[i].nTrailPoint = nTrailPointNext[sMoveSect[i].nTrailPoint];
+
+ }
+ else
+ {
+ int thepoint = nTrailPointPrev[sMoveSect[i].nTrailPoint];
+ sMoveSect[i].nTrailPoint = nTrailPointPrev[sMoveSect[i].nTrailPoint];
+
+ }
+ }
+
+ // loc_2393A:
+ if (sMoveSect[i].field_8 != -1)
+ {
+ MoveSector(sMoveSect[i].field_8, -1, &nXVel, &nYVel);
+ }
+
+ int var_2C = nXVel;
+ int var_30 = nYVel;
+
+ MoveSector(nSector, -1, &nXVel, &nYVel);
+
+ if (nXVel != var_2C || nYVel != var_30)
+ {
+ MoveSector(sMoveSect[i].field_8, -1, &var_2C, &var_30);
+ MoveSector(sMoveSect[i].field_8, -1, &nXVel, &nYVel);
+ }
+ }
+}
+
+void PostProcess()
+{
+ int i, j;
+
+ for (i = 0; i < nMoveSects; i++)
+ {
+ int nTrail = sMoveSect[i].nTrail;
+ sMoveSect[i].nTrailPoint = sTrail[nTrail].field_0;
+
+ if (sMoveSect[i].field_6 & 0x40) {
+ runlist_ChangeChannel(sMoveSect[i].field_14, 1);
+ }
+
+ short nSector = sMoveSect[i].nSector;
+
+ if (SectFlag[nSector] & kSectUnderwater)
+ {
+ sector[nSector].ceilingstat |= 0x40;
+ sector[nSector].floorstat &= 0xBFFF;
+
+ for (j = 0; j < nMoveSects; j++)
+ {
+ if (j != i && sMoveSect[i].nTrail == sMoveSect[j].nTrail)
+ {
+ sMoveSect[j].field_8 = sMoveSect[i].nSector;
+
+ SnapSectors(sMoveSect[j].nSector, sMoveSect[i].nSector, 0);
+ sMoveSect[i].nSector = -1;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < nBobs; i++)
+ {
+ if (sBob[i].field_3 == 0)
+ {
+ int bobID = sBobID[i];
+
+ for (j = 0; j < nBobs; j++)
+ {
+ if (j != i)
+ {
+ if (sBob[i].field_3 != 0 && sBobID[j] == bobID) {
+ SnapSectors(i, j, 0);
+ }
+ }
+ }
+ }
+ }
+
+ if (levelnew != kMap20)
+ {
+ // esi is i
+ for (i = 0; i < numsectors; i++)
+ {
+ int var_20 = 30000;
+
+ if (SectSpeed[i] && SectDepth[i] && !(SectFlag[i] & kSectLava))
+ {
+ SectSoundSect[i] = i;
+ SectSound[i] = StaticSound[kSound62];
+ }
+ else
+ {
+ // ebp and ecx are j
+ for (j = 0; j < numsectors; j++)
+ {
+ // loc_23CA6:
+
+ if (i != j && SectSpeed[j] && !(SectFlag[i] & kSectLava))
+ {
+ int xVal = wall[sector[i].wallptr].x - wall[sector[j].wallptr].x;
+ if (xVal < 0) {
+ xVal = -xVal;
+ }
+
+ int yVal = wall[sector[i].wallptr].x - wall[sector[j].wallptr].x;
+ if (yVal < 0) {
+ yVal = -yVal;
+ }
+
+ if (xVal < 15000 && yVal < 15000 && (xVal + yVal < var_20))
+ {
+ var_20 = xVal + yVal;
+ SectSoundSect[i] = j;
+ SectSound[i] = j;
+ }
+ }
+ }
+ }
+ }
+ }
+ else // nMap == kMap20)
+ {
+ // int var_24 = 0;
+ int ebp = 0;
+
+ for (i = 0; i < numsectors; i++)
+ {
+ SectSoundSect[i] = i;
+ SectSound[i] = StaticSound[kSound62];
+
+ int startwall = sector[ebp].wallptr;
+ int endwall = sector[ebp].wallptr + sector[ebp].wallnum;
+
+ int nWall = startwall;
+
+ while (nWall < endwall)
+ {
+ if (wall[nWall].picnum == kTile3603)
+ {
+ wall[nWall].pal = 1;
+ int nSprite = insertsprite(i, 407);
+ sprite[nSprite].cstat = 0x8000;
+ }
+
+ nWall++;
+ }
+ }
+
+ for (i = 0; i < kMaxSprites; i++)
+ {
+ if (sprite[i].statnum < kMaxStatus && sprite[i].picnum == kTile3603)
+ {
+ changespritestat(i, 407);
+ sprite[i].pal = 1;
+ }
+ }
+ }
+
+ // esi is i
+ for (i = 0; i < ObjectCount; i++)
+ {
+ int nObjectSprite = ObjectList[i].nSprite;
+
+ if (sprite[nObjectSprite].statnum == kStatExplodeTarget)
+ {
+ if (!ObjectList[i].field_10) {
+ ObjectList[i].field_10 = -1;
+ }
+ else
+ {
+ int edi = ObjectList[i].field_10;
+ ObjectList[i].field_10 = -1;
+
+ // ecx, ebx is j
+ for (j = 0; j < ObjectCount; j++)
+ {
+ if (i != j && sprite[ObjectList[j].nSprite].statnum == kStatExplodeTarget && edi == ObjectList[j].field_10)
+ {
+ ObjectList[i].field_10 = j;
+ ObjectList[j].field_10 = i;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/exhumed/src/object.h b/source/exhumed/src/object.h
new file mode 100644
index 000000000..2b3538fb5
--- /dev/null
+++ b/source/exhumed/src/object.h
@@ -0,0 +1,69 @@
+
+#ifndef __object_h__
+#define __object_h__
+
+#define kMaxPoints 1024
+#define kMaxSlides 128
+#define kMaxElevs 1024
+
+enum kStatus
+{
+ kStatDestructibleSprite = 97,
+ kStat98,
+ kStatExplodeTrigger = 141,
+ kStatExplodeTarget = 152
+};
+
+extern short nSmokeSparks;
+extern short nDronePitch;
+extern long lFinaleStart;
+extern short nFinaleSpr;
+
+void InitObjects();
+void InitElev();
+void InitPoint();
+void InitSlide();
+void InitWallFace();
+void DoDrips();
+void DoMovingSects();
+void DoFinale();
+void PostProcess();
+
+void FuncElev(int, int, int);
+void FuncWallFace(int, int, int);
+void FuncSlide(int, int, int);
+void FuncObject(int, int, int);
+void FuncTrap(int, int, int);
+void FuncEnergyBlock(int, int, int);
+void FuncSpark(int, int, int);
+
+void SnapBobs(short nSectorA, short nSectorB);
+
+short FindWallSprites(short nSector);
+
+void AddMovingSector(int nSector, int edx, int ebx, int ecx);
+
+int BuildWallSprite(int nSector);
+
+void ProcessTrailSprite(int nSprite, int nLotag, int nHitag);
+
+void AddSectorBob(int nSector, int nHitag, int bx);
+
+int BuildObject(short nSprite, int nOjectType, int nHitag);
+
+int BuildArrow(int nSprite, int nVal);
+
+int BuildFireBall(int nSprite, int a, int b);
+
+void BuildDrip(int nSprite);
+
+int BuildEnergyBlock(short nSector);
+
+int BuildElevC(int arg1, int nChannel, int nSector, int nWallSprite, int arg5, int arg6, int nCount, int zList ...);
+int BuildElevF(int nChannel, int nSector, int nWallSprite, int arg_4, int arg_5, int nCount, int zList ...);
+
+int BuildWallFace(short nChannel, short nWall, short nCount, int nPics ...);
+
+int BuildSlide(int nChannel, int edx, int ebx, int ecx, int arg1, int arg2, int arg3);
+
+#endif
diff --git a/source/exhumed/src/paul.cpp b/source/exhumed/src/paul.cpp
new file mode 100644
index 000000000..2f5627673
--- /dev/null
+++ b/source/exhumed/src/paul.cpp
@@ -0,0 +1,2 @@
+
+#include "paul.h"
diff --git a/source/exhumed/src/paul.h b/source/exhumed/src/paul.h
new file mode 100644
index 000000000..f952d77db
--- /dev/null
+++ b/source/exhumed/src/paul.h
@@ -0,0 +1,7 @@
+
+#ifndef __paul_h__
+#define __paul_h__
+
+
+
+#endif
diff --git a/source/exhumed/src/player.cpp b/source/exhumed/src/player.cpp
new file mode 100644
index 000000000..ec4433eb9
--- /dev/null
+++ b/source/exhumed/src/player.cpp
@@ -0,0 +1,3276 @@
+
+#include "player.h"
+#include "runlist.h"
+#include "exhumed.h"
+#include "names.h"
+#include "gun.h"
+#include "items.h"
+#include "engine.h"
+#include "move.h"
+#include "sequence.h"
+#include "lighting.h"
+#include "view.h"
+#include "bubbles.h"
+#include "random.h"
+#include "ra.h"
+#include "input.h"
+#include "light.h"
+#include "status.h"
+#include "types.h"
+#include "mouse.h"
+#include "keyboard.h"
+#include "control.h"
+#include "config.h"
+#include "sound.h"
+#include "init.h"
+#include "move.h"
+#include "trigdat.h"
+#include "anims.h"
+#include "grenade.h"
+#include "menu.h"
+#include "cd.h"
+#include "cdaudio.h"
+#include "map.h"
+#include "sound.h"
+#include
+#include
+#include
+
+struct PlayerSave
+{
+ int x;
+ int y;
+ int z;
+ short nSector;
+ short nAngle;
+};
+
+int lPlayerXVel = 0;
+int lPlayerYVel = 0;
+int nPlayerDAng = 0;
+short bobangle = 0;
+short bPlayerPan = 0;
+short bLockPan = 0;
+
+static actionSeq ActionSeq[] = {
+ {18, 0}, {0, 0}, {9, 0}, {27, 0}, {63, 0},
+ {72, 0}, {54, 0}, {45, 0}, {54, 0}, {81, 0},
+ {90, 0}, {99, 0}, {108, 0}, {8, 0}, {0, 0},
+ {139, 0}, {117, 1}, {119, 1}, {120, 1}, {121, 1},
+ {122, 1}
+};
+
+static short nHeightTemplate[] = { 0, 0, 0, 0, 0, 0, 7, 7, 7, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+short nActionEyeLevel[] = {
+ -14080, -14080, -14080, -14080, -14080, -14080, -8320,
+ -8320, -8320, -8320, -8320, -8320, -8320, -14080,
+ -14080, -14080, -14080, -14080, -14080, -14080, -14080
+};
+
+ushort nGunLotag[] = { 52, 53, 54, 55, 56, 57 };
+ushort nGunPicnum[] = { 57, 488, 490, 491, 878, 899, 3455 };
+
+sshort nItemText[] = {
+ -1, -1, -1, -1, -1, -1, 18, 20, 19, 13, -1, 10, 1, 0, 2, -1, 3,
+ -1, 4, 5, 9, 6, 7, 8, -1, 11, -1, 13, 12, 14, 15, -1, 16, 17,
+ -1, -1, -1, 21, 22, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+
+int nLocalPlayer = 0;
+
+short nBreathTimer[kMaxPlayers];
+short nPlayerSwear[kMaxPlayers];
+short nPlayerPushSect[kMaxPlayers];
+short nDeathType[kMaxPlayers];
+short nPlayerScore[kMaxPlayers];
+short nPlayerColor[kMaxPlayers];
+int nPlayerDY[kMaxPlayers];
+int nPlayerDX[kMaxPlayers];
+char playerNames[kMaxPlayers][11];
+short nPistolClip[kMaxPlayers];
+int nXDamage[kMaxPlayers];
+int nYDamage[kMaxPlayers];
+short nDoppleSprite[kMaxPlayers];
+short namelen[kMaxPlayers];
+short nPlayerOldWeapon[kMaxPlayers];
+short nPlayerClip[kMaxPlayers];
+short nPlayerPushSound[kMaxPlayers];
+short nTauntTimer[kMaxPlayers];
+short nPlayerTorch[kMaxPlayers];
+ushort nPlayerWeapons[kMaxPlayers]; // each set bit represents a weapon the player has
+short nPlayerLives[kMaxPlayers];
+short nPlayerItem[kMaxPlayers];
+Player PlayerList[kMaxPlayers];
+short nPlayerInvisible[kMaxPlayers];
+short nPlayerDouble[kMaxPlayers];
+short nPlayerViewSect[kMaxPlayers];
+short nPlayerFloorSprite[kMaxPlayers];
+PlayerSave sPlayerSave[kMaxPlayers];
+int totalvel[kMaxPlayers] = { 0 };
+sshort eyelevel[kMaxPlayers];
+short nNetStartSprite[kMaxPlayers] = { 0 };
+
+short nStandHeight;
+
+short nPlayerGrenade[kMaxPlayers];
+short nGrenadePlayer[50];
+
+short word_D282A[32];
+
+
+short PlayerCount;
+
+short nNetStartSprites;
+short nCurStartSprite;
+
+/*
+typedef struct
+{
+fixed dx;
+fixed dy;
+fixed dz;
+fixed dyaw;
+fixed dpitch;
+fixed droll;
+} ControlInfo;
+*/
+
+void PlayerInterruptKeys()
+{
+ ControlInfo info;
+
+ if (PlayerList[nLocalPlayer].nHealth == 0)
+ {
+ lPlayerYVel = 0;
+ lPlayerXVel = 0;
+ nPlayerDAng = 0;
+ return;
+ }
+
+ memset(&info, 0, sizeof(ControlInfo)); // this is done within CONTROL_GetInput() anyway
+ CONTROL_GetInput(&info);
+
+ info.dyaw *= (lMouseSens >> 1) + 1;
+
+ int nXVel, nYVel;
+
+ inita &= kAngleMask;
+
+ if (BUTTON(gamefunc_Run))
+ {
+ nXVel = Sin(inita + 512) * 12;
+ nYVel = sintable[inita] * 12;
+ }
+ else
+ {
+ nXVel = Sin(inita + 512) * 6;
+ nYVel = sintable[inita] * 6;
+ }
+
+ // loc_18E60
+ if (BUTTON(gamefunc_Move_Forward))
+ {
+ lPlayerXVel += nXVel;
+ lPlayerYVel += nYVel;
+ }
+ else if (BUTTON(gamefunc_Move_Backward))
+ {
+ lPlayerXVel -= nXVel;
+ lPlayerYVel -= nYVel;
+ }
+ else if (info.dz)
+ {
+ if (info.dz < -6400)
+ {
+ info.dz = -6400;
+ }
+ else if (info.dz > 6400)
+ {
+ info.dz = 6400;
+ }
+
+ // loc_18EE4
+ if (BUTTON(gamefunc_Mouseview))
+ {
+ int nVPan = nVertPan[nLocalPlayer] - (info.dz >> 7);
+
+ if (nVPan < 0)
+ {
+ nVPan = 0;
+ }
+ else if (nVPan > 184)
+ {
+ nVPan = 184;
+ }
+
+ nVertPan[nLocalPlayer] = nVPan;
+ }
+ else
+ {
+ if (BUTTON(gamefunc_Run))
+ {
+ lPlayerXVel += Sin(inita + 512) * ((-info.dz) >> 7);
+ lPlayerYVel += Sin(inita) * ((-info.dz) >> 7);
+ }
+ else
+ {
+ lPlayerXVel += Sin(inita + 512) * ((-info.dz) >> 8);
+ lPlayerYVel += Sin(inita) * ((-info.dz) >> 8);
+ }
+ }
+ }
+
+ // loc_18FD4
+ if (BUTTON(gamefunc_Strafe_Left))
+ {
+ lPlayerXVel += nYVel / 4;
+ lPlayerYVel -= nXVel / 4;
+ }
+ else if (BUTTON(gamefunc_Strafe_Right))
+ {
+ lPlayerXVel -= nYVel / 4;
+ lPlayerYVel += nXVel / 4;
+ }
+ else
+ {
+ if (BUTTON(gamefunc_Strafe))
+ {
+ if (BUTTON(gamefunc_Turn_Left))
+ {
+ lPlayerXVel += nYVel;
+ lPlayerYVel -= nXVel;
+ }
+ else if (BUTTON(gamefunc_Turn_Right))
+ {
+ lPlayerXVel -= nYVel;
+ lPlayerYVel += nXVel;
+ }
+ else
+ {
+ if (BUTTON(gamefunc_Run))
+ {
+ lPlayerXVel -= Sin(inita) * (info.dyaw >> 5);
+ lPlayerYVel += Sin(inita + 512) * (info.dyaw >> 5);
+ }
+ else
+ {
+ lPlayerXVel -= Sin(inita) * (info.dyaw >> 7);
+ lPlayerYVel += Sin(inita + 512) * (info.dyaw >> 7);
+ }
+ }
+ }
+ else
+ {
+ // normal, non strafing movement
+ if (BUTTON(gamefunc_Turn_Left))
+ {
+ nPlayerDAng -= 2;
+
+ if (BUTTON(gamefunc_Run))
+ {
+ if (nPlayerDAng < -12)
+ nPlayerDAng = -12;
+ }
+ else if (nPlayerDAng < -8)
+ {
+ nPlayerDAng = -8;
+ }
+ }
+ else if (BUTTON(gamefunc_Turn_Right))
+ {
+ nPlayerDAng += 2;
+
+ if (BUTTON(gamefunc_Run))
+ {
+ if (nPlayerDAng > 12)
+ nPlayerDAng = 12;
+ }
+ else if (nPlayerDAng > 8)
+ {
+ nPlayerDAng = 8;
+ }
+ }
+ else
+ {
+ int nAng = info.dyaw >> 8;
+
+ // loc_19201:
+ if (info.dyaw < 0)
+ {
+ if (nAng > -2) {
+ nAng = -2;
+ }
+
+ nPlayerDAng = nAng;
+ }
+ else if (info.dyaw > 0)
+ {
+ if (nAng < 2) {
+ nAng = 2;
+ }
+
+ nPlayerDAng = nAng;
+ }
+ }
+ }
+ }
+
+ // loc_19231
+ if (nPlayerDAng < 0)
+ {
+ nPlayerDAng++;
+ if (nPlayerDAng > 0)
+ nPlayerDAng = 0;
+ }
+
+ if (nPlayerDAng > 0)
+ {
+ nPlayerDAng--;
+ if (nPlayerDAng < 0)
+ nPlayerDAng = 0;
+ }
+
+ lPlayerXVel -= (lPlayerXVel >> 5) + (lPlayerXVel >> 6);
+ lPlayerYVel -= (lPlayerYVel >> 5) + (lPlayerYVel >> 6);
+}
+
+void RestoreSavePoint(int nPlayer, int *x, int *y, int *z, short *nSector, short *nAngle)
+{
+ *x = sPlayerSave[nPlayer].x;
+ *y = sPlayerSave[nPlayer].y;
+ *z = sPlayerSave[nPlayer].z;
+ *nSector = sPlayerSave[nPlayer].nSector;
+ *nAngle = sPlayerSave[nPlayer].nAngle;
+}
+
+void SetSavePoint(int nPlayer, int x, int y, int z, short nSector, short nAngle)
+{
+ sPlayerSave[nPlayer].x = x;
+ sPlayerSave[nPlayer].y = y;
+ sPlayerSave[nPlayer].z = z;
+ sPlayerSave[nPlayer].nSector = nSector;
+ sPlayerSave[nPlayer].nAngle = nAngle;
+}
+
+void feebtag(int x, int y, int z, int nSector, short *nSprite, int nVal2, int nVal3)
+{
+ *nSprite = -1;
+
+ int startwall = sector[nSector].wallptr;
+
+ int nWalls = sector[nSector].wallnum;
+
+ int var_20 = nVal2 & 2;
+ int var_14 = nVal2 & 1;
+
+ while (1)
+ {
+ if (nSector != -1)
+ {
+ short i = headspritesect[nSector];
+
+ while (i != -1)
+ {
+ short nNextSprite = nextspritesect[i];
+ short nStat = sprite[i].statnum;
+
+ if (nStat >= 900 && !(sprite[i].cstat & 0x8000))
+ {
+ int xDiff = sprite[i].x - x;
+ int yDiff = sprite[i].y - y;
+ int zDiff = sprite[i].z - z;
+
+ if (zDiff < 5120 && zDiff > -25600)
+ {
+ int theSqrt = ksqrt(xDiff * xDiff + yDiff * yDiff);
+
+ if (theSqrt < nVal3 && (nStat != 950 && nStat != 949 || !(var_14 & 1)) && (nStat != 912 && nStat != 913 || !(var_20 & 2)))
+ {
+ nVal3 = theSqrt;
+ *nSprite = i;
+ }
+ }
+ }
+
+ i = nNextSprite;
+ }
+ }
+
+ nWalls--;
+ if (nWalls < -1)
+ return;
+
+ nSector = wall[startwall].nextsector;
+ startwall++;
+ }
+}
+
+void InitPlayer()
+{
+ for (int i = 0; i < kMaxPlayers; i++) {
+ PlayerList[i].nSprite = -1;
+ }
+}
+
+void InitPlayerKeys(short nPlayer)
+{
+ PlayerList[nPlayer].keys = 0;
+}
+
+void InitPlayerInventory(short nPlayer)
+{
+ memset(&PlayerList[nPlayer], 0, sizeof(Player));
+
+ nPlayerItem[nPlayer] = -1;
+ nPlayerSwear[nPlayer] = 4;
+
+ ResetPlayerWeapons(nPlayer);
+
+ nPlayerLives[nPlayer] = kDefaultLives;
+
+ PlayerList[nPlayer].nSprite = -1;
+ PlayerList[nPlayer].nRun = -1;
+
+ nPistolClip[nPlayer] = 6;
+ nPlayerClip[nPlayer] = 100;
+
+ PlayerList[nPlayer].nCurrentWeapon = 0;
+
+ if (nPlayer == nLocalPlayer) {
+ bMapMode = 0;
+ }
+
+ nPlayerScore[nPlayer] = 0;
+
+ loadtile(kTile3571 + nPlayer);
+
+ nPlayerColor[nPlayer] = *(waloff[nPlayer + kTile3571] + tilesizx[nPlayer + kTile3571] * tilesizy[nPlayer + kTile3571] / 2);
+}
+
+// done
+short GetPlayerFromSprite(short nSprite)
+{
+ return RunData[sprite[nSprite].owner].nVal;
+}
+
+void RestartPlayer(short nPlayer)
+{
+ int nSprite = PlayerList[nPlayer].nSprite;
+ int nDopSprite = nDoppleSprite[nPlayer];
+
+ int floorspr;
+
+ if (nSprite > -1)
+ {
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+
+ changespritestat(nSprite, 0);
+
+ PlayerList[nPlayer].nSprite = -1;
+
+ int nFloorSprite = nPlayerFloorSprite[nPlayer];
+ if (nFloorSprite > -1) {
+ mydeletesprite(nFloorSprite);
+ }
+
+ if (nDopSprite > -1)
+ {
+ runlist_DoSubRunRec(sprite[nDopSprite].owner);
+ runlist_FreeRun(sprite[nDopSprite].lotag - 1);
+ mydeletesprite(nDopSprite);
+ }
+ }
+
+ nSprite = GrabBody();
+
+ mychangespritesect(nSprite, sPlayerSave[nPlayer].nSector);
+ changespritestat(nSprite, 100);
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ int nDSprite = insertsprite(sprite[nSprite].sectnum, 100);
+ nDoppleSprite[nPlayer] = nDSprite;
+
+ assert(nDSprite >= 0 && nDSprite < kMaxSprites);
+
+ if (nTotalPlayers > 1)
+ {
+ int nNStartSprite = nNetStartSprite[nCurStartSprite];
+ nCurStartSprite++;
+
+ if (nCurStartSprite >= nNetStartSprites) {
+ nCurStartSprite = 0;
+ }
+
+ sprite[nSprite].x = sprite[nNStartSprite].x;
+ sprite[nSprite].y = sprite[nNStartSprite].y;
+ sprite[nSprite].z = sprite[nNStartSprite].z;
+ mychangespritesect(nSprite, sprite[nNStartSprite].sectnum);
+ sprite[nSprite].ang = sprite[nNStartSprite].ang;
+
+ floorspr = insertsprite(sprite[nSprite].sectnum, 0);
+ assert(floorspr >= 0 && floorspr < kMaxSprites);
+
+ sprite[floorspr].x = sprite[nSprite].x;
+ sprite[floorspr].y = sprite[nSprite].y;
+ sprite[floorspr].z = sprite[nSprite].z;
+ sprite[floorspr].yrepeat = 64;
+ sprite[floorspr].xrepeat = 64;
+ sprite[floorspr].cstat = 32;
+ sprite[floorspr].picnum = nPlayer + kTile3571;
+ }
+ else
+ {
+ sprite[nSprite].x = sPlayerSave[nPlayer].x;
+ sprite[nSprite].y = sPlayerSave[nPlayer].y;
+ sprite[nSprite].z = sector[sPlayerSave[nPlayer].nSector].floorz;
+ sprite[nSprite].ang = sPlayerSave[nPlayer].nAngle;
+
+ floorspr = -1;
+ }
+
+ nPlayerFloorSprite[nPlayer] = floorspr;
+
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].clipdist = 58;
+ sprite[nSprite].pal = 0;
+ sprite[nSprite].xrepeat = 40;
+ sprite[nSprite].yrepeat = 40;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].picnum = seq_GetSeqPicnum(kSeqJoe, 18, 0);
+
+ int nHeight = GetSpriteHeight(nSprite);
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+
+ nStandHeight = nHeight;
+
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].extra = -1;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+
+ sprite[nDSprite].x = sprite[nSprite].x;
+ sprite[nDSprite].y = sprite[nSprite].y;
+ sprite[nDSprite].z = sprite[nSprite].z;
+ sprite[nDSprite].xrepeat = sprite[nSprite].xrepeat;
+ sprite[nDSprite].yrepeat = sprite[nSprite].yrepeat;
+ sprite[nDSprite].xoffset = 0;
+ sprite[nDSprite].yoffset = 0;
+ sprite[nDSprite].shade = sprite[nSprite].shade;
+ sprite[nDSprite].ang = sprite[nSprite].ang;
+ sprite[nDSprite].cstat = sprite[nSprite].cstat;
+
+ sprite[nDSprite].lotag = runlist_HeadRun() + 1;
+
+ PlayerList[nPlayer].nAction = 0;
+ PlayerList[nPlayer].nHealth = 800; // TODO - define
+
+ if (nNetPlayerCount) {
+ PlayerList[nPlayer].nHealth = 1600; // TODO - define
+ }
+
+ PlayerList[nPlayer].field_2 = 0;
+ PlayerList[nPlayer].nSprite = nSprite;
+ PlayerList[nPlayer].bIsMummified = kFalse;
+
+ if (PlayerList[nPlayer].invincibility >= 0) {
+ PlayerList[nPlayer].invincibility = 0;
+ }
+
+ nPlayerTorch[nPlayer] = 0;
+ PlayerList[nPlayer].nMaskAmount = 0;
+
+ SetTorch(nPlayer, 0);
+
+ nPlayerInvisible[nPlayer] = 0;
+
+ PlayerList[nPlayer].bIsFiring = 0;
+ PlayerList[nPlayer].field_34 = 0;
+ nPlayerViewSect[nPlayer] = sPlayerSave[nPlayer].nSector;
+ PlayerList[nPlayer].field_3A = 0;
+
+ nPlayerDouble[nPlayer] = 0;
+
+ PlayerList[nPlayer].nSeq = kSeqJoe;
+
+ nPlayerPushSound[nPlayer] = -1;
+
+ PlayerList[nPlayer].field_38 = -1;
+
+ if (PlayerList[nPlayer].nCurrentWeapon == 7) {
+ PlayerList[nPlayer].nCurrentWeapon = PlayerList[nPlayer].field_3C;
+ }
+
+ PlayerList[nPlayer].field_3C = 0;
+ PlayerList[nPlayer].nAir = 100;
+
+ if (levelnum <= kMap20)
+ {
+ RestoreMinAmmo(nPlayer);
+ }
+ else
+ {
+ ResetPlayerWeapons(nPlayer);
+ PlayerList[nPlayer].nMagic = 0;
+ }
+
+ nPlayerGrenade[nPlayer] = -1;
+ eyelevel[nPlayer] = -14080;
+ dVertPan[nPlayer] = 0;
+
+ nTemperature[nPlayer] = 0;
+
+ nYDamage[nPlayer] = 0;
+ nXDamage[nPlayer] = 0;
+
+ nVertPan[nPlayer] = 92;
+ nDestVertPan[nPlayer] = 92;
+ nBreathTimer[nPlayer] = 90;
+
+ nTauntTimer[nPlayer] = RandomSize(3) + 3;
+
+ sprite[nDSprite].owner = runlist_AddRunRec(sprite[nDSprite].lotag - 1, nPlayer | 0xA0000);
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nPlayer | 0xA0000);
+
+ if (PlayerList[nPlayer].nRun < 0) {
+ PlayerList[nPlayer].nRun = runlist_AddRunRec(NewRun, nPlayer | 0xA0000);
+ }
+
+ BuildRa(nPlayer);
+
+ if (nPlayer == nLocalPlayer)
+ {
+ nLocalSpr = nSprite;
+ nPlayerDAng = 0;
+
+ SetMagicFrame();
+ RestoreGreenPal();
+
+ bPlayerPan = 0;
+ bLockPan = 0;
+ }
+
+ sprintf(playerNames[nPlayer], "JOE%d", nPlayer);
+ namelen[nPlayer] = strlen(playerNames[nPlayer]);
+
+ totalvel[nPlayer] = 0;
+
+ memset(&sPlayerInput[nPlayer], 0, sizeof(PlayerInput));
+ sPlayerInput[nPlayer].nItem = -1;
+
+ nDeathType[nPlayer] = 0;
+ nQuake[nPlayer] = 0;
+
+ if (nPlayer == nLocalPlayer) {
+ SetHealthFrame(0);
+ }
+}
+
+// done
+int GrabPlayer()
+{
+ if (PlayerCount >= kMaxPlayers) {
+ return -1;
+ }
+
+ return PlayerCount++;
+}
+
+// checked OK on 26/03/2019
+void StartDeathSeq(int nPlayer, int nVal)
+{
+ FreeRa(nPlayer);
+
+ short nSprite = PlayerList[nPlayer].nSprite;
+ PlayerList[nPlayer].nHealth = 0;
+
+ short nLotag = sector[sprite[nSprite].sectnum].lotag;
+
+ if (nLotag > 0) {
+ runlist_SignalRun(nLotag - 1, nPlayer | 0x70000);
+ }
+
+ if (nPlayerGrenade[nPlayer] >= 0)
+ {
+ ThrowGrenade(nPlayer, 0, 0, 0, -10000);
+ }
+ else
+ {
+ if (nNetPlayerCount)
+ {
+ int nWeapon = PlayerList[nPlayer].nCurrentWeapon;
+
+ if (nWeapon > kWeaponSword && nWeapon <= kWeaponRing)
+ {
+ short nSector = sprite[nSprite].sectnum;
+ if (SectBelow[nSector] > -1) {
+ nSector = SectBelow[nSector];
+ }
+
+ int nGunSprite = GrabBodyGunSprite();
+ changespritesect(nGunSprite, nSector);
+
+ sprite[nGunSprite].x = sprite[nSprite].x;
+ sprite[nGunSprite].y = sprite[nSprite].y;
+ sprite[nGunSprite].z = sector[nSector].floorz - 512;
+
+ changespritestat(nGunSprite, nGunLotag[nWeapon] + 900);
+
+ sprite[nGunSprite].picnum = nGunPicnum[nWeapon];
+
+ BuildItemAnim(nGunSprite);
+ }
+ }
+ }
+
+ StopFiringWeapon(nPlayer);
+
+ nVertPan[nPlayer] = 92;
+ eyelevel[nPlayer] = -14080;
+ nPlayerInvisible[nPlayer] = 0;
+ dVertPan[nPlayer] = 15;
+
+ sprite[nSprite].cstat &= 0x7FFF;
+
+ SetNewWeaponImmediate(nPlayer, -2);
+
+ if (SectDamage[sprite[nSprite].sectnum] <= 0)
+ {
+ nDeathType[nPlayer] = nVal;
+ }
+ else
+ {
+ nDeathType[nPlayer] = 2;
+ }
+
+ nVal *= 2;
+
+ if (nVal || !(SectFlag[sprite[nSprite].sectnum] & kSectUnderwater))
+ {
+ PlayerList[nPlayer].nAction = nVal + 17;
+ }
+ else {
+ PlayerList[nPlayer].nAction = 16;
+ }
+
+ PlayerList[nPlayer].field_2 = 0;
+
+ sprite[nSprite].cstat &= 0xFEFE;
+
+ if (nTotalPlayers == 1)
+ {
+ short nLives = nPlayerLives[nPlayer];
+
+ if (nLives > 0) {
+ BuildStatusAnim((3 * (nLives - 1)) + 7, 0);
+ }
+
+ if (levelnum > 0) { // if not on the training level
+ nPlayerLives[nPlayer]--;
+ }
+
+ if (nPlayerLives[nPlayer] < 0) {
+ nPlayerLives[nPlayer] = 0;
+ }
+ }
+
+ totalvel[nPlayer] = 0;
+
+ if (nPlayer == nLocalPlayer) {
+ RefreshStatus();
+ }
+}
+
+int AddAmmo(int nPlayer, int nWeapon, int nAmmoAmount)
+{
+ if (!nAmmoAmount) {
+ nAmmoAmount = 1;
+ }
+
+ short nCurAmmo = PlayerList[nPlayer].nAmmo[nWeapon];
+
+ if (nCurAmmo >= 300 && nAmmoAmount > 0) {
+ return 0;
+ }
+
+ nAmmoAmount = nCurAmmo + nAmmoAmount;
+ if (nAmmoAmount > 300) {
+ nAmmoAmount = 300;
+ }
+
+ PlayerList[nPlayer].nAmmo[nWeapon] = nAmmoAmount;
+
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nWeapon == nCounterBullet) {
+ SetCounter(nAmmoAmount);
+ }
+ }
+
+ if (nWeapon == 1)
+ {
+ if (!nPistolClip[nPlayer]) {
+ nPistolClip[nPlayer] = 6;
+ }
+ }
+
+ return 1;
+}
+
+void SetPlayerMummified(int nPlayer, int bIsMummified)
+{
+ int nSprite = PlayerList[nPlayer].nSprite;
+
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+
+ PlayerList[nPlayer].bIsMummified = bIsMummified;
+
+ if (bIsMummified)
+ {
+ PlayerList[nPlayer].nAction = 13;
+ PlayerList[nPlayer].nSeq = kSeqMummy;
+ }
+ else
+ {
+ PlayerList[nPlayer].nAction = 0;
+ PlayerList[nPlayer].nSeq = kSeqJoe;
+ }
+
+ PlayerList[nPlayer].field_2 = 0;
+}
+
+void ShootStaff(int nPlayer)
+{
+ PlayerList[nPlayer].nAction = 15;
+ PlayerList[nPlayer].field_2 = 0;
+ PlayerList[nPlayer].nSeq = kSeqJoe;
+}
+
+void PlayAlert(char *str)
+{
+ StatusMessage(300, str);
+ PlayLocalSound(StaticSound[kSound63], 0);
+}
+
+void DoKenTest()
+{
+ int nPlayerSprite = PlayerList[0].nSprite; // CHECKME
+ int nSector = sprite[nPlayerSprite].sectnum;
+
+ for (int i = headspritesect[nSector]; ; i = nextspritesect[i])
+ {
+ if (i == -1) {
+ return;
+ }
+
+ if (nextspritesect[i] == i) {
+ bail2dos("ERROR in Ken's linked list!\n");
+ }
+ }
+}
+
+void FuncPlayer(int pA, int nDamage, int nRun)
+{
+ int var_48 = 0;
+ int var_40;
+
+ short nPlayer = RunData[nRun].nVal;
+ assert(nPlayer >= 0 && nPlayer < kMaxPlayers);
+
+ if (PlayerList[nPlayer].someNetVal == -1)
+ return;
+
+ short nPlayerSprite = PlayerList[nPlayer].nSprite;
+
+ short nDopple = nDoppleSprite[nPlayer];
+
+ short nAction = PlayerList[nPlayer].nAction;
+ short nActionB = PlayerList[nPlayer].nAction;
+
+ int nMessage = pA & 0x7F0000;
+
+ short nSprite2;
+
+ switch (nMessage)
+ {
+ case 0x90000:
+ {
+ seq_PlotSequence(pA & 0xFFFF, SeqOffsets[PlayerList[nPlayer].nSeq] + ActionSeq[nAction].a, PlayerList[nPlayer].field_2, ActionSeq[nAction].b);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ if (PlayerList[nPlayer].nHealth <= 0) {
+ return;
+ }
+
+ nDamage = runlist_CheckRadialDamage(nPlayerSprite);
+ if (!nDamage) {
+ return;
+ }
+
+ nSprite2 = nRadialOwner;
+ // fall through to case 0x80000
+ }
+
+ case 0x80000:
+ {
+ // Dunno how to do this otherwise... we fall through from above but don't want to do this check..
+ if (nMessage != 0xA0000)
+ {
+ if (!nDamage) {
+ return;
+ }
+
+ nSprite2 = pA & 0xFFFF;
+ }
+
+ // ok continue case 0x80000 as normal, loc_1C57C
+ if (!PlayerList[nPlayer].nHealth) {
+ return;
+ }
+
+ if (!PlayerList[nPlayer].invincibility)
+ {
+ PlayerList[nPlayer].nHealth -= nDamage;
+ if (nPlayer == nLocalPlayer)
+ {
+ TintPalette(nDamage >> 2, 0, 0);
+ SetHealthFrame(-1);
+ }
+ }
+
+ if (PlayerList[nPlayer].nHealth > 0)
+ {
+ if (nDamage > 40 || (totalmoves & 0xF) < 2)
+ {
+ if (PlayerList[nPlayer].invincibility) {
+ return;
+ }
+
+ if (SectFlag[sprite[nPlayerSprite].sectnum] & kSectUnderwater)
+ {
+ if (nAction != 12)
+ {
+ PlayerList[nPlayer].field_2 = 0;
+ PlayerList[nPlayer].nAction = 12;
+ return;
+ }
+ }
+ else
+ {
+ if (nAction != 4)
+ {
+ PlayerList[nPlayer].field_2 = 0;
+ PlayerList[nPlayer].nAction = 4;
+
+ if (nSprite2 > -1)
+ {
+ nPlayerSwear[nPlayer]--;
+ if (nPlayerSwear[nPlayer] <= 0)
+ {
+ D3PlayFX(StaticSound[kSound52], nDopple);
+ nPlayerSwear[nPlayer] = RandomSize(3) + 4;
+ }
+ }
+ }
+ }
+ }
+
+ return;
+ }
+ else
+ {
+ // ded
+ if (sprite[nSprite2].statnum == 100)
+ {
+ short nPlayer2 = GetPlayerFromSprite(nSprite2);
+
+ if (nPlayer2 == nPlayer) // player caused their own death
+ {
+ nPlayerScore[nPlayer]--;
+ }
+ else
+ {
+ nPlayerScore[nPlayer]++;
+ }
+ }
+ else if (nSprite2 < 0)
+ {
+ nPlayerScore[nPlayer]--;
+ }
+
+ if (nMessage == 0xA0000)
+ {
+ for (int i = 122; i <= 131; i++)
+ {
+ BuildCreatureChunk(nPlayerSprite, seq_GetSeqPicnum(kSeqJoe, i, 0));
+ }
+
+ StartDeathSeq(nPlayer, 1);
+ }
+ else
+ {
+ StartDeathSeq(nPlayer, 0);
+ }
+ }
+
+ return;
+ }
+
+ case 0x20000:
+ {
+ sprite[nPlayerSprite].xvel = sPlayerInput[nPlayer].xVel >> 14;
+ sprite[nPlayerSprite].yvel = sPlayerInput[nPlayer].yVel >> 14;
+
+ if (sPlayerInput[nPlayer].nItem > -1)
+ {
+ UseItem(nPlayer, sPlayerInput[nPlayer].nItem);
+ sPlayerInput[nPlayer].nItem = -1;
+ }
+
+ int var_EC = PlayerList[nPlayer].field_2;
+
+ sprite[nPlayerSprite].picnum = seq_GetSeqPicnum(PlayerList[nPlayer].nSeq, ActionSeq[nHeightTemplate[nAction]].a, var_EC);
+ sprite[nDopple].picnum = sprite[nPlayerSprite].picnum;
+
+ if (nPlayerTorch[nPlayer] > 0)
+ {
+ nPlayerTorch[nPlayer]--;
+ if (nPlayerTorch[nPlayer] == 0)
+ {
+ SetTorch(nPlayer, 0);
+ }
+ else
+ {
+ if (nPlayer != nLocalPlayer)
+ {
+ nFlashDepth = 5;
+ AddFlash(sprite[nPlayerSprite].sectnum,
+ sprite[nPlayerSprite].x,
+ sprite[nPlayerSprite].y,
+ sprite[nPlayerSprite].z, 0);
+ }
+ }
+ }
+
+ if (nPlayerDouble[nPlayer] > 0)
+ {
+ nPlayerDouble[nPlayer]--;
+ if (nPlayerDouble[nPlayer] == 150 && nPlayer == nLocalPlayer) {
+ PlayAlert("WEAPON POWER IS ABOUT TO EXPIRE");
+ }
+ }
+
+ if (nPlayerInvisible[nPlayer] > 0)
+ {
+ nPlayerInvisible[nPlayer]--;
+ if (nPlayerInvisible[nPlayer] == 0)
+ {
+ sprite[nPlayerSprite].cstat &= 0x7FFF; // set visible
+ short nFloorSprite = nPlayerFloorSprite[nPlayerSprite];
+
+ if (nFloorSprite > -1) {
+ sprite[nFloorSprite].cstat &= 0x7FFF; // set visible
+ }
+ }
+ else if (nPlayerInvisible[nPlayer] == 150 && nPlayer == nLocalPlayer)
+ {
+ PlayAlert("INVISIBILITY IS ABOUT TO EXPIRE");
+ }
+ }
+
+ if (PlayerList[nPlayer].invincibility > 0)
+ {
+ PlayerList[nPlayer].invincibility--;
+ if (PlayerList[nPlayer].invincibility == 150 && nPlayer == nLocalPlayer) {
+ PlayAlert("INVINCIBILITY IS ABOUT TO EXPIRE");
+ }
+ }
+
+ if (nQuake[nPlayer] != 0)
+ {
+ nQuake[nPlayer] = -nQuake[nPlayer];
+ if (nQuake[nPlayer] > 0)
+ {
+ nQuake[nPlayer] -= 512;
+ if (nQuake[nPlayer] < 0)
+ nQuake[nPlayer] = 0;
+ }
+ }
+
+ // loc_1A494:
+ sprite[nPlayerSprite].ang = ((sPlayerInput[nPlayer].nAngle << 2) + sprite[nPlayerSprite].ang) & kAngleMask;
+
+ // sprite[nPlayerSprite].zvel is modified within Gravity()
+ short zVel = sprite[nPlayerSprite].zvel;
+
+ Gravity(nPlayerSprite);
+
+ if (sprite[nPlayerSprite].zvel >= 6500 && zVel < 6500)
+ {
+ D3PlayFX(StaticSound[kSound17], 0);
+ }
+
+ // loc_1A4E6
+ short nSector = sprite[nPlayerSprite].sectnum;
+ short nSectFlag = SectFlag[nPlayerViewSect[nPlayer]];
+
+ int playerX = sprite[nPlayerSprite].x;
+ int playerY = sprite[nPlayerSprite].y;
+
+ int x = (sPlayerInput[nPlayer].xVel * 4) >> 2;
+ int y = (sPlayerInput[nPlayer].yVel * 4) >> 2;
+ int z = (sprite[nPlayerSprite].zvel * 4) >> 2;
+
+ if (sprite[nPlayerSprite].zvel > 8192)
+ sprite[nPlayerSprite].zvel = 8192;
+
+ if (PlayerList[nPlayer].bIsMummified)
+ {
+ x /= 2;
+ y /= 2;
+ }
+
+ int spr_x = sprite[nPlayerSprite].x;
+ int spr_y = sprite[nPlayerSprite].y;
+ int spr_z = sprite[nPlayerSprite].z;
+ int spr_sectnum = sprite[nPlayerSprite].sectnum;
+
+ // TODO
+ // nSectFlag & kSectUnderwater;
+
+ zVel = sprite[nPlayerSprite].zvel;
+
+ int nMove = 0; // TEMP
+
+ if (bSlipMode)
+ {
+ nMove = 0;
+
+ sprite[nPlayerSprite].x += (x >> 14);
+ sprite[nPlayerSprite].y += (y >> 14);
+
+ setsprite(nPlayerSprite, sprite[nPlayerSprite].x, sprite[nPlayerSprite].y, sprite[nPlayerSprite].z);
+
+ sprite[nPlayerSprite].z = sector[sprite[nPlayerSprite].sectnum].floorz;
+ }
+ else
+ {
+ nMove = movesprite(nPlayerSprite, x, y, z, 5120, -5120, CLIPMASK0);
+
+ short var_54 = sprite[nPlayerSprite].sectnum;
+
+ pushmove(&sprite[nPlayerSprite].x, &sprite[nPlayerSprite].y, &sprite[nPlayerSprite].z, &var_54, sprite[nPlayerSprite].clipdist << 2, 5120, -5120, CLIPMASK0);
+ if (var_54 != sprite[nPlayerSprite].sectnum) {
+ mychangespritesect(nPlayerSprite, var_54);
+ }
+ }
+
+ // loc_1A6E4
+ if (!inside(sprite[nPlayerSprite].x, sprite[nPlayerSprite].y, sprite[nPlayerSprite].sectnum))
+ {
+ mychangespritesect(nPlayerSprite, spr_sectnum);
+
+ sprite[nPlayerSprite].x = spr_x;
+ sprite[nPlayerSprite].y = spr_y;
+
+ if (zVel < sprite[nPlayerSprite].zvel) {
+ sprite[nPlayerSprite].zvel = zVel;
+ }
+ }
+
+// int _bTouchFloor = bTouchFloor;
+ short bUnderwater = SectFlag[sprite[nPlayerSprite].sectnum] & kSectUnderwater;
+
+ if (bUnderwater)
+ {
+ nXDamage[nPlayer] /= 2;
+ nYDamage[nPlayer] /= 2;
+ }
+
+ // Trigger Ramses?
+ if ((SectFlag[sprite[nPlayerSprite].sectnum] & 0x8000) && bTouchFloor)
+ {
+ if (nTotalPlayers <= 1)
+ {
+ sprite[nPlayerSprite].ang = GetAngleToSprite(nPlayerSprite, nSpiritSprite);
+
+ lPlayerXVel = 0;
+ lPlayerYVel = 0;
+
+ sprite[nPlayerSprite].xvel = 0;
+ sprite[nPlayerSprite].yvel = 0;
+ sprite[nPlayerSprite].zvel = 0;
+
+ nPlayerDAng = 0;
+
+ if (nFreeze < 1)
+ {
+ nFreeze = 1;
+ StopAllSounds();
+ StopLocalSound();
+ InitSpiritHead();
+
+ nDestVertPan[nPlayer] = 92;
+
+ if (levelnum == 11)
+ {
+ nDestVertPan[nPlayer] += 46;
+ }
+ else
+ {
+ nDestVertPan[nPlayer] += 11;
+ }
+ }
+ }
+ else
+ {
+ FinishLevel();
+ }
+
+ return;
+ }
+
+ if (nMove & 0x3C000)
+ {
+ if (bTouchFloor)
+ {
+ // Damage stuff..
+ nXDamage[nPlayer] /= 2;
+ nYDamage[nPlayer] /= 2;
+
+ if (nPlayer == nLocalPlayer)
+ {
+ short zVelB = zVel;
+
+ if (zVelB < 0) {
+ zVelB = -zVelB;
+ }
+
+ if (zVelB > 512) {
+ nDestVertPan[nPlayer] = 92;
+ }
+ }
+
+ if (zVel >= 6500)
+ {
+ sprite[nPlayerSprite].xvel >>= 2;
+ sprite[nPlayerSprite].yvel >>= 2;
+
+ runlist_DamageEnemy(nPlayerSprite, -1, ((zVel - 6500) >> 7) + 10);
+
+ if (PlayerList[nPlayer].nHealth <= 0)
+ {
+ sprite[nPlayerSprite].xvel = 0;
+ sprite[nPlayerSprite].yvel = 0;
+
+ StopSpriteSound(nPlayerSprite);
+// TODO PlayFXAtXYZ(StaticSound[kSoundJonFDie], sprite[nPlayerSprite].x, sprite[nPlayerSprite].y, sprite[nPlayerSprite].z, sprite[nPlayerSprite].sectnum |= 0x4000); // CHECKME
+ }
+ else
+ {
+ D3PlayFX(StaticSound[kSound27] | 0x2000, nPlayerSprite);
+ }
+ }
+ }
+
+ if (((nMove & 0xC000) == 0x4000) || ((nMove & 0xC000) == 0x8000))
+ {
+ int bx = 0;
+
+ if ((nMove & 0xC000) == 0x4000)
+ {
+ bx = nMove & 0x3FFF;
+ }
+ else if ((nMove & 0xC000) == 0x8000)
+ {
+ bx = wall[nMove & 0x3FFF].nextsector;
+ }
+
+ if (bx >= 0)
+ {
+ int var_B4 = bx;
+
+ if ((sector[bx].hitag == 45) && bTouchFloor)
+ {
+ int nNormal = GetWallNormal(nMove & 0x3FFF);
+ int nDiff = AngleDiff(nNormal, (sprite[nPlayerSprite].ang + 1024) & kAngleMask);
+
+ if (nDiff < 0) {
+ nDiff = -nDiff;
+ }
+
+ if (nDiff <= 256)
+ {
+ nPlayerPushSect[nPlayer] = bx;
+
+ int var_F4 = sPlayerInput[nPlayer].xVel;
+ int var_F8 = sPlayerInput[nPlayer].yVel;
+ int nMyAngle = GetMyAngle(sPlayerInput[nPlayer].xVel, sPlayerInput[nPlayer].yVel);
+
+ MoveSector(var_B4, nMyAngle, &var_F4, &var_F8);
+
+ if (nPlayerPushSound[nPlayer] <= -1)
+ {
+ nPlayerPushSound[nPlayer] = 1;
+ short nBlock = sector[nPlayerPushSect[nPlayer]].extra;
+ int nBlockSprite = sBlockInfo[nBlock].nSprite;
+
+ D3PlayFX(StaticSound[kSound23], nBlockSprite |= 0x40u);
+ }
+ else
+ {
+ sprite[nPlayerSprite].x = spr_x;
+ sprite[nPlayerSprite].y = spr_y;
+ sprite[nPlayerSprite].z = spr_z;
+
+ mychangespritesect(nPlayerSprite, spr_sectnum);
+ }
+
+ movesprite(nPlayerSprite, var_F4, var_F8, z, 5120, -5120, CLIPMASK0);
+ goto loc_1AB8E;
+ }
+ }
+ }
+ }
+ }
+
+ // loc_1AB46:
+ if (nPlayerPushSound[nPlayer] > -1)
+ {
+ if (nPlayerPushSect[nPlayer] > -1)
+ {
+// TODO StopSpriteSound(sBlockInfo[sector[nPlayerPushSect[nPlayer]].extra].nSprite);
+ }
+
+ nPlayerPushSound[nPlayer] = -1;
+ }
+
+loc_1AB8E:
+ if (!bPlayerPan && !bLockPan)
+ {
+ int nPanVal = ((spr_z - sprite[nPlayerSprite].z) / 32) + 92;
+
+ if (nPanVal < 0) {
+ nPanVal = 0;
+ }
+ else if (nPanVal > 183)
+ {
+ nPanVal = 183;
+ }
+
+ nDestVertPan[nPlayer] = nPanVal;
+ }
+
+ playerX -= sprite[nPlayerSprite].x;
+ playerY -= sprite[nPlayerSprite].y;
+
+ totalvel[nPlayer] = ksqrt((playerY * playerY) + (playerX * playerX));
+
+ int nViewSect = sprite[nPlayerSprite].sectnum;
+
+ int EyeZ = eyelevel[nPlayer] + sprite[nPlayerSprite].z + nQuake[nPlayer];
+
+ while (1)
+ {
+ int nCeilZ = sector[nViewSect].ceilingz;
+
+ if (EyeZ >= nCeilZ)
+ break;
+
+ if (SectAbove[nViewSect] <= -1)
+ break;
+
+ nViewSect = SectAbove[nViewSect];
+ }
+
+ // Do underwater sector check
+ if (bUnderwater)
+ {
+ if (nViewSect != sprite[nPlayerSprite].sectnum)
+ {
+ if ((nMove & 0xC000) == 0x8000)
+ {
+ int var_C4 = sprite[nPlayerSprite].x;
+ int var_D4 = sprite[nPlayerSprite].y;
+ int var_C8 = sprite[nPlayerSprite].z;
+
+ mychangespritesect(nPlayerSprite, nViewSect);
+
+ sprite[nPlayerSprite].x = spr_x;
+ sprite[nPlayerSprite].y = spr_y;
+
+ int var_FC = sector[nViewSect].floorz + (-5120);
+
+ sprite[nPlayerSprite].z = var_FC;
+
+ if ((movesprite(nPlayerSprite, x, y, 0, 5120, 0, CLIPMASK0) & 0xC000) == 0x8000)
+ {
+ mychangespritesect(nPlayerSprite, sprite[nPlayerSprite].sectnum);
+
+ sprite[nPlayerSprite].x = var_C4;
+ sprite[nPlayerSprite].y = var_D4;
+ sprite[nPlayerSprite].z = var_C8;
+ }
+ else
+ {
+ sprite[nPlayerSprite].z = var_FC - 256;
+ D3PlayFX(StaticSound[kSound42], nPlayerSprite);
+ }
+ }
+ }
+ }
+
+ // loc_1ADAF
+ nPlayerViewSect[nPlayer] = nViewSect;
+
+ nPlayerDX[nPlayer] = sprite[nPlayerSprite].x - spr_x;
+ nPlayerDY[nPlayer] = sprite[nPlayerSprite].y - spr_y;
+
+ int var_5C = SectFlag[nViewSect] & kSectUnderwater;
+
+ ushort buttons = sPlayerInput[nPlayer].buttons;
+
+ if (buttons & 0x40)
+ {
+ char strDeity[96]; // TODO - reduce in size?
+
+ char *strDMode = NULL;
+
+ if (PlayerList[nPlayer].invincibility >= 0)
+ {
+ PlayerList[nPlayer].invincibility = -1;
+ strDMode = "ON";
+ }
+ else
+ {
+ PlayerList[nPlayer].invincibility = 0;
+ strDMode = "OFF";
+ }
+
+ sPlayerInput[nPlayer].buttons &= 0xBF;
+
+ sprintf(strDeity, "Deity mode %s for player %d", strDMode, nPlayer);
+ StatusMessage(150, strDeity);
+ }
+ else if (buttons & 0x20)
+ {
+ FillWeapons(nPlayer);
+ StatusMessage(150, "All weapons loaded for player %d", nPlayer);
+ }
+ else if (buttons & 0x80)
+ {
+ PlayerList[nPlayer].keys = 0xFFFF;
+ StatusMessage(150, "All keys for player %d", nPlayer);
+ RefreshStatus();
+ }
+ else if (buttons & 0x100)
+ {
+ FillItems(nPlayer);
+ StatusMessage(150, "All items loaded for player %d", nPlayer);
+ }
+
+ // loc_1AEF5:
+ if (PlayerList[nPlayer].nHealth > 0)
+ {
+ if (PlayerList[nPlayer].nMaskAmount > 0)
+ {
+ PlayerList[nPlayer].nMaskAmount--;
+ if (PlayerList[nPlayer].nMaskAmount == 150 && nPlayer == nLocalPlayer) {
+ PlayAlert("MASK IS ABOUT TO EXPIRE");
+ }
+ }
+
+ if (!PlayerList[nPlayer].invincibility)
+ {
+ // Handle air
+ nBreathTimer[nPlayer]--;
+
+ if (nBreathTimer[nPlayer] <= 0)
+ {
+ nBreathTimer[nPlayer] = 90;
+
+ // if underwater
+ if (var_5C)
+ {
+ if (PlayerList[nPlayer].nMaskAmount > 0)
+ {
+ if (nPlayer == nLocalPlayer) {
+ BuildStatusAnim(132, 0);
+ }
+
+ airpages = 0;
+ D3PlayFX(StaticSound[kSound30], nPlayerSprite);
+
+ PlayerList[nPlayer].nAir = 100;
+
+ DoBubbles(nPlayer);
+ SetAirFrame();
+ }
+ else
+ {
+ PlayerList[nPlayer].nAir -= 25;
+ if (PlayerList[nPlayer].nAir > 0)
+ {
+ D3PlayFX(StaticSound[kSound25], nPlayerSprite);
+
+ DoBubbles(nPlayer);
+ SetAirFrame();
+ }
+ else
+ {
+ PlayerList[nPlayer].nHealth += (PlayerList[nPlayer].nAir << 2);
+ if (PlayerList[nPlayer].nHealth <= 0)
+ {
+ PlayerList[nPlayer].nHealth = 0;
+ StartDeathSeq(nPlayer, 0);
+ }
+
+ if (nPlayer == nLocalPlayer)
+ {
+ SetHealthFrame(-1);
+ }
+
+ PlayerList[nPlayer].nAir = 0;
+
+ if (PlayerList[nPlayer].nHealth < 300)
+ {
+ D3PlayFX(StaticSound[kSound79], nPlayerSprite);
+ }
+ else
+ {
+ D3PlayFX(StaticSound[kSound19], nPlayerSprite);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (nPlayer == nLocalPlayer)
+ {
+ BuildStatusAnim(132, 0);
+ }
+
+ airpages = 0;
+ }
+ }
+ }
+
+ // loc_1B0B9
+ if (var_5C) // if underwater
+ {
+ if (nPlayerTorch[nPlayer] > 0)
+ {
+ nPlayerTorch[nPlayer] = 0;
+ SetTorch(nPlayer, 0);
+ }
+ }
+ else
+ {
+ int nTmpSectNum = sprite[nPlayerSprite].sectnum;
+
+ if (totalvel[nPlayer] > 25 && sprite[nPlayerSprite].z > sector[nTmpSectNum].floorz)
+ {
+ if (SectDepth[nTmpSectNum] && !SectSpeed[nTmpSectNum] && !SectDamage[nTmpSectNum])
+ {
+ D3PlayFX(StaticSound[kSound42], nPlayerSprite);
+ }
+ }
+
+ // CHECKME - wrong place?
+ if (nSectFlag & kSectUnderwater)
+ {
+ if (PlayerList[nPlayer].nAir < 50)
+ {
+ D3PlayFX(StaticSound[kSound14], nPlayerSprite);
+ }
+
+ nBreathTimer[nPlayer] = 1;
+ }
+
+ nBreathTimer[nPlayer]--;
+ if (nBreathTimer[nPlayer] <= 0)
+ {
+ nBreathTimer[nPlayer] = 90;
+ if (nPlayer == nLocalPlayer)
+ {
+ BuildStatusAnim(132, 0);
+ }
+ }
+
+ if (PlayerList[nPlayer].nAir < 100)
+ {
+ PlayerList[nPlayer].nAir = 100;
+ SetAirFrame();
+ }
+ }
+
+ // loc_1B1EB
+ if (nTotalPlayers > 1)
+ {
+ int nFloorSprite = nPlayerFloorSprite[nPlayer];
+
+ sprite[nFloorSprite].x = sprite[nPlayerSprite].x;
+ sprite[nFloorSprite].y = sprite[nPlayerSprite].y;
+
+ if (sprite[nFloorSprite].sectnum != sprite[nPlayerSprite].sectnum)
+ {
+ mychangespritesect(nFloorSprite, sprite[nPlayerSprite].sectnum);
+ }
+
+ sprite[nFloorSprite].z = sector[sprite[nPlayerSprite].sectnum].floorz;
+ }
+
+ int var_30 = 0;
+
+ if (PlayerList[nPlayer].nHealth >= 800)
+ {
+ var_30 = 2;
+ }
+
+ if (PlayerList[nPlayer].nMagic >= 1000)
+ {
+ var_30 |= 1;
+ }
+
+ // code to handle item pickup?
+ short nearTagSector, nearTagWall, nearTagSprite;
+ long nearHitDist;
+
+ short nValB;
+
+ // neartag finds the nearest sector, wall, and sprite which has its hitag and/or lotag set to a value.
+ neartag(sprite[nPlayerSprite].x, sprite[nPlayerSprite].y, sprite[nPlayerSprite].z, sprite[nPlayerSprite].sectnum, sprite[nPlayerSprite].ang,
+ &nearTagSector, &nearTagWall, &nearTagSprite, &nearHitDist, 1024, 2);
+
+ feebtag(sprite[nPlayerSprite].x, sprite[nPlayerSprite].y, sprite[nPlayerSprite].z, sprite[nPlayerSprite].sectnum,
+ &nValB, var_30, 768);
+
+ // Item pickup code
+ if (nValB >= 0 && sprite[nValB].statnum >= 900)
+ {
+ int var_8C = 16;
+ int var_88 = 9;
+
+ int var_70 = sprite[nValB].statnum - 900;
+ int var_44 = 0;
+
+ // item lotags start at 6 (1-5 reserved?) so 0-offset them
+ int var_6C = var_70 - 6;
+
+ if (var_6C <= 54)
+ {
+ switch (var_6C)
+ {
+do_default:
+ default:
+ {
+ // loc_1B3C7
+ if (levelnum <= 20 || var_70 >= 25 && (var_70 <= 25 || var_70 == 50))
+ {
+ DestroyItemAnim(nValB);
+ mydeletesprite(nValB);
+ }
+ else
+ {
+ StartRegenerate(nValB);
+ }
+do_default_b:
+ // loc_1BA74
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+
+ break;
+ }
+ case 0: // Speed Loader
+ {
+ if (AddAmmo(nPlayer, 1, sprite[nValB].hitag))
+ {
+ var_88 = StaticSound[kSound69];
+ goto do_default;
+ }
+
+ break;
+ }
+ case 1: // Fuel Canister
+ {
+ if (AddAmmo(nPlayer, 3, sprite[nValB].hitag))
+ {
+ var_88 = StaticSound[kSound69];
+ goto do_default;
+ }
+ break;
+ }
+ case 2: // M - 60 Ammo Belt
+ {
+ if (AddAmmo(nPlayer, 2, sprite[nValB].hitag))
+ {
+ var_88 = StaticSound[kSound69];
+ CheckClip(nPlayer);
+ goto do_default;
+ }
+ break;
+ }
+ case 3: // Grenade
+ case 21:
+ case 49:
+ {
+ if (AddAmmo(nPlayer, 4, 1))
+ {
+ var_88 = StaticSound[kSound69];
+ if (!(nPlayerWeapons[nPlayer] & 0x10))
+ {
+ nPlayerWeapons[nPlayer] |= 0x10;
+ SetNewWeaponIfBetter(nPlayer, 4);
+ }
+
+ if (var_70 == 55)
+ {
+ sprite[nValB].cstat = 0x8000;
+ DestroyItemAnim(nValB);
+
+ // loc_1BA74: - repeated block, see in default case
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+ break;
+ }
+ else
+ {
+ goto do_default;
+ }
+ }
+ break;
+ }
+
+ case 4: // Pickable item
+ case 9: // Pickable item
+ case 10: // Reserved
+ case 18:
+ case 25:
+ case 28:
+ case 29:
+ case 30:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 45:
+ case 52:
+ {
+ goto do_default;
+ }
+
+ case 5: // Map
+ {
+ GrabMap();
+ goto do_default;
+ }
+
+ case 6: // Berry Twig
+ {
+ if (sprite[nValB].hitag == 0) {
+ break;
+ }
+
+ var_88 = 20;
+ int edx = 40;
+ // int ecx = 1;
+
+ if (edx <= 0 || (!(var_30 & 2)))
+ {
+ if (!PlayerList[nPlayer].invincibility || edx > 0)
+ {
+ PlayerList[nPlayer].nHealth += edx;
+ if (PlayerList[nPlayer].nHealth > 800)
+ {
+ PlayerList[nPlayer].nHealth = 800;
+ }
+ else
+ {
+ if (PlayerList[nPlayer].nHealth < 0)
+ {
+ var_88 = -1;
+ StartDeathSeq(nPlayer, 0);
+ }
+ }
+ }
+
+ if (nLocalPlayer == nPlayer)
+ {
+ SetHealthFrame(1);
+ }
+
+ if (var_70 == 12)
+ {
+ sprite[nValB].hitag = 0;
+ sprite[nValB].picnum++;
+
+ changespritestat(nValB, 0);
+
+ // loc_1BA74: - repeated block, see in default case
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+
+ break;
+ }
+ else
+ {
+ if (var_70 != 14)
+ {
+ var_88 = 21;
+ }
+ else
+ {
+ var_44 = var_8C;
+ var_88 = 22;
+ var_8C = 0;
+ }
+
+ goto do_default;
+ }
+ }
+
+ break;
+ }
+
+ case 7: // Blood Bowl
+ {
+ int edx = 160;
+ int ecx = 1;
+
+ // Same code as case 6 now till break
+ if (edx <= 0 || (!(var_30 & 2)))
+ {
+ if (!PlayerList[nPlayer].invincibility || edx > 0)
+ {
+ PlayerList[nPlayer].nHealth += edx;
+ if (PlayerList[nPlayer].nHealth > 800)
+ {
+ PlayerList[nPlayer].nHealth = 800;
+ }
+ else
+ {
+ if (PlayerList[nPlayer].nHealth < 0)
+ {
+ var_88 = -1;
+ StartDeathSeq(nPlayer, 0);
+ }
+ }
+ }
+
+ if (nLocalPlayer == nPlayer)
+ {
+ SetHealthFrame(1);
+ }
+
+ if (var_70 == 12)
+ {
+ sprite[nValB].hitag = 0;
+ sprite[nValB].picnum++;
+
+ changespritestat(nValB, 0);
+
+ // loc_1BA74: - repeated block, see in default case
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+
+ break;
+ }
+ else
+ {
+ if (var_70 != 14)
+ {
+ var_88 = 21;
+ }
+ else
+ {
+ var_44 = var_8C;
+ var_88 = 22;
+ var_8C = 0;
+ }
+
+ goto do_default;
+ }
+ }
+
+ break;
+ }
+
+ case 8: // Cobra Venom Bowl
+ {
+ int edx = -120;
+
+ // Same code as case 6 and 7 from now till break
+ if (edx <= 0 || (!(var_30 & 2)))
+ {
+ if (!PlayerList[nPlayer].invincibility || edx > 0)
+ {
+ PlayerList[nPlayer].nHealth += edx;
+ if (PlayerList[nPlayer].nHealth > 800)
+ {
+ PlayerList[nPlayer].nHealth = 800;
+ }
+ else
+ {
+ if (PlayerList[nPlayer].nHealth < 0)
+ {
+ var_88 = -1;
+ StartDeathSeq(nPlayer, 0);
+ }
+ }
+ }
+
+ if (nLocalPlayer == nPlayer)
+ {
+ SetHealthFrame(1);
+ }
+
+ if (var_70 == 12)
+ {
+ sprite[nValB].hitag = 0;
+ sprite[nValB].picnum++;
+
+ changespritestat(nValB, 0);
+
+ // loc_1BA74: - repeated block, see in default case
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+
+ break;
+ }
+ else
+ {
+ if (var_70 != 14)
+ {
+ var_88 = 21;
+ }
+ else
+ {
+ var_44 = var_8C;
+ var_88 = 22;
+ var_8C = 0;
+ }
+
+ goto do_default;
+ }
+ }
+
+ break;
+ }
+
+ case 11: // Bubble Nest
+ {
+ PlayerList[nPlayer].nAir += 10;
+ if (PlayerList[nPlayer].nAir > 100) {
+ PlayerList[nPlayer].nAir = 100; // TODO - constant
+ }
+
+ SetAirFrame();
+
+ if (nBreathTimer[nPlayer] < 89)
+ {
+ D3PlayFX(StaticSound[kSound13], nPlayerSprite);
+ }
+
+ nBreathTimer[nPlayer] = 90;
+ break;
+ }
+
+ case 12: // Still Beating Heart
+ {
+ if (GrabItem(nPlayer, kItemHeart)) {
+ goto do_default;
+ }
+
+ break;
+ }
+
+ case 13: // Scarab amulet(Invicibility)
+ {
+ if (GrabItem(nPlayer, kItemInvincibility)) {
+ goto do_default;
+ }
+
+ break;
+ }
+
+ case 14: // Severed Slave Hand(double damage)
+ {
+ if (GrabItem(nPlayer, kItemDoubleDamage)) {
+ goto do_default;
+ }
+
+ break;
+ }
+
+ case 15: // Unseen eye(Invisibility)
+ {
+ if (GrabItem(nPlayer, kItemInvisibility)) {
+ goto do_default;
+ }
+
+ break;
+ }
+
+ case 16: // Torch
+ {
+ if (GrabItem(nPlayer, kItemTorch)) {
+ goto do_default;
+ }
+
+ break;
+ }
+
+ case 17: // Sobek Mask
+ {
+ if (GrabItem(nPlayer, kItemMask)) {
+ goto do_default;
+ }
+
+ break;
+ }
+
+ case 19: // Extra Life
+ {
+ var_88 = -1;
+
+ if (nPlayerLives[nPlayer] >= kMaxPlayerLives) {
+ break;
+ }
+
+ nPlayerLives[nPlayer]++;
+
+ if (nPlayer == nLocalPlayer) {
+ BuildStatusAnim(((nPlayerLives[nPlayer] - 1) * 2) + 146, 0);
+ }
+
+ var_8C = 32;
+ var_44 = 32;
+ goto do_default;
+ }
+
+ // FIXME - lots of repeated code from here down!!
+ case 20: // sword pickup??
+ {
+ var_40 = 0;
+ int ebx = 0;
+
+ // loc_1B75D
+ int var_18 = 1 << var_40;
+
+ short weapons = nPlayerWeapons[nPlayer];
+
+ if (weapons & var_18)
+ {
+ if (levelnum > 20)
+ {
+ AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
+ }
+ }
+ else
+ {
+ weapons = var_40;
+
+ SetNewWeaponIfBetter(nPlayer, weapons);
+
+ nPlayerWeapons[nPlayer] |= var_18;
+
+ AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
+ }
+
+ if (var_40 == 2) {
+ CheckClip(nPlayer);
+ }
+
+ if (var_70 <= 50) {
+ goto do_default;
+ }
+
+ sprite[nValB].cstat = 0x8000;
+ DestroyItemAnim(nValB);
+////
+ // loc_1BA74: - repeated block, see in default case
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+
+ break;
+/////
+ }
+
+ case 22: // .357 Magnum Revolver
+ case 46:
+ {
+ var_40 = 1;
+ int ebx = 6;
+
+ // loc_1B75D
+ int var_18 = 1 << var_40;
+
+ short weapons = nPlayerWeapons[nPlayer];
+
+ if (weapons & var_18)
+ {
+ if (levelnum > 20)
+ {
+ AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
+ }
+ }
+ else
+ {
+ weapons = var_40;
+
+ SetNewWeaponIfBetter(nPlayer, weapons);
+
+ nPlayerWeapons[nPlayer] |= var_18;
+
+ AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
+ }
+
+ if (var_40 == 2) {
+ CheckClip(nPlayer);
+ }
+
+ if (var_70 <= 50) {
+ goto do_default;
+ }
+
+ sprite[nValB].cstat = 0x8000;
+ DestroyItemAnim(nValB);
+////
+ // loc_1BA74: - repeated block, see in default case
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+
+ break;
+/////
+ }
+
+ case 23: // M - 60 Machine Gun
+ case 47:
+ {
+ var_40 = 2;
+ int ebx = 24;
+
+ // loc_1B75D
+ int var_18 = 1 << var_40;
+
+ short weapons = nPlayerWeapons[nPlayer];
+
+ if (weapons & var_18)
+ {
+ if (levelnum > 20)
+ {
+ AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
+ }
+ }
+ else
+ {
+ weapons = var_40;
+
+ SetNewWeaponIfBetter(nPlayer, weapons);
+
+ nPlayerWeapons[nPlayer] |= var_18;
+
+ AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
+ }
+
+ if (var_40 == 2) {
+ CheckClip(nPlayer);
+ }
+
+ if (var_70 <= 50) {
+ goto do_default;
+ }
+
+ sprite[nValB].cstat = 0x8000;
+ DestroyItemAnim(nValB);
+////
+ // loc_1BA74: - repeated block, see in default case
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+
+ break;
+/////
+ }
+
+ case 24: // Flame Thrower
+ case 48:
+ {
+ var_40 = 3;
+ int ebx = 100;
+
+ // loc_1B75D
+ int var_18 = 1 << var_40;
+
+ short weapons = nPlayerWeapons[nPlayer];
+
+ if (weapons & var_18)
+ {
+ if (levelnum > 20)
+ {
+ AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
+ }
+ }
+ else
+ {
+ weapons = var_40;
+
+ SetNewWeaponIfBetter(nPlayer, weapons);
+
+ nPlayerWeapons[nPlayer] |= var_18;
+
+ AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
+ }
+
+ if (var_40 == 2) {
+ CheckClip(nPlayer);
+ }
+
+ if (var_70 <= 50) {
+ goto do_default;
+ }
+
+ sprite[nValB].cstat = 0x8000;
+ DestroyItemAnim(nValB);
+////
+ // loc_1BA74: - repeated block, see in default case
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+
+ break;
+/////
+ }
+
+ case 26: // Cobra Staff
+ case 50:
+ {
+ var_40 = 5;
+ int ebx = 20;
+
+ // loc_1B75D
+ int var_18 = 1 << var_40;
+
+ short weapons = nPlayerWeapons[nPlayer];
+
+ if (weapons & var_18)
+ {
+ if (levelnum > 20)
+ {
+ AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
+ }
+ }
+ else
+ {
+ weapons = var_40;
+
+ SetNewWeaponIfBetter(nPlayer, weapons);
+
+ nPlayerWeapons[nPlayer] |= var_18;
+
+ AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
+ }
+
+ if (var_40 == 2) {
+ CheckClip(nPlayer);
+ }
+
+ if (var_70 <= 50) {
+ goto do_default;
+ }
+
+ sprite[nValB].cstat = 0x8000;
+ DestroyItemAnim(nValB);
+////
+ // loc_1BA74: - repeated block, see in default case
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+
+ break;
+/////
+ }
+
+ case 27: // Eye of Ra Gauntlet
+ case 51:
+ {
+ var_40 = 6;
+ int ebx = 2;
+
+ // loc_1B75D
+ int var_18 = 1 << var_40;
+
+ short weapons = nPlayerWeapons[nPlayer];
+
+ if (weapons & var_18)
+ {
+ if (levelnum > 20)
+ {
+ AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
+ }
+ }
+ else
+ {
+ weapons = var_40;
+
+ SetNewWeaponIfBetter(nPlayer, weapons);
+
+ nPlayerWeapons[nPlayer] |= var_18;
+
+ AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
+ }
+
+ if (var_40 == 2) {
+ CheckClip(nPlayer);
+ }
+
+ if (var_70 <= 50) {
+ goto do_default;
+ }
+
+ sprite[nValB].cstat = 0x8000;
+ DestroyItemAnim(nValB);
+////
+ // loc_1BA74: - repeated block, see in default case
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+
+ break;
+/////
+ }
+
+ case 31: // Cobra staff ammo
+ {
+ if (AddAmmo(nPlayer, 5, 1)) {
+ var_88 = StaticSound[kSound69];
+ goto do_default;
+ }
+
+ break;
+ }
+
+ case 32: // Raw Energy
+ {
+ if (AddAmmo(nPlayer, 6, sprite[nValB].hitag)) {
+ var_88 = StaticSound[kSound69];
+ goto do_default;
+ }
+
+ break;
+ }
+
+ // Lots of repeated code for key handling
+ case 39: // Power key
+ {
+ int eax = 0;
+ int ecx;
+
+ var_88 = -1;
+
+ if (!eax)
+ {
+ ecx = 4096;
+ }
+ else
+ {
+ ecx = 4096 << eax;
+ }
+
+ if (PlayerList[nPlayer].keys != ecx)
+ {
+ if (nPlayer == nLocalPlayer) {
+ BuildStatusAnim(36, 0);
+ }
+
+ PlayerList[nPlayer].keys |= ecx;
+
+ if (nTotalPlayers > 1)
+ {
+ goto do_default_b;
+ }
+ else
+ {
+ goto do_default;
+ }
+#if 0
+ // loc_1BA74:
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+#endif
+ }
+
+ break;
+ }
+ case 40: // Time key
+ {
+ int eax = 1;
+ int ecx;
+
+ var_88 = -1;
+
+ if (!eax)
+ {
+ ecx = 4096;
+ }
+ else
+ {
+ ecx = 4096 << eax;
+ }
+
+ if (PlayerList[nPlayer].keys != ecx)
+ {
+ if (nPlayer == nLocalPlayer) {
+ BuildStatusAnim(36 + 2, 0);
+ }
+
+ PlayerList[nPlayer].keys |= ecx;
+
+ if (nTotalPlayers > 1)
+ {
+ goto do_default_b;
+ }
+ else
+ {
+ goto do_default;
+ }
+#if 0
+ if (nTotalPlayers > 1)
+ {
+ // loc_1BA74:
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+ }
+#endif
+ }
+
+ break;
+ }
+ case 41: // War key
+ {
+ int eax = 2;
+ int ecx;
+
+ var_88 = -1;
+
+ if (!eax)
+ {
+ ecx = 4096;
+ }
+ else
+ {
+ ecx = 4096 << eax;
+ }
+
+ if (PlayerList[nPlayer].keys != ecx)
+ {
+ if (nPlayer == nLocalPlayer) {
+ BuildStatusAnim(36 + 4, 0);
+ }
+
+ PlayerList[nPlayer].keys |= ecx;
+
+ if (nTotalPlayers > 1)
+ {
+ goto do_default_b;
+ }
+ else
+ {
+ goto do_default;
+ }
+#if 0
+ if (nTotalPlayers > 1)
+ {
+ // loc_1BA74:
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+ }
+#endif
+ }
+
+ break;
+ }
+ case 42: // Earth key
+ {
+ int eax = 3;
+ int ecx;
+
+ var_88 = -1;
+
+ if (!eax)
+ {
+ ecx = 4096;
+ }
+ else
+ {
+ ecx = 4096 << eax;
+ }
+
+ if (PlayerList[nPlayer].keys != ecx)
+ {
+ if (nPlayer == nLocalPlayer) {
+ BuildStatusAnim(36 + 6, 0);
+ }
+
+ PlayerList[nPlayer].keys |= ecx;
+
+ if (nTotalPlayers > 1)
+ {
+ goto do_default_b;
+ }
+ else
+ {
+ goto do_default;
+ }
+#if 0
+ if (nTotalPlayers > 1)
+ {
+ // loc_1BA74:
+ if (nPlayer == nLocalPlayer)
+ {
+ if (nItemText[var_70] > -1 && nTotalPlayers == 1)
+ {
+ StatusMessage(400, gString[nItemTextIndex + nItemText[var_70]]);
+ }
+
+ TintPalette(var_44, var_8C, 0);
+
+ if (var_88 > -1)
+ {
+ PlayLocalSound(var_88, 0);
+ }
+ }
+ }
+#endif
+ }
+
+ break;
+ }
+
+ case 43: // Magical Essence
+ case 44: // ?
+ {
+ if (PlayerList[nPlayer].nMagic >= 1000) {
+ break;
+ }
+
+ var_88 = StaticSound[kSound67];
+
+ PlayerList[nPlayer].nMagic += 100;
+ if (PlayerList[nPlayer].nMagic >= 1000) {
+ PlayerList[nPlayer].nMagic = 1000;
+ }
+
+ if (nLocalPlayer == nPlayer)
+ {
+ SetMagicFrame();
+ }
+
+ goto do_default;
+ }
+
+ case 53: // Scarab (Checkpoint)
+ {
+ if (nLocalPlayer == nPlayer)
+ {
+ short nAnim = sprite[nValB].owner;
+ AnimList[nAnim].nSeq++;
+ AnimFlags[nAnim] &= 0xEF;
+ AnimList[nAnim].field_2 = 0;
+
+ changespritestat(nValB, 899);
+ }
+
+ SetSavePoint(nPlayer, sprite[nPlayerSprite].x, sprite[nPlayerSprite].y, sprite[nPlayerSprite].z, sprite[nPlayerSprite].sectnum, sprite[nPlayerSprite].ang);
+ break;
+ }
+
+ case 54: // Golden Sarcophagus (End Level)
+ {
+ if (!bInDemo) {
+ FinishLevel();
+ }
+ else {
+ KB_Addch(32);
+ }
+
+ DestroyItemAnim(nValB);
+ mydeletesprite(nValB);
+ break;
+ }
+ }
+ }
+ }
+
+ // CORRECT ? // loc_1BAF9:
+ if (bTouchFloor)
+ {
+ if (sector[sprite[nPlayerSprite].sectnum].lotag > 0)
+ {
+ runlist_SignalRun(sector[sprite[nPlayerSprite].sectnum].lotag - 1, nPlayer | 0x50000);
+ }
+ }
+
+ if (nSector != sprite[nPlayerSprite].sectnum)
+ {
+ if (sector[nSector].lotag > 0)
+ {
+ runlist_SignalRun(sector[nSector].lotag - 1, nPlayer | 0x70000);
+ }
+
+ if (sector[sprite[nPlayerSprite].sectnum].lotag > 0)
+ {
+ runlist_SignalRun(sector[sprite[nPlayerSprite].sectnum].lotag - 1, nPlayer | 0x60000);
+ }
+ }
+
+ if (!PlayerList[nPlayer].bIsMummified)
+ {
+ if (buttons & kButtonOpen)
+ {
+ ClearSpaceBar(nPlayer);
+
+ if (nearTagWall >= 0 && wall[nearTagWall].lotag > 0)
+ {
+ runlist_SignalRun(wall[nearTagWall].lotag - 1, nPlayer | 0x40000);
+ }
+
+ if (nearTagSector >= 0 && sector[nearTagSector].lotag > 0)
+ {
+ runlist_SignalRun(sector[nearTagSector].lotag - 1, nPlayer | 0x40000);
+ }
+ }
+
+ // was int var_38 = buttons & 0x8
+ if (buttons & kButtonFire)
+ {
+ FireWeapon(nPlayer);
+ }
+ else
+ {
+ StopFiringWeapon(nPlayer);
+ }
+
+ // loc_1BC57:
+
+ // CHECKME - are we finished with 'nSector' variable at this point? if so, maybe set it to sprite[nPlayerSprite].sectnum so we can make this code a bit neater. Don't assume sprite[nPlayerSprite].sectnum == nSector here!!
+ if (nStandHeight > (sector[sprite[nPlayerSprite].sectnum].floorz - sector[sprite[nPlayerSprite].sectnum].ceilingz)) {
+ var_48 = 1;
+ }
+
+ // Jumping
+ if (buttons & kButtonJump)
+ {
+ if (bUnderwater)
+ {
+ sprite[nPlayerSprite].zvel = -2048;
+ nActionB = 10;
+ }
+ else if (bTouchFloor)
+ {
+ if (nAction < 6 || nAction > 8)
+ {
+ sprite[nPlayerSprite].zvel = -3584;
+ nActionB = 3;
+ }
+ }
+
+ // goto loc_1BE70:
+ }
+ else if (buttons & kButtonCrouch)
+ {
+ if (bUnderwater)
+ {
+ sprite[nPlayerSprite].zvel = 2048;
+ nActionB = 10;
+ }
+ else
+ {
+ int nEyeLevel = eyelevel[nPlayer];
+
+ if (nEyeLevel < -8320) {
+ eyelevel[nPlayer] = ((-8320 - nEyeLevel) >> 1) + nEyeLevel;
+ }
+
+ if (totalvel[nPlayer] < 1) {
+ nActionB = 6;
+ }
+ else {
+ nActionB = 7;
+ }
+ }
+
+ // goto loc_1BE70:
+ }
+ else
+ {
+ if (PlayerList[nPlayer].nHealth > 0)
+ {
+ int var_EC = nActionEyeLevel[nAction];
+ eyelevel[nPlayer] += (var_EC - eyelevel[nPlayer]) >> 1;
+
+ if (bUnderwater)
+ {
+ if (totalvel[nPlayer] <= 1)
+ nActionB = 9;
+ else
+ nActionB = 10;
+ }
+ else
+ {
+ // CHECKME - confirm branching in this area is OK
+ if (var_48)
+ {
+ // loc_1BD2E:
+ if (totalvel[nPlayer] < 1) {
+ nActionB = 6;
+ }
+ else {
+ nActionB = 7;
+ }
+ }
+ else
+ {
+ if (totalvel[nPlayer] <= 1) {
+ nActionB = 0;//bUnderwater; // this is just setting to 0
+ }
+ else if (totalvel[nPlayer] <= 30) {
+ nActionB = 2;
+ }
+ else
+ {
+ nActionB = 1;
+ }
+ }
+ }
+
+ // loc_1BE30
+ if (buttons & kButtonFire) // was var_38
+ {
+ if (bUnderwater)
+ {
+ nActionB = 11;
+ }
+ else
+ {
+ if (nActionB != 2 && nActionB != 1)
+ {
+ nActionB = 5;
+ }
+ }
+ }
+ }
+ else // player's health is 0
+ {
+ // loc_1BE30
+ if (buttons & kButtonFire) // was var_38
+ {
+ if (bUnderwater)
+ {
+ nActionB = 11;
+ }
+ else
+ {
+ if (nActionB != 2 && nActionB != 1)
+ {
+ nActionB = 5;
+ }
+ }
+ }
+ }
+ }
+
+ // loc_1BE70:
+ // Handle player pressing number keys to change weapon
+ uchar var_90 = (buttons >> 13) & 0xF;
+
+ if (var_90)
+ {
+ var_90--;
+
+ if (nPlayerWeapons[nPlayer] & (1 << var_90))
+ {
+ SetNewWeapon(nPlayer, var_90);
+ }
+ }
+ }
+ else // player is mummified
+ {
+ if (buttons & kButtonFire)
+ {
+ FireWeapon(nPlayer);
+ }
+
+ if (nAction != 15)
+ {
+ if (totalvel[nPlayer] <= 1)
+ {
+ nActionB = 13;
+ }
+ else
+ {
+ nActionB = 14;
+ }
+ }
+ }
+
+ // loc_1BF09
+ if (nActionB != nAction && nAction != 4)
+ {
+ nAction = nActionB;
+ PlayerList[nPlayer].nAction = nActionB;
+ PlayerList[nPlayer].field_2 = 0;
+ }
+
+ if (nPlayer == nLocalPlayer)
+ {
+ // TODO - tidy / consolidate repeating blocks of code here?
+ if (BUTTON(gamefunc_Look_Up))
+ {
+ bLockPan = kFalse;
+ if (nVertPan[nPlayer] < 180) {
+ nVertPan[nPlayer] += 4;
+ }
+
+ bPlayerPan = kTrue;
+ nDestVertPan[nPlayer] = nVertPan[nPlayer];
+ }
+ else if (BUTTON(gamefunc_Look_Down))
+ {
+ bLockPan = kFalse;
+ if (nVertPan[nPlayer] > 4) {
+ nVertPan[nPlayer] -= 4;
+ }
+
+ bPlayerPan = kTrue;
+ nDestVertPan[nPlayer] = nVertPan[nPlayer];
+ }
+ else if (BUTTON(gamefunc_Look_Straight))
+ {
+ bLockPan = kFalse;
+ bPlayerPan = kFalse;
+ nVertPan[nPlayer] = 92;
+ nDestVertPan[nPlayer] = 92;
+ }
+ else if (BUTTON(gamefunc_Aim_Up))
+ {
+ bLockPan = kTrue;
+ if (nVertPan[nPlayer] < 180) {
+ nVertPan[nPlayer] += 4;
+ }
+
+ bPlayerPan = kTrue;
+ nDestVertPan[nPlayer] = nVertPan[nPlayer];
+ }
+ else if (BUTTON(gamefunc_Aim_Down))
+ {
+ bLockPan = kTrue;
+ if (nVertPan[nPlayer] > 4) {
+ nVertPan[nPlayer] -= 4;
+ }
+
+ bPlayerPan = kTrue;
+ nDestVertPan[nPlayer] = nVertPan[nPlayer];
+ }
+
+ // loc_1C048:
+ if (totalvel[nPlayer] > 20) {
+ bPlayerPan = kFalse;
+ }
+
+ // loc_1C05E
+ short ecx = nDestVertPan[nPlayer] - nVertPan[nPlayer];
+
+ if (BUTTON(gamefunc_Mouseview))
+ {
+ ecx = 0;
+ }
+
+ if (ecx)
+ {
+ int eax = ecx / 4;
+
+ if (!eax)
+ {
+ if (ecx >= 0) {
+ ecx = 1;
+ }
+ else
+ {
+ ecx = -1;
+ }
+ }
+ else
+ {
+ ecx = ecx / 4;
+ eax = ecx;
+
+ if (eax > 4)
+ {
+ ecx = 4;
+ }
+ else if (eax < -4)
+ {
+ ecx = -4;
+ }
+ }
+
+ nVertPan[nPlayer] += ecx;
+ }
+ }
+ }
+ else // else, player's health is less than 0
+ {
+ if (buttons) {
+ int breakmehere = 1;
+ }
+
+ // loc_1C0E9
+ if (buttons & kButtonOpen)
+ {
+ ClearSpaceBar(nPlayer);
+
+ if (nAction >= 16)
+ {
+ if (nPlayer == nLocalPlayer)
+ {
+ StopAllSounds();
+ StopLocalSound();
+ GrabPalette();
+ }
+
+ PlayerList[nPlayer].nCurrentWeapon = nPlayerOldWeapon[nPlayer];
+
+ if (nPlayerLives[nPlayer] && nNetTime)
+ {
+ if (nAction != 20)
+ {
+ sprite[nPlayerSprite].picnum = seq_GetSeqPicnum(kSeqJoe, 120, 0);
+ sprite[nPlayerSprite].cstat = 0;
+ sprite[nPlayerSprite].z = sector[sprite[nPlayerSprite].sectnum].floorz;
+ }
+
+ // will invalidate nPlayerSprite
+ RestartPlayer(nPlayer);
+
+ nPlayerSprite = PlayerList[nPlayer].nSprite;
+ nDopple = nDoppleSprite[nPlayer];
+ }
+ else
+ {
+ if (CDplaying()) {
+ fadecdaudio();
+ }
+
+ if (levelnum == 20) {
+ DoFailedFinalScene();
+ }
+ else {
+ DoGameOverScene();
+ }
+
+ levelnew = 100;
+ }
+ }
+ }
+ }
+
+ // loc_1C201:
+ if (nLocalPlayer == nPlayer)
+ {
+ nLocalEyeSect = nPlayerViewSect[nLocalPlayer];
+ CheckAmbience(nLocalEyeSect);
+ }
+
+ int var_AC = SeqOffsets[PlayerList[nPlayer].nSeq] + ActionSeq[nAction].a;
+
+ seq_MoveSequence(nPlayerSprite, var_AC, PlayerList[nPlayer].field_2);
+ PlayerList[nPlayer].field_2++;
+
+ if (PlayerList[nPlayer].field_2 >= SeqSize[var_AC])
+ {
+ PlayerList[nPlayer].field_2 = 0;
+
+ switch (PlayerList[nPlayer].nAction)
+ {
+ default:
+ break;
+
+ case 3:
+ PlayerList[nPlayer].field_2 = SeqSize[var_AC] - 1;
+ break;
+ case 4:
+ PlayerList[nPlayer].nAction = 0;
+ break;
+ case 16:
+ PlayerList[nPlayer].field_2 = SeqSize[var_AC] - 1;
+
+ if (sprite[nPlayerSprite].z < sector[sprite[nPlayerSprite].sectnum].floorz) {
+ sprite[nPlayerSprite].z += 256;
+ }
+
+ if (!RandomSize(5))
+ {
+ int mouthX, mouthY, mouthZ;
+ short mouthSect;
+ WheresMyMouth(nPlayer, &mouthX, &mouthY, &mouthZ, &mouthSect);
+
+ BuildAnim(-1, 71, 0, mouthX, mouthY, sprite[nPlayerSprite].z + 3840, mouthSect, 75, 128);
+ }
+ break;
+ case 17:
+ PlayerList[nPlayer].nAction = 18;
+ break;
+ case 19:
+ sprite[nPlayerSprite].cstat |= 0x8000;
+ PlayerList[nPlayer].nAction = 20;
+ break;
+ }
+ }
+
+ // loc_1C3B4:
+ if (nPlayer == nLocalPlayer)
+ {
+ initx = sprite[nPlayerSprite].x;
+ inity = sprite[nPlayerSprite].y;
+ initz = sprite[nPlayerSprite].z;
+ initsect = sprite[nPlayerSprite].sectnum;
+ inita = sprite[nPlayerSprite].ang;
+ }
+
+ if (!PlayerList[nPlayer].nHealth)
+ {
+ nYDamage[nPlayer] = 0;
+ nXDamage[nPlayer] = 0;
+
+ if (eyelevel[nPlayer] >= -2816)
+ {
+ eyelevel[nPlayer] = -2816;
+ dVertPan[nPlayer] = 0;
+ }
+ else
+ {
+ if (nVertPan[nPlayer] < 92)
+ {
+ nVertPan[nPlayer] = 91;
+ eyelevel[nPlayer] -= (dVertPan[nPlayer] << 8);
+ }
+ else
+ {
+ nVertPan[nPlayer] += dVertPan[nPlayer];
+ if (nVertPan[nPlayer] >= 200)
+ {
+ nVertPan[nPlayer] = 199;
+ }
+ else if (nVertPan[nPlayer] <= 92)
+ {
+ if (!(SectFlag[sprite[nPlayerSprite].sectnum] & kSectUnderwater))
+ {
+ SetNewWeapon(nPlayer, nDeathType[nPlayer] + 8);
+ }
+ }
+
+ dVertPan[nPlayer]--;
+ }
+ }
+ }
+
+ // loc_1C4E1
+ sprite[nDopple].x = sprite[nPlayerSprite].x;
+ sprite[nDopple].y = sprite[nPlayerSprite].y;
+ sprite[nDopple].z = sprite[nPlayerSprite].z;
+
+ if (SectAbove[sprite[nPlayerSprite].sectnum] > -1)
+ {
+ sprite[nDopple].ang = sprite[nPlayerSprite].ang;
+ mychangespritesect(nDopple, SectAbove[sprite[nPlayerSprite].sectnum]);
+ sprite[nDopple].cstat = 0x101;
+ }
+ else
+ {
+ sprite[nDopple].cstat = 0x8000;
+ }
+
+ MoveWeapons(nPlayer);
+
+ return;
+ }
+ }
+}
diff --git a/source/exhumed/src/player.h b/source/exhumed/src/player.h
new file mode 100644
index 000000000..f8ec42fc9
--- /dev/null
+++ b/source/exhumed/src/player.h
@@ -0,0 +1,105 @@
+
+#ifndef __player_h__
+#define __player_h__
+
+#include "typedefs.h"
+
+void PlayerInterruptKeys();
+void RestoreSavePoint(int nPlayer, int *x, int *y, int *z, short *nSector, short *nAngle);
+void SetSavePoint(int nPlayer, int x, int y, int z, short nSector, short nAngle);
+void InitPlayer();
+void InitPlayerKeys(short nPlayer);
+void DoKenTest();
+int GrabPlayer();
+void InitPlayerInventory(short nPlayer);
+void RestartPlayer(short nPlayer);
+
+void FuncPlayer(int nSector, int nSprite, int nRun);
+
+#define kMaxPlayers 8
+#define kDefaultLives 3
+#define kMaxPlayerLives 5
+#define kMaxHealth 800
+
+extern int nLocalPlayer;
+
+extern int lPlayerXVel;
+extern int lPlayerYVel;
+extern int nPlayerDAng;
+
+struct Player
+{
+ short nHealth;
+ short field_2;
+ short nAction;
+ short nSprite;
+ short bIsMummified;
+ short someNetVal;
+ short invincibility;
+ short nAir;
+ short nSeq;
+ short nMaskAmount;
+ ushort keys;
+ short nMagic;
+ char items[8];
+ short nAmmo[7]; // TODO - kMaxWeapons?
+ short pad[2];
+
+ short nCurrentWeapon;
+ short field_34;
+ short bIsFiring;
+ short field_38;
+ short field_3A;
+ short field_3C;
+ short nRun;
+};
+
+extern short PlayerCount;
+
+extern short nPlayerTorch[];
+
+extern short nPlayerLives[];
+extern short nPlayerItem[];
+extern Player PlayerList[];
+extern short nPlayerInvisible[];
+extern short nPlayerDouble[];
+extern short nPlayerViewSect[];
+extern short nPlayerFloorSprite[];
+
+extern short nTauntTimer[];
+
+extern short nDoppleSprite[];
+
+extern ushort nPlayerWeapons[];
+
+extern short nPlayerOldWeapon[];
+extern short nPlayerGrenade[kMaxPlayers];
+extern short nGrenadePlayer[50];
+
+extern short nPistolClip[];
+
+extern short nPlayerScore[];
+
+extern short nPlayerClip[];
+
+extern short bobangle;
+
+extern int totalvel[];
+extern short eyelevel[];
+
+extern short nNetStartSprite[kMaxPlayers];
+extern short nNetStartSprites;
+extern short nCurStartSprite;
+
+extern int nXDamage[kMaxPlayers];
+extern int nYDamage[kMaxPlayers];
+
+extern int nPlayerDY[kMaxPlayers];
+extern int nPlayerDX[kMaxPlayers];
+
+short GetPlayerFromSprite(short nSprite);
+void SetPlayerMummified(int nPlayer, int bIsMummified);
+int AddAmmo(int nPlayer, int nWeapon, int nAmmoAmount);
+void ShootStaff(int nPlayer);
+
+#endif
diff --git a/source/exhumed/src/queen.cpp b/source/exhumed/src/queen.cpp
new file mode 100644
index 000000000..13712791b
--- /dev/null
+++ b/source/exhumed/src/queen.cpp
@@ -0,0 +1,1601 @@
+
+#include "exhumed.h"
+#include "aistuff.h"
+#include "engine.h"
+#include "queen.h"
+#include "move.h"
+#include "sequence.h"
+#include "runlist.h"
+#include "random.h"
+#include "wasp.h"
+#include "trigdat.h"
+#include "anims.h"
+#include "player.h"
+#include
+
+#define kMaxQueens 1
+#define kMaxEggs 10
+#define kMaxTails 7
+
+short QueenCount = 0;
+
+static actionSeq ActionSeq[] = {
+ { 0, 0 },
+ { 0, 0 },
+ { 9, 0 },
+ { 36, 0 },
+ { 18, 0 },
+ { 27, 0 },
+ { 45, 0 },
+ { 45, 0 },
+ { 54, 1 },
+ { 53, 1 },
+ { 55, 1 }
+};
+
+static actionSeq HeadSeq[] = {
+ { 56, 1 },
+ { 65, 0 },
+ { 65, 0 },
+ { 65, 0 },
+ { 65, 0 },
+ { 65, 0 },
+ { 74, 0 },
+ { 82, 0 },
+ { 90, 0 }
+};
+
+static actionSeq EggSeq[] = {
+ { 19, 1 },
+ { 18, 1 },
+ { 0, 0 },
+ { 9, 0 },
+ { 23, 1 },
+};
+
+int nQHead = 0;
+
+short nEggsFree;
+short nHeadVel;
+short nVelShift;
+
+short tailspr[kMaxTails];
+short nEggFree[kMaxEggs];
+
+short QueenChan[kMaxQueens];
+
+
+
+
+struct Queen
+{
+ short nHealth;
+ short field_2;
+ short nAction;
+ short nSprite;
+ short nTarget;
+ short field_A;
+ short field_C;
+ short pad;
+ short field_10;
+ short field_12;
+};
+
+struct Egg
+{
+ short nHealth;
+ short field_2;
+ short nAction;
+ short nSprite;
+ short field_8;
+ short nTarget;
+ short field_C;
+ short field_E;
+};
+
+struct Head
+{
+ short nHealth;
+ short field_2;
+ short nAction;
+ short nSprite;
+ short field_8;
+ short nTarget;
+ short field_C;
+ short field_E;
+};
+
+Egg QueenEgg[kMaxEggs];
+Queen QueenList[kMaxQueens];
+Head QueenHead;
+
+int MoveQX[25];
+int MoveQY[25];
+int MoveQZ[25];
+short MoveQS[25];
+short MoveQA[25];
+
+
+void InitQueens()
+{
+ QueenCount = 1;
+
+ for (int i = 0; i < kMaxEggs; i++)
+ {
+ nEggFree[i] = i;
+ QueenEgg[i].field_8 = -1;
+ }
+}
+
+int GrabEgg()
+{
+ if (!nEggsFree) {
+ return -1;
+ }
+
+ nEggsFree--;
+ return nEggFree[nEggsFree];
+}
+
+void BlowChunks(int nSprite)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ BuildCreatureChunk(nSprite, seq_GetSeqPicnum(16, i + 41, 0));
+ }
+}
+
+void DestroyEgg(short nEgg)
+{
+ short nSprite = QueenEgg[nEgg].nSprite;
+
+ if (QueenEgg[nEgg].nAction == 4)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ BuildCreatureChunk(nSprite, seq_GetSeqPicnum(kSeqQueenEgg, (i % 2) + 24, 0));
+ }
+ }
+ else
+ {
+ BuildAnim(-1, 34, 0, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum, sprite[nSprite].xrepeat, 4);
+ }
+
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_DoSubRunRec(sprite[nSprite].lotag - 1);
+ runlist_SubRunRec(QueenEgg[nEgg].field_8);
+
+ QueenEgg[nEgg].field_8 = -1;
+
+ mydeletesprite(nSprite);
+
+ nEggFree[nEggsFree] = nEgg;
+ nEggsFree++;
+}
+
+void DestroyAllEggs()
+{
+ for (int i = 0; i < kMaxEggs; i++)
+ {
+ if (QueenEgg[i].field_8 > -1)
+ {
+ DestroyEgg(i);
+ }
+ }
+}
+
+void SetHeadVel(short nSprite)
+{
+ short nAngle = sprite[nSprite].ang;
+
+ if (nVelShift < 0)
+ {
+ sprite[nSprite].xvel = Sin(nAngle + 512) << (schar)(-nVelShift);
+ sprite[nSprite].yvel = Sin(nAngle) << (schar)(-nVelShift);
+ }
+ else
+ {
+ sprite[nSprite].xvel = Sin(nAngle + 512) >> (schar)(nVelShift);
+ sprite[nSprite].yvel = Sin(nAngle) >> (schar)(nVelShift);
+ }
+}
+
+int QueenAngleChase(short nSprite, short nSprite2, int val1, int val2)
+{
+ short nAngle;
+
+ if (nSprite2 < 0)
+ {
+ sprite[nSprite].zvel = 0;
+ nAngle = sprite[nSprite].ang;
+ }
+ else
+ {
+ int nTileY = (tilesizy[sprite[nSprite2].picnum] * sprite[nSprite2].yrepeat) * 2;
+
+ int nMyAngle = GetMyAngle(sprite[nSprite2].x - sprite[nSprite].x, sprite[nSprite2].y - sprite[nSprite].y);
+
+ int edx = ((sprite[nSprite2].z - nTileY) - sprite[nSprite].z) >> 8;
+
+ int x = sprite[nSprite2].x - sprite[nSprite].x;
+ int y = sprite[nSprite2].y - sprite[nSprite].y;
+
+ int nSqrt = ksqrt(x * x + y * y);
+
+ int var_14 = GetMyAngle(nSqrt, edx);
+
+ int nAngDelta = AngleDelta(sprite[nSprite].ang, nMyAngle, 1024);
+ int nAngDeltaB = nAngDelta; // edx
+ int nAngDeltaC = nAngDelta; // edi
+
+ if (nAngDelta < 0) {
+ nAngDelta = -nAngDelta;
+ }
+
+ if (nAngDelta > 127)
+ {
+ nAngDelta = nAngDeltaB >> 7;
+ if (nAngDelta < 0) {
+ nAngDelta = -nAngDelta;
+ }
+
+ val1 = val1 / nAngDelta;
+
+ if (val1 < 256) {
+ val1 = 256;
+ }
+ }
+
+ // restore the value of nAngDelta
+ nAngDelta = nAngDeltaC;
+
+ if (nAngDelta < 0) {
+ nAngDelta = -nAngDelta;
+ }
+
+ if (nAngDelta > val2)
+ {
+ if (nAngDeltaC >= 0)
+ {
+ nAngDeltaC = val2;
+ }
+ else
+ {
+ nAngDeltaC = -val2;
+ }
+ }
+
+ nAngle = (nAngDeltaC + sprite[nSprite].ang) & kAngleMask;
+
+ sprite[nSprite].zvel = (AngleDelta(sprite[nSprite].zvel, var_14, 24) + sprite[nSprite].zvel) & kAngleMask;
+ }
+
+ sprite[nSprite].ang = nAngle;
+
+ int x = Sin(sprite[nSprite].zvel + 512);
+
+ if (x < 0) {
+ x = -x;
+ }
+
+ int v26 = x * ((val1 * Sin(nAngle + 512)) >> 14);
+ int v27 = x * ((val1 * Sin(nAngle)) >> 14);
+
+ int nSqrt = ksqrt(((v26 >> 8) * (v26 >> 8)) + ((v27 >> 8) * (v27 >> 8)));
+
+ return movesprite(nSprite, v26 >> 2, v27 >> 2, (Sin(bobangle) >> 5) + ((nSqrt * Sin(sprite[nSprite].zvel)) >> 13), 0, 0, CLIPMASK1);
+}
+
+int DestroyTailPart()
+{
+ if (!QueenHead.field_E) {
+ return 0;
+ }
+
+ QueenHead.field_E--;
+ int edx = QueenHead.field_E;
+
+ short nSprite = tailspr[edx];
+
+ BlowChunks(nSprite);
+ BuildExplosion(nSprite);
+
+ for (int i = 0; i < 5; i++)
+ {
+ short nHeight = GetSpriteHeight(nSprite);
+ BuildLavaLimb(nSprite, i, nHeight);
+ }
+
+ mydeletesprite(nSprite);
+ return 1;
+}
+
+void BuildTail()
+{
+ short nSprite = QueenHead.nSprite;
+
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].x;
+ int z = sprite[nSprite].x;
+ short nSector = sprite[nSprite].sectnum;
+
+ int i;
+
+ for (i = 0; i < kMaxTails; i++)
+ {
+ short nTailSprite = insertsprite(nSector, 121);
+ tailspr[i] = nTailSprite;
+
+ if (nTailSprite < 0) {
+ bail2dos("Can't create queen's tail!\n");
+ }
+
+ sprite[nTailSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nTailSprite].owner = runlist_AddRunRec(sprite[nTailSprite].lotag - 1, (i + 1) | 0x1B0000);
+ sprite[nTailSprite].shade = -12;
+ sprite[nTailSprite].x = x;
+ sprite[nTailSprite].y = y;
+ sprite[nTailSprite].hitag = 0;
+ sprite[nTailSprite].cstat = 0;
+ sprite[nTailSprite].clipdist = 100;
+ sprite[nTailSprite].xrepeat = 80;
+ sprite[nTailSprite].yrepeat = 80;
+ sprite[nTailSprite].picnum = 1;
+ sprite[nTailSprite].pal = sector[sprite[nTailSprite].sectnum].ceilingpal;
+ sprite[nTailSprite].xoffset = 0;
+ sprite[nTailSprite].yoffset = 0;
+ sprite[nTailSprite].z = z;
+ sprite[nTailSprite].extra = -1;
+ }
+
+ for (i = 0; i < 24 + 1; i++)
+ {
+ MoveQX[i] = x;
+ MoveQZ[i] = z;
+ MoveQY[i] = y;
+ assert(nSector >= 0 && nSector < kMaxSectors);
+ MoveQS[i] = nSector;
+ }
+
+ nQHead = 0;
+ QueenHead.field_E = 7;
+}
+
+int BuildQueenEgg(short nQueen, int nVal)
+{
+ int nEgg = GrabEgg();
+ if (nEgg < 0) {
+ return -1;
+ }
+
+ short nSprite = QueenList[nQueen].nSprite;
+
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ short nSector = sprite[nSprite].sectnum;
+ int nFloorZ = sector[nSector].floorz;
+ short nAngle = sprite[nSprite].ang;
+
+ int nSprite2 = insertsprite(nSector, 121);
+ assert(nSprite2 >= 0 && nSprite2 < kMaxSprites);
+
+ sprite[nSprite2].x = x;
+ sprite[nSprite2].y = y;
+ sprite[nSprite2].z = nFloorZ;
+ sprite[nSprite2].pal = 0;
+ sprite[nSprite2].clipdist = 50;
+ sprite[nSprite2].xoffset = 0;
+ sprite[nSprite2].yoffset = 0;
+ sprite[nSprite2].shade = -12;
+ sprite[nSprite2].picnum = 1;
+ sprite[nSprite2].ang = (RandomSize(9) + (nAngle - 256)) & kAngleMask;
+
+ if (nVal)
+ {
+ sprite[nSprite2].xrepeat = 60;
+ sprite[nSprite2].yrepeat = 60;
+ sprite[nSprite2].xvel = 0;
+ sprite[nSprite2].yvel = 0;
+ sprite[nSprite2].zvel = -2000;
+ sprite[nSprite2].cstat = 0x101;
+ }
+ else
+ {
+ sprite[nSprite2].xrepeat = 30;
+ sprite[nSprite2].yrepeat = 30;
+ sprite[nSprite2].xvel = Sin(sprite[nSprite2].ang + 512);
+ sprite[nSprite2].yvel = Sin(sprite[nSprite2].ang);
+ sprite[nSprite2].zvel = -6000;
+ sprite[nSprite2].cstat = 0;
+ }
+
+ sprite[nSprite2].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite2].extra = -1;
+ sprite[nSprite2].hitag = 0;
+
+ GrabTimeSlot(3);
+
+ QueenEgg[nEgg].nHealth = 200;
+ QueenEgg[nEgg].field_2 = 0;
+ QueenEgg[nEgg].nSprite = nSprite2;
+ QueenEgg[nEgg].field_E = nVal;
+ QueenEgg[nEgg].nTarget = QueenList[nQueen].nTarget;
+
+ if (nVal)
+ {
+ nVal = 4;
+ QueenEgg[nEgg].field_C = 200;
+ }
+
+ QueenEgg[nEgg].nAction = nVal;
+
+ sprite[nSprite2].owner = runlist_AddRunRec(sprite[nSprite2].lotag - 1, nEgg | 0x1D0000);
+ QueenEgg[nEgg].field_8 = runlist_AddRunRec(NewRun, nEgg | 0x1D0000);
+
+ return 0;
+}
+
+void FuncQueenEgg(int a, int nDamage, int nRun)
+{
+ short nEgg = RunData[nRun].nVal;
+
+ int var_14 = 0;
+
+ short nSprite = QueenEgg[nEgg].nSprite;
+ short nAction = QueenEgg[nEgg].nAction;
+
+ short nTarget;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Queenhead\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, SeqOffsets[kSeqQueenEgg] + EggSeq[nAction].a, QueenEgg[nEgg].field_2, EggSeq[nAction].b);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ if (sprite[nRadialSpr].statnum == 121) {
+ return;
+ }
+
+ if (!(sprite[nSprite].cstat & 0x101)) {
+ return;
+ }
+
+ nDamage = runlist_CheckRadialDamage(nSprite);
+
+ QueenEgg[nEgg].nHealth -= nDamage;
+ return;
+ }
+
+ case 0x80000:
+ {
+ if (!nDamage) {
+ return;
+ }
+
+ if (QueenEgg[nEgg].nHealth <= 0) {
+ return;
+ }
+
+ QueenEgg[nEgg].nHealth -= nDamage;
+
+ if (QueenEgg[nEgg].nHealth > 0) {
+ return;
+ }
+
+ DestroyEgg(nEgg);
+ return;
+ }
+
+ case 0x20000:
+ {
+ if (QueenEgg[nEgg].nHealth <= 0)
+ {
+ DestroyEgg(nEgg);
+ return;
+ }
+
+ if (!nAction || nAction == 4) {
+ Gravity(nSprite);
+ }
+
+ short nSeq = SeqOffsets[kSeqQueenEgg] + EggSeq[nAction].a;
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, QueenEgg[nEgg].field_2);
+
+ if (nAction != 4)
+ {
+ seq_MoveSequence(nSprite, nSeq, QueenEgg[nEgg].field_2);
+
+ QueenEgg[nEgg].field_2++;
+ if (QueenEgg[nEgg].field_2 >= SeqSize[nSeq])
+ {
+ QueenEgg[nEgg].field_2 = 0;
+ var_14 = 1;
+ }
+
+ nTarget = UpdateEnemy(&QueenEgg[nEgg].nTarget);
+ QueenEgg[nEgg].nTarget = nTarget;
+
+ if (nTarget < 0 || (sprite[nTarget].cstat & 0x101))
+ {
+ nTarget = FindPlayer(-nSprite, 1000);
+ QueenEgg[nEgg].nTarget = nTarget;
+ }
+ else
+ {
+ QueenEgg[nEgg].nTarget = -1;
+ QueenEgg[nEgg].nAction = 0;
+ }
+ }
+
+ switch (nAction)
+ {
+ default:
+ return;
+
+ case 0:
+ {
+ int nMov = MoveCreature(nSprite);
+ if (!nMov) {
+ return;
+ }
+
+ if (nMov == 0x20000)
+ {
+ short nAngle;
+
+ if ((nMov & 0xC000) == 0x8000)
+ {
+ nAngle = GetWallNormal(nMov & 0x3FFF);
+ }
+ else if ((nMov & 0xC000) == 0xC000)
+ {
+ nAngle = sprite[nMov & 0x3FFF].ang;
+ }
+
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].xvel = Sin(nAngle + 512) >> 1;
+ sprite[nSprite].yvel = Sin(nAngle) >> 1;
+ }
+ else
+ {
+ if (!RandomSize(1))
+ {
+ QueenEgg[nEgg].nAction = 1;
+ QueenEgg[nEgg].field_2 = 0;
+ }
+ else
+ {
+ DestroyEgg(nEgg);
+ }
+ }
+
+ return;
+ }
+
+ case 1:
+ {
+ if (!var_14) {
+ return;
+ }
+
+ QueenEgg[nEgg].nAction = 3;
+
+ sprite[nSprite].cstat = 0x101;
+ return;
+ }
+
+ case 2:
+ case 3:
+ {
+ int nMov = QueenAngleChase(nSprite, nTarget, nHeadVel, 64);
+
+ if ((nMov & 0xC000) == 0x8000)
+ {
+ sprite[nSprite].ang += (RandomSize(9) + 768);
+ sprite[nSprite].ang &= kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 3;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 3;
+ sprite[nSprite].zvel = -RandomSize(5);
+ }
+ else if ((nMov & 0xC000) == 0xC000)
+ {
+ if (sprite[nMov & 0x3FFF].statnum != 121)
+ {
+ runlist_DamageEnemy(nMov & 0x3FFF, nSprite, 5);
+ }
+
+ sprite[nSprite].ang += (RandomSize(9) + 768);
+ sprite[nSprite].ang &= kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 3;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 3;
+ sprite[nSprite].zvel = -RandomSize(5);
+ }
+
+ return;
+ }
+
+ case 4:
+ {
+ int nMov = MoveCreature(nSprite);
+
+ if (nMov == 0x20000)
+ {
+ sprite[nSprite].zvel = -(sprite[nSprite].zvel - 256);
+ if (sprite[nSprite].zvel < -512)
+ {
+ sprite[nSprite].zvel = 0;
+ }
+ }
+
+ QueenEgg[nEgg].field_C--;
+ if (QueenEgg[nEgg].field_C > 0) {
+ return;
+ }
+
+ short nWaspSprite = BuildWasp(-2, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum, sprite[nSprite].ang);
+ sprite[nSprite].z = sprite[nWaspSprite].z;
+
+ DestroyEgg(nEgg);
+ return;
+ }
+ }
+ }
+ }
+}
+
+int BuildQueenHead(short nQueen)
+{
+ short nSprite = QueenList[nQueen].nSprite;
+
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ short nAngle = sprite[nSprite].ang;
+ short nSector = sprite[nSprite].sectnum;
+ int z = sector[nSector].floorz;
+
+ int nSprite2 = insertsprite(nSector, 121);
+ assert(nSprite2 >= 0 && nSprite2 < kMaxSprites);
+
+ sprite[nSprite2].x = x;
+ sprite[nSprite2].y = y;
+ sprite[nSprite2].z = z;
+ sprite[nSprite2].clipdist = 70;
+ sprite[nSprite2].xrepeat = 80;
+ sprite[nSprite2].yrepeat = 80;
+ sprite[nSprite2].cstat = 0;
+ sprite[nSprite2].picnum = 1;
+ sprite[nSprite2].shade = -12;
+ sprite[nSprite2].pal = 0;
+ sprite[nSprite2].xoffset = 0;
+ sprite[nSprite2].yoffset = 0;
+ sprite[nSprite2].ang = nAngle;
+
+ nVelShift = 2;
+ SetHeadVel(nSprite2);
+
+ sprite[nSprite2].zvel = -8192;
+ sprite[nSprite2].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite2].hitag = 0;
+ sprite[nSprite2].extra = -1;
+
+ GrabTimeSlot(3);
+
+ QueenHead.nHealth = 20; // 800;
+ QueenHead.nAction = 0;
+ QueenHead.nTarget = QueenList[nQueen].nTarget;
+ QueenHead.field_2 = 0;
+ QueenHead.nSprite = nSprite2;
+ int nSector2 = sprite[QueenHead.nSprite].sectnum;
+ assert(nSector2 >= 0 && nSector2 < kMaxSectors);
+
+ QueenHead.field_C = 0;
+
+ sprite[nSprite2].owner = runlist_AddRunRec(sprite[nSprite2].lotag - 1, 0x1B0000);
+
+ QueenHead.field_8 = runlist_AddRunRec(NewRun, 0x1B0000);
+ QueenHead.field_E = 0;
+
+ return 0;
+}
+
+void FuncQueenHead(int a, int nDamage, int nRun)
+{
+ short nHead = RunData[nRun].nVal;
+
+ short nSprite = QueenHead.nSprite;
+ int nSector = sprite[nSprite].sectnum;
+ assert(nSector >= 0 && nSector < kMaxSectors);
+
+ short nAction = QueenHead.nAction;
+
+ short nTarget;
+
+ int var_14 = 0;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Queenhead\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0x90000:
+ {
+ short nSeq = SeqOffsets[kSeqQueen];
+
+ int edx;
+
+ if (nHead)
+ {
+ edx = 1;
+ nSeq += 73;
+ }
+ else
+ {
+ edx = HeadSeq[nAction].b;
+ nSeq += HeadSeq[nAction].a;
+ }
+
+ seq_PlotSequence(a & 0xFFFF, nSeq, QueenHead.field_2, edx);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ if (sprite[nRadialSpr].statnum == 121) {
+ return;
+ }
+
+ if (!(sprite[nSprite].cstat & 0x101)) {
+ return;
+ }
+
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ if (!nDamage) {
+ return;
+ }
+ // fall through to case 0x80000
+ }
+
+ case 0x80000:
+ {
+ if (QueenHead.nHealth <= 0) {
+ return;
+ }
+
+ if (!nDamage) {
+ return;
+ }
+
+ QueenHead.nHealth -= nDamage;
+
+ if (!RandomSize(4))
+ {
+ QueenHead.nTarget = a & 0xFFFF;
+ QueenHead.nAction = 7;
+ QueenHead.field_2 = 0;
+ }
+
+ if (QueenHead.nHealth > 0) {
+ return;
+ }
+
+ if (DestroyTailPart())
+ {
+ QueenHead.nHealth = 10; // 200;
+ nHeadVel += 100;
+ return;
+ }
+ else
+ {
+ QueenHead.nAction = 5;
+ QueenHead.field_2 = 0;
+ QueenHead.field_C = 0;
+ QueenHead.field_E = 80;
+ sprite[nSprite].cstat = 0;
+ return;
+ }
+ }
+
+ case 0x20000:
+ {
+ if (nAction == 0) {
+ Gravity(nSprite);
+ }
+
+ short nSeq = SeqOffsets[kSeqQueen] + HeadSeq[QueenHead.nAction].a;
+
+ seq_MoveSequence(nSprite, nSeq, QueenHead.field_2);
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, QueenHead.field_2);
+
+ QueenHead.field_2++;
+ if (QueenHead.field_2 >= SeqSize[nSeq])
+ {
+ QueenHead.field_2 = 0;
+ var_14 = 1;
+ }
+
+ nTarget = QueenHead.nTarget;
+
+ if (nTarget <= -1)
+ {
+ nTarget = FindPlayer(nSprite, 1000);
+ QueenHead.nTarget = nTarget;
+ }
+ else
+ {
+ if (!(sprite[nTarget].cstat & 0x101))
+ {
+ nTarget = -1;
+ QueenHead.nTarget = nTarget;
+ }
+ }
+
+ switch (nAction)
+ {
+ default:
+ return;
+
+ case 0:
+ {
+ if (QueenHead.field_C > 0)
+ {
+ QueenHead.field_C--;
+ if (QueenHead.field_C == 0)
+ {
+ BuildTail();
+
+ QueenHead.nAction = 6;
+ nHeadVel = 800;
+ sprite[nSprite].cstat = 0x101;
+ return;
+ }
+
+ if (QueenHead.field_C < 60) {
+ sprite[nSprite].shade--;
+ }
+
+ return;
+ }
+ else
+ {
+ int nMov = MoveCreature(nSprite);
+
+ // original BUG - this line doesn't exist in original code?
+ short nNewAng = sprite[nSprite].ang;
+
+ if ((nMov & 0xFC000) == 0xC000)
+ {
+ nNewAng = sprite[nMov & 0x3FFF].ang;
+ }
+ else if ((nMov & 0xFC000) == 0x8000)
+ {
+ nNewAng = GetWallNormal(nMov & 0x3FFF);
+ }
+ else if ((nMov & 0xFC000) == 0x20000)
+ {
+ sprite[nSprite].zvel = -(sprite[nSprite].zvel >> 1);
+
+ if (sprite[nSprite].zvel > -256)
+ {
+ nVelShift = 100;
+ sprite[nSprite].zvel = 0;
+ }
+ }
+ else
+ {
+ return;
+ }
+
+ // original BUG - var_18 isn't being set if the check above == 0x20000 ?
+ sprite[nSprite].ang = nNewAng;
+ nVelShift++;
+
+ if (nVelShift < 5)
+ {
+ SetHeadVel(nSprite);
+ return;
+ }
+ else
+ {
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+
+ if (sprite[nSprite].zvel == 0)
+ {
+ QueenHead.field_C = 120;
+ }
+
+ return;
+ }
+ }
+
+ return;
+ }
+
+ case 1:
+ {
+ if ((sprite[nTarget].z - 51200) <= sprite[nSprite].z)
+ {
+ sprite[nSprite].z -= 2048;
+ break;
+ }
+ else
+ {
+ QueenHead.nAction = 4;
+ QueenHead.field_2 = 0;
+ }
+
+ return;
+ }
+
+ case 2:
+ case 3:
+ {
+ return;
+ }
+
+ case 4:
+ case 7:
+ case 8:
+ {
+ if (var_14)
+ {
+ int nRnd = RandomSize(2);
+
+ if (nRnd == 0)
+ {
+ QueenHead.nAction = 4;
+ }
+ else
+ {
+ if (nRnd == 1) {
+ QueenHead.nAction = 7;
+ }
+ else {
+ QueenHead.nAction = 8;
+ }
+ }
+ }
+
+ if (nTarget > -1)
+ {
+ int nMov = QueenAngleChase(nSprite, nTarget, nHeadVel, 64);
+
+ if ((nMov & 0xC000) == 0x8000) {
+ break;
+ }
+
+ if ((nMov & 0xC000) == 0xC000)
+ {
+ if ((nMov & 0x3FFF) == nTarget)
+ {
+ runlist_DamageEnemy(nTarget, nSprite, 10);
+// TODO D3PlayFX((StaticSound[kSoundQTail] | 0x2000)) & 0xFFFF, nSprite);
+
+ sprite[nSprite].ang += RandomSize(9) + 768;
+ sprite[nSprite].ang &= kAngleMask;
+
+ sprite[nSprite].zvel = (-20) - RandomSize(6);
+
+ SetHeadVel(nSprite);
+ }
+ }
+ }
+
+ break;
+ }
+
+ case 5:
+ {
+ QueenHead.field_C--;
+ if (QueenHead.field_C > 0) {
+ return;
+ }
+
+ short ax = QueenHead.field_E;
+
+ QueenHead.field_C = 3;
+ QueenHead.field_E--;
+
+ if (ax == 0)
+ {
+ BuildExplosion(nSprite);
+
+ int i;
+
+ for (i = 0; i < 10; i++)
+ {
+ BlowChunks(nSprite);
+ }
+
+ for (i = 0; i < 20; i++)
+ {
+ BuildLavaLimb(nSprite, i, GetSpriteHeight(nSprite));
+ }
+
+ runlist_SubRunRec(sprite[nSprite].owner);
+ runlist_SubRunRec(QueenHead.field_8);
+ mydeletesprite(nSprite);
+ runlist_ChangeChannel(QueenChan[0], 1);
+ }
+ else
+ {
+ if (QueenHead.field_E >= 15 || QueenHead.field_E < 10)
+ {
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ int z = sprite[nSprite].z;
+ short nSector = sprite[nSprite].sectnum;
+
+ sprite[nSprite].xrepeat = 127 - QueenHead.field_E;
+ sprite[nSprite].yrepeat = 127 - QueenHead.field_E;
+
+ sprite[nSprite].cstat = 0x8000;
+
+ int dx = Sin((RandomSize(11) & kAngleMask) + 512) << 10;
+ int dy = Sin(RandomSize(11) & kAngleMask) << 10;
+ int dz = (RandomSize(5) - RandomSize(5)) << 7;
+
+ int nMov = movesprite(nSprite, dx, dy, dz, 0, 0, CLIPMASK1);
+
+ BlowChunks(nSprite);
+ BuildExplosion(nSprite);
+
+ mychangespritesect(nSprite, nSector);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+
+ if (QueenHead.field_E >= 10) {
+ return;
+ }
+
+ int ecx = (10 - QueenHead.field_E) * 2;
+
+ while (ecx > 0)
+ {
+ BuildLavaLimb(nSprite, ecx, GetSpriteHeight(nSprite));
+ ecx--;
+ }
+ }
+ }
+
+ return;
+ }
+
+ case 6:
+ {
+ if (var_14 != 0)
+ {
+ QueenHead.nAction = 1;
+ QueenHead.field_2 = 0;
+ return;
+ }
+ else
+ {
+ if ((sprite[nTarget].z - 51200) > sprite[nSprite].z)
+ {
+ QueenHead.nAction = 4;
+ QueenHead.field_2 = 0;
+ return;
+ }
+ else
+ {
+ sprite[nSprite].z -= 2048;
+ }
+ }
+
+ break;
+ }
+ }
+
+ // switch break. MoveQS stuff?
+ MoveQX[nQHead] = sprite[nSprite].x;
+ MoveQY[nQHead] = sprite[nSprite].y;
+ MoveQZ[nQHead] = sprite[nSprite].z;
+ assert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors);
+ MoveQS[nQHead] = sprite[nSprite].sectnum;
+ MoveQA[nQHead] = sprite[nSprite].ang;
+
+ short nHd = nQHead;
+
+ for (int i = 0; i < QueenHead.field_E; i++)
+ {
+ nHd -= 3;
+ if (nHd < 0) {
+ nHd += (24 + 1); // TODO - enum/define for these
+ //assert(nHd < 24 && nHd >= 0);
+ }
+
+ int var_20 = MoveQS[nHd];
+ short nTSprite = tailspr[i];
+
+ if (var_20 != sprite[nTSprite].sectnum)
+ {
+ assert(var_20 >= 0 && var_20 < kMaxSectors);
+ mychangespritesect(nSprite, var_20);
+ }
+
+ sprite[nTSprite].x = MoveQX[nHd];
+ sprite[nTSprite].y = MoveQY[nHd];
+ sprite[nTSprite].z = MoveQZ[nHd];
+ sprite[nTSprite].ang = MoveQA[nHd];
+ }
+
+ nQHead++;
+ if (nQHead >= 25)
+ {
+ nQHead = 0;
+ }
+
+ return;
+ }
+ }
+}
+
+int BuildQueen(int nSprite, int x, int y, int z, int nSector, int nAngle, int nChannel)
+{
+ int xVal = x;
+ int yVal = y;
+ int zVal = z;
+
+ QueenCount--;
+
+ short nQueen = QueenCount;
+ if (nQueen < 0) {
+ return -1;
+ }
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(nSector, 121);
+ }
+ else
+ {
+ changespritestat(nSprite, 121);
+ yVal = sprite[nSprite].y;
+ zVal = sector[sprite[nSprite].sectnum].floorz;
+ nAngle = sprite[nSprite].ang;
+ }
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = xVal;
+ sprite[nSprite].y = yVal;
+ sprite[nSprite].z = zVal;
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].pal = 0;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].clipdist = 100;
+ sprite[nSprite].xrepeat = 80;
+ sprite[nSprite].yrepeat = 80;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].extra = -1;
+ sprite[nSprite].hitag = 0;
+
+ GrabTimeSlot(3);
+
+ QueenList[nQueen].nAction = 0;
+ QueenList[nQueen].nHealth = 20; //4000;
+ QueenList[nQueen].field_2 = 0;
+ QueenList[nQueen].nSprite = nSprite;
+ QueenList[nQueen].nTarget = -1;
+ QueenList[nQueen].field_A = 0;
+ QueenList[nQueen].field_10 = 5;
+ QueenList[nQueen].field_C = 0;
+
+ QueenChan[nQueen] = nChannel;
+
+ nHeadVel = 800;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nQueen | 0x1A0000);
+
+ runlist_AddRunRec(NewRun, nQueen | 0x1A0000);
+
+ nCreaturesLeft++;
+
+ return nQueen | 0x1A0000;
+}
+
+void SetQueenSpeed(short nSprite, int nSpeed)
+{
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> (2 - nSpeed);
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> (2 - nSpeed);
+}
+
+void FuncQueen(int a, int nDamage, int nRun)
+{
+ int var_18 = 0;
+
+ short nQueen = RunData[nRun].nVal;
+ assert(nQueen >= 0 && nQueen < kMaxQueens);
+
+ int nMessage = a & 0x7F0000;
+
+ short nSprite = QueenList[nQueen].nSprite;
+ short nAction = QueenList[nQueen].nAction;
+ short si = QueenList[nQueen].field_A;
+ short nTarget = QueenList[nQueen].nTarget;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Queen\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ if (sprite[nRadialSpr].statnum == 121) {
+ return;
+ }
+
+ if (!(sprite[nSprite].cstat & 0x101)) {
+ return;
+ }
+
+ nDamage = runlist_CheckRadialDamage(nSprite);
+
+ if (!nDamage) {
+ return;
+ }
+ } // fall through to case 0x80000
+
+ case 0x80000:
+ {
+ if (QueenList[nQueen].nHealth <= 0) {
+ return;
+ }
+
+ QueenList[nQueen].nHealth -= nDamage;
+
+ if (QueenList[nQueen].nHealth > 0)
+ {
+ if (si <= 0) {
+ return;
+ }
+
+ if (RandomSize(4)) {
+ return;
+ }
+
+ QueenList[nQueen].nAction = 7;
+ QueenList[nQueen].field_2 = 0;
+ return;
+ }
+ else
+ {
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+
+ QueenList[nQueen].field_A++;
+
+ short dx = QueenList[nQueen].field_A;
+
+ if (QueenList[nQueen].field_A == 1)
+ {
+ QueenList[nQueen].nHealth = 20; //4000;
+ QueenList[nQueen].nAction = 7;
+
+ BuildAnim(-1, 36, 0, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z - 7680, sprite[nSprite].sectnum, sprite[nSprite].xrepeat, 4);
+ }
+ else if (QueenList[nQueen].field_A == 2)
+ {
+ QueenList[nQueen].nHealth = 20; // 4000;
+ QueenList[nQueen].nAction = 7;
+
+ DestroyAllEggs();
+ }
+ else if (QueenList[nQueen].field_A == 3)
+ {
+ QueenList[nQueen].nAction = 8;
+ QueenList[nQueen].nHealth = 0;
+
+ nCreaturesLeft--;
+ }
+
+ QueenList[nQueen].field_2 = 0;
+ }
+
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, SeqOffsets[kSeqQueen] + ActionSeq[nAction].a, QueenList[nQueen].field_2, ActionSeq[nAction].b);
+ return;
+ }
+
+ case 0x20000:
+ {
+ if (si < 3) {
+ Gravity(nSprite);
+ }
+
+ short nSeq = SeqOffsets[kSeqQueen] + ActionSeq[nAction].a;
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, QueenList[nQueen].field_2);
+
+ seq_MoveSequence(nSprite, nSeq, QueenList[nQueen].field_2);
+
+ QueenList[nQueen].field_2++;
+ if (QueenList[nQueen].field_2 >= SeqSize[nSeq])
+ {
+ QueenList[nQueen].field_2 = 0;
+ var_18 = 1;
+ }
+
+ short nFlag = FrameFlag[SeqBase[nSeq] + QueenList[nQueen].field_2];
+
+ if (nTarget > -1)
+ {
+ if (nAction < 7)
+ {
+ if (!(sprite[nSprite].cstat & 0x101))
+ {
+ nTarget = -1;
+ QueenList[nQueen].nTarget = -1;
+ QueenList[nQueen].nAction = 0;
+ }
+ }
+ }
+
+ if (nAction > 10) {
+ return;
+ }
+
+ switch (nAction)
+ {
+ case 0:
+ {
+ if (nTarget < 0)
+ {
+ nTarget = FindPlayer(nSprite, 60);
+ }
+
+ if (nTarget < 0) {
+ return;
+ }
+
+ QueenList[nQueen].nAction = QueenList[nQueen].field_A + 1;
+ QueenList[nQueen].field_2 = 0;
+ QueenList[nQueen].nTarget = nTarget;
+ QueenList[nQueen].field_C = RandomSize(7);
+
+ SetQueenSpeed(nSprite, si);
+
+ return;
+ }
+
+ case 1:
+ case 2:
+ case 3:
+ {
+ QueenList[nQueen].field_C--;
+
+ if ((nQueen & 0x1F) == (totalmoves & 0x1F))
+ {
+ if (si < 2)
+ {
+ if (QueenList[nQueen].field_C > 0)
+ {
+ if (QueenList[nQueen].field_10 < 5)
+ {
+ QueenList[nQueen].field_10++;
+ }
+
+ // then to PLOTSPRITE
+ }
+ else
+ {
+ QueenList[nQueen].field_2 = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ QueenList[nQueen].nAction = si + 4;
+ QueenList[nQueen].field_C = RandomSize(6) + 30;
+ return;
+ }
+ }
+ else
+ {
+ if (QueenList[nQueen].field_C <= 0)
+ {
+ if (nWaspCount < 100)
+ {
+ QueenList[nQueen].nAction = 6;
+ QueenList[nQueen].field_2 = 0;
+ return;
+ }
+ else
+ {
+ QueenList[nQueen].field_C = 30000;
+ // then to PLOTSPRITE
+ }
+ }
+ }
+
+ // loc_35B4B
+ PlotCourseToSprite(nSprite, nTarget);
+ SetQueenSpeed(nSprite, si);
+ }
+
+ int nMov = MoveCreatureWithCaution(nSprite);
+
+ if ((nMov & 0xC000) == 0xC000)
+ {
+ if ((si == 2) && ((nMov & 0x3FFF) == nTarget))
+ {
+ runlist_DamageEnemy(nTarget, nSprite, 5);
+ }
+ else
+ {
+ sprite[nSprite].ang += 256;
+ sprite[nSprite].ang &= kAngleMask;
+
+ SetQueenSpeed(nSprite, si);
+ }
+ }
+ else if ((nMov & 0xC000) == 0x8000)
+ {
+ sprite[nSprite].ang += 256;
+ sprite[nSprite].ang &= kAngleMask;
+
+ SetQueenSpeed(nSprite, si);
+ }
+
+ // loc_35BD2
+ if (nAction && nTarget != -1)
+ {
+ if (!(sprite[nTarget].cstat & 0x101))
+ {
+ QueenList[nQueen].nAction = 0;
+ QueenList[nQueen].field_2 = 0;
+ QueenList[nQueen].field_C = 100;
+ QueenList[nQueen].nTarget = -1;
+
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ return;
+ }
+ }
+
+ return;
+ }
+
+ case 4:
+ case 5:
+ {
+ if (var_18 && QueenList[nQueen].field_10 <= 0)
+ {
+ QueenList[nQueen].nAction = 0;
+ QueenList[nQueen].field_C = 15;
+ }
+ else
+ {
+ if (nFlag & 0x80)
+ {
+ QueenList[nQueen].field_10--;
+
+ PlotCourseToSprite(nSprite, nTarget);
+
+ if (si)
+ {
+ BuildQueenEgg(nQueen, 0);
+ }
+ else
+ {
+ BuildBullet(nSprite, 12, 0, 0, -1, sprite[nSprite].ang, nTarget + 10000, 1);
+ }
+ }
+ }
+
+ return;
+ }
+
+ case 6:
+ {
+ if (var_18)
+ {
+ BuildQueenEgg(nQueen, 1);
+ QueenList[nQueen].nAction = 3;
+ QueenList[nQueen].field_C = RandomSize(6) + 60;
+ }
+
+ return;
+ }
+
+ case 7:
+ {
+ if (var_18)
+ {
+ QueenList[nQueen].nAction = 0;
+ QueenList[nQueen].field_2 = 0;
+ }
+
+ return;
+ }
+
+ case 8:
+ case 9:
+ {
+ if (var_18)
+ {
+ if (nAction != 9)
+ {
+ QueenList[nQueen].nAction++;
+ return;
+ }
+
+ QueenList[nQueen].field_C--;
+ if (QueenList[nQueen].field_C <= 0)
+ {
+ sprite[nSprite].cstat = 0;
+
+ for (int i = 0; i < 20; i++)
+ {
+ short nChunkSprite = BuildCreatureChunk(nSprite, seq_GetSeqPicnum(kSeqQueen, 57, 0)) & 0xFFFF;
+
+ sprite[nChunkSprite].picnum = i % 3 + 3117;
+ sprite[nChunkSprite].yrepeat = 100;
+ sprite[nChunkSprite].xrepeat = 100;
+ }
+
+ short nChunkSprite = BuildCreatureChunk(nSprite, seq_GetSeqPicnum(kSeqQueen, 57, 0));
+
+ sprite[nChunkSprite].picnum = 3126;
+ sprite[nChunkSprite].yrepeat = 100;
+ sprite[nChunkSprite].xrepeat = 100;
+/* TODO
+ PlayFXAtXYZ(
+ StaticSound[40],
+ sprite[nSprite].x,
+ sprite[nSprite].y,
+ sprite[nSprite].z,
+ sprite[nSprite].sectnum);
+*/
+ BuildQueenHead(nQueen);
+
+ QueenList[nQueen].nAction++;
+ }
+ }
+
+ return;
+ }
+
+ case 10:
+ {
+ sprite[nSprite].cstat &= 0xFEFE;
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/source/exhumed/src/queen.h b/source/exhumed/src/queen.h
new file mode 100644
index 000000000..d652d0239
--- /dev/null
+++ b/source/exhumed/src/queen.h
@@ -0,0 +1,13 @@
+
+#ifndef __queen_h__
+#define __queen_h__
+
+void InitQueens();
+
+int BuildQueen(int nSprite, int x, int y, int z, int nSector, int nAngle, int nVal);
+
+void FuncQueenEgg(int, int, int);
+void FuncQueenHead(int, int, int);
+void FuncQueen(int, int, int);
+
+#endif
diff --git a/source/exhumed/src/ra.cpp b/source/exhumed/src/ra.cpp
new file mode 100644
index 000000000..76ccc57fa
--- /dev/null
+++ b/source/exhumed/src/ra.cpp
@@ -0,0 +1,276 @@
+
+#include "ra.h"
+#include "runlist.h"
+#include "engine.h"
+#include "exhumed.h"
+#include "player.h"
+#include "move.h"
+#include "sequence.h"
+#include "input.h"
+#include "gun.h"
+#include "bullet.h"
+#include
+
+/* bjd - the content of the ra.* files originally resided in gun.c I think... */
+
+//#define kMaxRA 8
+
+RA Ra[kMaxPlayers]; // one Ra for each player
+short RaCount;
+
+static actionSeq ActionSeq[] = {
+ {2, 1}, {0, 0}, {1, 0}, {2, 0}
+};
+
+void FreeRa(short nPlayer)
+{
+ int nRun = Ra[nPlayer].field_4;
+ int nSprite = Ra[nPlayer].nSprite;
+
+ runlist_SubRunRec(nRun);
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+
+ mydeletesprite(nSprite);
+}
+
+int BuildRa(short nPlayer)
+{
+ short nPlayerSprite = PlayerList[nPlayer].nSprite;
+
+ int nSprite = insertsprite(sprite[nPlayerSprite].sectnum, 203);
+
+ sprite[nSprite].cstat = 0x8000;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].extra = -1;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nPlayer | 0x210000);
+ sprite[nSprite].pal = 1;
+ sprite[nSprite].xrepeat = 64;
+ sprite[nSprite].yrepeat = 64;
+ sprite[nSprite].x = sprite[nPlayerSprite].x;
+ sprite[nSprite].y = sprite[nPlayerSprite].y;
+ sprite[nSprite].z = sprite[nPlayerSprite].z;
+
+// GrabTimeSlot(3);
+
+ Ra[nPlayer].nSprite = nSprite;
+
+ Ra[nPlayer].field_4 = runlist_AddRunRec(NewRun, nPlayer | 0x210000);
+ Ra[nPlayer].nTarget = -1;
+ Ra[nPlayer].field_2 = 0;
+ Ra[nPlayer].field_0 = 0;
+ Ra[nPlayer].field_C = 0;
+ Ra[nPlayer].field_E = nPlayer;
+
+ return nPlayer | 0x210000;
+}
+
+void InitRa()
+{
+ RaCount = 0;
+ memset(Ra, 0, sizeof(RA) * kMaxPlayers);
+}
+
+void MoveRaToEnemy(short nPlayer)
+{
+ short nTarget = Ra[nPlayer].nTarget;
+ short nSprite = Ra[nPlayer].nSprite;
+ short field_0 = Ra[nPlayer].field_0;
+
+ if (nTarget != -1)
+ {
+ if (!(sprite[nTarget].cstat & 0x101) || sprite[nTarget].sectnum == kMaxSectors)
+ {
+ Ra[nPlayer].nTarget = -1;
+ if (!field_0 || field_0 == 3) {
+ return;
+ }
+
+ Ra[nPlayer].field_0 = 3;
+ Ra[nPlayer].field_2 = 0;
+ return;
+ }
+ else
+ {
+ if (sprite[nSprite].sectnum != sprite[nTarget].sectnum) {
+ mychangespritesect(nSprite, sprite[nTarget].sectnum);
+ }
+ }
+ }
+ else
+ {
+ if (field_0 == 1 || field_0 == 2)
+ {
+ Ra[nPlayer].field_0 = 3;
+ Ra[nPlayer].field_2 = 0;
+ return;
+ }
+
+ if (field_0) {
+ return;
+ }
+
+ sprite[nSprite].cstat = 0x8000;
+ nTarget = PlayerList[nPlayer].nSprite;
+ }
+
+ sprite[nSprite].x = sprite[nTarget].x;
+ sprite[nSprite].y = sprite[nTarget].y;
+ sprite[nSprite].z = sprite[nTarget].z - GetSpriteHeight(nTarget);
+
+ if (sprite[nSprite].sectnum != sprite[nTarget].sectnum) {
+ mychangespritesect(nSprite, sprite[nTarget].sectnum);
+ }
+}
+
+void FuncRa(int a, int nDamage, int nRun)
+{
+ short nPlayer = RunData[nRun].nVal;
+ short nCurrentWeapon = PlayerList[nPlayer].nCurrentWeapon;
+
+ int var_14 = 0;
+
+ short edx = SeqOffsets[kSeqEyeHit] + ActionSeq[Ra[nPlayer].field_0].a;
+ short nSprite = Ra[nPlayer].nSprite;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Ra\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0x30000:
+ case 0xA0000:
+ return;
+
+ case 0x20000:
+ {
+ Ra[nPlayer].nTarget = sPlayerInput[nPlayer].nTarget;
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(edx, Ra[nPlayer].field_2);
+
+ if (Ra[nPlayer].field_0)
+ {
+ seq_MoveSequence(nSprite, edx, Ra[nPlayer].field_2);
+
+ Ra[nPlayer].field_2++;
+ if (Ra[nPlayer].field_2 >= SeqSize[edx])
+ {
+ Ra[nPlayer].field_2 = 0;
+ var_14 = 1;
+ }
+ }
+
+ switch (Ra[nPlayer].field_0)
+ {
+ case 0:
+ {
+ MoveRaToEnemy(nPlayer);
+
+ if (!Ra[nPlayer].field_C || Ra[nPlayer].nTarget <= -1)
+ {
+ sprite[nSprite].cstat = 0x8000;
+ }
+ else
+ {
+ sprite[nSprite].cstat &= 0x7FFF;
+ Ra[nPlayer].field_0 = 1;
+ Ra[nPlayer].field_2 = 0;
+ }
+
+ return;
+ }
+
+ case 1:
+ {
+ if (!Ra[nPlayer].field_C)
+ {
+ Ra[nPlayer].field_0 = 3;
+ Ra[nPlayer].field_2 = 0;
+ }
+ else
+ {
+ if (var_14) {
+ Ra[nPlayer].field_0 = 2;
+ }
+
+ MoveRaToEnemy(nPlayer);
+ }
+
+ return;
+ }
+
+ case 2:
+ {
+ MoveRaToEnemy(nPlayer);
+
+ if (nCurrentWeapon != kWeaponRing)
+ {
+ Ra[nPlayer].field_0 = 3;
+ Ra[nPlayer].field_2 = 0;
+ }
+ else
+ {
+ if (Ra[nPlayer].field_2 || Ra[nPlayer].nTarget <= -1)
+ {
+ if (!var_14) {
+ return;
+ }
+
+ Ra[nPlayer].field_0 = 3;
+ Ra[nPlayer].field_2 = 0;
+ }
+ else
+ {
+ if (PlayerList[nPlayer].nAmmo[kWeaponRing] > 0)
+ {
+ runlist_DamageEnemy(Ra[nPlayer].nTarget, PlayerList[Ra[nPlayer].field_E].nSprite, BulletInfo[kWeaponRing].nDamage);
+ AddAmmo(nPlayer, kWeaponRing, -WeaponInfo[kWeaponRing].d);
+ SetQuake(nSprite, 100);
+ }
+ else
+ {
+ Ra[nPlayer].field_0 = 3;
+ Ra[nPlayer].field_2 = 0;
+ SelectNewWeapon(nPlayer);
+ }
+ }
+ }
+
+ return;
+ }
+
+ case 3:
+ {
+ if (var_14)
+ {
+ sprite[nSprite].cstat |= 0x8000;
+ Ra[nPlayer].field_0 = 0;
+ Ra[nPlayer].field_2 = 0;
+ Ra[nPlayer].field_C = 0;
+ }
+
+ return;
+ }
+
+ default:
+ return;
+ }
+ }
+
+ case 0x90000:
+ {
+ short nSprite2 = a & 0xFFFF;
+ seq_PlotSequence(nSprite2, edx, Ra[nPlayer].field_2, 1);
+ tsprite[nSprite2].owner = -1;
+ return;
+ }
+ }
+}
diff --git a/source/exhumed/src/ra.h b/source/exhumed/src/ra.h
new file mode 100644
index 000000000..ca1b5a36c
--- /dev/null
+++ b/source/exhumed/src/ra.h
@@ -0,0 +1,25 @@
+
+#ifndef __ra_h__
+#define __ra_h__
+
+struct RA
+{
+ short field_0;
+ short field_2;
+ short field_4;
+ short nSprite;
+ short nTarget;
+ short field_A;
+ short field_C;
+ short field_E;
+};
+
+extern RA Ra[];
+
+void FreeRa(short nPlayer);
+int BuildRa(short nPlayer);
+void InitRa();
+void MoveRaToEnemy(short nPlayer);
+void FuncRa(int, int, int);
+
+#endif
diff --git a/source/exhumed/src/random.cpp b/source/exhumed/src/random.cpp
new file mode 100644
index 000000000..173d8987f
--- /dev/null
+++ b/source/exhumed/src/random.cpp
@@ -0,0 +1,63 @@
+
+#include "random.h"
+
+int randA = 0;
+int randB = 0x11111111;
+int randC = 0x1010101;
+
+
+void InitRandom()
+{
+ randA = 0;
+ randB = 0x11111111;
+ randC = 0x1010101;
+}
+
+// TODO - checkme
+int RandomBit()
+{
+ randA = (randA >> 1) | (((randA ^ ((randA >> 1) ^ (randA >> 2) ^ (randA >> 31) ^ (randA >> 6) ^ (randA >> 4))) & 1) << 31);
+ randB = (randB >> 1) | ((((randB >> 2) ^ (randB >> 30)) & 1) << 30);
+ randC = (randC >> 1) | ((((randC >> 1) ^ (randC >> 28)) & 1) << 28);
+ return ((randA == 0) & randC | (randB & randA)) & 1;
+}
+
+char RandomByte()
+{
+ char randByte = RandomBit() << 7;
+ randByte |= RandomBit() << 6;
+ randByte |= RandomBit() << 5;
+ randByte |= RandomBit() << 4;
+ randByte |= RandomBit() << 3;
+ randByte |= RandomBit() << 2;
+ randByte |= RandomBit() << 1;
+ randByte |= RandomBit();
+ return randByte;
+}
+
+short RandomWord()
+{
+ short randWord = RandomByte() << 8;
+ randWord |= RandomByte();
+ return randWord;
+}
+
+long RandomLong()
+{
+ long randLong = RandomWord() << 16;
+ randLong |= RandomWord();
+ return randLong;
+}
+
+int RandomSize(int nSize)
+{
+ int randSize = 0;
+
+ while (nSize > 0)
+ {
+ randSize = randSize * 2 | RandomBit();
+ nSize--;
+ }
+
+ return randSize;
+}
diff --git a/source/exhumed/src/random.h b/source/exhumed/src/random.h
new file mode 100644
index 000000000..b41430247
--- /dev/null
+++ b/source/exhumed/src/random.h
@@ -0,0 +1,12 @@
+
+#ifndef __random_h__
+#define __random_h__
+
+void InitRandom();
+int RandomBit();
+char RandomByte();
+short RandomWord();
+long RandomLong();
+int RandomSize(int nSize);
+
+#endif
diff --git a/source/exhumed/src/rat.cpp b/source/exhumed/src/rat.cpp
new file mode 100644
index 000000000..927fef919
--- /dev/null
+++ b/source/exhumed/src/rat.cpp
@@ -0,0 +1,383 @@
+
+#include "engine.h"
+#include "rat.h"
+#include "sequence.h"
+#include "runlist.h"
+#include "random.h"
+#include "view.h"
+#include "init.h"
+#include "exhumed.h"
+#include "move.h"
+#include
+
+#define kMaxRats 50
+
+short nMinChunk;
+short nPlayerPic; // why is this here?
+short nRatCount;
+short nMaxChunk;
+
+struct Rat
+{
+ short a;
+ short nAction;
+ short nSprite;
+ short d;
+ short nTarget;
+ short f;
+ short g;
+ short _pad;
+};
+
+Rat RatList[kMaxRats];
+
+static actionSeq ActionSeq[] = { { 0, 1}, {1, 0}, {1, 0}, {9, 1}, {0, 1} };
+
+
+void InitRats()
+{
+ nRatCount = 0;
+ nMinChunk = 9999;
+ nMaxChunk = -1;
+
+ for (int i = 122; i < 131; i++)
+ {
+ int nPic = seq_GetSeqPicnum(kSeqJoe, i, 0);
+
+ if (nPic < nMinChunk)
+ nMinChunk = nPic;
+
+ if (nPic > nMaxChunk)
+ nMaxChunk = nPic;
+ }
+
+ nPlayerPic = seq_GetSeqPicnum(kSeqJoe, 120, 0);
+}
+
+void SetRatVel(short nSprite)
+{
+ sprite[nSprite].xvel = (short)Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nSprite].yvel = (short)Sin(sprite[nSprite].ang) >> 2;
+}
+
+int BuildRat(short nSprite, int x, int y, int z, short nSector, int nAngle)
+{
+ if (nRatCount >= kMaxRats) {
+ return -1;
+ }
+
+ short nRat = nRatCount++;
+
+ if (nSprite < 0)
+ {
+ nSprite = insertsprite(nSector, 108);
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ }
+ else
+ {
+ sprite[nSprite].ang = nAngle;
+ changespritestat(nSprite, 108);
+ }
+
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ sprite[nSprite].clipdist = 30;
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].xrepeat = 50;
+ sprite[nSprite].yrepeat = 50;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].extra = -1;
+
+ if (nAngle >= 0) {
+ RatList[nRat].nAction = 2;
+ }
+ else {
+ RatList[nRat].nAction = 4;
+ }
+
+ RatList[nRat].a = 0;
+ RatList[nRat].nSprite = nSprite;
+ RatList[nRat].nTarget = -1;
+ RatList[nRat].f = RandomSize(5);
+ RatList[nRat].g = RandomSize(3);
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nRat | 0x240000);
+
+ RatList[nRat].d = runlist_AddRunRec(NewRun, nRat | 0x240000);
+ return 0;
+}
+
+int FindFood(short nSprite)
+{
+ short nSector = sprite[nSprite].sectnum;
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ int z = sprite[nSprite].z;
+
+ int z2 = z + sector[nSector].ceilingz;
+
+ if (nChunkTotal)
+ {
+ int nSprite2 = nChunkSprite[RandomSize(7) % nChunkTotal];
+ if (nSprite2 != -1)
+ {
+ if (cansee(x, y, z2, nSector, sprite[nSprite2].x, sprite[nSprite2].y, sprite[nSprite2].z, sprite[nSprite2].sectnum)) {
+ return nSprite2;
+ }
+ }
+ }
+
+ if (!nBodyTotal) {
+ return -1;
+ }
+
+ int nSprite2 = nChunkSprite[RandomSize(7) % nBodyTotal];
+ if (nSprite2 != -1)
+ {
+ if (nPlayerPic == sprite[nSprite2].picnum)
+ {
+ if (cansee(x, y, z, nSector, sprite[nSprite2].x, sprite[nSprite2].y, sprite[nSprite2].z, sprite[nSprite2].sectnum)) {
+ return nSprite2;
+ }
+ }
+ }
+
+ return -1;
+}
+
+void FuncRat(int a, int nDamage, int nRun)
+{
+ short nRat = RunData[nRun].nVal;
+ short nSprite = RatList[nRat].nSprite;
+
+ short nAction = RatList[nRat].nAction;
+
+ int var_20 = 0;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Rathead\n", nMessage);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ // fall through to 0x80000
+ }
+ case 0x80000:
+ {
+ if (nDamage)
+ {
+ sprite[nSprite].cstat = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ RatList[nRat].nAction = 3;
+ RatList[nRat].a = 0;
+ }
+ break;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a, SeqOffsets[kSeqRat] + ActionSeq[nAction].a, RatList[nRat].a, ActionSeq[nAction].b);
+ return;
+ }
+
+ case 0x20000:
+ {
+ int nSeq = SeqOffsets[kSeqRat] + ActionSeq[nAction].a;
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, RatList[nRat].a);
+
+ seq_MoveSequence(nSprite, nSeq, RatList[nRat].a);
+
+ RatList[nRat].a++;
+ if (RatList[nRat].a >= SeqSize[nSeq])
+ {
+ var_20 = 1;
+ RatList[nRat].a = 0;
+ }
+
+ short nTarget = RatList[nRat].nTarget;
+
+ Gravity(nSprite);
+
+ switch (nAction)
+ {
+ default:
+ {
+ return;
+ }
+
+ case 0:
+ {
+ RatList[nRat].f--;
+ if (RatList[nRat].f > 0) {
+ return;
+ }
+
+ int xVal = sprite[nSprite].x - sprite[nTarget].x;
+ if (xVal < 0) {
+ xVal = -xVal;
+ }
+
+ int yVal = sprite[nSprite].y - sprite[nTarget].y;
+ if (yVal < 0) {
+ yVal = -yVal;
+ }
+
+ if (xVal > 50 || yVal > 50)
+ {
+ RatList[nRat].nAction = 2;
+ RatList[nRat].a = 0;
+ RatList[nRat].nTarget = -1;
+
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ return;
+ }
+
+ RatList[nRat].a ^= 1;
+ RatList[nRat].f = RandomSize(5) + 4;
+ RatList[nRat].g--;
+
+ if (RatList[nRat].g <= 0)
+ {
+ short nFoodSprite = FindFood(nSprite);
+ if (nFoodSprite == -1) {
+ return;
+ }
+
+ RatList[nRat].nTarget = nFoodSprite;
+
+ PlotCourseToSprite(nSprite, nFoodSprite);
+ SetRatVel(nSprite);
+
+ RatList[nRat].nAction = 1;
+ RatList[nRat].g = 900;
+ RatList[nRat].a = 0;
+ }
+
+ return;
+ }
+ case 1:
+ {
+ RatList[nRat].g--;
+
+ if (RatList[nRat].g <= 0)
+ {
+ RatList[nRat].nAction = 2;
+ RatList[nRat].a = 0;
+ sprite[nSprite].yvel = 0;
+ RatList[nRat].nTarget = -1;
+ sprite[nSprite].xvel = 0;
+ }
+
+ MoveCreature(nSprite);
+
+ int xVal = sprite[nSprite].x - sprite[nTarget].x;
+ if (xVal < 0) {
+ xVal = -xVal;
+ }
+
+ int yVal = sprite[nSprite].y - sprite[nTarget].y;
+ if (yVal < 0) {
+ yVal = -yVal;
+ }
+
+ if (xVal >= 50 || yVal >= 50)
+ {
+ RatList[nRat].f--;
+ if (RatList[nRat].f < 0)
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+ SetRatVel(nSprite);
+
+ RatList[nRat].f = 32;
+ }
+
+ return;
+ }
+
+ RatList[nRat].nAction = 0;
+ RatList[nRat].a = 0;
+
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+
+ RatList[nRat].g = RandomSize(3);
+ return;
+ }
+ case 2:
+ {
+ if (sprite[nSprite].xvel | sprite[nSprite].yvel | sprite[nSprite].zvel) {
+ MoveCreature(nSprite);
+ }
+
+ RatList[nRat].f--;
+ if (RatList[nRat].f <= 0)
+ {
+ RatList[nRat].nTarget = FindFood(nSprite);
+
+ if (RatList[nRat].nTarget <= -1)
+ {
+ RatList[nRat].f = RandomSize(6);
+ if (sprite[nSprite].xvel | sprite[nSprite].yvel)
+ {
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ return;
+ }
+
+ sprite[nSprite].ang = RandomSize(11);
+ SetRatVel(nSprite);
+ return;
+ }
+ else
+ {
+ PlotCourseToSprite(nSprite, RatList[nRat].nTarget);
+ SetRatVel(nSprite);
+ RatList[nRat].nAction = 1;
+ RatList[nRat].g = 900;
+ RatList[nRat].a = 0;
+ return;
+ }
+ }
+
+ return;
+ }
+ case 3:
+ {
+ if (var_20 != 0)
+ {
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+ runlist_SubRunRec(RatList[nRat].d);
+
+ sprite[nSprite].cstat = 0x8000;
+ mydeletesprite(nSprite);
+ }
+ return;
+ }
+ }
+
+ break;
+ }
+ }
+}
diff --git a/source/exhumed/src/rat.h b/source/exhumed/src/rat.h
new file mode 100644
index 000000000..6984c62eb
--- /dev/null
+++ b/source/exhumed/src/rat.h
@@ -0,0 +1,11 @@
+
+#ifndef __rat_h__
+#define __rat_h__
+
+void InitRats();
+void SetRatVel(short nSprite);
+int BuildRat(short nSprite, int x, int y, int z, short nSector, int nAngle);
+int FindFood(short nSprite);
+void FuncRat(int a, int b, int nRun);
+
+#endif
diff --git a/source/exhumed/src/record.cpp b/source/exhumed/src/record.cpp
new file mode 100644
index 000000000..0fed613fa
--- /dev/null
+++ b/source/exhumed/src/record.cpp
@@ -0,0 +1,152 @@
+
+#include "record.h"
+#include "typedefs.h"
+#include "save.h"
+#include
+#include
+
+short record_mode = 0;
+int record_limit = -1;
+int record_index = 16384;
+uchar record_buffer[16384];
+FILE *record_file;
+
+struct RecordHeader
+{
+ char signature[4];
+ short b;
+};
+
+RecordHeader record_head;
+
+
+BYTE GetRecord()
+{
+ if (record_index >= 16384)
+ {
+ record_index = 0;
+
+ int nRead = fread(record_buffer, 1, 16384, record_file);
+
+ if (nRead < 16384) {
+ record_limit = 16384;
+ }
+ else {
+ record_limit = -1;
+ }
+ }
+
+ if (record_limit > 0)
+ {
+ if (record_limit <= record_index)
+ {
+ record_mode = 3;
+ }
+ }
+
+ return record_buffer[record_index++];
+}
+
+void PutRecord(BYTE record)
+{
+ BYTE val_10 = record;
+
+ if (record_index >= 16384)
+ {
+ record_index = 0;
+
+ fwrite(record_buffer, 16384, 1, record_file);
+ }
+
+ record_buffer[record_index++] = val_10;
+}
+
+int OpenRecord(const char *filename, short *edx)
+{
+ record_file = fopen(filename, "rb");
+ if (record_file)
+ {
+ if (!fread(&record_head, sizeof(record_head), 1, record_file)) {
+ return 0;
+ }
+
+ if (memcmp(record_head.signature, "LOBO", 4) == 0) {
+ return 0;
+ }
+
+ *edx = record_head.b;
+
+ record_index = 16384;
+ record_limit = -1;
+ record_mode = 2;
+
+ return 1;
+ }
+ else
+ {
+ record_file = fopen(filename, "wb");
+ if (!record_file) {
+ return 0;
+ }
+
+ strncpy(record_head.signature, "LOBO", 4);
+ record_head.b = *edx;
+
+ if (!fwrite(&record_head, sizeof(record_head), 1, record_file)) {
+ return 0;
+ }
+
+ record_index = 0;
+ record_limit = -1;
+ record_mode = 1;
+
+ return 1;
+ }
+}
+
+int ExecRecord(BYTE *pRecord, int nSize)
+{
+ if (record_mode == 2)
+ {
+ for (int i = 0; i < nSize; i++)
+ {
+ pRecord[i] = GetRecord();
+ }
+ }
+ else if (record_mode == 1)
+ {
+ for (int i = 0; i < nSize; i++)
+ {
+ PutRecord(pRecord[i]);
+ }
+ }
+
+ if (record_mode == 3) {
+ return 0;
+ }
+ else {
+ return 1;
+ }
+}
+
+int CloseRecord()
+{
+ if (record_mode == 1)
+ {
+ loadgame(0);
+
+ if (record_index)
+ {
+ if (!fwrite(record_buffer, record_index, 1, record_file)) {
+ return 0;
+ }
+ }
+ }
+ else if (record_mode == 2 || record_mode == 3)
+ {
+ loadgame(1);
+ }
+
+ fclose(record_file);
+ return 1;
+}
diff --git a/source/exhumed/src/record.h b/source/exhumed/src/record.h
new file mode 100644
index 000000000..90df23d26
--- /dev/null
+++ b/source/exhumed/src/record.h
@@ -0,0 +1,7 @@
+
+#ifndef __record_h__
+#define __record_h__
+
+extern short record_mode;
+
+#endif
diff --git a/source/exhumed/src/rex.cpp b/source/exhumed/src/rex.cpp
new file mode 100644
index 000000000..922af493c
--- /dev/null
+++ b/source/exhumed/src/rex.cpp
@@ -0,0 +1,480 @@
+
+#include "rex.h"
+#include "exhumed.h"
+#include "engine.h"
+#include "runlist.h"
+#include "move.h"
+#include "sequence.h"
+#include "sound.h"
+#include "random.h"
+#include "trigdat.h"
+#include "player.h"
+#include "aistuff.h"
+#include
+
+#define kMaxRex 50
+
+short RexCount = 0;
+short RexChan[kMaxRex];
+
+struct Rex
+{
+ short nHealth;
+ short field_2;
+ short nAction;
+ short nSprite;
+ short nTarget;
+ short field_A;
+};
+
+Rex RexList[kMaxRex];
+
+static actionSeq ActionSeq[] = {
+ {29, 0},
+ {0, 0},
+ {0, 0},
+ {37, 0},
+ {9, 0},
+ {18, 0},
+ {27, 1},
+ {28, 1}
+};
+
+
+void InitRexs()
+{
+ RexCount = kMaxRex;
+}
+
+int BuildRex(short nSprite, int x, int y, int z, short nSector, short nAngle, int nVal)
+{
+ RexCount--;
+
+ int nRex = RexCount;
+ if (nRex < 0) {
+ return -1;
+ }
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(nSector, 119);
+ }
+ else
+ {
+ changespritestat(nSprite, 119);
+ x = sprite[nSprite].x;
+ y = sprite[nSprite].y;
+ z = sector[sprite[nSprite].sectnum].floorz;
+ nAngle = sprite[nSprite].ang;
+ }
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].z = z;
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].clipdist = 80;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].xrepeat = 64;
+ sprite[nSprite].yrepeat = 64;
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].extra = -1;
+
+ GrabTimeSlot(3);
+
+ RexList[nRex].nAction = 0;
+ RexList[nRex].nHealth = 4000;
+ RexList[nRex].field_2 = 0;
+ RexList[nRex].nSprite = nSprite;
+ RexList[nRex].nTarget = -1;
+ RexList[nRex].field_A = 0;
+ RexChan[nRex] = nVal;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nRex | 0x180000);
+
+ // this isn't stored anywhere...
+ runlist_AddRunRec(NewRun, nRex | 0x180000);
+
+ nCreaturesLeft++;
+
+ return nRex | 0x180000;
+}
+
+void FuncRex(int a, int nDamage, int nRun)
+{
+ short nRex = RunData[nRun].nVal;
+ assert(nRex >= 0 && nRex < kMaxRex);
+
+ int var_1C = 0;
+
+ short nAction = RexList[nRex].nAction;
+ short nSprite = RexList[nRex].nSprite;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Rex\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ if (nAction == 5)
+ {
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ }
+ // fall through to case 0x80000
+ }
+
+ case 0x80000:
+ {
+ if (nDamage)
+ {
+ short nTarget = a & 0xFFFF;
+ if (nTarget >= 0 && sprite[nTarget].statnum == 100)
+ {
+ RexList[nRex].nTarget = nTarget;
+ }
+
+ if (RexList[nRex].nAction == 5 && RexList[nRex].nHealth > 0)
+ {
+ RexList[nRex].nHealth -= nDamage;
+
+ if (RexList[nRex].nHealth <= 0)
+ {
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ RexList[nRex].nHealth = 0;
+ sprite[nSprite].cstat &= 0xFEFE;
+ nCreaturesLeft--;
+
+ if (nAction < 6)
+ {
+ RexList[nRex].nAction = 6;
+ RexList[nRex].field_2 = 0;
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, SeqOffsets[kSeqRex] + ActionSeq[nAction].a, RexList[nRex].field_2, ActionSeq[nAction].b);
+ return;
+ }
+
+ case 0x20000:
+ {
+ Gravity(nSprite);
+
+ int nSeq = SeqOffsets[kSeqRex] + ActionSeq[nAction].a;
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, RexList[nRex].field_2);
+
+ int ecx;
+
+ if (nAction != 2) {
+ ecx = 1;
+ }
+ else {
+ ecx = 2;
+ }
+
+ // moves the mouth open and closed as it's idle?
+ do
+ {
+ ecx--;
+
+ seq_MoveSequence(nSprite, nSeq, RexList[nRex].field_2);
+
+ RexList[nRex].field_2++;
+ if (RexList[nRex].field_2 >= SeqSize[nSeq])
+ {
+ RexList[nRex].field_2 = 0;
+ var_1C = 1;
+ }
+ } while (ecx != -1);
+
+ int nFlag = FrameFlag[SeqBase[nSeq] + RexList[nRex].field_2];
+
+ short nTarget = RexList[nRex].nTarget;
+
+ if (nAction > 7) {
+ return;
+ }
+
+ switch (nAction)
+ {
+ default:
+ return;
+
+ // OK
+ case 0:
+ {
+ if (!RexList[nRex].field_A)
+ {
+ if ((nRex & 0x1F) == (totalmoves & 0x1F))
+ {
+ if (nTarget < 0)
+ {
+ short nAngle = sprite[nSprite].ang; // make backup of this variable
+ RexList[nRex].nTarget = FindPlayer(nSprite, 60);
+ sprite[nSprite].ang = nAngle;
+ }
+ else
+ {
+ RexList[nRex].field_A = 60;
+ }
+ }
+ }
+ else
+ {
+ RexList[nRex].field_A--;
+ if (RexList[nRex].field_A <= 0)
+ {
+ RexList[nRex].nAction = 1;
+ RexList[nRex].field_2 = 0;
+
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
+
+ D3PlayFX(StaticSound[kSound48], nSprite);
+
+ RexList[nRex].field_A = 30;
+ }
+ }
+
+ return;
+ }
+
+ // OK
+ case 1:
+ {
+ if (RexList[nRex].field_A > 0)
+ {
+ RexList[nRex].field_A--;
+ }
+
+ if ((nRex & 0x0F) == (totalmoves & 0x0F))
+ {
+ if (!RandomSize(1))
+ {
+ RexList[nRex].nAction = 5;
+ RexList[nRex].field_2 = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ return;
+ }
+ else
+ {
+ if (((PlotCourseToSprite(nSprite, nTarget) >> 8) >= 60) || RexList[nRex].field_A > 0)
+ {
+ sprite[nSprite].xvel = Sin((sprite[nSprite].ang & 0xFFF8) + 512) >> 2;
+ sprite[nSprite].yvel = Sin((sprite[nSprite].ang & 0xFFF8)) >> 2;
+ }
+ else
+ {
+ RexList[nRex].nAction = 2;
+ RexList[nRex].field_A = 240;
+ D3PlayFX(StaticSound[kSound48], nSprite);
+ RexList[nRex].field_2 = 0;
+ return;
+ }
+ }
+ }
+
+ int nVal = MoveCreatureWithCaution(nSprite);
+
+ if ((nVal & 0xC000) == 0x8000)
+ {
+ sprite[nSprite].ang = (sprite[nSprite].ang + 256) & kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
+ RexList[nRex].nAction = 1;
+ RexList[nRex].field_2 = 0;
+ nAction = 1;
+ break;
+ }
+ else if ((nVal & 0xC000) == 0xC000)
+ {
+ if ((nVal & 0x3FFF) == nTarget)
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+ RexList[nRex].nAction = 4;
+ RexList[nRex].field_2 = 0;
+ break;
+ }
+ else
+ {
+ sprite[nSprite].ang = (sprite[nSprite].ang + 256) & kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
+ RexList[nRex].nAction = 1;
+ RexList[nRex].field_2 = 0;
+ nAction = 1;
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case 2:
+ {
+ RexList[nRex].field_A--;
+ if (RexList[nRex].field_A > 0)
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 1;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 1;
+
+ int nVal = MoveCreatureWithCaution(nSprite);
+
+ if ((nVal & 0x0C000) == 0x8000)
+ {
+ SetQuake(nSprite, 25);
+ RexList[nRex].field_A = 60;
+
+ sprite[nSprite].ang = (sprite[nSprite].ang + 256) & kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 2;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 2;
+ RexList[nRex].nAction = 1;
+ RexList[nRex].field_2 = 0;
+ nAction = 1;
+ break;
+ }
+ else if ((nVal & 0x0C000) == 0x0C000)
+ {
+ RexList[nRex].nAction = 3;
+ RexList[nRex].field_2 = 0;
+
+ short nSprite2 = nVal & 0x3FFF;
+
+ if (sprite[nSprite2].statnum && sprite[nSprite2].statnum < 107)
+ {
+ short nAngle = sprite[nSprite].ang;
+
+ runlist_DamageEnemy(nSprite2, nSprite, 15);
+
+ int ebx = Sin(nAngle + 512) * 15;
+ int edx = Sin(nAngle) * 15;
+
+ if (sprite[nSprite2].statnum == 100)
+ {
+ short nPlayer = GetPlayerFromSprite(nSprite2);
+ nXDamage[nPlayer] += (ebx << 4);
+ nYDamage[nPlayer] += (edx << 4);
+ sprite[nSprite2].zvel = -3584;
+ }
+ else
+ {
+ sprite[nSprite2].xvel += (ebx >> 3);
+ sprite[nSprite2].yvel += (edx >> 3);
+ sprite[nSprite2].zvel = -2880;
+ }
+ }
+
+ RexList[nRex].field_A >>= 2;
+ }
+ }
+ else
+ {
+ RexList[nRex].nAction = 1;
+ RexList[nRex].field_2 = 0;
+ RexList[nRex].field_A = 90;
+ }
+
+ return;
+ }
+
+ case 3:
+ {
+ if (var_1C)
+ {
+ RexList[nRex].nAction = 2;
+ }
+ return;
+ }
+
+ case 4:
+ {
+ if (nTarget != -1)
+ {
+ if (PlotCourseToSprite(nSprite, nTarget) < 768)
+ {
+ if (nFlag & 0x80)
+ {
+ runlist_DamageEnemy(nTarget, nSprite, 15);
+ }
+
+ break;
+ }
+ }
+
+ RexList[nRex].nAction = 1;
+ break;
+ }
+
+ case 5:
+ {
+ if (var_1C)
+ {
+ RexList[nRex].nAction = 1;
+ RexList[nRex].field_A = 15;
+ }
+ return;
+ }
+
+ case 6:
+ {
+ if (var_1C)
+ {
+ RexList[nRex].nAction = 7;
+ RexList[nRex].field_2 = 0;
+ runlist_ChangeChannel(RexChan[nRex], 1);
+ }
+ return;
+ }
+
+ case 7:
+ {
+ sprite[nSprite].cstat &= 0xFEFE;
+ return;
+ }
+ }
+
+ // break-ed
+ if (nAction > 0)
+ {
+ if ((nTarget != -1) && (!(sprite[nTarget].cstat & 0x101)))
+ {
+ RexList[nRex].nAction = 0;
+ RexList[nRex].field_2 = 0;
+ RexList[nRex].field_A = 0;
+ RexList[nRex].nTarget = -1;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+ }
+ return;
+ }
+ }
+}
diff --git a/source/exhumed/src/rex.h b/source/exhumed/src/rex.h
new file mode 100644
index 000000000..ba095ed07
--- /dev/null
+++ b/source/exhumed/src/rex.h
@@ -0,0 +1,9 @@
+
+#ifndef __rex_h__
+#define __rex_h__
+
+void InitRexs();
+int BuildRex(short nSprite, int x, int y, int z, short nSector, short nAngle, int nVal);
+void FuncRex(int, int, int);
+
+#endif
diff --git a/source/exhumed/src/roach.cpp b/source/exhumed/src/roach.cpp
new file mode 100644
index 000000000..f4bf91c12
--- /dev/null
+++ b/source/exhumed/src/roach.cpp
@@ -0,0 +1,391 @@
+
+#include "exhumed.h"
+#include "engine.h"
+#include "runlist.h"
+#include "roach.h"
+#include "typedefs.h"
+#include "sequence.h"
+#include "move.h"
+#include "random.h"
+#include "trigdat.h"
+#include "bullet.h"
+#include "items.h"
+#include
+
+#define kMaxRoach 100
+
+sshort RoachSprite = -1;
+sshort RoachCount = -1;
+
+static actionSeq ActionSeq[] = {{ 24, 0 }, { 0, 0 }, { 0, 0 }, { 16, 0 }, { 8, 0 }, { 32, 1 }, { 42, 1 }};
+
+struct Roach
+{
+ short nHealth;
+ short field_2;
+ short nType;
+ short nSprite;
+ short nTarget;
+ short field_A;
+ short field_C;
+ short field_E;
+};
+
+Roach RoachList[kMaxRoach];
+
+
+/* Kilmaat Sentry */
+
+void InitRoachs()
+{
+ RoachCount = kMaxRoach;
+ RoachSprite = 1;
+}
+
+// TODO - make EAX a bool type?
+int BuildRoach(int eax, int nSprite, int x, int y, int z, short nSector, int angle)
+{
+ RoachCount--;
+ if (RoachCount < 0) {
+ return -1;
+ }
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(nSector, 105);
+ }
+ else
+ {
+ changespritestat(nSprite, 105);
+ x = sprite[nSprite].x;
+ y = sprite[nSprite].y;
+ z = sector[sprite[nSprite].sectnum].floorz;
+ angle = sprite[nSprite].ang;
+ }
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ sprite[nSprite].clipdist = 60;
+ sprite[nSprite].ang = angle;
+ sprite[nSprite].xrepeat = 40;
+ sprite[nSprite].yrepeat = 40;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].extra = -1;
+
+// GrabTimeSlot(3);
+
+ if (eax)
+ {
+ RoachList[RoachCount].nType = 0;
+ }
+ else
+ {
+ RoachList[RoachCount].nType = 1;
+ }
+
+ RoachList[RoachCount].nSprite = nSprite;
+ RoachList[RoachCount].field_2 = 0;
+ RoachList[RoachCount].field_C = 0;
+ RoachList[RoachCount].nTarget = -1;
+ RoachList[RoachCount].nHealth = 600;
+
+ sprite[nSprite].owner = (sprite[nSprite].lotag - 1, RoachCount | 0x1C0000);
+ RoachList[RoachCount].field_A = runlist_AddRunRec(NewRun, RoachCount | 0x1C0000);
+
+ nCreaturesLeft++;
+
+ return RoachCount | 0x1C0000;
+}
+
+void GoRoach(short nSprite)
+{
+ sprite[nSprite].xvel = (Sin(sprite[nSprite].ang + 512) >> 1) - (Sin(sprite[nSprite].ang + 512) >> 3);
+ sprite[nSprite].yvel = (Sin(sprite[nSprite].ang) >> 1) - (Sin(sprite[nSprite].ang) >> 3);
+}
+
+void FuncRoach(int a, int b, int nRun)
+{
+ short nRoach = RunData[nRun].nVal;
+ assert(nRoach >= 0 && nRoach < kMaxRoach);
+
+ int var_24 = 0;
+
+ short nSprite = RoachList[nRoach].nSprite;
+ short nType = RoachList[nRoach].nType;
+
+ int nDamage = b;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Roach\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, ActionSeq[nType].a + SeqOffsets[kSeqRoach], RoachList[nRoach].field_2, ActionSeq[nType].b);
+ return;
+ }
+
+ case 0x0A0000: // fall through to next case
+ {
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ }
+ case 0x80000:
+ {
+ if (nDamage)
+ {
+ if (RoachList[nRoach].nHealth <= 0) {
+ return;
+ }
+
+ RoachList[nRoach].nHealth -= nDamage;
+ if (RoachList[nRoach].nHealth <= 0)
+ {
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ RoachList[nRoach].nHealth = 0;
+ sprite[nSprite].cstat &= 0x0FEFE;
+ nCreaturesLeft++;
+
+ if (nType < 5)
+ {
+ DropMagic(nSprite);
+ RoachList[nRoach].nType = 5;
+ RoachList[nRoach].field_2 = 0;
+ }
+ }
+ else
+ {
+ short nSprite2 = a & 0xFFFF;
+ if (nSprite2 < 0) {
+ return;
+ }
+
+ if (sprite[nSprite2].statnum < 199) {
+ RoachList[nRoach].nTarget = nSprite2;
+ }
+
+ if (nType == 0)
+ {
+ RoachList[nRoach].nType = 2;
+ GoRoach(nSprite);
+ RoachList[nRoach].field_2 = 0;
+ }
+ else
+ {
+ if (!RandomSize(4))
+ {
+ RoachList[nRoach].nType = 4;
+ RoachList[nRoach].field_2 = 0;
+ }
+ }
+ }
+ }
+
+ return;
+ }
+
+ case 0x20000:
+ {
+ Gravity(nSprite);
+
+ int nSeq = SeqOffsets[kSeqRoach] + ActionSeq[RoachList[nRoach].nType].a;
+ int var_28 = nSeq;
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(var_28, RoachList[nRoach].field_2);
+ seq_MoveSequence(nSprite, var_28, RoachList[nRoach].field_2);
+
+ RoachList[nRoach].field_2++;
+ if (RoachList[nRoach].field_2 >= SeqSize[var_28])
+ {
+ var_24 = 1;
+ RoachList[nRoach].field_2 = 0;
+ }
+
+ int nFlag = FrameFlag[SeqBase[nSeq] + RoachList[nRoach].field_2];
+ short nTarget = RoachList[nRoach].nTarget;
+
+ if (nType > 5) {
+ return;
+ }
+
+ switch (nType)
+ {
+ case 0:
+ {
+ if (RoachList[nRoach].field_2 == 1)
+ {
+ RoachList[nRoach].field_C--;
+ if (RoachList[nRoach].field_C <= 0)
+ {
+ RoachList[nRoach].field_C = RandomSize(6);
+ }
+ else
+ {
+ RoachList[nRoach].field_2 = 0;
+ }
+ }
+
+ if ((nRoach & 0xF) == (totalmoves & 0xF) && nTarget < 0)
+ {
+ short nTarget = FindPlayer(nSprite, 50);
+ if (nTarget >= 0)
+ {
+ RoachList[nRoach].nType = 2;
+ RoachList[nRoach].field_2 = 0;
+ RoachList[nRoach].nTarget = nTarget;
+ GoRoach(nSprite);
+ }
+ }
+
+ return;
+ }
+
+ case 1:
+ {
+ // parltly the same as case 0...
+ if ((nRoach & 0xF) == (totalmoves & 0xF) && nTarget < 0)
+ {
+ short nTarget = FindPlayer(nSprite, 100);
+ if (nTarget >= 0)
+ {
+ RoachList[nRoach].nType = 2;
+ RoachList[nRoach].field_2 = 0;
+ RoachList[nRoach].nTarget = nTarget;
+ GoRoach(nSprite);
+ }
+ }
+
+ return;
+ }
+
+ case 2:
+ {
+ if ((totalmoves & 0xF) == (nRoach & 0xF))
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+ GoRoach(nSprite);
+ }
+
+ int nVal = MoveCreatureWithCaution(nSprite);
+
+ if ((nVal & 0x0C000) == 49152)
+ {
+ if ((nVal & 0x3FFF) == nTarget)
+ {
+ // repeated below
+ RoachList[nRoach].field_E = RandomSize(2) + 1;
+ RoachList[nRoach].nType = 3;
+
+ sprite[nSprite].xvel = sprite[nSprite].yvel = 0;
+ sprite[nSprite].ang = GetMyAngle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+
+ RoachList[nRoach].field_2 = 0;
+ }
+ }
+ else if ((nVal & 0x0C000) == 32768)
+ {
+ sprite[nSprite].ang = (sprite[nSprite].ang + 256) & kAngleMask;
+ GoRoach(nSprite);
+ }
+ //else if ((nVal & 0x0C000) < 32768)
+ else
+ {
+ if (RoachList[nRoach].field_C)
+ {
+ RoachList[nRoach].field_C--;
+ }
+ else
+ {
+ // same as above
+ RoachList[nRoach].field_E = RandomSize(2) + 1;
+ RoachList[nRoach].nType = 3;
+
+ sprite[nSprite].xvel = sprite[nSprite].yvel = 0;
+ sprite[nSprite].ang = GetMyAngle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+
+ RoachList[nRoach].field_2 = 0;
+ }
+ }
+
+ if (nTarget != -1 && !(sprite[nTarget].cstat & 0x101))
+ {
+ RoachList[nRoach].nType = 1;
+ RoachList[nRoach].field_2 = 0;
+ RoachList[nRoach].field_C = 100;
+ RoachList[nRoach].nTarget = -1;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+
+ return;
+ }
+
+ case 3:
+ {
+ if (var_24)
+ {
+ RoachList[nRoach].field_E--;
+ if (RoachList[nRoach].field_E <= 0)
+ {
+ RoachList[nRoach].nType = 2;
+ GoRoach(nSprite);
+ RoachList[nRoach].field_2 = 0;
+ RoachList[nRoach].field_C = RandomSize(7);
+ }
+ }
+ else
+ {
+ if (nFlag & 0x80)
+ {
+ BuildBullet(nSprite, 13, 0, 0, -1, sprite[nSprite].ang, nTarget + 10000, 1);
+ }
+ }
+
+ return;
+ }
+
+ case 4:
+ {
+ if (var_24)
+ {
+ RoachList[nRoach].nType = 2;
+ RoachList[nRoach].field_2 = 0;
+ }
+
+ return;
+ }
+
+ case 5:
+ {
+ if (var_24)
+ {
+ sprite[nSprite].cstat = 0;
+ RoachList[nRoach].nType = 6;
+ RoachList[nRoach].field_2 = 0;
+ }
+
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/source/exhumed/src/roach.h b/source/exhumed/src/roach.h
new file mode 100644
index 000000000..6004a290e
--- /dev/null
+++ b/source/exhumed/src/roach.h
@@ -0,0 +1,11 @@
+
+#ifndef __roach_h__
+#define __roach_h__
+
+void InitRoachs();
+
+int BuildRoach(int eax, int nSprite, int x, int y, int z, short nSector, int angle);
+
+void FuncRoach(int a, int b, int nRun);
+
+#endif
diff --git a/source/exhumed/src/runlist.cpp b/source/exhumed/src/runlist.cpp
new file mode 100644
index 000000000..7c317f936
--- /dev/null
+++ b/source/exhumed/src/runlist.cpp
@@ -0,0 +1,1757 @@
+
+#include "exhumed.h"
+#include "engine.h"
+#include "runlist.h"
+#include "player.h"
+#include "trigdat.h"
+#include "move.h"
+#include "random.h"
+#include "mummy.h"
+#include "fish.h"
+#include "lion.h"
+#include "rex.h"
+#include "set.h"
+#include "rat.h"
+#include "wasp.h"
+#include "anubis.h"
+#include "snake.h"
+#include "scorp.h"
+#include "ra.h"
+#include "spider.h"
+#include "bullet.h"
+#include "queen.h"
+#include "roach.h"
+#include "bubbles.h"
+#include "lavadude.h"
+#include "grenade.h"
+#include "object.h"
+#include "switch.h"
+#include "anims.h"
+#include "sound.h"
+#include "init.h"
+#include "lighting.h"
+#include
+
+//#define kFuncMax 0x260000 // the number 38 stored in the high word of an int
+#define kFuncMax 39
+#define kMaxRunStack 200
+
+
+short RunCount = -1;
+short nRadialSpr = -1;
+short nStackCount = 0;
+short word_966BE = 0;
+short ChannelList = -1;
+short ChannelLast = -1;
+
+int nRadialOwner;
+int nDamageRadius;
+int nRadialDamage;
+short RunChain;
+short NewRun;
+
+int sRunStack[kMaxRunStack];
+short RunFree[kMaxRuns];
+RunChannel sRunChannels[kMaxChannels];
+
+
+RunStruct RunData[kMaxRuns];
+
+short word_96760 = 0;
+
+/* variables
+ Name: _sRunStack
+ Name: _RunFree
+ Name: _channel
+ Name: _RunData
+ Name: _nRadialOwner
+ Name: _nDamageRadius
+ Name: _nRadialDamage
+ Name: _RunCount
+ Name: _nRadialSpr
+ Name: _nStackCount
+*/
+
+AiFunc aiFunctions[kFuncMax] = {
+ FuncElev,
+ FuncSwReady,
+ FuncSwPause,
+ FuncSwStepOn,
+ FuncSwNotOnPause,
+ FuncSwPressSector,
+ FuncSwPressWall,
+ FuncWallFace,
+ FuncSlide,
+ FuncAnubis,
+ FuncPlayer, // 10
+ FuncBullet,
+ FuncSpider,
+ FuncCreatureChunk,
+ FuncMummy,
+ FuncGrenade,
+ FuncAnim,
+ FuncSnake,
+ FuncFish,
+ FuncLion,
+ FuncBubble, // 20
+ FuncLava,
+ FuncLavaLimb,
+ FuncObject,
+ FuncRex,
+ FuncSet,
+ FuncQueen,
+ FuncQueenHead,
+ FuncRoach,
+ FuncQueenEgg,
+ FuncWasp, // 30
+ FuncTrap,
+ FuncFishLimb,
+ FuncRa, // 33
+ FuncScorp,
+ FuncSoul,
+ FuncRat,
+ FuncEnergyBlock,
+ FuncSpark,
+};
+
+
+
+int runlist_GrabRun()
+{
+ assert(RunCount > 0 && RunCount <= kMaxRuns);
+
+ RunCount--;
+
+ return RunFree[RunCount];
+}
+
+int runlist_FreeRun(int nRun)
+{
+ assert(RunCount >= 0 && RunCount < kMaxRuns);
+ assert(nRun >= 0 && nRun < kMaxRuns);
+
+ RunFree[RunCount] = nRun;
+ RunCount++;
+
+ RunData[nRun]._6 = -1;
+ RunData[nRun].nMoves = -1;
+ RunData[nRun]._4 = RunData[nRun]._6;
+
+ return 1;
+}
+
+// done
+int runlist_HeadRun()
+{
+ int nRun = runlist_GrabRun();
+
+ RunData[nRun]._4 = -1;
+ RunData[nRun]._6 = -1;
+
+ return nRun;
+}
+
+// sub 4
+void runlist_InitRun()
+{
+ int i;
+
+ RunCount = kMaxRuns;
+ nStackCount = 0;
+
+ for (i = 0; i < kMaxRuns; i++)
+ {
+ RunData[i].nMoves = -1;
+ RunData[i]._6 = -1;
+ RunFree[i] = i;
+ RunData[i]._4 = -1;
+ }
+
+ int nRun = runlist_HeadRun();
+ RunChain = nRun;
+ NewRun = nRun;
+
+ for (i = 0; i < kMaxPlayers; i++) {
+ PlayerList[i].nRun = -1;
+ }
+
+ nRadialSpr = -1;
+}
+
+int runlist_UnlinkRun(int nRun)
+{
+ assert(nRun >= 0 && nRun < kMaxRuns);
+
+ if (nRun == RunChain)
+ {
+ RunChain = RunData[nRun]._4;
+ return nRun;
+ }
+
+ if (RunData[nRun]._6 >= 0)
+ {
+ RunData[RunData[nRun]._6]._4 = RunData[nRun]._4;
+ }
+
+ if (RunData[nRun]._4 >= 0)
+ {
+ RunData[RunData[nRun]._4]._6 = RunData[nRun]._6;
+ }
+
+ return nRun;
+}
+
+// done ?
+int runlist_InsertRun(int RunLst, int RunNum)
+{
+ assert(RunLst >= 0 && RunLst < kMaxRuns);
+ assert(RunNum >= 0 && RunNum < kMaxRuns);
+
+ RunData[RunNum]._6 = RunLst;
+ int val = RunData[RunLst]._4;
+ RunData[RunNum]._4 = val;
+
+ if (val >= 0) {
+ RunData[val]._6 = RunNum;
+ }
+
+ RunData[RunLst]._4 = RunNum;
+ return RunNum;
+}
+
+// done
+int runlist_AddRunRec(int a, int b)
+{
+ int nRun = runlist_GrabRun();
+
+ RunData[nRun].nMoves = b; // TODO - split this into the two shorts?
+
+ runlist_InsertRun(a, nRun);
+ return nRun;
+}
+
+void runlist_DoSubRunRec(int RunPtr)
+{
+ assert(RunPtr >= 0 && RunPtr < kMaxRuns);
+
+ runlist_UnlinkRun(RunPtr);
+ runlist_FreeRun(RunPtr);
+}
+
+void runlist_CleanRunRecs()
+{
+ int nextPtr = RunChain;
+
+ if (nextPtr >= 0)
+ {
+ assert(nextPtr < kMaxRuns);
+ nextPtr = RunData[nextPtr]._4;
+ }
+
+ while (nextPtr >= 0)
+ {
+ int runPtr = nextPtr;
+ assert(runPtr < kMaxRuns);
+
+ int val = RunData[runPtr].nRef; // >> 16;
+ nextPtr = RunData[runPtr]._4;
+
+ if (val < 0) {
+ runlist_DoSubRunRec(runPtr);
+ }
+ }
+}
+
+// done
+void runlist_SubRunRec(int RunPtr)
+{
+ assert(RunPtr >= 0 && RunPtr < kMaxRuns);
+
+ RunData[RunPtr].nMoves = -totalmoves;
+}
+
+void runlist_SendMessageToRunRec(int nRun, int edx, int nDamage)
+{
+ int nFunc = RunData[nRun].nRef;// >> 16;
+
+ if (nFunc < 0) {
+ return;
+ }
+
+ assert(nFunc >= 0 && nFunc <= kFuncMax);
+
+ if (nFunc > kFuncMax) {
+ return;
+ }
+
+ assert(nFunc < kFuncMax); // REMOVE
+
+ // do function pointer call here.
+ aiFunctions[nFunc](edx, nDamage, nRun);
+}
+
+void runlist_ExplodeSignalRun()
+{
+ short nextPtr = RunChain;
+
+ if (nextPtr >= 0)
+ {
+ assert(nextPtr < kMaxRuns);
+ nextPtr = RunData[nextPtr]._4;
+ }
+
+ // LOOP
+ while (nextPtr >= 0)
+ {
+ int runPtr = nextPtr;
+ assert(runPtr < kMaxRuns);
+
+ int val = RunData[runPtr].nMoves;
+ nextPtr = RunData[runPtr]._4;
+
+ if (val >= 0)
+ {
+ runlist_SendMessageToRunRec(runPtr, 0xA0000, 0);
+ }
+ }
+}
+
+void runlist_PushMoveRun(int eax)
+{
+ if (nStackCount < kMaxRunStack)
+ {
+ sRunStack[nStackCount] = eax;
+ nStackCount++;
+ }
+}
+
+int runlist_PopMoveRun()
+{
+ if (nStackCount <= 0) {
+ bail2dos("PopMoveRun() called inappropriately\n");
+ }
+
+ nStackCount--;
+ return sRunStack[nStackCount];
+}
+
+void runlist_SignalRun(int NxtPtr, int edx)
+{
+ if (NxtPtr == RunChain && word_966BE != 0) {
+ runlist_PushMoveRun(edx);
+ return;
+ }
+
+ while (1)
+ {
+ word_966BE = 1;
+
+ if (NxtPtr >= 0)
+ {
+ assert(NxtPtr < kMaxRuns);
+ NxtPtr = RunData[NxtPtr]._4;
+ }
+
+ while (NxtPtr >= 0)
+ {
+ int RunPtr = NxtPtr;
+
+ if (RunPtr >= 0)
+ {
+ assert(RunPtr < kMaxRuns);
+ int val = RunData[RunPtr].nMoves;
+ NxtPtr = RunData[RunPtr]._4;
+
+ if (val >= 0) {
+ runlist_SendMessageToRunRec(RunPtr, edx, 0);
+ }
+ }
+ }
+
+ word_966BE = 0;
+ if (nStackCount == 0) {
+ return;
+ }
+
+ edx = runlist_PopMoveRun();
+ NxtPtr = RunChain;
+ }
+}
+
+void runlist_InitChan()
+{
+ ChannelList = -1;
+ ChannelLast = -1;
+
+ for (int i = 0; i < kMaxChannels; i++)
+ {
+ sRunChannels[i].c = -1;
+ sRunChannels[i].a = runlist_HeadRun();
+ sRunChannels[i].b = -1;
+ sRunChannels[i].d = 0;
+ }
+}
+
+void runlist_ChangeChannel(int eax, short dx)
+{
+ if (sRunChannels[eax].b < 0)
+ {
+ short nChannel = ChannelList;
+ ChannelList = eax;
+ sRunChannels[eax].b = nChannel;
+ }
+
+ sRunChannels[eax].c = dx;
+ sRunChannels[eax].d |= 2;
+}
+
+void runlist_ReadyChannel(short eax)
+{
+ if (sRunChannels[eax].b < 0)
+ {
+ short nChannel = ChannelList;
+ ChannelList = eax;
+ sRunChannels[eax].b = nChannel;
+ }
+
+ sRunChannels[eax].d |= 1;
+}
+
+void runlist_ProcessChannels()
+{
+#if 1
+ short v0; // di@1
+ short v1; // si@1
+ short *v2; // ebx@3
+ short v3; // cx@3
+ short v4; // cx@5
+ int v5; // eax@11
+ int result; // eax@13
+ short b; // [sp+0h] [bp-1Ch]@3
+ short d;
+
+ do
+ {
+ v0 = -1;
+ v1 = -1;
+
+ while (ChannelList >= 0)
+ {
+ b = sRunChannels[ChannelList].b;
+ d = sRunChannels[ChannelList].d;
+ //v3 = v2[3];
+ //b = v2[1];
+
+ if (d & 2)
+ {
+ sRunChannels[ChannelList].d = d ^ 2;
+ //v2[3] = v3 ^ 2;
+ runlist_SignalRun(sRunChannels[ChannelList].a, ChannelList | 0x10000);
+ }
+
+// v4 = v3 & 1;
+ if (d & 1)
+ {
+ sRunChannels[ChannelList].d ^= 1;
+// *((_BYTE *)v2 + offsetof(RunChannel, d)) ^= 1u;
+ runlist_SignalRun(sRunChannels[ChannelList].a, 0x30000);
+ }
+
+ if (sRunChannels[ChannelList].d)
+ {
+ if (v1 == -1)
+ {
+ v1 = ChannelList;
+ v0 = ChannelList;
+ }
+ else
+ {
+ v5 = v0;
+ v0 = ChannelList;
+ sRunChannels[v5].b = ChannelList;
+ }
+ }
+ else
+ {
+ sRunChannels[ChannelList].b = -1;
+ }
+ ChannelList = b;
+ }
+ result = v1;
+ ChannelList = v1;
+ } while (v1 != -1);
+
+#else
+ int edi = -1;
+ int esi = edi;
+
+ while (1)
+ {
+ short nChannel = ChannelList;
+ if (nChannel < 0)
+ {
+ ChannelList = esi;
+ if (esi != -1)
+ {
+ edi = -1;
+ esi = edi;
+ continue;
+ }
+ else {
+ return;
+ }
+ }
+
+ short b = sRunChannels[nChannel].b;
+ short d = sRunChannels[nChannel].d;
+
+ if (d & 2)
+ {
+ sRunChannels[nChannel].d = d ^ 2;
+ runlist_SignalRun(sRunChannels[nChannel].a, ChannelList | 0x10000);
+ }
+
+ if (d & 1)
+ {
+ sRunChannels[nChannel].d = d ^ 1;
+ runlist_SignalRun(sRunChannels[nChannel].a, 0x30000);
+ }
+
+ if (sRunChannels[nChannel].d == 0)
+ {
+ sRunChannels[ChannelList].b = -1;
+ }
+ else
+ {
+ if (esi == -1)
+ {
+ esi = ChannelList;
+ edi = esi;
+ }
+ else
+ {
+ sRunChannels[edi].b = ChannelList;
+ edi = ChannelList;
+ }
+ }
+
+ ChannelList = b;
+ }
+#endif
+}
+
+int runlist_FindChannel(short ax)
+{
+ for (int i = 0; i < kMaxChannels; i++)
+ {
+ if (sRunChannels[i].c == -1)
+ {
+ sRunChannels[i].c = ax;
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+int runlist_AllocChannel(int a)
+{
+ if (a)
+ {
+ for (int i = 0; i < kMaxChannels; i++)
+ {
+ if (sRunChannels[i].c == a) {
+ return i;
+ }
+ }
+ }
+
+ return runlist_FindChannel(a);
+}
+
+void runlist_ExecObjects()
+{
+ runlist_ProcessChannels();
+ runlist_SignalRun(RunChain, 0x20000);
+}
+
+void runlist_ProcessSectorTag(int nSector, int lotag, int hitag)
+{
+ int zListA[8];
+ int zListB[8];
+
+ int _lotag = lotag;
+ int nChannel = runlist_AllocChannel(hitag % 1000);
+ assert(nChannel >= 0); // REMOVE
+
+ int var_2C = 1000;
+ int var_24 = (hitag / 1000) << 12;
+ int var_18 = lotag / 1000;
+
+ if (!var_18) {
+ var_18 = 1;
+ }
+
+ var_18 <<= 2;
+
+ _lotag = (lotag % 1000);
+ int eax = _lotag - 1;
+
+ switch (eax)
+ {
+ case 0: // Ceiling Doom door
+ {
+ /*
+ This function searches z-coordinates of neighboring sectors to find the
+ closest (next) ceiling starting at the given z-coordinate (thez).
+ */
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, -1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].ceilingz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwPress = BuildSwPressSector(nChannel, BuildLink(1, 1), nSector, var_24);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwPress);
+
+ int nSwPause = BuildSwPause(nChannel, BuildLink(2, -1, 0), 60);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwPause);
+ return;
+ }
+
+ case 1: // Floor Doom door
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].ceilingz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwPress = BuildSwPressSector(nChannel, BuildLink(1, 1), nSector, var_24);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwPress);
+
+ int nSwPause = BuildSwPause(nChannel, BuildLink(2, -1, 0), 60);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwPause);
+ return;
+ }
+
+ case 2:
+ case 3:
+ case 18:
+ case 19:
+ case 21:
+ case 28:
+ case 29:
+ case 45:
+ case 46:
+ case 59:
+ case 64:
+ case 65:
+ case 66:
+ case 68:
+ case 71:
+ case 72:
+ case 73:
+ case 75:
+ case 76:
+ case 77:
+ case 78:
+ case 80:
+ case 81:
+ case 82:
+ case 83:
+ case 84:
+ {
+ return;
+ }
+
+ case 4: // Permanent floor raise
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz + 1, -1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].ceilingz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 5: // Touchplate floor lower, single
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), 400, 400, 2, sector[nextSector].floorz, sector[nSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwStepOn(nChannel, BuildLink(2, 1, 1), nSector);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+
+ sector[nSector].floorz = sector[nextSector].floorz;
+ return;
+ }
+
+ case 6: // Touchplate floor lower, multiple
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwStepOn(nChannel, BuildLink(1, 1), nSector);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+
+ int nSwitch2 = BuildSwNotOnPause(nChannel, BuildLink(2, -1, 0), nSector, 8);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch2);
+ return;
+ }
+
+ case 7: // Permanent floor lower
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 8: // Switch activated lift down
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPause(nChannel, BuildLink(2, -1, 0), 150);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 9: // Touchplate Floor Raise
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwStepOn(nChannel, BuildLink(1, 1), nSector);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+
+ int nSwitch2 = BuildSwNotOnPause(nChannel, BuildLink(2, -1, 0), nSector, 8);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch2);
+ return;
+ }
+
+ case 10: // Permanent floor raise
+ case 13: // Sector raise / lower
+ case 37: // Sector raise / lower
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 11: // Switch activated lift up
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPause(nChannel, BuildLink(2, -1, 0), 150);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 12: // Bobbing floor
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwReady(nChannel, BuildLink(2, 1, 0));
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 14: // Sector raise/lower
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 15: // Stuttering noise (floor makes noise)
+ {
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), 200, var_18 * 100, 2, sector[nSector].ceilingz, sector[nSector].floorz - 8);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwStepOn(nChannel, BuildLink(1, 1), nSector);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+
+ int nSwitch2 = BuildSwReady(nChannel, BuildLink(2, -1, 0));
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch2);
+ return;
+ }
+
+ case 16: // Reserved?
+ {
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), 200, var_18 * 100, 2, sector[nSector].ceilingz, sector[nSector].floorz - 8);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwReady(nChannel, BuildLink(2, -1, 0));
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 17: // Raises floor AND lowers ceiling
+ {
+ int ebx = ((sector[nSector].floorz - sector[nSector].ceilingz) / 2) + sector[nSector].ceilingz;
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), 200, var_18 * 100, 2, sector[nSector].floorz, ebx);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int ebx2 = (((sector[nSector].floorz - sector[nSector].ceilingz) / 2) + sector[nSector].ceilingz) - 8;
+
+ int nElev2 = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), 200, var_18 * 100, 2, sector[nSector].ceilingz, ebx2);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev2);
+
+ int nSwitch = BuildSwStepOn(nChannel, BuildLink(1, 1), nSector);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 20: // Touchplate
+ {
+ int nSwitch = BuildSwStepOn(nChannel, BuildLink(2, 1, 1), nSector);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 22: // Floor raise, Sychronize
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), 32767, 200, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPause(nChannel, BuildLink(2, -1, 0), var_18 * 60);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 23: // Ceiling door, channel trigger only
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, -1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPause(nChannel, BuildLink(2, -1, 0), 60);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 24:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPause(nChannel, BuildLink(2, -1, 0), 300);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 25:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPause(nChannel, BuildLink(2, -1, 0), 450);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 26:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPause(nChannel, BuildLink(2, -1, 0), 600);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 27:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPause(nChannel, BuildLink(2, -1, 0), 900);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 30: // Touchplate
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), 0x7FFF, 0x7FFF, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwStepOn(nChannel, BuildLink(1, 1), nSector);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 31:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), 0x7FFF, 0x7FFF, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 32: // Ceiling Crusher
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, -1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevC(20, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nextSector].ceilingz, sector[nSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 33: // Triggerable Ceiling Crusher(Inactive)
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, -1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevC(28, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nextSector].ceilingz, sector[nSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 34: // Destructible sector
+ case 35:
+ {
+ nEnergyTowers++;
+
+ int nEnergyBlock = BuildEnergyBlock(nSector);
+
+ if (_lotag == 36) {
+ nFinaleSpr = nEnergyBlock;
+ }
+
+ return;
+ }
+
+ case 36:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 38: // Touchplate
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), 0x7FFF, 0x7FFF, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwStepOn(nChannel, BuildLink(1, 1), nSector);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+
+ int nSwitch2 = BuildSwNotOnPause(nChannel, BuildLink(2, -1, 0), nSector, 8);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch2);
+ return;
+ }
+
+ case 39: // Moving sector(follows waypoints)
+ {
+ AddMovingSector(nSector, lotag, hitag % 1000, 2);
+ return;
+ }
+
+ case 40: // Moving sector(follows waypoints)
+ {
+ AddMovingSector(nSector, lotag, hitag % 1000, 18);
+ return;
+ }
+
+ case 41: // Moving sector(follows waypoints)
+ {
+ AddMovingSector(nSector, lotag, hitag % 1000, 58);
+ return;
+ }
+
+ case 42: // Moving sector(follows waypoints)
+ {
+ AddMovingSector(nSector, lotag, hitag % 1000, 122);
+ return;
+ }
+
+ case 43: // Moving sector(follows waypoints)
+ {
+ AddMovingSector(nSector, lotag, hitag % 1000, 90);
+ return;
+ }
+
+ case 44: // Pushbox sector
+ {
+ CreatePushBlock(nSector);
+ return;
+ }
+
+ case 47: // Ceiling lower
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, -1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), 200, var_18 * 100, 2, sector[nSector].ceilingz, sector[nextSector].ceilingz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 48:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, -1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), 200, var_18 * 100, 2, sector[nSector].ceilingz, sector[nextSector].ceilingz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 49: // Floor lower / raise
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), 0x7FFF, 200, 2, sector[nextSector].floorz, sector[nSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 50:
+ {
+ int edx = ((sector[nSector].floorz - sector[nSector].ceilingz) / 2) + sector[nSector].ceilingz;
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), 200, var_18 * 100, 2, sector[nSector].floorz, edx);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int eax = (((sector[nSector].floorz - sector[nSector].ceilingz) / 2) + sector[nSector].ceilingz) - 8;
+
+ nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), 200, var_18 * 100, 2, sector[nSector].ceilingz, eax);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwReady(nChannel, BuildLink(2, 1, 0));
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 51:
+ {
+ int eax = ((sector[nSector].floorz - sector[nSector].ceilingz) / 2) + sector[nSector].ceilingz;
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, eax, sector[nSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ eax = ((sector[nSector].floorz - sector[nSector].ceilingz) / 2) + sector[nSector].ceilingz;
+
+ nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, eax, sector[nSector].ceilingz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPressSector(nChannel, BuildLink(1, 1), nSector, var_24);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+
+ nSwitch = BuildSwPause(nChannel, BuildLink(2, -1, 0), 60);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 52:
+ {
+ int eax = ((sector[nSector].floorz - sector[nSector].ceilingz) / 2) + sector[nSector].ceilingz;
+
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, eax, sector[nSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ eax = ((sector[nSector].floorz - sector[nSector].ceilingz) / 2) + sector[nSector].ceilingz;
+
+ nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, eax, sector[nSector].ceilingz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPause(nChannel, BuildLink(2, -1, 0), 150);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 53:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, -1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].ceilingz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPressSector(nChannel, BuildLink(1, 1), nSector, var_24);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 54:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, -1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].ceilingz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPressSector(nChannel, BuildLink(1, 1), nSector, var_24);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 55:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, -1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].ceilingz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 56:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].ceilingz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 57:
+ {
+ int nSwitch = BuildSwPressSector(nChannel, BuildLink(1, 1), nSector, var_24);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+
+ // Fall through to case 62
+ }
+ case 62:
+ {
+ if (_lotag == 63) {
+ nEnergyChan = nChannel;
+ }
+
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, -1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].ceilingz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+ return;
+ }
+
+ case 58:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwStepOn(nChannel, BuildLink(1, 1), nSector);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+
+ int nSwitch2 = BuildSwNotOnPause(nChannel, BuildLink(1, 1), nSector, 60);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch2);
+ return;
+ }
+
+ case 60:
+ {
+ zListB[0] = sector[nSector].floorz;
+ int var_1C = 1;
+
+ while (1)
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, -1);
+ if (nextSector < 0 || var_1C >= 8) {
+ break;
+ }
+
+ zListB[var_1C] = sector[nextSector].floorz;
+
+ var_1C++;
+ }
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, var_1C,
+ zListB[0], zListB[1], zListB[2], zListB[3], zListB[4], zListB[5], zListB[6], zListB[7]);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ return;
+ }
+
+ case 61:
+ {
+ zListA[0] = sector[nSector].floorz;
+ int var_20 = 1;
+
+ while (1)
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ if (nextSector < 0 || var_20 >= 8) {
+ break;
+ }
+
+ zListA[var_20] = sector[nextSector].floorz;
+
+ var_20++;
+ }
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, var_20,
+ zListA[0], zListA[1], zListA[2], zListA[3], zListA[4], zListA[5], zListA[6], zListA[7]);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ return;
+ }
+
+ case 63:
+ {
+ int nSwitch = BuildSwStepOn(nChannel, BuildLink(2, 0, 0), nSector);
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+
+ return;
+ }
+
+ case 67:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].floorz, 1, 1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevF(nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ return;
+ }
+
+ case 69:
+ case 70:
+ {
+ short nextSector = nextsectorneighborz(nSector, sector[nSector].ceilingz, -1, -1);
+ assert(nextSector > -1);
+
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].floorz, sector[nextSector].ceilingz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ int nSwitch = BuildSwPressSector(nChannel, BuildLink(1, 1), nSector, var_24);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+
+ int nSwitch2 = BuildSwPause(nChannel, BuildLink(2, -1, 0), 60);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch2);
+
+ return;
+ }
+
+ case 74:
+ {
+ int nElev = BuildElevC(0, nChannel, nSector, FindWallSprites(nSector), var_18 * 100, var_18 * 100, 2, sector[nSector].ceilingz, sector[nSector].floorz);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nElev);
+
+ return;
+ }
+
+ case 79:
+ {
+ SectFlag[nSector] |= 0x8000;
+ return;
+ }
+ }
+}
+
+void runlist_ProcessWallTag(int nWall, short lotag, short hitag)
+{
+ int nChannel = runlist_AllocChannel(hitag % 1000);
+ assert(nChannel >= 0 && nChannel < kMaxChannels);
+
+ int var_18 = 0; // TODO - FIXME CHECKME. This doesn't seem to be initialised in the ASM?
+ int var_28;
+
+ int var_20 = 0; // TODO - FIXME CHECKME. This doesn't seem to be initialised in the ASM?
+ int var_34;
+
+ int var_14 = 0; // TODO - FIXME CHECKME. This doesn't seem to be initialised in the ASM?
+ int var_24;
+
+ int var_38 = 0; // TODO - FIXME CHECKME. This doesn't seem to be initialised in the ASM?
+ int var_2C;
+
+ int eax = lotag / 1000;
+ if (!eax) {
+ eax = 1;
+ }
+
+ int edx = lotag % 1000;
+ int edi = edx;
+ eax <<= 2;
+
+ switch (edx)
+ {
+ case 1:
+ {
+ int nWallFace = BuildWallFace(nChannel, nWall, 2, wall[nWall].picnum, wall[nWall].picnum + 1);
+ runlist_AddRunRec(sRunChannels[nChannel].a, nWallFace);
+
+ int nSwitch = BuildSwPressWall(nChannel, BuildLink(2, edi, 0), nWall);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 6:
+ {
+ int nSwitch = BuildSwPressWall(nChannel, BuildLink(2, 1, 0), nWall);
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 7: // Regular switch
+ {
+ int nWallFace = BuildWallFace(nChannel, nWall, 2, wall[nWall].picnum, wall[nWall].picnum + 1);
+ runlist_AddRunRec(sRunChannels[nChannel].a, nWallFace);
+
+ int nSwitch = BuildSwPressWall(nChannel, BuildLink(1, 1), nWall);
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 8:
+ {
+ int nWallFace = BuildWallFace(nChannel, nWall, 2, wall[nWall].picnum, wall[nWall].picnum + 1);
+ runlist_AddRunRec(sRunChannels[nChannel].a, nWallFace);
+
+ int nSwitch = BuildSwPressWall(nChannel, BuildLink(2, -1, 0), nWall);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 9: // Invisible switch
+ {
+ int nSwitch = BuildSwPressWall(nChannel, BuildLink(2, 1, 1), nWall);
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 10:
+ {
+ int nSwitch = BuildSwPressWall(nChannel, BuildLink(2, -1, 0), nWall);
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSwitch);
+ return;
+ }
+
+ case 12:
+ {
+ short nStart = nWall;
+
+ while (1)
+ {
+ nWall = wall[nWall].point2;
+
+ if (nStart == nWall) {
+ break;
+ }
+
+ var_28 = var_18;
+ var_18 = nWall;
+ }
+
+ short nWall2 = wall[nStart].point2;
+ short nWall3 = wall[nWall2].point2;
+ short nWall4 = wall[nWall3].point2;
+
+ int nSlide = BuildSlide(nChannel, nStart, var_18, var_28, nWall2, nWall3, nWall4);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSlide);
+ return;
+ }
+
+ case 14:
+ {
+ short nStart = nWall;
+
+ while (1)
+ {
+ nWall = wall[nWall].point2;
+
+ if (nStart == nWall) {
+ break;
+ }
+
+ var_34 = var_20;
+ var_20 = nWall;
+ }
+
+ short nWall2 = wall[nStart].point2;
+ short nWall3 = wall[nWall2].point2;
+ short nWall4 = wall[nWall3].point2;
+
+ int nSlide = BuildSlide(nChannel, nStart, var_20, var_34, nWall2, nWall3, nWall4);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSlide);
+ return;
+ }
+
+ case 16:
+ {
+ short nStart = nWall;
+
+ while (1)
+ {
+ nWall = wall[nWall].point2;
+
+ if (nStart == nWall) {
+ break;
+ }
+
+ var_24 = var_14;
+ var_14 = nWall;
+ }
+
+ short nWall2 = wall[nStart].point2;
+ short nWall3 = wall[nWall2].point2;
+ short nWall4 = wall[nWall3].point2;
+
+ int nSlide = BuildSlide(nChannel, nStart, var_14, var_24, nWall2, nWall3, nWall4);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSlide);
+ return;
+ }
+
+ case 19:
+ {
+ short nStart = nWall;
+
+ while (1)
+ {
+ nWall = wall[nWall].point2;
+
+ if (nStart == nWall) {
+ break;
+ }
+
+ var_2C = var_38;
+ var_38 = nWall;
+ }
+
+ short nWall2 = wall[nStart].point2;
+ short nWall3 = wall[nWall2].point2;
+ short nWall4 = wall[nWall3].point2;
+
+ int nSlide = BuildSlide(nChannel, nStart, var_38, var_2C, nWall2, nWall3, nWall4);
+
+ runlist_AddRunRec(sRunChannels[nChannel].a, nSlide);
+ return;
+ }
+
+ case 21:
+ {
+ return;
+ }
+
+ case 24:
+ {
+ AddFlow(nWall, eax, 3);
+ return;
+ }
+
+ case 25:
+ {
+ AddFlow(nWall, eax, 2);
+ return;
+ }
+ }
+}
+
+int runlist_CheckRadialDamage(short nSprite)
+{
+ if (nSprite == nRadialSpr) {
+ return 0;
+ }
+
+ if (!(sprite[nSprite].cstat & 0x101)) {
+ return 0;
+ }
+
+ if (sprite[nSprite].statnum >= kMaxStatus || sprite[nRadialSpr].statnum >= kMaxStatus) {
+ return 0;
+ }
+
+ if (sprite[nSprite].statnum != 100 && nSprite == nRadialOwner) {
+ return 0;
+ }
+
+ int x = (sprite[nSprite].x - sprite[nRadialSpr].x) >> 8;
+ int y = (sprite[nSprite].y - sprite[nRadialSpr].y) >> 8;
+ int z = (sprite[nSprite].z - sprite[nRadialSpr].z) >> 12;
+
+ if (x < 0) {
+ x = -x;
+ }
+
+ if (x > nDamageRadius) {
+ return 0;
+ }
+
+ if (y < 0) {
+ y = -y;
+ }
+
+ if (y > nDamageRadius) {
+ return 0;
+ }
+
+ if (z < 0) {
+ z = -z;
+ }
+
+ if (z > nDamageRadius) {
+ return 0;
+ }
+
+ int edi = 0;
+
+ int nDist = ksqrt(x * x + y * y);
+
+ if (nDist < nDamageRadius)
+ {
+ ushort nCStat = sprite[nSprite].cstat;
+ sprite[nSprite].cstat = 0x101;
+
+ if (((kStatExplodeTarget - sprite[nSprite].statnum) <= 1) ||
+ cansee(sprite[nRadialSpr].x,
+ sprite[nRadialSpr].y,
+ sprite[nRadialSpr].z - 512,
+ sprite[nRadialSpr].sectnum,
+ sprite[nSprite].x,
+ sprite[nSprite].y,
+ sprite[nSprite].z - 8192,
+ sprite[nSprite].sectnum))
+ {
+ edi = (nRadialDamage * (nDamageRadius - nDist)) / nDamageRadius;
+
+ if (edi < 0) {
+ edi = 0;
+ }
+ else if (edi > 20)
+ {
+ int nAngle = GetMyAngle(x, y);
+ sprite[nSprite].xvel += (short)((edi * Sin(nAngle + 512)) >> 3);
+ sprite[nSprite].yvel += (short)((edi * Sin(nAngle)) >> 3);
+ sprite[nSprite].zvel -= edi * 24;
+
+ if (sprite[nSprite].zvel < -3584) {
+ sprite[nSprite].zvel = -3584;
+ }
+ }
+ }
+
+ sprite[nSprite].cstat = nCStat;
+ }
+
+ if (edi > 0x7FFF) {
+ edi = 0x7FFF;
+ }
+
+ return edi;
+}
+
+void runlist_RadialDamageEnemy(short nSprite, short nDamage, short nRadius)
+{
+ if (!nRadius) {
+ return;
+ }
+
+ word_96760++;
+
+ if (nRadialSpr == -1)
+ {
+ nRadialDamage = nDamage * 4;
+ nDamageRadius = nRadius;
+ nRadialSpr = nSprite;
+ nRadialOwner = sprite[nSprite].owner;
+
+ runlist_ExplodeSignalRun();
+
+ nRadialSpr = -1;
+ word_96760--;
+ }
+}
+
+void runlist_DamageEnemy(short nSprite, short nSprite2, short nDamage)
+{
+ if (sprite[nSprite].statnum >= kMaxStatus) {
+ return;
+ }
+
+ short nRun = sprite[nSprite].owner;
+
+ if (nRun <= -1) {
+ return;
+ }
+
+ runlist_SendMessageToRunRec(nRun, nSprite2 | 0x80000, nDamage * 4);
+
+ if (nCreaturesLeft <= 0) {
+ return;
+ }
+
+ if (sprite[nSprite2].statnum != 100) {
+ return;
+ }
+
+ short nPlayer = GetPlayerFromSprite(nSprite2);
+ nTauntTimer[nPlayer]--;
+
+ if (nTauntTimer[nPlayer] <= 0)
+ {
+ // Do a taunt
+ int nPlayerSprite = PlayerList[nPlayer].nSprite;
+ int nSector = sprite[nPlayerSprite].sectnum;
+
+ if (!(SectFlag[nSector] & kSectUnderwater))
+ {
+ int ebx = 0x4000;
+
+ if (nPlayer == nLocalPlayer) {
+ ebx = 0x6000;
+ }
+
+ int nDopSprite = nDoppleSprite[nPlayer];
+ D3PlayFX(StaticSound[kSoundTauntStart + (RandomSize(3) % 5)], nDopSprite | ebx);
+ }
+
+ nTauntTimer[nPlayer] = RandomSize(3) + 3;
+ }
+}
diff --git a/source/exhumed/src/runlist.h b/source/exhumed/src/runlist.h
new file mode 100644
index 000000000..3cef49782
--- /dev/null
+++ b/source/exhumed/src/runlist.h
@@ -0,0 +1,64 @@
+
+#ifndef __runlist_h__
+#define __runlist_h__
+
+#include "typedefs.h"
+
+#define kMaxRuns 25600
+#define kMaxChannels 4096
+
+struct RunStruct
+{
+ union
+ {
+ int nMoves;
+ struct
+ {
+ short nVal;
+ short nRef;
+ };
+ };
+
+ short _4;
+ short _6;
+};
+
+struct RunChannel
+{
+ short a;
+ short b;
+ short c;
+ short d;
+};
+
+typedef void(*AiFunc)(int, int, int nRun);
+
+extern RunStruct RunData[kMaxRuns];
+extern RunChannel sRunChannels[kMaxChannels];
+extern short NewRun;
+extern int nRadialOwner;
+extern short nRadialSpr;
+
+void runlist_InitRun();
+
+int runlist_GrabRun();
+int runlist_FreeRun(int nRun);
+int runlist_AddRunRec(int a, int b);
+int runlist_HeadRun();
+void runlist_InitChan();
+void runlist_ChangeChannel(int eax, short dx);
+void runlist_ReadyChannel(short eax);
+void runlist_ProcessSectorTag(int nSector, int lotag, int hitag);
+int runlist_AllocChannel(int a);
+void runlist_DoSubRunRec(int RunPtr);
+void runlist_SubRunRec(int RunPtr);
+void runlist_ProcessWallTag(int nWall, short lotag, short hitag);
+int runlist_CheckRadialDamage(short nSprite);
+void runlist_RadialDamageEnemy(short nSprite, short nDamage, short nRadius);
+void runlist_DamageEnemy(short nSprite, short nSprite2, short nDamage);
+void runlist_SignalRun(int NxtPtr, int edx);
+
+void runlist_CleanRunRecs();
+void runlist_ExecObjects();
+
+#endif
diff --git a/source/exhumed/src/save.cpp b/source/exhumed/src/save.cpp
new file mode 100644
index 000000000..49f89c511
--- /dev/null
+++ b/source/exhumed/src/save.cpp
@@ -0,0 +1,104 @@
+
+#include "save.h"
+#include
+#include
+#include
+#include
+#include "engine.h"
+
+int savegame(int nSlot)
+{
+ char filename[92];
+
+ if (nSlot < 0 || nSlot >= 10) {
+ return 0;
+ }
+
+ sprintf(filename, "save%1d.gam", nSlot);
+
+ int hFile = open(filename, 609, 128);
+ if (hFile != -1)
+ {
+#if 0 // TODO
+ write(hFile, &numsectors, sizeof(numsectors));
+ write(hFile, sector, sizeof(SECTOR) * numsectors);
+ write(hFile, &numwalls, sizeof(numwalls));
+ write(hFile, wall, sizeof(WALL) * numwalls);
+ write(hFile, sprite, sizeof(SPRITE) * kMaxSprites);
+ write(hFile, headspritesect, sizeof(headspritesect));
+ write(hFile, prevspritesect, sizeof(prevspritesect));
+ write(hFile, nextspritesect, sizeof(nextspritesect));
+ write(hFile, headspritestat, sizeof(headspritestat));
+ write(hFile, prevspritestat, sizeof(prevspritestat));
+ write(hFile, nextspritestat, sizeof(nextspritestat));
+ write(hFile, startumost, sizeof(startumost));
+ write(hFile, startdmost, sizeof(startdmost));
+ write(hFile, &brightness, 2);
+ write(hFile, &visibility, 4);
+ write(hFile, ¶llaxtype, 1);
+ write(hFile, ¶llaxyoffs, 4);
+ write(hFile, pskyoff, 512);
+ write(hFile, &pskybits, 2);
+ write(hFile, &inita, 2);
+ write(hFile, &initsect, 2);
+ write(hFile, &initx, 4);
+ write(hFile, &inity, 4);
+ write(hFile, &initz, 4);
+ write(hFile, &levelnum, 2);
+#endif
+ close(hFile);
+ }
+
+ return 1; // CHECKME
+}
+
+int loadgame(int nSlot)
+{
+ char filename[92];
+
+ if (nSlot < 0 || nSlot >= 10) {
+ return 0;
+ }
+
+ sprintf(filename, "save%1d.gam", nSlot);
+
+ int hFile = open(filename, 514, 256);
+ if (hFile != -1)
+ {
+#if 0 // TODO
+ read(hFile, &numsectors, sizeof(numsectors));
+ read(hFile, sector, sizeof(SECTOR) * numsectors);
+ read(hFile, &numwalls, sizeof(numwalls));
+ read(hFile, wall, sizeof(WALL) * numwalls);
+ read(hFile, sprite, sizeof(SPRITE) * kMaxSprites);
+ read(hFile, headspritesect, sizeof(headspritesect));
+ read(hFile, prevspritesect, sizeof(prevspritesect));
+ read(hFile, nextspritesect, sizeof(nextspritesect));
+ read(hFile, headspritestat, sizeof(headspritestat));
+ read(hFile, prevspritestat, sizeof(prevspritestat));
+ read(hFile, nextspritestat, sizeof(nextspritestat));
+ read(hFile, startumost, sizeof(startumost));
+ read(hFile, startdmost, sizeof(startdmost));
+ read(hFile, &brightness, 2);
+ read(hFile, &visibility, 4);
+ read(hFile, ¶llaxtype, 1);
+ read(hFile, ¶llaxyoffs, 4);
+ read(hFile, pskyoff, 512);
+ read(hFile, &pskybits, 2);
+ read(hFile, &inita, 2);
+ read(hFile, &initsect, 2);
+ read(hFile, &initx, 4);
+ read(hFile, &inity, 4);
+ read(hFile, &initz, 4);
+ read(hFile, &levelnum, 2);
+
+ lPlayerXVel = 0;
+ lPlayerYVel = 0;
+ nPlayerDAng = 0;
+#endif
+ close(hFile);
+ }
+
+ return 1; // CHECKME
+}
+
diff --git a/source/exhumed/src/save.h b/source/exhumed/src/save.h
new file mode 100644
index 000000000..48cd1f5b7
--- /dev/null
+++ b/source/exhumed/src/save.h
@@ -0,0 +1,8 @@
+
+#ifndef __save_h__
+#define __save_h__
+
+int savegame(int nSlot);
+int loadgame(int nSlot);
+
+#endif
diff --git a/source/exhumed/src/scorp.cpp b/source/exhumed/src/scorp.cpp
new file mode 100644
index 000000000..7a3809f5f
--- /dev/null
+++ b/source/exhumed/src/scorp.cpp
@@ -0,0 +1,488 @@
+
+#include "engine.h"
+#include "scorp.h"
+#include "runlist.h"
+#include "exhumed.h"
+#include "move.h"
+#include "sequence.h"
+#include "sound.h"
+#include "random.h"
+#include "trigdat.h"
+#include "bullet.h"
+#include "spider.h"
+#include
+
+/*
+ Selkis Boss AI code
+*/
+
+short ScorpCount = -1;
+
+Scorpion scorpion[kMaxScorpions];
+short ScorpChan[kMaxScorpions];
+
+static actionSeq ActionSeq[] = {
+ {0, 0},
+ {8, 0},
+ {29, 0},
+ {19, 0},
+ {45, 1},
+ {46, 1},
+ {47, 1},
+ {48, 1},
+ {50, 1},
+ {53, 1}
+};
+
+
+void InitScorp()
+{
+ ScorpCount = kMaxScorpions;
+}
+
+int BuildScorp(short nSprite, int x, int y, int z, short nSector, short nAngle, int nChannel)
+{
+ ScorpCount--;
+ if (ScorpCount < 0) {
+ return -1;
+ }
+
+ short nScorp = ScorpCount;
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(nSector, 122);
+ }
+ else
+ {
+ changespritestat(nSprite, 122);
+
+ x = sprite[nSprite].x;
+ y = sprite[nSprite].y;
+ z = sector[sprite[nSprite].sectnum].floorz;
+ nAngle = sprite[nSprite].ang;
+ }
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].clipdist = 70;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].xrepeat = 80;
+ sprite[nSprite].yrepeat = 80;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].extra = -1;
+ sprite[nSprite].hitag = 0;
+
+// GrabTimeSlot(3);
+
+ scorpion[ScorpCount].nHealth = 20000;
+ scorpion[ScorpCount].nFrame = 0;
+ scorpion[ScorpCount].nAction = 0;
+ scorpion[ScorpCount].nSprite = nSprite;
+ scorpion[ScorpCount].nTarget = -1;
+ scorpion[ScorpCount].g = 0;
+ scorpion[ScorpCount].i = 1;
+
+ ScorpChan[nScorp] = nChannel;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nScorp | 0x220000);
+ scorpion[nScorp].f = runlist_AddRunRec(NewRun, nScorp | 0x220000);
+
+ nCreaturesLeft++;
+
+ return nScorp | 0x220000;
+}
+
+void FuncScorp(int a, int nDamage, int nRun)
+{
+ short nScorp = RunData[nRun].nVal;
+ assert(nScorp >= 0 && nScorp < kMaxScorpions);
+
+ int edi = 0;
+
+ short nSprite = scorpion[nScorp].nSprite;
+ short nAction = scorpion[nScorp].nAction;
+
+ short nTarget = -1;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Scorp\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, SeqOffsets[kSeqScorp] + ActionSeq[nAction].a, scorpion[nScorp].nFrame, ActionSeq[nAction].b);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ if (!nDamage) {
+ return;
+ }
+ // else fall through to case 0x80000
+ }
+
+ case 0x80000:
+ {
+ if (scorpion[nScorp].nHealth <= 0) {
+ return;
+ }
+
+ scorpion[nScorp].nHealth -= nDamage;
+
+ if (scorpion[nScorp].nHealth <= 0)
+ {
+ scorpion[nScorp].nHealth = 0;
+
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+
+ scorpion[nScorp].nAction = 4;
+ scorpion[nScorp].nFrame = 0;
+
+ sprite[nSprite].cstat &= 0xFEFE;
+
+ nCreaturesLeft--;
+
+ scorpion[nScorp].g = 10;
+ return;
+ }
+ else
+ {
+ nTarget = a & 0xFFFF;
+
+ if (nTarget >= 0)
+ {
+ if (sprite[nSprite].statnum == 100 || (sprite[nSprite].statnum < 199 && !RandomSize(5)))
+ {
+ scorpion[nScorp].nTarget = nTarget;
+ }
+ }
+
+ if (!RandomSize(5))
+ {
+ scorpion[nScorp].nAction = RandomSize(2) + 4;
+ scorpion[nScorp].nFrame = 0;
+ return;
+ }
+
+ if (RandomSize(2)) {
+ return;
+ }
+
+ D3PlayFX(StaticSound[kSound41], nSprite);
+
+ goto FS_Pink_A;
+ }
+ }
+
+ case 0x20000:
+ {
+ if (scorpion[nScorp].nHealth) {
+ Gravity(nSprite);
+ }
+
+ int nSeq = SeqOffsets[kSeqScorp] + ActionSeq[nAction].a;
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, scorpion[nScorp].nFrame);
+ seq_MoveSequence(nSprite, nSeq, scorpion[nScorp].nFrame);
+
+ scorpion[nScorp].nFrame++;
+
+ if (scorpion[nScorp].nFrame >= SeqSize[nSeq])
+ {
+ scorpion[nScorp].nFrame = 0;
+ edi = 1;
+ }
+
+ int nFlag = FrameFlag[SeqBase[nSeq] + scorpion[nScorp].nFrame];
+ nTarget = scorpion[nScorp].nTarget;
+
+ switch (nAction)
+ {
+ default:
+ return;
+
+ case 0:
+ {
+ if (scorpion[nScorp].g > 0)
+ {
+ scorpion[nScorp].g--;
+ return;
+ }
+
+ if ((nScorp & 31) == (totalmoves & 31))
+ {
+ if (nTarget < 0)
+ {
+ nTarget = FindPlayer(nSprite, 500);
+
+ if (nTarget >= 0)
+ {
+ D3PlayFX(StaticSound[kSound41], nSprite);
+
+ scorpion[nScorp].nFrame = 0;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512);
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang);
+
+ scorpion[nScorp].nAction = 1;
+ scorpion[nScorp].nTarget = nTarget;
+ }
+ }
+ }
+
+ return;
+ }
+
+ case 1:
+ {
+ scorpion[nScorp].i--;
+
+ if (scorpion[nScorp].i <= 0)
+ {
+ scorpion[nScorp].i = RandomSize(5);
+ // GOTO FS_Pink_A:
+ goto FS_Pink_A;
+ }
+ else
+ {
+ int nMove = MoveCreatureWithCaution(nSprite);
+ if ((nMove & 0xC000) == 0xC000)
+ {
+ if (nTarget == (nMove & 0x3FFF))
+ {
+ int nAngle = getangle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+ if (AngleDiff(sprite[nSprite].ang, nAngle) < 64)
+ {
+ scorpion[nScorp].nAction = 2;
+ scorpion[nScorp].nFrame = 0;
+ }
+
+ // GOTO FS_Red
+ goto FS_Red;
+ }
+ else
+ {
+// GOTO FS_Pink_A
+ goto FS_Pink_A;
+ }
+ }
+ else if ((nMove & 0xC000) == 0x8000)
+ {
+ // GOTO FS_Pink_A
+ goto FS_Pink_A;
+ }
+ else
+ {
+ // GOTO FS_Pink_B
+ goto FS_Pink_B;
+ }
+ }
+ }
+
+ case 2:
+ {
+ if (nTarget == -1)
+ {
+ scorpion[nScorp].nAction = 0;
+ scorpion[nScorp].g = 5;
+ }
+ else
+ {
+ if (PlotCourseToSprite(nSprite, nTarget) >= 768)
+ {
+ scorpion[nScorp].nAction = 1;
+ }
+ else if (nFlag & 0x80)
+ {
+ runlist_DamageEnemy(nTarget, nSprite, 7);
+ }
+ }
+
+ // GOTO FS_Red
+ goto FS_Red;
+ }
+
+ case 3:
+ {
+ if (edi)
+ {
+ scorpion[nScorp].h--;
+ if (scorpion[nScorp].h <= 0)
+ {
+ scorpion[nScorp].nAction = 1;
+
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512);
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang);
+
+ scorpion[nScorp].nFrame = 0;
+ return;
+ }
+ }
+
+ if (!(nFlag & 0x80)) {
+ return;
+ }
+
+ short nBulletSprite = BuildBullet(nSprite, 16, 0, 0, -1, sprite[nSprite].ang, nTarget + 10000, 1) & 0xFFFF;
+ if (nBulletSprite > -1)
+ {
+ PlotCourseToSprite(nBulletSprite, nTarget);
+ }
+
+ return;
+ }
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ {
+ if (!edi) {
+ return;
+ }
+
+ if (scorpion[nScorp].nHealth > 0)
+ {
+ scorpion[nScorp].nAction = 1;
+ scorpion[nScorp].nFrame = 0;
+ scorpion[nScorp].g = 0;
+ return;
+ }
+
+ scorpion[nScorp].g--;
+ if (scorpion[nScorp].g <= 0)
+ {
+ scorpion[nScorp].nAction = 8;
+ }
+ else
+ {
+ scorpion[nScorp].nAction = RandomBit() + 6;
+ }
+
+ return;
+ }
+
+ case 8:
+ {
+ if (edi)
+ {
+ scorpion[nScorp].nAction++; // set to 9
+ scorpion[nScorp].nFrame = 0;
+
+ runlist_ChangeChannel(ScorpChan[nScorp], 1);
+ return;
+ }
+
+ int nSpider = BuildSpider(-1, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum, sprite[nSprite].ang);
+ if (nSpider != -1)
+ {
+ short nSpiderSprite = nSpider & 0xFFFF;
+
+ sprite[nSpiderSprite].ang = RandomSize(11);
+
+ int nRnd = RandomSize(5) + 1;
+
+ sprite[nSpiderSprite].xvel = (Sin(sprite[nSpiderSprite].ang + 512) >> 8) * nRnd;
+ sprite[nSpiderSprite].yvel = (Sin(sprite[nSpiderSprite].ang) >> 8) * nRnd;
+ sprite[nSpiderSprite].zvel = (-(RandomSize(5) + 3)) << 8;
+ }
+
+ return;
+ }
+
+ case 9:
+ {
+ sprite[nSprite].cstat &= 0xFEFE;
+
+ if (edi)
+ {
+ runlist_SubRunRec(scorpion[nScorp].f);
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+
+ mydeletesprite(nSprite);
+ }
+
+ return;
+ }
+ }
+
+ break;
+ }
+ }
+
+FS_Pink_A:
+ PlotCourseToSprite(nSprite, nTarget);
+ sprite[nSprite].ang += RandomSize(7) - 63;
+ sprite[nSprite].ang &= kAngleMask;
+
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512);
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang);
+
+FS_Pink_B:
+ if (scorpion[nScorp].g)
+ {
+ scorpion[nScorp].g--;
+ }
+ else
+ {
+ scorpion[nScorp].g = 45;
+
+ if (cansee(sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z - GetSpriteHeight(nSprite), sprite[nSprite].sectnum,
+ sprite[nTarget].x, sprite[nTarget].y, sprite[nTarget].z - GetSpriteHeight(nTarget), sprite[nTarget].sectnum))
+ {
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].ang = GetMyAngle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+
+ scorpion[nScorp].h = RandomSize(2) + RandomSize(3);
+
+ if (!scorpion[nScorp].h) {
+ scorpion[nScorp].g = RandomSize(5);
+ }
+ else
+ {
+ scorpion[nScorp].nAction = 3;
+ scorpion[nScorp].nFrame = 0;
+ }
+ }
+ }
+
+FS_Red:
+ if (!nAction || nTarget == -1) {
+ return;
+ }
+
+ if (!(sprite[nTarget].cstat & 0x101))
+ {
+ scorpion[nScorp].nAction = 0;
+ scorpion[nScorp].nFrame = 0;
+ scorpion[nScorp].g = 30;
+ scorpion[nScorp].nTarget = -1;
+
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ }
+}
diff --git a/source/exhumed/src/scorp.h b/source/exhumed/src/scorp.h
new file mode 100644
index 000000000..9b5c1bacf
--- /dev/null
+++ b/source/exhumed/src/scorp.h
@@ -0,0 +1,28 @@
+
+#ifndef __scorp_h__
+#define __scorp_h__
+
+/*
+ Selkis Boss AI code
+*/
+
+#define kMaxScorpions 5
+
+struct Scorpion
+{
+ short nHealth;
+ short nFrame;
+ short nAction;
+ short nSprite;
+ short nTarget;
+ short f;
+ short g;
+ schar h;
+ schar i;
+};
+
+void InitScorp();
+int BuildScorp(short nSprite, int x, int y, int z, short nSector, short nAngle, int nChannel);
+void FuncScorp(int, int, int);
+
+#endif
diff --git a/source/exhumed/src/sequence.cpp b/source/exhumed/src/sequence.cpp
new file mode 100644
index 000000000..3152e462c
--- /dev/null
+++ b/source/exhumed/src/sequence.cpp
@@ -0,0 +1,658 @@
+
+#include "typedefs.h"
+#include "sequence.h"
+#include "engine.h"
+#include "exhumed.h"
+#include "sound.h"
+#include "player.h"
+#include "trigdat.h"
+#include "move.h"
+#include "view.h"
+#include "init.h"
+#ifndef __WATCOMC__
+#include
+#include // for printf
+#else
+#include
+#include
+#endif
+
+// TEMP
+#include
+
+#define kMaxSequences 4096
+#define kMaxSEQFiles 78
+#define kMaxSEQFrames 18000
+#define kMaxSEQChunks 21000
+
+short sequences = 0;
+short frames = 0;
+short chunks = 0;
+short nPilotLightFrame;
+short nPilotLightCount;
+
+short nPilotLightBase;
+short laststatustile;
+
+short nShadowWidth = 1;
+short nFlameHeight = 1;
+
+short SeqBase[kMaxSequences];
+short SeqSize[kMaxSequences];
+short SeqFlag[kMaxSequences];
+
+short FrameSound[kMaxSEQFrames];
+short FrameSize[kMaxSEQFrames];
+short FrameBase[kMaxSEQFrames];
+short FrameFlag[kMaxSEQFrames];
+
+short ChunkYpos[kMaxSEQChunks];
+short ChunkXpos[kMaxSEQChunks];
+short ChunkPict[kMaxSEQChunks];
+short ChunkFlag[kMaxSEQChunks];
+
+
+char *SeqNames[kMaxSEQFiles] =
+{
+ "rothands",
+ "sword",
+ "pistol",
+ "m_60",
+ "flamer", // 4
+ "grenade",
+ "cobra",
+ "bonesaw",
+ "scramble",
+ "glove",
+ "mummy", // 10
+ "skull",
+ "poof",
+ "kapow",
+ "fireball",
+ "bubble",
+ "spider", // 16
+ "anubis",
+ "anuball",
+ "fish",
+ "snakehed", // 20?
+ "snakbody",
+ "wasp",
+ "cobrapow",
+ "scorp",
+ "joe", // 25
+ "status",
+ "dead",
+ "deadex",
+ "anupoof",
+ "skulpoof", // 30
+ "bullet",
+ "shadow",
+ "grenroll",
+ "grenboom",
+ "splash",
+ "grenpow",
+ "skulstrt",
+ "firepoof",
+ "bloodhit",
+ "lion", // 40
+ "items",
+ "lavag", // 42
+ "lsplash",
+ "lavashot",
+ "smokebal",
+ "firepot",
+ "rex",
+ "set", // 48
+ "queen",
+ "roach", // 50
+ "hawk",
+ "setghost",
+ "setgblow",
+ "bizztail",
+ "bizzpoof",
+ "queenegg",
+ "roacshot",
+ "backgrnd",
+ "screens", // 59
+ "arrow",
+ "fonts",
+ "drips",
+ "firetrap",
+ "magic2",
+ "creepy",
+ "slider", // 66
+ "ravolt",
+ "eyehit",
+ "font2", // 69
+ "seebubbl",
+ "blood",
+ "drum",
+ "poof2",
+ "deadbrn",
+ "grenbubb",
+ "rochfire",
+ "rat"
+};
+
+short SeqOffsets[kMaxSEQFiles];
+
+
+int seq_ReadSequence(char *seqName)
+{
+ int i;
+ char buffer[200];
+ buffer[0] = '\0';
+
+ strcat(buffer, seqName);
+ strcat(buffer, ".seq");
+
+ int hFile = kopen4load(buffer, 1);
+ if (hFile == -1)
+ {
+ printf("Unable to open '%s'!\n", buffer);
+ kclose(hFile);
+ return 0;
+ }
+
+ short tag;
+ kread(hFile, &tag, sizeof(tag));
+ if (tag < 'HI' || tag > 'HI' && tag != 'SD')
+ {
+ printf("Unsupported sequence version!\n");
+ kclose(hFile);
+ return 0;
+ }
+
+ short centerx, centery; // TODO - are global vars?
+ short nSeqs;
+ kread(hFile, ¢erx, sizeof(centerx));
+ kread(hFile, ¢ery, sizeof(centery));
+ kread(hFile, &nSeqs, sizeof(nSeqs));
+
+ if (nSeqs <= 0 || sequences + nSeqs >= kMaxSequences)
+ {
+ if (nSeqs < 0)
+ {
+ printf("Invalid sequence count!\n");
+ kclose(hFile);
+ return 0;
+ }
+ else {
+ bail2dos("Not enough sequences available! Increase array!\n");
+ }
+ }
+
+ kread(hFile, &SeqBase[sequences], nSeqs * sizeof(SeqBase[0]));
+ kread(hFile, &SeqSize[sequences], nSeqs * sizeof(SeqSize[0]));
+ kread(hFile, &SeqFlag[sequences], nSeqs * sizeof(SeqFlag[0]));
+
+ for (i = 0; i < nSeqs; i++)
+ {
+ SeqBase[sequences + i] += frames;
+ }
+
+ sshort nFrames;
+ kread(hFile, &nFrames, sizeof(nFrames));
+
+ if (nFrames <= 0 || frames + nFrames >= kMaxSEQFrames)
+ {
+ if (nFrames < 0 )
+ {
+ printf("Invalid frame count!\n");
+ kclose(hFile);
+ return 0;
+ }
+ else {
+ bail2dos("Not enough frames available! Increase FRAMEMAX!\n");
+ }
+ }
+
+ kread(hFile, &FrameBase[frames], nFrames * sizeof(FrameBase[0]));
+ kread(hFile, &FrameSize[frames], nFrames * sizeof(FrameSize[0]));
+ kread(hFile, &FrameFlag[frames], nFrames * sizeof(FrameFlag[0]));
+ memset(&FrameSound[frames], -1, nFrames * sizeof(FrameSound[0]));
+
+ for (i = 0; i < nFrames; i++)
+ {
+ FrameBase[frames + i] += chunks;
+ }
+
+ sshort nChunks;
+ kread(hFile, &nChunks, sizeof(nChunks));
+
+ if (nChunks < 0 || chunks + nChunks >= kMaxSEQChunks)
+ {
+ if (nChunks < 0 )
+ {
+ printf("Invalid chunk count!\n");
+ kclose(hFile);
+ return 0;
+ }
+ else {
+ bail2dos("Not enough chunks available! Increase CHUNKMAX!\n");
+ }
+ }
+
+ kread(hFile, &ChunkXpos[chunks], nChunks * sizeof(ChunkXpos[0]));
+ kread(hFile, &ChunkYpos[chunks], nChunks * sizeof(ChunkYpos[0]));
+ kread(hFile, &ChunkPict[chunks], nChunks * sizeof(ChunkPict[0]));
+ kread(hFile, &ChunkFlag[chunks], nChunks * sizeof(ChunkFlag[0]));
+
+ for (i = 0; i < nChunks; i++)
+ {
+ ChunkXpos[chunks + i] -= centerx;
+ ChunkYpos[chunks + i] -= centery;
+ }
+
+ sequences += nSeqs;
+ FrameBase[frames + nFrames] = chunks + nChunks;
+ frames += nFrames;
+ SeqBase[sequences] = frames;
+ chunks += nChunks;
+
+ if (tag == 'SD')
+ {
+ short var_20;
+ kread(hFile, &var_20, sizeof(var_20));
+
+ for (i = 0; i < var_20; i++)
+ {
+ kread(hFile, &buffer[i * 10], 8);
+ }
+
+ short var_24;
+ kread(hFile, &var_24, sizeof(var_24));
+
+ for (i = 0; i < var_24; i++)
+ {
+ short var_28, var_2C;
+ kread(hFile, &var_28, sizeof(var_28));
+ kread(hFile, &var_2C, sizeof(var_2C));
+
+ int hSound = 0;
+ // int hSound = LoadSound();
+
+ FrameSound[frames + var_28] = hSound | (var_2C & 0xFE00);
+ }
+ }
+
+ kclose(hFile);
+ return nSeqs;
+}
+
+int seq_GetFirstSeqPicnum(int nSeq)
+{
+ int i = SeqOffsets[nSeq];
+ i = SeqBase[i];
+ i = FrameBase[i];
+ i = ChunkPict[i];
+
+ return i;
+}
+
+void seq_LoadSequences()
+{
+ int i;
+
+ for (i = 0; i < kMaxSEQFiles; i++)
+ {
+ SeqOffsets[i] = sequences;
+
+ if (seq_ReadSequence(SeqNames[i]) == 0) {
+ printf("Error loading '%s'\n", SeqNames[i]);
+ }
+ }
+
+ nShadowPic = seq_GetFirstSeqPicnum(kSeqShadow);
+ nShadowWidth = tilesizx[nShadowPic];
+
+ nFlameHeight = tilesizy[seq_GetFirstSeqPicnum(kSeqFirePoof)];
+
+ nBackgroundPic = seq_GetFirstSeqPicnum(kSeqBackgrnd);
+
+ nPilotLightBase = SeqBase[SeqOffsets[kSeqFlamer] + 3];
+ nPilotLightCount = SeqSize[SeqOffsets[kSeqFlamer] + 3];
+ nPilotLightFrame = 0;
+
+ nFontFirstChar = seq_GetFirstSeqPicnum(kSeqFont2);
+
+ short nSize = SeqSize[SeqOffsets[kSeqFont2]];
+
+ for (i = 0; i < nSize; i++)
+ {
+ picanm[nFontFirstChar + i] &= 0xFF0000FF;
+ }
+}
+
+void seq_DrawStatusSequence(short nSequence, ushort edx, short ebx)
+{
+ edx += SeqBase[nSequence];
+
+ short nFrameBase = FrameBase[edx];
+ sshort nFrameSize = FrameSize[edx];
+
+ while (1)
+ {
+ nFrameSize--;
+ if (nFrameSize < 0)
+ break;
+
+ uchar nStat = 1; // (thex, they) is middle
+
+ laststatusx = ChunkXpos[nFrameBase] + 160;
+ laststatusy = ChunkYpos[nFrameBase] + 100 + ebx;
+
+ int thex = laststatusx;
+ int they = laststatusy;
+
+ if (laststatusx >= 155 && laststatusx <= 162) {
+ laststatusx = 159;
+ }
+
+ // TEMP
+ if (laststatusy == 188 && laststatusx == 159)
+ laststatusy = 189;
+
+
+
+ short chunkFlag = ChunkFlag[nFrameBase];
+
+ if (chunkFlag & 1) {
+ nStat = 0x9; // (thex, they) is middle, and x-flipped
+ }
+
+ if (chunkFlag & 2) {
+ nStat |= 0x10; // y-flipped
+ }
+
+ laststatustile = ChunkPict[nFrameBase];
+
+ if (bHiRes) {
+ nStat |= 0x2; // scale and clip to viewing window
+ }
+
+ overwritesprite(laststatusx, laststatusy, laststatustile, 0, nStat, kPalNormal);
+ nFrameBase++;
+ }
+}
+
+short seq_GetFrameFlag(short val, short nFrame)
+{
+ return FrameFlag[SeqBase[val] + nFrame];
+}
+
+void seq_DrawPilotLightSeq(int xOffset, int yOffset)
+{
+ short nSect = nPlayerViewSect[nLocalPlayer];
+
+ if (!(SectFlag[nSect] & kSectUnderwater))
+ {
+ short nFrame = nPilotLightBase + nPilotLightFrame;
+ short nFrameBase = FrameBase[nFrame];
+ short nFrameSize = FrameSize[nFrame];
+
+ while (1)
+ {
+ nFrameSize--;
+ if (nFrameSize < 0)
+ return;
+
+ short nTile = ChunkPict[nFrameBase];
+ int x = ChunkXpos[nFrameBase] + (160 + xOffset);
+ int y = ChunkYpos[nFrameBase] + (100 + yOffset);
+
+ rotatesprite(x << 16, y << 16, 0x10000, (-8 * nPlayerDAng) & kAngleMask, nTile, -127, 1, 2, windowx1, windowy1, windowx2, windowy2);
+ nFrameBase++;
+ }
+ }
+}
+
+/*
+ 6 parameters
+
+ arg0 - shade?
+
+*/
+
+int seq_DrawGunSequence(int nSeqOffset, short dx, int xOffs, int yOffs, int nShade, int nPal)
+{
+ short nFrame = SeqBase[nSeqOffset] + dx;
+ short nFrameBase = FrameBase[nFrame];
+ short nFrameSize = FrameSize[nFrame];
+ short frameFlag = FrameFlag[nFrame];
+
+ while (1)
+ {
+ nFrameSize--;
+ if (nFrameSize < 0)
+ break;
+
+ uchar nStat = 3;
+ int x = ChunkXpos[nFrameBase] + 160;
+ int y = ChunkYpos[nFrameBase] + 100;
+
+ if (ChunkFlag[nFrameBase] & 1) {
+ nStat = 11;
+ }
+
+ if (ChunkFlag[nFrameBase] & 2) {
+ nStat |= 0x10;
+ }
+
+ short nTile = ChunkPict[nFrameBase];
+
+ if (frameFlag & 4) {
+ nShade = -100;
+ }
+
+ if (nPlayerInvisible[nLocalPlayer]) {
+ nStat |= 0x4;
+ }
+
+ overwritesprite(x + xOffs, y + yOffs, nTile, nShade, nStat, nPal);
+ nFrameBase++;
+ }
+
+ return frameFlag;
+}
+
+int seq_GetFrameSound(int val, int edx)
+{
+ return FrameSound[SeqBase[val] + edx];
+}
+
+void seq_MoveSequence(short nSprite, short nSeq, short bx)
+{
+ assert(nSeq >= 0); // TEMP
+
+ int nSound = FrameSound[SeqBase[nSeq] + bx];
+ if (nSound == -1) {
+ return;
+ }
+
+ if (nSprite > -1) {
+ D3PlayFX(nSound, nSprite);
+ }
+ else {
+ PlayLocalSound(nSound, 0);
+ }
+}
+
+int seq_GetSeqPicnum2(short nSeq, short nFrame)
+{
+ short nBase = FrameBase[SeqBase[nSeq] + nFrame];
+ return ChunkPict[nBase];
+}
+
+int seq_GetSeqPicnum(short nSeq, short edx, short ebx)
+{
+ edx += SeqOffsets[nSeq];
+ ebx += SeqBase[edx];
+ short c = FrameBase[ebx];
+
+ return ChunkPict[c];
+}
+
+int seq_PlotArrowSequence(short nSprite, short nSeq, int nVal)
+{
+ int nAngle = GetMyAngle(nCamerax - tsprite[nSprite].x, nCameray - tsprite[nSprite].y);
+
+ int nSeqOffset = ((((tsprite[nSprite].ang + 512) - nAngle) + 128) & kAngleMask) >> 8;
+
+ short nFrame = SeqBase[nSeqOffset + nSeq] + nVal;
+
+ short nFrameBase = FrameBase[nFrame];
+ short nFrameSize = FrameSize[nFrame];
+
+ uchar nShade = tsprite[nSprite].shade;
+ short nStat = tsprite[nSprite].cstat;
+
+ nStat |= 0x80;
+
+ if (nSeqOffset & 3) {
+ nStat |= 0x18;
+ }
+ else {
+ nStat &= 0x0E7;
+ }
+
+ if (FrameFlag[nFrame] & 4) {
+ nShade -= 100;
+ }
+
+ tsprite[nSprite].cstat = nStat;
+ tsprite[nSprite].shade = nShade;
+ tsprite[nSprite].statnum = nFrameSize;
+
+ if (ChunkFlag[nFrameBase] & 1)
+ {
+ tsprite[nSprite].xoffset = ChunkXpos[nFrameBase];
+ tsprite[nSprite].cstat |= 4;
+ }
+ else
+ {
+ tsprite[nSprite].xoffset = -ChunkXpos[nFrameBase];
+ }
+
+ tsprite[nSprite].yoffset = -ChunkYpos[nFrameBase];
+ tsprite[nSprite].picnum = ChunkPict[nFrameBase];
+
+ return ChunkPict[nFrameBase];
+}
+
+int seq_PlotSequence(short nSprite, short edx, short nFrame, short ecx)
+{
+ int nAngle = GetMyAngle(nCamerax - tsprite[nSprite].x, nCameray - tsprite[nSprite].y);
+
+ int val;
+
+ if (ecx & 1)
+ {
+ val = 0;
+ }
+ else
+ {
+ val = (((tsprite[nSprite].ang - nAngle) + 128) & kAngleMask) >> 8;
+ }
+
+ int eax = SeqBase[edx] + nFrame;
+ int edi = SeqBase[edx + val] + nFrame;
+
+ short nBase = FrameBase[edi];
+ short nSize = FrameSize[edi];
+
+ schar shade = tsprite[nSprite].shade;
+
+ if (FrameFlag[eax] & 4)
+ {
+ shade -= 100;
+ }
+
+ short nPict = ChunkPict[nBase];
+
+ if (ecx & 0x100)
+ {
+ edx = -3;
+ }
+ else
+ {
+ edx = 100;
+ }
+
+ int esi = nSize + 1;
+ esi += edx;
+
+ int var_14 = edx + 1;
+ short nOwner = tsprite[nSprite].owner;
+
+ while (1)
+ {
+ esi--;
+ nSize--;
+
+ if (esi < var_14) {
+ break;
+ }
+
+ tsprite[spritesortcnt].x = tsprite[nSprite].x;
+ tsprite[spritesortcnt].y = tsprite[nSprite].y;
+ tsprite[spritesortcnt].z = tsprite[nSprite].z;
+ tsprite[spritesortcnt].shade = shade;
+ tsprite[spritesortcnt].pal = tsprite[nSprite].pal;
+ tsprite[spritesortcnt].xrepeat = tsprite[nSprite].xrepeat;
+ tsprite[spritesortcnt].yrepeat = tsprite[nSprite].yrepeat;
+ tsprite[spritesortcnt].ang = tsprite[nSprite].ang;
+ tsprite[spritesortcnt].owner = tsprite[nSprite].owner;
+ tsprite[spritesortcnt].sectnum = tsprite[nSprite].sectnum;
+ tsprite[spritesortcnt].cstat = tsprite[nSprite].cstat |= 0x80;
+ tsprite[spritesortcnt].statnum = esi;
+
+ if (ChunkFlag[nBase] & 1)
+ {
+ tsprite[spritesortcnt].xoffset = ChunkXpos[nBase];
+ tsprite[spritesortcnt].cstat |= 4; // x-flipped
+ }
+ else
+ {
+ tsprite[spritesortcnt].xoffset = -ChunkXpos[nBase];
+ }
+
+ tsprite[spritesortcnt].yoffset = -ChunkYpos[nBase];
+ tsprite[spritesortcnt].picnum = ChunkPict[nBase];
+
+ spritesortcnt++;
+ nBase++;
+ }
+
+ if (!(tsprite[nSprite].cstat & 0x101) || (sprite[nOwner].statnum == 100 && nNetPlayerCount))
+ {
+ tsprite[nSprite].owner = -1;
+ }
+ else
+ {
+ short nSector = tsprite[nSprite].sectnum;
+ int nFloorZ = sector[nSector].floorz;
+
+ if (nFloorZ <= eyelevel[nLocalPlayer] + initz) {
+ tsprite[nSprite].owner = -1;
+ }
+ else
+ {
+ tsprite[nSprite].picnum = nShadowPic;
+
+ int edx = ((tilesizx[nPict] << 5) / nShadowWidth) - ((nFloorZ - tsprite[nSprite].z) >> 10);
+ if (edx < 1) {
+ edx = 1;
+ }
+
+ tsprite[nSprite].cstat = 0x22; // transluscence, floor sprite
+ tsprite[nSprite].z = nFloorZ + 1;
+ tsprite[nSprite].yrepeat = (uchar)edx;
+ tsprite[nSprite].xrepeat = (uchar)edx;
+ tsprite[nSprite].statnum = -3;
+ tsprite[nSprite].pal = 0;
+ }
+ }
+
+ return nPict;
+}
diff --git a/source/exhumed/src/sequence.h b/source/exhumed/src/sequence.h
new file mode 100644
index 000000000..77a78b8fa
--- /dev/null
+++ b/source/exhumed/src/sequence.h
@@ -0,0 +1,125 @@
+
+#ifndef __sequence_h__
+#define __sequence_h__
+
+#include "typedefs.h"
+
+enum {
+ kSeqRothands = 0,
+ kSeqSword,
+ kSeqPistol,
+ kSeqM60,
+ kSeqFlamer,
+ kSeqGrenade,
+ kSeqCobra,
+ kSeqBoneSaw,
+ kSeqScramble,
+ kSeqGlove,
+ kSeqMummy,
+ kSeqSkull,
+ kSeqPoof,
+ kSeqKapow,
+ kSeqFireball,
+ kSeqBubble,
+ kSeqSpider,
+ kSeqAnubis,
+ kSeqAnuBall,
+ kSeqFish,
+ kSeqSnakehed,
+ kSeqSnakBody,
+ kSeqWasp,
+ kSeqCobraPow,
+ kSeqScorp,
+ kSeqJoe, // player pic
+ kSeqStatus,
+ kSeqDead,
+ kSeqDeadEx,
+ kSeqAnuPoof,
+ kSeqSkulPoof,
+ kSeqBullet,
+ kSeqShadow,
+ kSeqGrenRoll,
+ kSeqGrenBoom,
+ kSeqSplash,
+ kSeqGrenPow,
+ kSeqSkulSrt,
+ kSeqFirePoof,
+ kSeqBloodHit,
+ kSeqLion,
+ kSeqItems,
+ kSeqLavag,
+ kSeqLsplash,
+ kSeqLavaShot,
+ kSeqSmokeBal,
+ kSeqFirePot,
+ kSeqRex,
+ kSeqSet,
+ kSeqQueen,
+ kSeqRoach,
+ kSeqHawk,
+ kSeqSetGhost,
+ kSeqSetGBlow,
+ kSeqBizzTail,
+ kSeqBizzPoof,
+ kSeqQueenEgg,
+ kSeqRoacShot,
+ kSeqBackgrnd,
+ kSeqScreens,
+ kSeqArrow,
+ kSeqFonts,
+ kSeqDrips,
+ kSeqFireTrap,
+ kSeqMagic2,
+ kSeqCreepy,
+ kSeqSlider,
+ kSeqRavolt, // 67
+ kSeqEyeHit,
+ kSeqFont2,
+ kSeqSeeBubbl,
+ kSeqBlood,
+ kSeqDrum,
+ kSeqPoof2,
+ kSeqDeadBrn, // 74
+ kSeqGrenBubb,
+ kSeqRochfire,
+ kSeqRat
+};
+
+struct actionSeq
+{
+ short a;
+ short b;
+};
+
+extern short frames;
+
+extern short SeqBase[];
+extern short SeqSize[];
+extern short SeqOffsets[];
+
+extern short FrameFlag[];
+
+extern short nShadowWidth;
+extern short nFlameHeight;
+
+extern short nPilotLightFrame;
+extern short nPilotLightCount;
+
+extern short laststatustile;
+
+extern int laststatusx;
+extern int laststatusy;
+
+void seq_LoadSequences();
+void seq_MoveSequence(short nSprite, short nSeq, short bx);
+int seq_GetSeqPicnum2(short nSeq, short nFrame);
+int seq_GetSeqPicnum(short nSeq, short edx, short ebx);
+void seq_DrawStatusSequence(short nSequence, ushort edx, short ebx);
+
+int seq_DrawGunSequence(int nSeqOffset, short dx, int xOffs, int yOffs, int nShade, int nPal);
+short seq_GetFrameFlag(short val, short nFrame);
+int seq_PlotSequence(short nSprite, short edx, short nFrame, short ecx);
+int seq_PlotArrowSequence(short nSprite, short nSeq, int nVal);
+void seq_DrawPilotLightSeq(int xOffset, int yOffset);
+
+#endif
diff --git a/source/exhumed/src/serial.cpp b/source/exhumed/src/serial.cpp
new file mode 100644
index 000000000..679918c51
--- /dev/null
+++ b/source/exhumed/src/serial.cpp
@@ -0,0 +1,26 @@
+
+#include "typedefs.h"
+#include "serial.h"
+
+short bSendBye = kFalse;
+
+
+void UpdateSerialInputs()
+{
+
+}
+
+void ClearSerialInbuf()
+{
+
+}
+
+void HangUp()
+{
+
+}
+
+void UnInitSerial()
+{
+
+}
diff --git a/source/exhumed/src/serial.h b/source/exhumed/src/serial.h
new file mode 100644
index 000000000..52fe66071
--- /dev/null
+++ b/source/exhumed/src/serial.h
@@ -0,0 +1,12 @@
+
+#ifndef __serial_h__
+#define __serial_h__
+
+extern short bSendBye;
+
+void UpdateSerialInputs();
+void ClearSerialInbuf();
+void HangUp();
+void UnInitSerial();
+
+#endif
diff --git a/source/exhumed/src/set.cpp b/source/exhumed/src/set.cpp
new file mode 100644
index 000000000..b5c226376
--- /dev/null
+++ b/source/exhumed/src/set.cpp
@@ -0,0 +1,670 @@
+
+#include "set.h"
+#include "engine.h"
+#include "exhumed.h"
+#include "runlist.h"
+#include "sequence.h"
+#include "random.h"
+#include "move.h"
+#include "trigdat.h"
+#include "bullet.h"
+#include
+
+#define kMaxSets 10
+
+short SetCount = 0;
+
+static actionSeq ActionSeq[] = {
+ {0, 0},
+ {77, 1},
+ {78, 1},
+ {0, 0},
+ {9, 0},
+ {63, 0},
+ {45, 0},
+ {18, 0},
+ {27, 0},
+ {36, 0},
+ {72, 1},
+ {74, 1}
+};
+
+struct Set
+{
+ short nHealth;
+ short field_2;
+ short nAction;
+ short nSprite;
+ short nTarget;
+ short field_A;
+ short field_C;
+ short field_D;
+ short field_E;
+};
+
+Set SetList[kMaxSets];
+short SetChan[kMaxSets];
+
+
+void InitSets()
+{
+ SetCount = kMaxSets;
+}
+
+int BuildSet(short nSprite, int x, int y, int z, short nSector, short nAngle, int nVal)
+{
+ SetCount--;
+
+ short nSet = SetCount;
+ if (nSet < 0) {
+ return -1;
+ }
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(nSector, 120);
+ }
+ else
+ {
+ changespritestat(nSprite, 120);
+ x = sprite[nSprite].x;
+ y = sprite[nSprite].y;
+ z = sector[sprite[nSprite].sectnum].floorz;
+ nAngle = sprite[nSprite].ang;
+ }
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].clipdist = 110;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].xrepeat = 87;
+ sprite[nSprite].yrepeat = 96;
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].extra = -1;
+
+ // GrabTimeSlot(3);
+
+ SetList[nSet].nAction = 1;
+ SetList[nSet].nHealth = 8000;
+ SetList[nSet].nSprite = nSprite;
+ SetList[nSet].field_2 = 0;
+ SetList[nSet].nTarget = -1;
+ SetList[nSet].field_A = 90;
+ SetList[nSet].field_C = 0;
+ SetList[nSet].field_D = 0;
+
+ SetChan[nSet] = nVal;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nSet | 0x190000);
+
+ // this isn't stored anywhere...
+ runlist_AddRunRec(NewRun, nSet | 0x190000);
+
+ nCreaturesLeft++;
+
+ return nSet | 0x190000;
+}
+
+int BuildSoul(int nSet)
+{
+ int nSetSprite = SetList[nSet].nSprite;
+ int nSprite = insertsprite(sprite[nSetSprite].sectnum, 0);
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].cstat = 0x8000u;
+ sprite[nSprite].shade = -127;
+ sprite[nSprite].xrepeat = 1;
+ sprite[nSprite].yrepeat = 1;
+ sprite[nSprite].pal = 0;
+ sprite[nSprite].clipdist = 5;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].picnum = seq_GetSeqPicnum(kSeqSet, 75, 0);
+ sprite[nSprite].ang = RandomSize(11);
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 65280 - RandomSize(10);
+ sprite[nSprite].x = sprite[nSetSprite].x;
+ sprite[nSprite].y = sprite[nSetSprite].y;
+
+ short nSector = sprite[nSprite].sectnum;
+ sprite[nSprite].z = (RandomSize(8) << 8) + 8192 + sector[nSector].ceilingz - GetSpriteHeight(nSprite);
+
+ sprite[nSprite].hitag = nSet;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].extra = 0;
+
+// GrabTimeSlot(3);
+
+ sprite[nSprite].owner = runlist_AddRunRec(NewRun, nSprite | 0x230000);
+
+ return nSprite | 0x230000;
+}
+
+void FuncSoul(int pA, int, int nRun)
+{
+ short nSoulSprite = RunData[nRun].nVal;
+
+ int nMessage = pA & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x20000:
+ {
+ seq_MoveSequence(nSoulSprite, SeqOffsets[kSeqSet] + 75, 0);
+
+ if (sprite[nSoulSprite].xrepeat < 32)
+ {
+ sprite[nSoulSprite].xrepeat++;
+ sprite[nSoulSprite].yrepeat++;
+ }
+
+ sprite[nSoulSprite].extra += (nSoulSprite & 0x0F) + 5;
+ sprite[nSoulSprite].extra &= 0x7FF;
+
+ int ebx = (Sin(sprite[nSoulSprite].extra + 512) >> 7);// *Sin(sprite[nSoulSprite].ang);
+
+ if (movesprite(nSoulSprite, Sin(sprite[nSoulSprite].ang + 512) * ebx, Sin(sprite[nSoulSprite].ang) * ebx, sprite[nSoulSprite].zvel, 5120, 0, CLIPMASK0) & 0x10000)
+ {
+ int nSet = sprite[nSoulSprite].hitag;
+ int nSetSprite = SetList[nSet].nSprite;
+
+ sprite[nSoulSprite].cstat = 0;
+ sprite[nSoulSprite].yrepeat = 1;
+ sprite[nSoulSprite].xrepeat = 1;
+ sprite[nSoulSprite].x = sprite[nSetSprite].x;
+ sprite[nSoulSprite].y = sprite[nSetSprite].y;
+ sprite[nSoulSprite].z = sprite[nSetSprite].z - (GetSpriteHeight(nSetSprite) >> 1);
+ mychangespritesect(nSoulSprite, sprite[nSetSprite].sectnum);
+ return;
+ }
+ }
+
+ case 0x80000:
+ case 0xA0000:
+ case 0x90000:
+ return;
+
+ default:
+ DebugOut("unknown msg %d for Soul\n", nMessage);
+ }
+}
+
+void FuncSet(int a, int nDamage, int nRun)
+{
+ int var_24 = 0;
+
+ short nSet = RunData[nRun].nVal;
+ assert(nSet >= 0 && nSet < kMaxSets);
+
+ short nSprite = SetList[nSet].nSprite;
+ short nAction = SetList[nSet].nAction;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %d for Set\n", nMessage);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ if (nAction == 5)
+ {
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ // fall through to case 0x80000
+ }
+ }
+
+ case 0x80000:
+ {
+ if (nDamage && SetList[nSet].nHealth > 0)
+ {
+ if (nAction != 1)
+ {
+ SetList[nSet].nHealth -= nDamage;
+ }
+
+ if (SetList[nSet].nHealth > 0 && nAction == 1)
+ {
+ SetList[nSet].nAction = 2;
+ SetList[nSet].field_2 = 0;
+ }
+ else
+ {
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ SetList[nSet].nHealth = 0;
+ sprite[nSprite].cstat &= 0xFEFE;
+
+ nCreaturesLeft--;
+
+ if (nAction < 10)
+ {
+ SetList[nSet].field_2 = 0;
+ SetList[nSet].nAction = 10;
+ }
+ }
+ }
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a, SeqOffsets[kSeqSet] + ActionSeq[nAction].a, SetList[nSet].field_2, ActionSeq[nAction].b);
+ return;
+ }
+
+ case 0x20000:
+ {
+ Gravity(nSprite);
+
+ short nSeq = SeqOffsets[kSeqSet] + ActionSeq[SetList[nSet].nAction].a;
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, SetList[nSet].field_2);
+ seq_MoveSequence(nSprite, nSeq, SetList[nSet].field_2);
+
+ if (nAction == 3)
+ {
+ if (SetList[nSet].field_D) {
+ SetList[nSet].field_2++;
+ }
+ }
+
+ SetList[nSet].field_2++;
+ if (SetList[nSet].field_2 >= SeqSize[nSeq])
+ {
+ SetList[nSet].field_2 = 0;
+ var_24 = 1;
+ }
+
+ short nFlag = FrameFlag[SeqBase[nSeq] + SetList[nSet].field_2];
+ short nTarget = SetList[nSet].nTarget;
+
+ if (nTarget > -1 && nAction < 10)
+ {
+ if (!(sprite[nTarget].cstat & 0x101))
+ {
+ SetList[nSet].nTarget = -1;
+ SetList[nSet].nAction = 0;
+ nTarget = -1;
+ SetList[nSet].field_2 = 0;
+ }
+ }
+
+ int nVal = MoveCreature(nSprite);
+ int nSprite_b = nSprite;
+
+ pushmove(&sprite[nSprite].x, &sprite[nSprite].y, &sprite[nSprite].z, &sprite[nSprite].sectnum, sprite[nSprite].clipdist << 2, 5120, -5120, CLIPMASK0);
+
+ if (sprite[nSprite].zvel > 4000)
+ {
+ if (nVal & 0x20000)
+ {
+ SetQuake(nSprite_b, 100);
+ }
+ }
+
+ switch (nAction)
+ {
+ default:
+ return;
+
+ case 0:
+ {
+ if ((nSet & 0x1F) == (totalmoves & 0x1F))
+ {
+ if (nTarget < 0)
+ {
+ nTarget = FindPlayer(nSprite, 1000);
+ }
+
+ if (nTarget >= 0)
+ {
+ SetList[nSet].nAction = 3;
+ SetList[nSet].field_2 = 0;
+ SetList[nSet].nTarget = nTarget;
+
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 1;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 1;
+ }
+ }
+
+ return;
+ }
+
+ case 1:
+ {
+ if (FindPlayer(nSprite, 1000) >= 0)
+ {
+ SetList[nSet].nAction = 2;
+ SetList[nSet].field_2 = 0;
+ }
+
+ return;
+ }
+
+ case 2:
+ {
+ if (var_24)
+ {
+ SetList[nSet].nAction = 7;
+ SetList[nSet].field_C = 0;
+ SetList[nSet].field_2 = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+
+ SetList[nSet].nTarget = FindPlayer(nSprite, 1000);
+ }
+ return;
+ }
+
+ case 3:
+ {
+ if (nTarget != -1)
+ {
+ if (nFlag & 0x10 && nVal != 0x20000)
+ {
+ SetQuake(nSprite, 100);
+ }
+
+ int nCourse = PlotCourseToSprite(nSprite, nTarget);
+
+ if ((nSet & 0x1F) == (totalmoves & 0x1F))
+ {
+ int nRand = RandomSize(1);
+
+ switch (nRand)
+ {
+ case 0:
+ case 2:
+ {
+ SetList[nSet].field_C = 0;
+ SetList[nSet].nAction = 7;
+ SetList[nSet].field_2 = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ return;
+ }
+ case 1:
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+
+ SetList[nSet].nAction = 6;
+ SetList[nSet].field_2 = 0;
+ SetList[nSet].field_E = 5;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ return;
+ }
+ default:
+ {
+ if (nCourse <= 100)
+ {
+ SetList[nSet].field_D = 0;
+ }
+ else
+ {
+ SetList[nSet].field_D = 1;
+ }
+ break;
+ }
+ }
+ }
+
+ // loc_338E2
+ sprite[nSprite].xvel = Sin((sprite[nSprite].ang & 0xF8) + 512) >> 1;
+ sprite[nSprite].yvel = Sin((sprite[nSprite].ang & 0xF8)) >> 1;
+
+ if (SetList[nSet].field_D)
+ {
+ sprite[nSprite].xvel *= 2;
+ sprite[nSprite].yvel *= 2;
+ }
+
+ if ((nVal & 0xC000) == 0x8000)
+ {
+ short nWall = nVal & 0xC000;
+ short nSector = wall[nWall].nextsector;
+
+ if (nSector >= 0)
+ {
+ if ((sprite[nSprite].z - sector[nSector].floorz) < 55000)
+ {
+ if (sprite[nSprite].z > sector[nSector].ceilingz)
+ {
+ SetList[nSet].field_C = 1;
+ SetList[nSet].nAction = 7;
+ SetList[nSet].field_2 = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ return;
+ }
+ }
+ }
+
+ sprite[nSprite].ang = (sprite[nSprite].ang + 100) & kAngleMask;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> 1;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> 1;
+ break;
+ }
+ else if ((nVal & 0xC000) == 0xC000)
+ {
+ if (nTarget)
+ {
+ int nAng = getangle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+ if (AngleDiff(sprite[nSprite].ang, nAng) < 64)
+ {
+ SetList[nSet].nAction = 4;
+ SetList[nSet].field_2 = 0;
+ }
+ break;
+ }
+ else
+ {
+ SetList[nSet].field_C = 1;
+ SetList[nSet].nAction = 7;
+ SetList[nSet].field_2 = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ return;
+ }
+ }
+ }
+ else
+ {
+ SetList[nSet].nAction = 0;
+ SetList[nSet].field_2 = 0;
+ return;
+ }
+
+ return; // CHECKME
+ }
+
+ case 4:
+ {
+ if (nTarget == -1)
+ {
+ SetList[nSet].nAction = 0;
+ SetList[nSet].field_A = 50;
+ break;
+ }
+ else
+ {
+ if (PlotCourseToSprite(nSprite, nTarget) >= 768)
+ {
+ SetList[nSet].nAction = 3;
+ break;
+ }
+ else
+ {
+ if (nFlag & 0x80)
+ {
+ runlist_DamageEnemy(nTarget, nSprite, 5);
+ break;
+ }
+ }
+ }
+ }
+
+ case 5:
+ {
+ if (var_24)
+ {
+ SetList[nSet].nAction = 0;
+ SetList[nSet].field_A = 15;
+ }
+ return;
+ }
+
+ case 6:
+ {
+ if (nFlag & 0x80)
+ {
+ // low 16 bits of returned var contains the sprite index, the high 16 the bullet number
+ int nBullet = BuildBullet(nSprite, 11, 0, 0, -1, sprite[nSprite].ang, nTarget + 10000, 1);
+ SetBulletEnemy(nBullet >> 16, nTarget); // isolate the bullet number (shift off the sprite index)
+
+ SetList[nSet].field_E--;
+ if (SetList[nSet].field_E <= 0 || !RandomBit())
+ {
+ if (!RandomBit())
+ {
+ // TODO - same as block belowm
+ SetList[nSet].nAction = 0;
+ SetList[nSet].field_2 = 0;
+ }
+ }
+ }
+ return;
+ }
+
+ case 7:
+ {
+ if (var_24)
+ {
+ if (SetList[nSet].field_C)
+ {
+ sprite[nSprite].zvel = -10000;
+ }
+ else
+ {
+ sprite[nSprite].zvel = -(PlotCourseToSprite(nSprite, nTarget));
+ }
+
+ SetList[nSet].nAction = 8;
+ SetList[nSet].field_2 = 0;
+
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512);
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang);
+ }
+ return;
+ }
+
+ case 8:
+ {
+ if (var_24)
+ {
+ SetList[nSet].field_2 = SeqSize[nSeq] - 1;
+ }
+
+ if (nVal & 0x20000)
+ {
+ SetQuake(nSprite, 200);
+ SetList[nSet].nAction = 9;
+ SetList[nSet].field_2 = 0;
+ }
+ return;
+ }
+
+ case 9:
+ {
+ sprite[nSprite].xvel >>= 1;
+ sprite[nSprite].yvel >>= 1;
+
+ if (var_24)
+ {
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+
+ PlotCourseToSprite(nSprite, nTarget);
+
+ SetList[nSet].nAction = 6;
+ SetList[nSet].field_2 = 0;
+ SetList[nSet].field_E = 5;
+
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+ return;
+ }
+
+ case 10:
+ {
+ if (nFlag & 0x80)
+ {
+ sprite[nSprite].z -= GetSpriteHeight(nSprite);
+ BuildCreatureChunk(nSprite, seq_GetSeqPicnum(kSeqSet, 76, 0));
+ sprite[nSprite].z += GetSpriteHeight(nSprite);
+ }
+
+ if (var_24)
+ {
+ SetList[nSet].nAction = 11;
+ SetList[nSet].field_2 = 0;
+
+ runlist_ChangeChannel(SetChan[nSet], 1);
+
+ for (int i = 0; i < 20; i++)
+ {
+ BuildSoul(nSet);
+ }
+ }
+ return;
+ }
+
+ case 11:
+ {
+ sprite[nSprite].cstat &= 0x0FEFE;
+ return;
+ }
+ }
+
+ // loc_33AE3: ?
+ if (nAction)
+ {
+ if (nTarget != -1)
+ {
+ if (!(sprite[nTarget].cstat & 0x101))
+ {
+ SetList[nSet].nAction = 0;
+ SetList[nSet].field_2 = 0;
+ SetList[nSet].field_A = 100;
+ SetList[nSet].nTarget = -1;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ }
+ }
+ }
+
+ return;
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/exhumed/src/set.h b/source/exhumed/src/set.h
new file mode 100644
index 000000000..34f814bf7
--- /dev/null
+++ b/source/exhumed/src/set.h
@@ -0,0 +1,10 @@
+
+#ifndef __set_h__
+#define __set_h__
+
+void InitSets();
+int BuildSet(short nSprite, int x, int y, int z, short nSector, short nAngle, int nVal);
+void FuncSoul(int, int, int);
+void FuncSet(int, int, int);
+
+#endif
diff --git a/source/exhumed/src/snake.cpp b/source/exhumed/src/snake.cpp
new file mode 100644
index 000000000..37f48e3be
--- /dev/null
+++ b/source/exhumed/src/snake.cpp
@@ -0,0 +1,417 @@
+
+#include "engine.h"
+#include "exhumed.h"
+#include "snake.h"
+#include "status.h"
+#include "player.h"
+#include "runlist.h"
+#include "sequence.h"
+#include "bullet.h"
+#include "input.h"
+#include "anims.h"
+#include "lighting.h"
+#include "sound.h"
+#include "move.h"
+#include "trigdat.h"
+#include "gun.h"
+#include
+#include
+
+#define kMaxSnakes 50
+
+int nSnakeCount = 0;
+int nSnakesFree;
+
+short SnakeFree[kMaxSnakes];
+short nPlayerSnake[kMaxPlayers];
+
+Snake SnakeList[kMaxSnakes];
+short nSnakePlayer[kMaxSnakes];
+
+
+void InitSnakes()
+{
+ nSnakeCount = 0;
+
+ for (int i = 0; i < kMaxSnakes; i++) {
+ SnakeFree[i] = i;
+ }
+
+ nSnakesFree = kMaxSnakes;
+ memset(nPlayerSnake, 0, sizeof(nPlayerSnake));
+}
+
+short GrabSnake()
+{
+ nSnakesFree--;
+ return SnakeFree[nSnakesFree];
+}
+
+void DestroySnake(int nSnake)
+{
+ short nRun = SnakeList[nSnake].nRun;
+ runlist_SubRunRec(nRun);
+
+ for (int i = 0; i < kSnakeSprites; i++)
+ {
+ short nSprite = SnakeList[nSnake].nSprites[i];
+
+ runlist_DoSubRunRec(sprite[nSprite].lotag - 1);
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+
+ mydeletesprite(nSprite);
+ }
+
+ SnakeFree[nSnakesFree] = nSnake;
+ nSnakesFree++;
+
+ if (nSnake == nSnakeCam)
+ {
+ nSnakeCam = -1;
+ if (!bFullScreen) {
+ RefreshStatus();
+ }
+ }
+}
+
+void ExplodeSnakeSprite(int nSprite, short nPlayer)
+{
+ short nDamage = BulletInfo[kWeaponStaff].nDamage;
+
+ if (nPlayerDouble[nPlayer] > 0) {
+ nDamage *= 2;
+ }
+
+ // take a copy of this, to revert after call to runlist_RadialDamageEnemy()
+ short nOwner = sprite[nSprite].owner;
+ sprite[nSprite].owner = PlayerList[nPlayer].nSprite;
+
+ runlist_RadialDamageEnemy(nSprite, nDamage, BulletInfo[kWeaponStaff].field_10);
+
+ sprite[nSprite].owner = nOwner;
+
+ BuildAnim(-1, 23, 0, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum, 40, 4);
+
+ AddFlash(sprite[nSprite].sectnum, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, 128);
+
+ StopSpriteSound(nSprite);
+}
+
+int BuildSnake(short nPlayer, short zVal)
+{
+ if (!nSnakesFree)
+ return -1;
+
+ zVal -= 1280;
+
+ short nPlayerSprite = PlayerList[nPlayer].nSprite;
+ short nViewSect = nPlayerViewSect[nPlayer];
+ short nPic = seq_GetSeqPicnum(kSeqSnakBody, 0, 0);
+
+ int x = sprite[nPlayerSprite].x;
+ int y = sprite[nPlayerSprite].y;
+ int z = (sprite[nPlayerSprite].z + zVal) - 2560;
+ short nAngle = sprite[nPlayerSprite].ang;
+
+ short hitsect, hitwall, hitsprite;
+ int hitx, hity, hitz;
+
+ short nSprite;
+
+ hitscan(x, y, z, sprite[nPlayerSprite].sectnum, Sin(nAngle + 512), Sin(nAngle), 0, &hitsect, &hitwall, &hitsprite, &hitx, &hity, &hitz, CLIPMASK1);
+
+ int nSqrt = ksqrt(((hity - y) * (hity - y)) + ((hitx - x) * (hitx - x)));
+
+ if (nSqrt < sintable[512] >> 4)
+ {
+ BackUpBullet(&hitx, &hity, nAngle);
+ nSprite = insertsprite(hitsect, 202);
+ sprite[nSprite].x = hitx;
+ sprite[nSprite].y = hity;
+ sprite[nSprite].z = hitz;
+
+ ExplodeSnakeSprite(nSprite, nPlayer);
+ mydeletesprite(nSprite);
+ return -1;
+ }
+ else
+ {
+ short nTarget;
+
+ if (hitsprite < 0 || sprite[hitsprite].statnum < 90 || sprite[hitsprite].statnum > 199) {
+ nTarget = sPlayerInput[nPlayer].nTarget;
+ }
+ else {
+ nTarget = hitsprite;
+ }
+
+ short nSnake = GrabSnake();
+// int var_40 = 0;
+
+ uchar var_18 = 0; // var_40 + var_40; // CHECKME ??
+
+// GrabTimeSlot(3);
+
+ short var_24;
+
+ for (int i = 0; i < kSnakeSprites; i++)
+ {
+ nSprite = insertsprite(nViewSect, 202);
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].owner = nPlayerSprite;
+ sprite[nSprite].picnum = nPic;
+
+ if (i != 0)
+ {
+ sprite[nSprite].x = sprite[var_24].x;
+ sprite[nSprite].y = sprite[var_24].y;
+ sprite[nSprite].z = sprite[var_24].z;
+ sprite[nSprite].xrepeat = 40 - (var_18 + i);
+ sprite[nSprite].yrepeat = 40 - (var_18 + i);
+ }
+ else
+ {
+ sprite[nSprite].x = sprite[nPlayerSprite].x;
+ sprite[nSprite].y = sprite[nPlayerSprite].y;
+ sprite[nSprite].z = sprite[nPlayerSprite].z + zVal;
+ sprite[nSprite].xrepeat = 32;
+ sprite[nSprite].yrepeat = 32;
+ nViewSect = sprite[nSprite].sectnum;
+ var_24 = nSprite;
+ }
+
+ sprite[nSprite].clipdist = 10;
+ sprite[nSprite].cstat = 0;
+ sprite[nSprite].shade = -64;
+ sprite[nSprite].pal = 0;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].ang = sprite[nPlayerSprite].ang;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].extra = -1;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+
+ SnakeList[nSnake].nSprites[i] = nSprite;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, ((nSnake << 8) | i) | 0x110000);
+
+ var_18 += 2;
+// var_40++;
+ }
+
+ SnakeList[nSnake].nRun = runlist_AddRunRec(NewRun, nSnake | 0x110000);
+ SnakeList[nSnake].c[1] = 2;
+ SnakeList[nSnake].c[5] = 5;
+ SnakeList[nSnake].c[2] = 4;
+ SnakeList[nSnake].c[3] = 6;
+ SnakeList[nSnake].c[4] = 7;
+ SnakeList[nSnake].c[6] = 6;
+ SnakeList[nSnake].c[7] = 7;
+ SnakeList[nSnake].nEnemy = nTarget;
+ SnakeList[nSnake].sC = 1200;
+ SnakeList[nSnake].sE = 0;
+ nSnakePlayer[nSnake] = nPlayer;
+ nPlayerSnake[nPlayer] = nSnake;
+
+ if (bSnakeCam)
+ {
+ if (nSnakeCam < 0) {
+ nSnakeCam = nSnake;
+ }
+ }
+
+// TODO D3PlayFX(StaticSound[kSound6], var_24);
+ }
+
+ return nSprite;
+}
+
+int FindSnakeEnemy(short nSnake)
+{
+ short nPlayer = nSnakePlayer[nSnake];
+ short nPlayerSprite = PlayerList[nPlayer].nSprite;
+
+ short nSprite = SnakeList[nSnake].nSprites[0]; // CHECKME
+
+ short nAngle = sprite[nSprite].ang;
+ short nSector = sprite[nSprite].sectnum;
+
+ int esi = 2048;
+
+ int nEnemy = -1;
+
+ for (int i = headspritesect[nSector]; i >= 0; i = nextspritesect[i])
+ {
+ if (sprite[i].statnum >= 90 && sprite[i].statnum < 150 && sprite[i].cstat & 0x101)
+ {
+ if (i != nPlayerSprite && (!(sprite[i].cstat & 0x8000)))
+ {
+ int nAngle2 = (nAngle - GetAngleToSprite(nSprite, i)) & kAngleMask;
+ if (nAngle2 < esi)
+ {
+ nEnemy = i;
+ esi = nAngle2;
+ }
+ }
+ }
+ }
+
+ if (nEnemy == -1)
+ {
+ SnakeList[nSnake].nEnemy--;
+ if (SnakeList[nSnake].nEnemy < -25)
+ {
+ nEnemy = nPlayerSprite;
+ SnakeList[nSnake].nEnemy = nPlayerSprite;
+ }
+ }
+ else
+ {
+ SnakeList[nSnake].nEnemy = nEnemy;
+ }
+
+ return nEnemy;
+}
+
+void FuncSnake(int a, int nDamage, int nRun)
+{
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ {
+ DebugOut("unknown msg %x for bullet\n", a & 0x7F0000);
+ return;
+ }
+
+ case 0x90000:
+ {
+ short nSnake = RunData[nRun].nVal;
+ short nSprite = a & 0xFFFF;
+
+ if (nSnake & 0xFF) {
+ seq_PlotSequence(nSprite, SeqOffsets[kSeqSnakBody], 0, 0);
+ }
+ else {
+ seq_PlotSequence(nSprite, SeqOffsets[kSeqSnakehed], 0, 0);
+ }
+
+ tsprite[nSprite].owner = -1;
+ return;
+ }
+
+ case 0xA0000:
+ {
+ return;
+ }
+
+ case 0x20000:
+ {
+ short nSnake = RunData[nRun].nVal;
+ assert(nSnake >= 0 && nSnake < kMaxSnakes);
+
+ short nSprite = SnakeList[nSnake].nSprites[0];
+
+ seq_MoveSequence(nSprite, SeqOffsets[kSeqSnakehed], 0);
+
+ short nEnemySprite = SnakeList[nSnake].nEnemy;
+
+ int nMov;
+ int zVal;
+
+ if (nEnemySprite >= 0 && (sprite[nEnemySprite].cstat & 0x101))
+ {
+ zVal = sprite[nSprite].z;
+
+ nMov = AngleChase(nSprite, nEnemySprite, 1200, SnakeList[nSnake].sE, 32);
+
+ zVal = sprite[nSprite].z - zVal;
+ }
+ else
+ {
+ if (!(sprite[nEnemySprite].cstat & 0x101)) {
+ SnakeList[nSnake].nEnemy = -1;
+ }
+
+ nMov = movesprite(nSprite,
+ 600 * Sin(sprite[nSprite].ang + 512),
+ 600 * Sin(sprite[nSprite].ang),
+ Sin(SnakeList[nSnake].sE) >> 5,
+ 0, 0, 1);
+
+ FindSnakeEnemy(nSnake);
+
+ zVal = 0;
+ }
+
+ if (nMov)
+ {
+ short nPlayer = nSnakePlayer[nSnake];
+ ExplodeSnakeSprite(SnakeList[nSnake].nSprites[0], nPlayer);
+
+ nPlayerSnake[nPlayer] = -1;
+ nSnakePlayer[nSnake] = -1;
+
+ DestroySnake(nSnake);
+ return;
+ }
+ else
+ {
+ short nAngle = sprite[nSprite].ang;
+ int var_30 = -(64 * Sin(nAngle + 512));
+ int var_34 = -(64 * Sin(nAngle));
+
+ int var_40 = var_30 + (var_30 * 8);
+ int var_4C = var_30 + (var_34 * 8);
+
+ int var_20 = SnakeList[nSnake].sE;
+
+ SnakeList[nSnake].sE = (SnakeList[nSnake].sE + 64) & 0x7FF;
+
+ int var_28 = (nAngle + 512) & kAngleMask;
+ short nSector = sprite[nSprite].sectnum;
+
+ int x = sprite[nSprite].x;
+ int y = sprite[nSprite].y;
+ int z = sprite[nSprite].z;
+
+ int ebp = -(zVal * 7);
+
+ int var_18 = var_28;
+
+ for (int i = 7; i > 0; i--)
+ {
+ int nSprite2 = SnakeList[nSnake].nSprites[i];
+
+ sprite[nSprite2].ang = nAngle;
+ sprite[nSprite2].x = x;
+ sprite[nSprite2].y = y;
+ sprite[nSprite2].z = z;
+
+ mychangespritesect(nSprite2, nSector);
+
+ var_40 = var_40 - var_30;
+ var_4C = var_4C - var_34;
+
+ ebp += zVal;
+
+ int eax = Sin(var_20) * SnakeList[nSnake].c[i];
+ eax >>= 9;
+
+ int ecx = eax * Sin(var_28 + 512);
+
+ eax = sintable[var_18] * eax;
+
+ movesprite(nSprite2, var_40 + ecx, var_4C + eax, ebp, 0, 0, CLIPMASK1);
+
+ var_20 = (var_20 + 128) & kAngleMask;
+ }
+ }
+ }
+ }
+}
diff --git a/source/exhumed/src/snake.h b/source/exhumed/src/snake.h
new file mode 100644
index 000000000..a44c215e6
--- /dev/null
+++ b/source/exhumed/src/snake.h
@@ -0,0 +1,39 @@
+
+#ifndef __snake_h__
+#define __snake_h__
+
+#define kSnakeSprites 8 // or rename to kSnakeParts?
+
+// 32bytes
+struct Snake
+{
+ short nEnemy; // nRun
+ short nSprites[kSnakeSprites];
+
+ short sC;
+ short nRun;
+
+ // array?
+ char c[8];
+ /*
+ char c1;
+ char c2;
+ char c3;
+ char c4;
+ char c5;
+ char c6;
+ char c7;
+ char c8;
+ */
+
+ short sE;
+};
+
+extern Snake SnakeList[];
+
+void InitSnakes();
+short GrabSnake();
+int BuildSnake(short nPlayer, short zVal);
+void FuncSnake(int, int, int);
+
+#endif
diff --git a/source/exhumed/src/sound.cpp b/source/exhumed/src/sound.cpp
new file mode 100644
index 000000000..cc91c4656
--- /dev/null
+++ b/source/exhumed/src/sound.cpp
@@ -0,0 +1,416 @@
+
+#include "sound.h"
+#include "init.h"
+
+#if 0
+extern "C" {
+#include "usrhooks.h"
+#include "music.h"
+#include "multivoc.h"
+#include "fx_man.h"
+#include "midi.h"
+#include "mpu401.h"
+}
+#endif
+
+short gMusicVolume = 200;
+short gFXVolume = 200;
+short nSoundsPlaying = 0;
+short nAmbientChannel = -1;
+
+short nStopSound;
+short nStoneSound;
+short nSwitchSound;
+
+short nLocalEyeSect;
+short nElevSound;
+short nCreepyTimer;
+
+char *soundFiles[kMaxSoundFiles] =
+{
+ "spl_big",
+ "spl_smal",
+ "bubble_l",
+ "grn_drop",
+ "p_click",
+ "grn_roll",
+ "cosprite",
+ "m_chant0",
+ "anu_icu",
+ "item_reg",
+ "item_spe", // 10
+ "item_key",
+ "torch_on", // 12
+ "jon_bnst",
+ "jon_gasp",
+ "jon_land",
+ "jon_gags",
+ "jon_fall",
+ "jon_drwn",
+ "jon_air1",
+ "jon_glp1", // 20
+ "jon_bbwl",
+ "jon_pois",
+ "amb_ston",
+ "cat_icu",
+ "bubble_h",
+ "set_land",
+ "jon_hlnd",
+ "jon_laf2",
+ "spi_jump",
+ "jon_scub", // 30
+ "item_use",
+ "tr_arrow",
+ "swi_foot",
+ "swi_ston",
+ "swi_wtr1",
+ "tr_fire",
+ "m_skull5",
+ "spi_atak",
+ "anu_hit",
+ "fishdies", // 40
+ "scrp_icu",
+ "jon_wade",
+ "amb_watr",
+ "tele_1",
+ "wasp_stg",
+ "res",
+ "drum4",
+ "rex_icu",
+ "m_hits_u",
+ "q_tail", // 50
+ "vatr_mov",
+ "jon_hit3",
+ "jon_t_2", // 53
+ "jon_t_1",
+ "jon_t_5",
+ "jon_t_6",
+ "jon_t_8",
+ "jon_t_4",
+ "rasprit1",
+ "jon_fdie", // 60
+ "wijaf1",
+ "ship_1",
+ "saw_on",
+ "ra_on",
+ "amb_ston", // 65
+ "vatr_stp", // 66
+ "mana1",
+ "mana2",
+ "ammo",
+ "pot_pc1", // 70?
+ "pot_pc2",
+ "weapon",
+ "alarm",
+ "tick1",
+ "scrp_zap", // 75
+ "jon_t_3",
+ "jon_laf1",
+ "blasted",
+ "jon_air2" // 79
+};
+
+short StaticSound[kMaxSoundFiles];
+
+// TODO - temp location. Needs to exist within config file
+//
+// Sound variables
+//
+int FXDevice;
+int MusicDevice;
+int FXVolume;
+int MusicVolume;
+int SoundToggle;
+int MusicToggle;
+int VoiceToggle;
+int AmbienceToggle;
+//fx_blaster_config BlasterConfig;
+int NumVoices;
+int NumChannels;
+int NumBits;
+int MixRate;
+//int32 MidiPort;
+int ReverseStereo;
+
+int nNextFreq;
+int nTotalSoundBytes;
+int nSoundCount;
+short nSwirlyFrames;
+
+short nDistTable[256];
+
+struct ActiveSound
+{
+/*
+ short _0
+ short _2
+ short _4
+ short _6
+ byte _7
+
+ short _10
+ short _12
+ int _14
+ int _18
+ int _22;
+ int _26
+
+ int _30; // x val
+ int _34; // y val
+ int _38; // z val
+ short _42
+ short _44
+*/
+};
+
+
+void CreateDistTable()
+{
+ int eax = 260;
+
+ for (int i = 0; i < 256; i++)
+ {
+ if (eax <= 65280)
+ {
+ nDistTable[i] = eax >> 8;
+
+ eax = (eax * eax) >> 8;
+ }
+ else
+ {
+ nDistTable[i] = 255;
+ }
+ }
+}
+
+void InitSoundInfo()
+{
+
+}
+
+int UpdateSounds()
+{
+ return 1;
+}
+
+int LocalSoundPlaying()
+{
+ return 0;
+}
+
+// for ASS only
+void testcallback(unsigned long num)
+{
+#if 0
+ short tempi, tempj, tempk;
+
+ if ((long)num < 0)
+ {
+ if (lumplockbyte[-num] >= 200)
+ lumplockbyte[-num]--;
+ return;
+ }
+
+ tempk = Sound[num].num;
+
+ if (tempk > 0)
+ {
+ if ((soundm[num] & 16) == 0)
+ for (tempj = 0; tempj
+
+short SpiderSprite = -1;
+short SpiderCount = 0;
+
+#define kMaxSpiders 100
+
+struct Spider
+{
+ short nHealth;
+ short b;
+ short nAction;
+ short nSprite;
+ short nTarget;
+ short f;
+ short g;
+ short h;
+};
+
+Spider SpiderList[kMaxSpiders];
+
+static actionSeq ActionSeq[] = {
+ {16, 0},
+ {8, 0},
+ {32, 0},
+ {24, 0},
+ {0, 0},
+ {40, 1},
+ {41, 1},
+};
+
+void InitSpider()
+{
+ SpiderCount = 0;
+ SpiderSprite = 1;
+}
+
+int BuildSpider(int nSprite, int x, int y, int z, short nSector, int angle)
+{
+ SpiderCount++;
+
+ int nSpider = SpiderCount;
+ if (nSpider >= kMaxSpiders) {
+ return -1;
+ }
+
+ if (nSprite == -1)
+ {
+ nSprite = insertsprite(nSector, 99);
+ }
+ else
+ {
+ changespritestat(nSprite, 99);
+ x = sprite[nSprite].x;
+ y = sprite[nSprite].y;
+ z = sprite[nSprite].z;
+ angle = sprite[nSprite].ang;
+ }
+
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ sprite[nSprite].cstat = 257;
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].clipdist = 15;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].xrepeat = 40;
+ sprite[nSprite].yrepeat = 40;
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].ang = angle;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].extra = -1;
+
+// GrabTimeSlot(3);
+
+ SpiderList[nSpider].nAction = 0;
+ SpiderList[nSpider].b = 0;
+ SpiderList[nSpider].nSprite = nSprite;
+ SpiderList[nSpider].nTarget = -1;
+ SpiderList[nSpider].nHealth = 160;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nSpider | 0xC0000);
+
+ SpiderList[nSpider].h = runlist_AddRunRec(NewRun, nSpider | 0xC0000);
+
+ nCreaturesLeft++;
+
+ return nSpider | 0xC0000;
+}
+
+void FuncSpider(int a, int nDamage, int nRun)
+{
+ short nSpider = RunData[nRun].nVal;
+ assert(nSpider >= 0 && nSpider < kMaxSpiders);
+
+ int var_14;
+
+ short nSprite = SpiderList[nSpider].nSprite;
+ short nAction = SpiderList[nSpider].nAction;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x20000:
+ {
+ var_14 = 6;
+
+ if (SpiderList[nSpider].nHealth)
+ {
+ if (sprite[nSprite].cstat & 8)
+ {
+ sprite[nSprite].z = sector[sprite[nSprite].sectnum].ceilingz + GetSpriteHeight(nSprite);
+ }
+ else
+ {
+ Gravity(nSprite);
+ }
+ }
+
+ int nSeq = SeqOffsets[kSeqSpider] + ActionSeq[nAction].a;
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, SpiderList[nSpider].b);
+
+ seq_MoveSequence(nSprite, nSeq, SpiderList[nSpider].b);
+
+ int nFrameFlag = FrameFlag[SeqBase[nSeq] + SpiderList[nSpider].b];
+
+ SpiderList[nSpider].b++;
+ if (SpiderList[nSpider].b >= SeqSize[nSeq]) {
+ SpiderList[nSpider].b = 0;
+ }
+
+ short nTarget = SpiderList[nSpider].nTarget;
+
+ if (nTarget <= -1 || sprite[nTarget].cstat & 0x101)
+ {
+ switch (nAction)
+ {
+ case 0:
+ {
+ if ((nSpider & 0x1F) == (totalmoves & 0x1F))
+ {
+ if (nTarget < 0) {
+ nTarget = FindPlayer(nSprite, 100);
+ }
+
+ if (nTarget >= 0)
+ {
+ SpiderList[nSpider].nAction = 1;
+ SpiderList[nSpider].b = 0;
+ SpiderList[nSpider].nTarget = nTarget;
+
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512);
+ sprite[nSprite].yvel = sintable[sprite[nSprite].ang];
+ return;
+ }
+ }
+
+ break;
+ }
+ case 1:
+ {
+ if (nTarget >= 0) {
+ var_14++;
+ }
+goto case_3;
+ break;
+ }
+ case 4:
+ {
+ if (!SpiderList[nSpider].b)
+ {
+ SpiderList[nSpider].b = 0;
+ SpiderList[nSpider].nAction = 1;
+ }
+ //break; // fall through
+ }
+ case 3:
+ {
+case_3:
+ short nSector = sprite[nSprite].sectnum;
+
+ if (sprite[nSprite].cstat & 8)
+ {
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].z = sector[nSector].ceilingz + (tilesizy[sprite[nSprite].picnum] << 5);
+
+ if (sector[nSector].ceilingstat & 1)
+ {
+ sprite[nSprite].cstat ^= 8;
+ sprite[nSprite].zvel = 1;
+
+ SpiderList[nSpider].nAction = 3;
+ SpiderList[nSpider].b = 0;
+ }
+ }
+
+ if ((totalmoves & 0x1F) == (nSpider & 0x1F))
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+
+ if (RandomSize(3))
+ {
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512);
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang);
+ }
+ else
+ {
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ }
+
+ if (SpiderList[nSpider].nAction == 1 && RandomBit())
+ {
+ if (sprite[nSprite].cstat & 8)
+ {
+ sprite[nSprite].cstat ^= 8u;
+ sprite[nSprite].zvel = 1;
+ sprite[nSprite].z = sector[nSector].ceilingz + GetSpriteHeight(nSprite);
+ }
+ else
+ {
+ sprite[nSprite].zvel = -5120;
+ }
+
+ SpiderList[nSpider].nAction = 3;
+ SpiderList[nSpider].b = 0;
+
+ if (!RandomSize(3)) {
+ D3PlayFX(StaticSound[kSound29], nSprite);
+ }
+ }
+ }
+ break;
+ }
+ case 5:
+ {
+ if (!SpiderList[nSpider].b)
+ {
+ runlist_DoSubRunRec(sprite[nSprite].owner);
+ runlist_FreeRun(sprite[nSprite].lotag - 1);
+ runlist_SubRunRec(SpiderList[nSpider].h);
+ sprite[nSprite].cstat = 0x8000;
+ mydeletesprite(nSprite);
+ }
+ return;
+ }
+ case 2:
+ {
+ if (nTarget != -1)
+ {
+ if (nFrameFlag & 0x80)
+ {
+ runlist_DamageEnemy(nTarget, nSprite, 3);
+ D3PlayFX(StaticSound[kSound38], nSprite);
+ }
+
+ if (PlotCourseToSprite(nSprite, nTarget) < 1024) {
+ return;
+ }
+
+ SpiderList[nSpider].nAction = 1;
+ }
+ else
+ {
+ SpiderList[nSpider].nAction = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].yvel = 0;
+ }
+
+ SpiderList[nSpider].b = 0;
+ break;
+ }
+ }
+ }
+ else
+ {
+ SpiderList[nSpider].nTarget = -1;
+ SpiderList[nSpider].nAction = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ SpiderList[nSpider].b = 0;
+ }
+
+ int nMov = movesprite(nSprite, sprite[nSprite].xvel << var_14, sprite[nSprite].yvel << var_14, sprite[nSprite].zvel, 1280, -1280, CLIPMASK0);
+
+ if (!nMov)
+ return;
+
+ if (nMov & 0x10000
+ && sprite[nSprite].zvel < 0
+ && (hihit & 0xC000) != 0xC000
+ && !((sector[sprite[nSprite].sectnum].ceilingstat) & 1))
+ {
+ sprite[nSprite].cstat |= 8;
+ sprite[nSprite].z = GetSpriteHeight(nSprite) + sector[sprite[nSprite].sectnum].ceilingz;
+ sprite[nSprite].zvel = 0;
+
+ SpiderList[nSpider].nAction = 1;
+ SpiderList[nSpider].b = 0;
+ return;
+ }
+ else
+ {
+ switch (nMov & 0xC000)
+ {
+ case 0x8000:
+ {
+ sprite[nSprite].ang = (sprite[nSprite].ang + 256) & 0x7EF;
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512);
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang);
+ return;
+ }
+ case 0xC000:
+ {
+ if ((nMov & 0x3FFF) == nTarget)
+ {
+ int nAng = getangle(sprite[nTarget].x - sprite[nSprite].x, sprite[nTarget].y - sprite[nSprite].y);
+ if (AngleDiff(sprite[nSprite].ang, nAng) < 64)
+ {
+ SpiderList[nSpider].nAction = 2;
+ SpiderList[nSpider].b = 0;
+ }
+ }
+ return;
+ }
+ }
+
+ if (SpiderList[nSpider].nAction == 3)
+ {
+ SpiderList[nSpider].nAction = 1;
+ SpiderList[nSpider].b = 0;
+ }
+ return;
+ }
+
+ return;
+ }
+
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, SeqOffsets[kSeqSpider] + ActionSeq[nAction].a, SpiderList[nSpider].b, ActionSeq[nAction].b);
+ break;
+ }
+
+ case 0xA0000:
+ {
+ if (SpiderList[nSpider].nHealth <= 0)
+ return;
+
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ // fall through
+ }
+
+ case 0x80000:
+ {
+ if (!nDamage)
+ return;
+
+ short nTarget = a & 0xFFFF;
+
+ SpiderList[nSpider].nHealth -= nDamage;
+ if (SpiderList[nSpider].nHealth > 0)
+ {
+ if (sprite[nTarget].statnum == 100)
+ {
+ SpiderList[nSpider].nTarget = nTarget;
+ }
+
+ SpiderList[nSpider].nAction = 4;
+ SpiderList[nSpider].b = 0;
+ }
+ else
+ {
+ // creature is dead, make some chunks
+ SpiderList[nSpider].nHealth = 0;
+ sprite[nSprite].cstat &= 0x0FEFE;
+
+ SpiderList[nSpider].nAction = 5;
+ nCreaturesLeft--;
+ SpiderList[nSpider].b = 0;
+
+ for (int i = 0; i < 7; i++)
+ {
+ BuildCreatureChunk(nSprite, seq_GetSeqPicnum(kSeqSpider, i + 41, 0));
+ }
+ }
+
+ return;
+ }
+
+ default:
+ {
+ DebugOut("unknown msg %d for Spider\n", a & 0x7F0000);
+ break;
+ }
+ }
+}
diff --git a/source/exhumed/src/spider.h b/source/exhumed/src/spider.h
new file mode 100644
index 000000000..2730f3c9d
--- /dev/null
+++ b/source/exhumed/src/spider.h
@@ -0,0 +1,9 @@
+
+#ifndef __spider_h__
+#define __spider_h__
+
+void InitSpider();
+int BuildSpider(int nSprite, int x, int y, int z, short nSector, int angle);
+void FuncSpider(int a, int b, int nRun);
+
+#endif
diff --git a/source/exhumed/src/status.cpp b/source/exhumed/src/status.cpp
new file mode 100644
index 000000000..943263f5f
--- /dev/null
+++ b/source/exhumed/src/status.cpp
@@ -0,0 +1,859 @@
+
+#include "engine.h"
+#include "player.h"
+#include "anims.h"
+#include "status.h"
+#include "exhumed.h"
+#include "sequence.h"
+#include "init.h"
+#include "names.h"
+#include "items.h"
+#include "view.h"
+#include "trigdat.h"
+#include
+#include
+#include
+#include
+#include "typedefs.h"
+
+short nMaskY;
+static short nAnimsFree = 0;
+
+short statusmask[1600];
+
+short message_timer = 0;
+char message_text[80];
+int magicperline;
+int airperline;
+int healthperline;
+int nAirFrames;
+int nCounter;
+int nCounterDest;
+
+short nStatusSeqOffset;
+short nItemFrames;
+
+int laststatusx;
+int laststatusy;
+
+sshort nItemSeq;
+short nDigit[3];
+
+short nMagicFrames;
+short nHealthLevel;
+short nItemFrame;
+short nMeterRange;
+short nMagicLevel;
+short nHealthFrame;
+short nMagicFrame;
+
+short statusx;
+short statusy;
+short nHealthFrames;
+
+short airframe;
+
+sshort nFirstAnim;
+sshort nLastAnim;
+short nItemAltSeq;
+
+short airpages = 0;
+
+short ammodelay = 3;
+short ammopages = 4;
+
+short nCounterBullet = -1;
+
+
+// 8 bytes
+struct statusAnim
+{
+ short s1;
+ short s2;
+ sshort nPage;
+ schar c1;
+ schar c2;
+};
+
+#define kMaxStatusAnims 50
+
+statusAnim StatusAnim[kMaxStatusAnims];
+uchar StatusAnimsFree[kMaxStatusAnims];
+char StatusAnimFlags[kMaxStatusAnims];
+
+short nItemSeqOffset[] = {91, 72, 76, 79, 68, 87, 83};
+
+short word_9AD54[kMaxPlayers] = {0, 0, 0, 0, 0, 0, 0, 0};
+int dword_9AD64[kMaxPlayers] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+void SetCounterDigits();
+void SetItemSeq();
+void SetItemSeq2(int nSeqOffset);
+
+
+int BuildStatusAnim(int val, int nFlags)
+{
+ if (nAnimsFree <= 0) {
+ return -1;
+ }
+
+ nAnimsFree--;
+
+ uchar nStatusAnim = StatusAnimsFree[nAnimsFree];
+
+ StatusAnim[nStatusAnim].c1 = -1;
+ StatusAnim[nStatusAnim].c2 = nLastAnim;
+
+ if (nLastAnim < 0) {
+ nFirstAnim = nStatusAnim;
+ }
+ else {
+ StatusAnim[nLastAnim].c1 = nStatusAnim;
+ }
+
+ nLastAnim = nStatusAnim;
+
+ StatusAnim[nStatusAnim].s1 = val;
+ StatusAnim[nStatusAnim].s2 = 0;
+ StatusAnimFlags[nStatusAnim] = nFlags;
+ StatusAnim[nStatusAnim].nPage = numpages;
+ return nStatusAnim;
+}
+
+void RefreshStatus()
+{
+ short nLives = nPlayerLives[nLocalPlayer];
+ if (nLives < 0 || nLives > kMaxPlayerLives) {
+ bail2dos("illegal value for nPlayerLives #%d\n", nLocalPlayer);
+ }
+
+ // draws the red dots that indicate the lives amount
+ BuildStatusAnim(2 * nLives + 145, 0);
+
+ ushort nKeys = PlayerList[nLocalPlayer].keys;
+
+ int val = 37;
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (nKeys & 0x1000) {
+ BuildStatusAnim(val, 0);
+ }
+
+ nKeys >>= 1;
+ val += 2;
+ }
+
+ barpages = numpages;
+
+ SetPlayerItem(nLocalPlayer, nPlayerItem[nLocalPlayer]);
+ SetHealthFrame(0);
+ SetMagicFrame();
+ SetAirFrame();
+}
+
+void InitStatus()
+{
+ nStatusSeqOffset = SeqOffsets[kSeqStatus];
+ nHealthFrames = SeqSize[nStatusSeqOffset + 1];
+ int nPicNum = seq_GetSeqPicnum(kSeqStatus, 1, 0);
+ nMagicFrames = SeqSize[nStatusSeqOffset + 129];
+ nHealthFrame = 0;
+ nMagicFrame = 0;
+ nHealthLevel = 0;
+ nMagicLevel = 0;
+ nMeterRange = tilesizy[nPicNum];
+ magicperline = 1000 / nMeterRange;
+ healthperline = 800 / nMeterRange;
+ nAirFrames = SeqSize[nStatusSeqOffset + 133];
+ airperline = 100 / nAirFrames;
+ nCounter = 0;
+ nCounterDest = 0;
+
+ memset(nDigit, 0, sizeof(nDigit));
+
+ SetCounter(0);
+ SetHealthFrame(0);
+ SetMagicFrame();
+
+ for (int i = 0; i < kMaxStatusAnims; i++) {
+ StatusAnimsFree[i] = i;
+ }
+
+ nLastAnim = -1;
+ nFirstAnim = -1;
+ nItemSeq = -1;
+ nAnimsFree = kMaxStatusAnims;
+ statusx = nScreenWidth - 320;
+ textpages = 0;
+ message_timer = 0;
+ statusy = nScreenHeight - 200;
+}
+
+void MoveStatusAnims()
+{
+// sshort nAnim = nFirstAnim;
+
+ for (int i = nFirstAnim; i >= 0; i = StatusAnim[i].c1)
+ {
+ seq_MoveSequence(-1, nStatusSeqOffset + StatusAnim[i].s1, StatusAnim[i].s2);
+
+ StatusAnim[i].s2++;
+
+ short nSize = SeqSize[nStatusSeqOffset + StatusAnim[i].s1];
+
+ if (StatusAnim[i].s2 >= nSize)
+ {
+ if (StatusAnimFlags[i] & 0x10) {
+ StatusAnim[i].s2 = 0;
+ }
+ else {
+ StatusAnim[i].s2 = nSize - 1;
+ }
+ }
+ }
+
+#if 0
+ while (nAnim != -1)
+ {
+ seq_MoveSequence(-1, nStatusSeqOffset + StatusAnim[nAnim].s1, StatusAnim[nAnim].s2);
+
+ StatusAnim[nAnim].s2++;
+
+ short nSize = SeqSize[nStatusSeqOffset + StatusAnim[nAnim].s1];
+
+ if (StatusAnim[nAnim].s2 >= nSize)
+ {
+ if (StatusAnimFlags[nAnim] & 0x10)
+ StatusAnim[nAnim].s2 = 0;
+ else
+ StatusAnim[nAnim].s2 = nSize - 1;
+ }
+
+ nAnim = StatusAnim[nAnim].c1;
+ }
+#endif
+}
+
+void DestroyStatusAnim(short nAnim)
+{
+ short c1 = StatusAnim[nAnim].c1;
+ short c2 = StatusAnim[nAnim].c2;
+
+ if (c2 >= 0) {
+ StatusAnim[c2].c1 = c1;
+ }
+
+ if (c1 >= 0) {
+ StatusAnim[c1].c2 = c2;
+ }
+
+ if (nAnim == nFirstAnim) {
+ nFirstAnim = c1;
+ }
+
+ if (nAnim == nLastAnim) {
+ nLastAnim = c2;
+ }
+
+ StatusAnimsFree[nAnimsFree] = (uchar)nAnim;
+ nAnimsFree++;
+}
+
+void DrawStatusAnims()
+{
+ sshort nAnim = nFirstAnim;
+
+ while (nAnim != -1)
+ {
+ int nextAnim = StatusAnim[nAnim].c1;
+
+ int nSequence = nStatusSeqOffset + StatusAnim[nAnim].s1;
+
+ seq_DrawStatusSequence(nSequence, StatusAnim[nAnim].s2, 0);
+
+ if (StatusAnim[nAnim].s2 >= (SeqSize[nSequence] - 1))
+ {
+ if (!(StatusAnimFlags[nAnim] & 0x10))
+ {
+ StatusAnim[nAnim].nPage--;
+ if (StatusAnim[nAnim].nPage <= 0) {
+ DestroyStatusAnim(nAnim);
+ }
+ }
+ }
+
+ nAnim = nextAnim;
+ }
+}
+
+void SetMagicFrame()
+{
+ nMagicLevel = (1000 - PlayerList[nLocalPlayer].nMagic) / magicperline;
+
+ if (nMagicLevel >= nMeterRange) {
+ nMagicLevel = nMeterRange - 1;
+ }
+
+ if (nMagicLevel < 0) {
+ nMagicLevel = 0;
+ }
+
+ SetItemSeq();
+}
+
+void SetHealthFrame(short nVal)
+{
+ nHealthLevel = (800 - PlayerList[nLocalPlayer].nHealth) / healthperline;
+
+ if (nHealthLevel >= nMeterRange ) {
+ nHealthLevel = nMeterRange - 1;
+ }
+
+ if (nHealthLevel < 0) {
+ nHealthLevel = 0;
+ }
+
+ if (nVal < 0) {
+ BuildStatusAnim(4, 0);
+ }
+}
+
+void SetAirFrame()
+{
+ airframe = PlayerList[nLocalPlayer].nAir / airperline;
+
+ if (airframe < nAirFrames)
+ {
+ if (airframe < 0) {
+ airframe = 0;
+ }
+ }
+ else
+ {
+ airframe = nAirFrames - 1;
+ }
+
+ airpages = numpages;
+}
+
+void SetCounter(short nVal)
+{
+ if (nVal <= 999)
+ {
+ if (nVal < 0) {
+ nVal = 0;
+ }
+ }
+ else {
+ nVal = 999;
+ }
+
+ nCounterDest = nVal;
+}
+
+void SetCounterImmediate(short nVal)
+{
+ SetCounter(nVal);
+ nCounter = nCounterDest;
+
+ SetCounterDigits();
+}
+
+void SetCounterDigits()
+{
+ nDigit[2] = 3 * (nCounter / 100 % 10);
+ nDigit[1] = 3 * (nCounter / 10 % 10);
+ nDigit[0] = 3 * (nCounter % 10);
+ ammopages = numpages;
+}
+
+void SetItemSeq()
+{
+ short nItem = nPlayerItem[nLocalPlayer];
+ if (nItem < 0)
+ {
+ nItemSeq = -1;
+ return;
+ }
+
+ short nOffset = nItemSeqOffset[nItem];
+
+ SetItemSeq2(nOffset);
+}
+
+void SetItemSeq2(int nSeqOffset)
+{
+ short nItem = nPlayerItem[nLocalPlayer];
+
+ if (nItemMagic[nItem] <= PlayerList[nLocalPlayer].nMagic) {
+ nItemAltSeq = 0;
+ }
+ else {
+ nItemAltSeq = 2;
+ }
+
+ nItemFrame = 0;
+ nItemSeq = nSeqOffset + nItemAltSeq;
+ nItemFrames = SeqSize[nItemSeq + nStatusSeqOffset];
+}
+
+void SetPlayerItem(short nPlayer, short nItem)
+{
+ nPlayerItem[nPlayer] = nItem;
+
+ if (nPlayer == nLocalPlayer)
+ {
+ SetItemSeq();
+ if (nItem >= 0) {
+ BuildStatusAnim((2 * PlayerList[nLocalPlayer].items[nItem]) + 156, 0);
+ }
+ }
+}
+
+void SetNextItem(int nPlayer)
+{
+ short nItem = nPlayerItem[nPlayer];
+
+ int i;
+
+ for (i = 6; i > 0; i--)
+ {
+ nItem++;
+ if (nItem == 6)
+ nItem = 0;
+
+ if (PlayerList[nPlayer].items[nItem] != 0)
+ break;
+ }
+
+ if (i > 0) {
+ SetPlayerItem(nPlayer, nItem);
+ }
+}
+
+void SetPrevItem(int nPlayer)
+{
+ if (nPlayerItem[nPlayer] == -1)
+ return;
+
+ int nItem = nPlayerItem[nPlayer];
+
+ int i;
+
+ for (i = 6; i > 0; i--)
+ {
+ nItem--;
+ if (nItem < 0)
+ nItem = 5;
+
+ if (PlayerList[nPlayer].items[nItem] != 0)
+ break;
+ }
+
+ if (i > 0) {
+ SetPlayerItem(nPlayer, nItem);
+ }
+}
+
+void MoveStatus()
+{
+ if (nItemSeq >= 0)
+ {
+ nItemFrame++;
+
+ if (nItemFrame >= nItemFrames)
+ {
+ if (nItemSeq == 67) {
+ SetItemSeq();
+ }
+ else
+ {
+ nItemSeq -= nItemAltSeq;
+
+ if (nItemAltSeq || totalmoves & 0x1F)
+ {
+ if (nItemSeq < 2) {
+ nItemAltSeq = 0;
+ }
+ }
+ else
+ {
+ nItemAltSeq = 1;
+ }
+
+ nItemFrame = 0;
+ nItemSeq += nItemAltSeq;
+ nItemFrames = SeqSize[nStatusSeqOffset + nItemSeq];
+ }
+ }
+ }
+
+ if (message_timer)
+ {
+ message_timer -= 4;
+ if (message_timer <= 0)
+ {
+ if (screensize < nScreenWidth) {
+ textpages = numpages;
+ }
+
+ message_timer = 0;
+ }
+ }
+
+ MoveStatusAnims();
+
+ if (nCounter == nCounterDest)
+ {
+ nCounter = nCounterDest;
+ ammopages = numpages;
+ ammodelay = 3;
+ return;
+ }
+ else
+ {
+ ammodelay--;
+ if (ammodelay > 0) {
+ return;
+ }
+ }
+
+ ammopages = numpages;
+
+ int eax = nCounterDest - nCounter;
+
+ if (eax <= 0)
+ {
+ if (eax >= -30)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ nDigit[i]--;
+
+ if (nDigit[i] < 0)
+ {
+ nDigit[i] += 30;
+ }
+
+ if (nDigit[i] < 27) {
+ break;
+ }
+ }
+ }
+ else
+ {
+ nCounter += (nCounterDest - nCounter) >> 1;
+ SetCounterDigits();
+ return;
+ }
+ }
+ else
+ {
+ if (eax <= 30)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ nDigit[i]++;
+
+ if (nDigit[i] <= 27) {
+ break;
+ }
+
+ if (nDigit[i] >= 30) {
+ nDigit[i] -= 30;
+ }
+ }
+ }
+ else
+ {
+ nCounter += (nCounterDest - nCounter) >> 1;
+ SetCounterDigits();
+ return;
+ }
+ }
+
+ if (!(nDigit[0] % 3)) {
+ nCounter = nDigit[0] / 3 + 100 * (nDigit[2] / 3) + 10 * (nDigit[1] / 3);
+ }
+
+ eax = nCounterDest - nCounter;
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ ammodelay = 4 - (eax >> 1);
+ if (ammodelay < 1) {
+ ammodelay = 1;
+ }
+}
+
+void UnMaskStatus()
+{
+ for (int i = 0; i < nScreenWidth; i++) {
+ startdmost[i] = nScreenHeight;
+ }
+}
+
+void MaskStatus()
+{
+ for (int i = 0; i < nScreenWidth; i++)
+ {
+ short bx = startdmost[i];
+ short cx = statusmask[i];
+
+ if (bx > cx) {
+ startdmost[i] = cx;
+ }
+ }
+}
+
+void LoadStatus()
+{
+ int i;
+ short nSize;
+ short tmp;
+ short buffer[1024];
+// memset(buffer, 0, sizeof(buffer)); // bjd - added by me
+
+ for (i = 0; i < nScreenWidth; i++) {
+ statusmask[i] = nScreenHeight;
+ }
+
+ nMaskY = nScreenHeight;
+
+ int hStatus = kopen4load("status.msk", 1);
+ if (!hStatus) {
+ return;
+ }
+
+ kread(hStatus, &nSize, sizeof(nSize));
+
+ int nCount = nSize >> 1;
+
+ kread(hStatus, &tmp, sizeof(tmp));
+ kread(hStatus, buffer, nSize);
+
+ kclose(hStatus);
+
+ short *pStatusMask = statusmask;
+
+ for (i = 0; i < nCount; i++)
+ {
+ int v8 = nScreenHeight - ((nScreenHeight * buffer[i]) / 200);
+ *pStatusMask++ = nScreenHeight - v8;
+
+ if (bHiRes) {
+ *pStatusMask++ = nScreenHeight - v8;
+ }
+
+ if (nScreenHeight - v8 < nMaskY) {
+ nMaskY = nScreenHeight - v8;
+ }
+ }
+}
+
+void StatusMessage(int messageTime, const char *fmt, ...)
+{
+ message_timer = messageTime;
+
+ va_list args;
+ va_start(args, fmt);
+
+ vsprintf(message_text, fmt, args);
+
+ if (screensize < nScreenWidth) {
+ textpages = numpages;
+ }
+}
+
+void DrawStatus()
+{
+ char numberBuf[10] = {0};
+ char stringBuf[20] = {0};
+ char coordBuf[50] = {0}; // not sure of the size for this?
+
+ if (!bFullScreen && nNetTime)
+ {
+ // bjd - commenting out this check seems to fix the black status bar at 320x200 resolution
+// if (bHiRes) {
+ NoClip();
+// }
+
+ if (barpages > 0)
+ {
+ // draw the main bar itself
+ seq_DrawStatusSequence(nStatusSeqOffset, 0, 0);
+ barpages--;
+ }
+
+ seq_DrawStatusSequence(nStatusSeqOffset + 128, 0, 0);
+ seq_DrawStatusSequence(nStatusSeqOffset + 127, 0, 0);
+ seq_DrawStatusSequence(nStatusSeqOffset + 1, nHealthFrame, nHealthLevel);
+ seq_DrawStatusSequence(nStatusSeqOffset + 129, nMagicFrame, nMagicLevel);
+
+ nHealthFrame++;
+ if (nHealthFrame >= nHealthFrames) {
+ nHealthFrame = 0;
+ }
+
+ nMagicFrame++;
+ if (nMagicFrame >= nMagicFrames) {
+ nMagicFrame = 0;
+ }
+
+ seq_DrawStatusSequence(nStatusSeqOffset + 125, 0, 0); // draw ankh on health pool
+ seq_DrawStatusSequence(nStatusSeqOffset + 130, 0, 0); // draw health pool frame (top)
+ seq_DrawStatusSequence(nStatusSeqOffset + 131, 0, 0); // magic pool frame (bottom)
+
+ if (nItemSeq >= 0) {
+ seq_DrawStatusSequence(nItemSeq + nStatusSeqOffset, nItemFrame, 0);
+ }
+
+ // draws health level dots and other things
+ DrawStatusAnims();
+
+ if (airpages)
+ {
+ seq_DrawStatusSequence(nStatusSeqOffset + 133, airframe, 0);
+ airpages--;
+ }
+
+ // Draw compass
+ seq_DrawStatusSequence(nStatusSeqOffset + 35, ((inita + 128) & kAngleMask) >> 8, 0);
+
+ if (bCoordinates)
+ {
+ char *cFPS = itoa(lastfps, numberBuf, 10);
+ printext(nScreenWidth - 20, nViewTop, cFPS, kTile159, -1);
+ }
+
+ if (ammopages)
+ {
+ ammopages--;
+ seq_DrawStatusSequence(nStatusSeqOffset + 44, nDigit[2], 0);
+ seq_DrawStatusSequence(nStatusSeqOffset + 45, nDigit[1], 0);
+ seq_DrawStatusSequence(nStatusSeqOffset + 46, nDigit[0], 0);
+ }
+
+ // bjd - commenting out this check seems to fix the black status bar at 320x200 resolution
+// if (bHiRes) {
+ Clip();
+// }
+ }
+
+ if (nNetPlayerCount)
+ {
+ NoClip();
+
+ int shade;
+
+ if (totalclock / kTimerTicks & 1) {
+ shade = -100;
+ }
+ else {
+ shade = 127;
+ }
+
+ int nTile = kTile3593;
+
+ int x = 320 / (nTotalPlayers + 1);
+
+ for (int i = 0; i < nTotalPlayers; i++)
+ {
+ int nScore = nPlayerScore[i];
+ if (word_9AD54[i] == nScore)
+ {
+ int v9 = dword_9AD64[i];
+ if (v9 && v9 <= totalclock) {
+ dword_9AD64[i] = 0;
+ }
+ }
+ else
+ {
+ word_9AD54[i] = nScore;
+ dword_9AD64[i] = totalclock + 30;
+ }
+
+ overwritesprite(x, 7, nTile, 0, 3, kPalNormal);
+
+ if (i != nLocalPlayer) {
+ shade = -100;
+ }
+
+ sprintf(stringBuf, "%d", nPlayerScore[i]);
+ int nStringLen = MyGetStringWidth(stringBuf);
+
+ myprintext(x - (nStringLen / 2), 4, stringBuf, shade);
+
+ x *= 2;
+ nTile++;
+ }
+
+ if (nNetTime >= 0)
+ {
+ int y = nViewTop;
+
+ if (nNetTime)
+ {
+ int v12 = (nNetTime + 29) / 30 % 60;
+ int v13 = (nNetTime + 29) / 1800;
+ nNetTime += 29;
+
+ sprintf(stringBuf, "%d.%02d", v13, v12);
+
+ if (bHiRes) {
+ y = nViewTop / 2;
+ }
+
+ if (nViewTop <= 0) {
+ y += 20;
+ }
+ else {
+ y += 15;
+ }
+
+ nNetTime -= 29;
+ }
+ else
+ {
+ y = 100;
+ strcpy(stringBuf, "GAME OVER");
+ }
+
+ int nLenString = MyGetStringWidth(stringBuf);
+ myprintext((320 - nLenString) / 2, y, stringBuf, 0);
+ }
+
+ Clip();
+ }
+
+ if (bCoordinates)
+ {
+ int nSprite = PlayerList[nLocalPlayer].nSprite;
+
+ int x = (nViewLeft + nViewRight) / 2;
+
+ sprintf(coordBuf, "X %d", sprite[nSprite].x);
+ printext(x, nViewTop + 1, coordBuf, kTile159, 255);
+
+ sprintf(coordBuf, "Y %d", sprite[nSprite].y);
+ printext(x, nViewTop + 10, coordBuf, kTile159, 255);
+ }
+
+ if (bHolly)
+ {
+ sprintf(message_text, "HOLLY: %s", sHollyStr);
+ printext(0, 0, message_text, kTile159, 255);
+ }
+ else if (nSnakeCam < 0)
+ {
+ if (message_timer) {
+ printext(0, 0, message_text, kTile159, 255);
+ }
+ }
+ else
+ {
+ printext(0, 0, "S E R P E N T C A M", kTile159, 255);
+ }
+}
diff --git a/source/exhumed/src/status.h b/source/exhumed/src/status.h
new file mode 100644
index 000000000..98880db0a
--- /dev/null
+++ b/source/exhumed/src/status.h
@@ -0,0 +1,32 @@
+
+#ifndef __status_h__
+#define __status_h__
+
+
+extern short nMaskY;
+extern short nCounterBullet;
+extern short airpages;
+
+void RefreshStatus();
+void InitStatus();
+void UnMaskStatus();
+void MaskStatus();
+void LoadStatus();
+void SetPlayerItem(short nPlayer, short nItem);
+void SetMagicFrame();
+void SetHealthFrame(short nVal);
+void SetAirFrame();
+
+void MoveStatus();
+
+void DrawStatus();
+
+int BuildStatusAnim(int val, int nFlags);
+
+void SetNextItem(int nPlayer);
+void SetPrevItem(int nPlayer);
+
+void SetCounter(short nVal);
+void SetCounterImmediate(short nVal);
+
+#endif
diff --git a/source/exhumed/src/stream.cpp b/source/exhumed/src/stream.cpp
new file mode 100644
index 000000000..c284cde74
--- /dev/null
+++ b/source/exhumed/src/stream.cpp
@@ -0,0 +1,2 @@
+
+#include "stream.h"
diff --git a/source/exhumed/src/stream.h b/source/exhumed/src/stream.h
new file mode 100644
index 000000000..1b6dc3dc0
--- /dev/null
+++ b/source/exhumed/src/stream.h
@@ -0,0 +1,7 @@
+
+#ifndef __stream_h__
+#define __stream_h__
+
+
+
+#endif
diff --git a/source/exhumed/src/switch.cpp b/source/exhumed/src/switch.cpp
new file mode 100644
index 000000000..1ab033e88
--- /dev/null
+++ b/source/exhumed/src/switch.cpp
@@ -0,0 +1,523 @@
+
+#include "switch.h"
+#include "exhumed.h"
+#include "runlist.h"
+#include "engine.h"
+#include "player.h"
+#include
+#include
+
+short LinkCount = -1;
+short SwitchCount = -1;
+
+schar LinkMap[kMaxLinks][8];
+
+struct Switch
+{
+ short field_0;
+ short field_2;
+ short nChannel;
+ short nLink;
+ short field_8;
+ short nSector;
+ short field_C;
+ short nWall;
+ short field_10;
+ short field_12;
+ short field_14;
+ char pad[10];
+};
+
+Switch SwitchData[kMaxSwitches];
+
+
+
+void InitLink()
+{
+ LinkCount = kMaxLinks;
+}
+
+int BuildLink(int nCount, int argList ...)
+{
+ if (LinkCount <= 0) {
+ return -1;
+ }
+
+ int *pList = &argList;
+
+ LinkCount--;
+
+ for (int i = 0; i < 8; i++)
+ {
+ int ebx;
+
+ if (i >= nCount)
+ {
+ ebx = -1;
+ }
+ else
+ {
+ ebx = *pList;
+ pList++;
+ }
+
+ LinkMap[LinkCount][i] = (schar)ebx;
+ }
+
+ return LinkCount;
+}
+
+void InitSwitch()
+{
+ SwitchCount = kMaxSwitches;
+ memset(SwitchData, 0, sizeof(SwitchData));
+}
+
+int BuildSwReady(int nChannel, short nLink)
+{
+ if (SwitchCount <= 0 || nLink < 0) {
+ bail2dos("Too many switch readys!\n");
+ return -1;
+ }
+
+ SwitchCount--;
+ SwitchData[SwitchCount].nChannel = nChannel;
+ SwitchData[SwitchCount].nLink = nLink;
+
+ return SwitchCount | 0x10000;
+}
+
+void FuncSwReady(int a, int, int nRun)
+{
+ short nSwitch = RunData[nRun].nVal;
+ assert(nSwitch >= 0 && nSwitch < kMaxSwitches);
+
+ int nMessage = a & 0x7F0000;
+
+ short nChannel = SwitchData[nSwitch].nChannel;
+ short nLink = SwitchData[nSwitch].nLink;
+
+ switch (nMessage)
+ {
+ case 0x10000:
+ return;
+
+ case 0x30000:
+ {
+ assert(sRunChannels[nChannel].c < 8);
+ schar nVal = LinkMap[nLink][sRunChannels[nChannel].c];
+ if (nVal >= 0) {
+ runlist_ChangeChannel(nChannel, nVal);
+ }
+
+ break;
+ }
+
+ default:
+ return;
+ }
+}
+
+int BuildSwPause(int nChannel, int nLink, int ebx)
+{
+ for (int i = kMaxSwitches - 1; i >= SwitchCount; i--)
+ {
+ if (SwitchData[i].nChannel == nChannel && SwitchData[i].field_2 != 0) {
+ return i | 0x20000;
+ }
+ }
+
+ if (SwitchCount <= 0 || nLink < 0) {
+ bail2dos("Too many switches!\n");
+ return -1;
+ }
+
+ SwitchCount--;
+
+ SwitchData[SwitchCount].nChannel = nChannel;
+ SwitchData[SwitchCount].nLink = nLink;
+ SwitchData[SwitchCount].field_2 = ebx;
+ SwitchData[SwitchCount].field_8 = -1;
+
+ return SwitchCount | 0x20000;
+}
+
+void FuncSwPause(int a, int, int nRun)
+{
+ short nSwitch = RunData[nRun].nVal;
+ assert(nSwitch >= 0 && nSwitch < kMaxSwitches);
+
+ int nMessage = a & 0x7F0000;
+
+ short nChannel = SwitchData[nSwitch].nChannel;
+ short nLink = SwitchData[nSwitch].nLink;
+
+ switch (nMessage)
+ {
+ default:
+ return;
+
+ case 0x10000:
+ {
+ if (SwitchData[nSwitch].field_8 >= 0)
+ {
+ runlist_SubRunRec(SwitchData[nSwitch].field_8);
+ SwitchData[nSwitch].field_8 = -1;
+ }
+
+ return;
+ }
+
+ case 0x20000:
+ {
+ SwitchData[nSwitch].field_0--;
+ if (SwitchData[nSwitch].field_0 <= 0)
+ {
+ runlist_SubRunRec(SwitchData[nSwitch].field_8);
+ SwitchData[nSwitch].field_8 = -1;
+
+ assert(sRunChannels[nChannel].c < 8);
+ assert(nLink < 1024);
+
+ runlist_ChangeChannel(nChannel, LinkMap[nLink][sRunChannels[nChannel].c]);
+ }
+
+ return;
+ }
+
+ case 0x30000:
+ {
+ assert(sRunChannels[nChannel].c < 8);
+
+ if (LinkMap[nLink][sRunChannels[nChannel].c] < 0) {
+ return;
+ }
+
+ if (SwitchData[nSwitch].field_8 >= 0) {
+ return;
+ }
+
+ SwitchData[nSwitch].field_8 = runlist_AddRunRec(NewRun, RunData[nRun].nMoves);
+
+ int eax;
+
+ if (SwitchData[nSwitch].field_2 <= 0)
+ {
+ eax = 100;
+ }
+ else
+ {
+ eax = SwitchData[nSwitch].field_2;
+ }
+
+ SwitchData[nSwitch].field_0 = eax;
+ return;
+ }
+ }
+}
+
+int BuildSwStepOn(int nChannel, int nLink, int nSector)
+{
+ if (SwitchCount <= 0 || nLink < 0 || nSector < 0)
+ bail2dos("Too many switches!\n");
+
+ int nSwitch = --SwitchCount;
+
+ SwitchData[nSwitch].nChannel = nChannel;
+ SwitchData[nSwitch].nLink = nLink;
+ SwitchData[nSwitch].nSector = nSector;
+ SwitchData[nSwitch].field_C = -1;
+
+ return nSwitch | 0x30000;
+}
+
+void FuncSwStepOn(int a, int, int nRun)
+{
+ short nSwitch = RunData[nRun].nVal;
+ assert(nSwitch >= 0 && nSwitch < kMaxSwitches);
+
+ short nLink = SwitchData[nSwitch].nLink;
+ short nChannel = SwitchData[nSwitch].nChannel;
+ short nSector = SwitchData[nSwitch].nSector;
+
+ assert(sRunChannels[nChannel].c < 8);
+
+ schar var_14 = LinkMap[nLink][sRunChannels[nChannel].c];
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ return;
+
+ case 0x10000:
+ {
+ if (SwitchData[nSwitch].field_C >= 0)
+ {
+ runlist_SubRunRec(SwitchData[nSwitch].field_C);
+ SwitchData[nSwitch].field_C = -1;
+ }
+
+ if (var_14 >= 0)
+ {
+ SwitchData[nSwitch].field_C = runlist_AddRunRec(sector[nSector].lotag - 1, RunData[nRun].nMoves);
+ }
+
+ return;
+ }
+
+ case 0x50000:
+ {
+ if (var_14 != sRunChannels[nChannel].c)
+ {
+ short nWall = sector[nSector].wallptr;
+// TODO PlayFXAtXYZ(StaticSound[nSwitchSound], wall[nWall].x, wall[nWall].y, sector[nSector].floorz, nSector);
+
+ assert(sRunChannels[nChannel].c < 8);
+
+ runlist_ChangeChannel(nChannel, LinkMap[nLink][sRunChannels[nChannel].c]);
+ }
+ }
+
+ return;
+ }
+
+}
+
+int BuildSwNotOnPause(int nChannel, int nLink, int nSector, int ecx)
+{
+ if (SwitchCount <= 0 || nLink < 0 || nSector < 0)
+ bail2dos("Too many switches!\n");
+
+ int nSwitch = --SwitchCount;
+
+ SwitchData[nSwitch].nChannel = nChannel;
+ SwitchData[nSwitch].nLink = nLink;
+ SwitchData[nSwitch].field_2 = ecx;
+ SwitchData[nSwitch].nSector = nSector;
+ SwitchData[nSwitch].field_8 = -1;
+ SwitchData[nSwitch].field_C = -1;
+
+ return nSwitch | 0x40000;
+}
+
+void FuncSwNotOnPause(int a, int, int nRun)
+{
+ short nSwitch = RunData[nRun].nVal;
+ assert(nSwitch >= 0 && nSwitch < kMaxSwitches);
+
+ int nMessage = a & 0x7F0000;
+
+ short nChannel = SwitchData[nSwitch].nChannel;
+ short nLink = SwitchData[nSwitch].nLink;
+
+ switch (nMessage)
+ {
+ default:
+ return;
+
+ case 0x10000:
+ {
+ if (SwitchData[nSwitch].field_C >= 0)
+ {
+ runlist_SubRunRec(SwitchData[nSwitch].field_C);
+ SwitchData[nSwitch].field_C = -1;
+ }
+
+ if (SwitchData[nSwitch].field_8 >= 0)
+ {
+ runlist_SubRunRec(SwitchData[nSwitch].field_8);
+ SwitchData[nSwitch].field_8 = -1;
+ }
+
+ return;
+ }
+
+ case 0x20000:
+ {
+ SwitchData[nSwitch].field_0 -= 4;
+ if (SwitchData[nSwitch].field_0 <= 0)
+ {
+ assert(sRunChannels[nChannel].c < 8);
+
+ runlist_ChangeChannel(nChannel, LinkMap[nLink][sRunChannels[nChannel].c]);
+ }
+
+ return;
+ }
+
+ case 0x30000:
+ {
+ assert(sRunChannels[nChannel].c < 8);
+
+ if (LinkMap[nLink][sRunChannels[nChannel].c] >= 0)
+ {
+ if (SwitchData[nSwitch].field_8 < 0)
+ {
+ SwitchData[nSwitch].field_8 = runlist_AddRunRec(NewRun, RunData[nRun].nMoves);
+
+ short nSector = SwitchData[nSwitch].nSector;
+
+ SwitchData[nSwitch].field_0 = SwitchData[nSwitch].field_2;
+ SwitchData[nSwitch].field_C = runlist_AddRunRec(sector[nSector].lotag - 1, RunData[nRun].nMoves);
+ }
+ }
+
+ return;
+ }
+
+ case 0x50000:
+ {
+ SwitchData[nSwitch].field_0 = SwitchData[nSwitch].field_2;
+ return;
+ }
+ }
+}
+
+int BuildSwPressSector(int nChannel, int nLink, int nSector, int ecx)
+{
+ if (SwitchCount <= 0 || nLink < 0 || nSector < 0)
+ bail2dos("Too many switches!\n");
+
+ int nSwitch = --SwitchCount;
+
+ SwitchData[nSwitch].nChannel = nChannel;
+ SwitchData[nSwitch].nLink = nLink;
+ SwitchData[nSwitch].nSector = nSector;
+ SwitchData[nSwitch].field_12 = ecx;
+ SwitchData[nSwitch].field_C = -1;
+
+ return nSwitch | 0x50000;
+}
+
+void FuncSwPressSector(int a, int, int nRun)
+{
+ short nSwitch = RunData[nRun].nVal;
+ assert(nSwitch >= 0 && nSwitch < kMaxSwitches);
+
+ int nMessage = a & 0x7F0000;
+
+ short nChannel = SwitchData[nSwitch].nChannel;
+ short nLink = SwitchData[nSwitch].nLink;
+ short nPlayer = a & 0xFFFF;
+
+ switch (nMessage)
+ {
+ default:
+ return;
+
+ case 0x10000:
+ {
+ if (SwitchData[nSwitch].field_C >= 0)
+ {
+ runlist_SubRunRec(SwitchData[nSwitch].field_C);
+ SwitchData[nSwitch].field_C = -1;
+ }
+
+ assert(sRunChannels[nChannel].c < 8);
+
+ if (LinkMap[nLink][sRunChannels[nChannel].c] < 0) {
+ return;
+ }
+
+ short nSector = SwitchData[nSwitch].nSector;
+
+ SwitchData[nSwitch].field_C = runlist_AddRunRec(sector[nSector].lotag - 1, RunData[nRun].nMoves);
+ return;
+ }
+
+ case 0x40000:
+ {
+ if ((PlayerList[nPlayer].keys & SwitchData[nSwitch].field_12) == SwitchData[nSwitch].field_12)
+ {
+ runlist_ChangeChannel(nChannel, LinkMap[nLink][sRunChannels[nChannel].c]);
+ }
+ else
+ {
+ if (SwitchData[nSwitch].field_12)
+ {
+ short nSprite = PlayerList[nPlayer].nSprite;
+ // TODO PlayFXAtXYZ(StaticSound[nSwitchSound], sprite[nSprite].x, sprite[nSprite].y, 0, sprite[nSprite].sectnum);
+
+ StatusMessage(300, "YOU NEED THE KEY FOR THIS DOOR");
+ }
+ }
+ }
+ }
+}
+
+int BuildSwPressWall(short nChannel, short nLink, short nWall)
+{
+ if (SwitchCount <= 0 || nLink < 0 || nWall < 0) {
+ bail2dos("Too many switches!\n");
+ }
+
+ SwitchCount--;
+
+ SwitchData[SwitchCount].nChannel = nChannel;
+ SwitchData[SwitchCount].nLink = nLink;
+ SwitchData[SwitchCount].nWall = nWall;
+ SwitchData[SwitchCount].field_10 = -1;
+ SwitchData[SwitchCount].field_14 = 0;
+
+ return SwitchCount | 0x60000;
+}
+
+void FuncSwPressWall(int a, int, int nRun)
+{
+ short nSwitch = RunData[nRun].nVal;
+ assert(nSwitch >= 0 && nSwitch < kMaxSwitches);
+
+ short nChannel = SwitchData[nSwitch].nChannel;
+ short nLink = SwitchData[nSwitch].nLink;
+
+ // TEMP
+// assert(nLink < 1024);
+// assert(nChannel < 8);
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ default:
+ return;
+
+ case 0x30000:
+ {
+ if (SwitchData[nSwitch].field_10 >= 0)
+ {
+ runlist_SubRunRec(SwitchData[nSwitch].field_10);
+ SwitchData[nSwitch].field_10 = -1;
+ }
+
+ if (LinkMap[nLink][sRunChannels[nChannel].c] >= 0)
+ {
+ short nWall = SwitchData[nSwitch].nWall;
+ SwitchData[nSwitch].field_10 = runlist_AddRunRec(wall[nWall].lotag - 1, RunData[nRun].nMoves);
+ }
+
+ return;
+ }
+
+ case 0x40000:
+ {
+ schar cx = LinkMap[nLink][sRunChannels[nChannel].c];
+
+ runlist_ChangeChannel(nChannel, LinkMap[nLink][sRunChannels[nChannel].c]);
+
+ if (cx < 0 || LinkMap[nLink][cx] < 0)
+ {
+ runlist_SubRunRec(SwitchData[nSwitch].field_10);
+ SwitchData[nSwitch].field_10 = -1;
+ }
+
+ short nWall = SwitchData[nSwitch].nWall;
+ short nSector = SwitchData[nSwitch].nSector; // CHECKME - where is this set??
+
+// TODO PlayFXAtXYZ(StaticSound[nSwitchSound], wall[nWall].x, wall[nWall].y, 0, nSector);
+
+ return;
+ }
+ }
+}
diff --git a/source/exhumed/src/switch.h b/source/exhumed/src/switch.h
new file mode 100644
index 000000000..d105ca71f
--- /dev/null
+++ b/source/exhumed/src/switch.h
@@ -0,0 +1,27 @@
+
+#ifndef __switch_h__
+#define __switch_h__
+
+#define kMaxLinks 1024
+#define kMaxSwitches 1024
+
+void InitLink();
+void InitSwitch();
+
+void FuncSwReady(int, int, int);
+void FuncSwPause(int, int, int);
+void FuncSwStepOn(int, int, int);
+void FuncSwNotOnPause(int, int, int);
+void FuncSwPressSector(int, int, int);
+void FuncSwPressWall(int, int, int);
+
+int BuildSwPause(int nChannel, int nLink, int ebx);
+int BuildSwNotOnPause(int nChannel, int nLink, int nSector, int ecx);
+int BuildLink(int nCount, int argList ...);
+int BuildSwPressSector(int nChannel, int nLink, int nSector, int ecx);
+int BuildSwStepOn(int nChannel, int nLink, int nSector);
+int BuildSwReady(int nChannel, short nLink);
+
+int BuildSwPressWall(short nChannel, short nLink, short nWall);
+
+#endif
diff --git a/source/exhumed/src/text2.cpp b/source/exhumed/src/text2.cpp
new file mode 100644
index 000000000..705f5d934
--- /dev/null
+++ b/source/exhumed/src/text2.cpp
@@ -0,0 +1,2 @@
+
+#include "text2.h"
diff --git a/source/exhumed/src/text2.h b/source/exhumed/src/text2.h
new file mode 100644
index 000000000..d6ba45501
--- /dev/null
+++ b/source/exhumed/src/text2.h
@@ -0,0 +1,7 @@
+
+#ifndef __text2_h__
+#define __text2_h__
+
+
+
+#endif
diff --git a/source/exhumed/src/timer.cpp b/source/exhumed/src/timer.cpp
new file mode 100644
index 000000000..a618801f5
--- /dev/null
+++ b/source/exhumed/src/timer.cpp
@@ -0,0 +1,47 @@
+
+#include "timer.h"
+#include "exhumed.h"
+
+#ifndef __WATCOMC__
+extern "C" {
+ #include "baselayer.h"
+}
+#endif
+
+#ifdef __WATCOMC__
+
+#include
+#include
+#include
+
+void (__interrupt __far *oldtimerhandler)();
+void __interrupt __far timerhandler();
+#else
+void timerhandler();
+#endif
+
+void InitTimer()
+{
+ htimer = 1;
+
+#ifndef __WATCOMC__
+ inittimer(kTimerTicks);
+ installusertimercallback(timerhandler);
+#else
+
+ outp(0x43, 0x34);
+ outp(0x40, (1193181 / kTimerTicks) & 255);
+ outp(0x40, (1193181 / kTimerTicks) >> 8);
+ oldtimerhandler = _dos_getvect(0x8);
+ _disable(); _dos_setvect(0x8, timerhandler); _enable();
+
+#endif
+}
+
+#ifdef __WATCOMC__
+void uninittimer()
+{
+ outp(0x43, 0x34); outp(0x40, 0); outp(0x40, 0);
+ _disable(); _dos_setvect(0x8, oldtimerhandler); _enable();
+}
+#endif
diff --git a/source/exhumed/src/timer.h b/source/exhumed/src/timer.h
new file mode 100644
index 000000000..0b8c2a05b
--- /dev/null
+++ b/source/exhumed/src/timer.h
@@ -0,0 +1,13 @@
+
+#ifndef __timer_h__
+#define __timer_h__
+
+#define kTimerTicks 120
+
+void InitTimer();
+
+#ifdef __WATCOMC__
+void uninittimer();
+#endif
+
+#endif
\ No newline at end of file
diff --git a/source/exhumed/src/trigdat.cpp b/source/exhumed/src/trigdat.cpp
new file mode 100644
index 000000000..2e55eb5b5
--- /dev/null
+++ b/source/exhumed/src/trigdat.cpp
@@ -0,0 +1,151 @@
+
+#include "trigdat.h"
+#ifndef __WATCOMC__
+#include
+#else
+#include
+#endif
+
+short AngTable[] = {0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,7,8,8,8,8,8,8,9,9,9,9,9,9,10,10,10,10,10,10,10,11,11,11,11,11,11,12,12,12,12,12,12,13,13,13,13,13,13,14,14,14,14,14,14,14,15,15,15,15,15,15,16,16,16,16,16,16,17,17,17,17,17,17,17,18,18,18,18,18,18,19,19,19,19,19,19,20,20,20,20,20,20,20,21,21,21,21,21,21,22,22,22,22,22,22,23,23,23,23,23,23,24,24,24,24,24,24,24,25,25,25,25,25,25,26,26,26,26,26,26,27,27,27,27,27,27,27,28,28,28,28,28,28,29,29,29,29,29,29,30,30,30,30,30,30,30,31,31,31,31,31,31,32,32,32,32,32,32,33,33,33,33,33,33,33,34,34,34,34,34,34,35,35,35,35,35,35,35,36,36,36,36,36,36,37,37,37,37,37,37,38,38,38,38,38,38,38,39,39,39,39,39,39,40,40,40,40,40,40,41,41,41,41,41,41,41,42,42,42,42,42,42,43,43,43,43,43,43,43,44,44,44,44,44,44,45,45,45,45,45,45,46,46,46,46,46,46,46,47,47,47,47,47,47,48,48,48,48,48,48,48,49,49,49,49,49,49,50,50,50,50,50,50,51,51,51,51,51,51,51,52,52,52,52,52,52,53,53,53,53,53,53,53,54,54,54,54,54,54,55,55,55,55,55,55,55,56,56,56,56,56,56,57,57,57,57,57,57,57,58,58,58,58,58,58,59,59,59,59,59,59,59,60,60,60,60,60,60,61,61,61,61,61,61,61,62,62,62,62,62,62,63,63,63,63,63,63,63,64,64,64,64,64,64,65,65,65,65,65,65,65,66,66,66,66,66,66,67,67,67,67,67,67,67,68,68,68,68,68,68,69,69,69,69,69,69,69,70,70,70,70,70,70,70,71,71,71,71,71,71,72,72,72,72,72,72,72,73,73,73,73,73,73,74,74,74,74,74,74,74,75,75,75,75,75,75,75,76,76,76,76,76,76,77,77,77,77,77,77,77,78,78,78,78,78,78,78,79,79,79,79,79,79,80,80,80,80,80,80,80,81,81,81,81,81,81,81,82,82,82,82,82,82,83,83,83,83,83,83,83,84,84,84,84,84,84,84,85,85,85,85,85,85,86,86,86,86,86,86,86,87,87,87,87,87,87,87,88,88,88,88,88,88,88,89,89,89,89,89,89,90,90,90,90,90,90,90,91,91,91,91,91,91,91,92,92,92,92,92,92,92,93,93,93,93,93,93,93,94,94,94,94,94,94,94,95,95,95,95,95,95,96,96,96,96,96,96,96,97,97,97,97,97,97,97,98,98,98,98,98,98,98,99,99,99,99,99,99,99,100,100,100,100,100,100,100,101,101,101,101,101,101,101,102,102,102,102,102,102,102,103,103,103,103,103,103,103,104,104,104,104,104,104,104,105,105,105,105,105,105,105,106,106,106,106,106,106,106,107,107,107,107,107,107,107,108,108,108,108,108,108,108,109,109,109,109,109,109,109,110,110,110,110,110,110,110,111,111,111,111,111,111,111,112,112,112,112,112,112,112,113,113,113,113,113,113,113,114,114,114,114,114,114,114,115,115,115,115,115,115,115,116,116,116,116,116,116,116,117,117,117,117,117,117,117,117,118,118,118,118,118,118,118,119,119,119,119,119,119,119,120,120,120,120,120,120,120,121,121,121,121,121,121,121,122,122,122,122,122,122,122,122,123,123,123,123,123,123,123,124,124,124,124,124,124,124,125,125,125,125,125,125,125,125,126,126,126,126,126,126,126,127,127,127,127,127,127,127,128,128,128,128,128,128,128,128,129,129,129,129,129,129,129,130,130,130,130,130,130,130,131,131,131,131,131,131,131,131,132,132,132,132,132,132,132,133,133,133,133,133,133,133,133,134,134,134,134,134,134,134,135,135,135,135,135,135,135,135,136,136,136,136,136,136,136,137,137,137,137,137,137,137,137,138,138,138,138,138,138,138,139,139,139,139,139,139,139,139,140,140,140,140,140,140,140,141,141,141,141,141,141,141,141,142,142,142,142,142,142,142,142,143,143,143,143,143,143,143,144,144,144,144,144,144,144,144,145,145,145,145,145,145,145,145,146,146,146,146,146,146,146,146,147,147,147,147,147,147,147,148,148,148,148,148,148,148,148,149,149,149,149,149,149,149,149,150,150,150,150,150,150,150,150,151,151,151,151,151,151,151,151,152,152,152,152,152,152,152,153,153,153,153,153,153,153,153,154,154,154,154,154,154,154,154,155,155,155,155,155,155,155,155,156,156,156,156,156,156,156,156,157,157,157,157,157,157,157,157,158,158,158,158,158,158,158,158,159,159,159,159,159,159,159,159,160,160,160,160,160,160,160,160,161,161,161,161,161,161,161,161,162,162,162,162,162,162,162,162,162,163,163,163,163,163,163,163,163,164,164,164,164,164,164,164,164,165,165,165,165,165,165,165,165,166,166,166,166,166,166,166,166,167,167,167,167,167,167,167,167,167,168,168,168,168,168,168,168,168,169,169,169,169,169,169,169,169,170,170,170,170,170,170,170,170,170,171,171,171,171,171,171,171,171,172,172,172,172,172,172,172,172,173,173,173,173,173,173,173,173,173,174,174,174,174,174,174,174,174,175,175,175,175,175,175,175,175,175,176,176,176,176,176,176,176,176,177,177,177,177,177,177,177,177,177,178,178,178,178,178,178,178,178,178,179,179,179,179,179,179,179,179,180,180,180,180,180,180,180,180,180,181,181,181,181,181,181,181,181,181,182,182,182,182,182,182,182,182,183,183,183,183,183,183,183,183,183,184,184,184,184,184,184,184,184,184,185,185,185,185,185,185,185,185,185,186,186,186,186,186,186,186,186,186,187,187,187,187,187,187,187,187,188,188,188,188,188,188,188,188,188,189,189,189,189,189,189,189,189,189,190,190,190,190,190,190,190,190,190,191,191,191,191,191,191,191,191,191,192,192,192,192,192,192,192,192,192,192,193,193,193,193,193,193,193,193,193,194,194,194,194,194,194,194,194,194,195,195,195,195,195,195,195,195,195,196,196,196,196,196,196,196,196,196,197,197,197,197,197,197,197,197,197,197,198,198,198,198,198,198,198,198,198,199,199,199,199,199,199,199,199,199,200,200,200,200,200,200,200,200,200,200,201,201,201,201,201,201,201,201,201,202,202,202,202,202,202,202,202,202,202,203,203,203,203,203,203,203,203,203,204,204,204,204,204,204,204,204,204,204,205,205,205,205,205,205,205,205,205,206,206,206,206,206,206,206,206,206,206,207,207,207,207,207,207,207,207,207,207,208,208,208,208,208,208,208,208,208,209,209,209,209,209,209,209,209,209,209,210,210,210,210,210,210,210,210,210,210,211,211,211,211,211,211,211,211,211,211,212,212,212,212,212,212,212,212,212,212,213,213,213,213,213,213,213,213,213,213,214,214,214,214,214,214,214,214,214,214,215,215,215,215,215,215,215,215,215,215,216,216,216,216,216,216,216,216,216,216,217,217,217,217,217,217,217,217,217,217,218,218,218,218,218,218,218,218,218,218,219,219,219,219,219,219,219,219,219,219,219,220,220,220,220,220,220,220,220,220,220,221,221,221,221,221,221,221,221,221,221,222,222,222,222,222,222,222,222,222,222,222,223,223,223,223,223,223,223,223,223,223,224,224,224,224,224,224,224,224,224,224,224,225,225,225,225,225,225,225,225,225,225,226,226,226,226,226,226,226,226,226,226,226,227,227,227,227,227,227,227,227,227,227,228,228,228,228,228,228,228,228,228,228,228,229,229,229,229,229,229,229,229,229,229,229,230,230,230,230,230,230,230,230,230,230,230,231,231,231,231,231,231,231,231,231,231,231,232,232,232,232,232,232,232,232,232,232,232,233,233,233,233,233,233,233,233,233,233,233,234,234,234,234,234,234,234,234,234,234,234,235,235,235,235,235,235,235,235,235,235,235,236,236,236,236,236,236,236,236,236,236,236,237,237,237,237,237,237,237,237,237,237,237,238,238,238,238,238,238,238,238,238,238,238,238,239,239,239,239,239,239,239,239,239,239,239,240,240,240,240,240,240,240,240,240,240,240,240,241,241,241,241,241,241,241,241,241,241,241,242,242,242,242,242,242,242,242,242,242,242,242,243,243,243,243,243,243,243,243,243,243,243,244,244,244,244,244,244,244,244,244,244,244,244,245,245,245,245,245,245,245,245,245,245,245,245,246,246,246,246,246,246,246,246,246,246,246,246,247,247,247,247,247,247,247,247,247,247,247,248,248,248,248,248,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,249,249,249,249,249,250,250,250,250,250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,251,251,251,251,252,252,252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,253,253,254,254,254,254,254,254,254,254,254,254,254,254,254,255,255,255,255,255,255,255,255,255,255,255,255,256,256,256,256,256,256};
+
+
+int GetMyAngle(int x, int y)
+{
+ int ebx = -x;
+ int esi = y << 11;
+ int ecx = y;
+ int edx = y;
+
+ if (ebx >= 0)
+ {
+ // left path
+
+ edx = ebx << 11;
+
+ if (y >= 0)
+ {
+ if (ebx == y) {
+ return 768;
+ }
+ else // loc_2F318:
+ {
+ if (y > ebx)
+ {
+ return (AngTable[(edx / y) & kAngleMask] + 512) & kAngleMask;
+ }
+ else
+ {
+ // loc_2F33C:
+ return ((512 - AngTable[(esi / ebx) & kAngleMask]) + 512) & kAngleMask;
+ }
+ }
+ }
+ else
+ {
+ // loc_2F35D:
+ ecx = -y;
+
+ if (ebx == ecx) {
+ return 1280;
+ }
+ else if (ebx <= ecx)
+ {
+ return ((1024 - AngTable[(edx / ecx) & kAngleMask]) + 512) & kAngleMask;
+ }
+ else
+ {
+ edx = ecx << 11;
+ return (AngTable[(edx / ebx) & kAngleMask] + 1024) & kAngleMask;
+ }
+ }
+ }
+ else
+ {
+ if (edx >= 0)
+ {
+ ebx = -ebx;
+
+ if (ebx == edx) {
+ return 256;
+ }
+ else if (ebx > edx)
+ {
+ return (AngTable[(esi / ebx) & kAngleMask] + 2048) & kAngleMask;
+ }
+ else
+ {
+ edx = ebx << 11;
+ return ((2048 - AngTable[(edx / ecx) & kAngleMask]) + 512) & kAngleMask;
+ }
+ }
+ else
+ {
+ ebx = -ebx;
+ ecx = -ecx;
+
+ if (ebx == ecx) {
+ return 1792;
+ }
+ else if (ebx >= ecx)
+ {
+ edx = ecx << 11;
+ return ((1536 - AngTable[(edx / ebx) & kAngleMask]) + 512) & kAngleMask;
+ }
+ else
+ {
+ edx = ebx << 11;
+ return (AngTable[(edx / ecx) & kAngleMask] + 1536) & kAngleMask;
+ }
+ }
+ }
+}
+
+// 100% done
+int AngleDiff(short a, short b)
+{
+ int diff = (b - a) & kAngleMask;
+
+ if (diff > 1024) {
+ diff = 2048 - diff;
+ }
+ return diff;
+}
+
+// unused
+int AnglePick(short a, short b)
+{
+ int nRet = b;
+
+ if (AngleDiff(a, b) > 512)
+ {
+ nRet ^= 0x400;
+ }
+
+ return nRet;
+}
+
+int AngleDelta(int a, int b, int c)
+{
+ int diff = b - a;
+
+ if (diff >= 0)
+ {
+ if (diff > 1024) {
+ diff = -(2048 - diff);
+ }
+ }
+ else if (diff < -1024)
+ {
+ diff += 2048;
+ }
+
+ if (abs(diff) > c)
+ {
+ if (diff < 0) {
+ return -diff;
+ }
+
+ diff = c;
+ }
+ return diff;
+}
diff --git a/source/exhumed/src/trigdat.h b/source/exhumed/src/trigdat.h
new file mode 100644
index 000000000..23140b937
--- /dev/null
+++ b/source/exhumed/src/trigdat.h
@@ -0,0 +1,11 @@
+
+#ifndef __trigdat_h__
+#define __trigdat_h__
+
+#define kAngleMask 0x7FF
+
+int GetMyAngle(int x, int y);
+int AngleDiff(short a, short b);
+int AngleDelta(int a, int b, int c);
+
+#endif
diff --git a/source/exhumed/src/typedefs.h b/source/exhumed/src/typedefs.h
new file mode 100644
index 000000000..5e53a6473
--- /dev/null
+++ b/source/exhumed/src/typedefs.h
@@ -0,0 +1,24 @@
+
+#ifndef __typedefs_h__
+#define __typedefs_h__
+
+typedef unsigned char uchar;
+typedef signed char schar;
+
+typedef unsigned short ushort;
+typedef signed short sshort;
+
+typedef unsigned long ulong;
+typedef signed long slong;
+
+typedef unsigned char BYTE;
+
+typedef unsigned char BOOL;
+
+#define kTrue (0 == 0)
+#define kFalse (0 == 1)
+
+#define TRUE kTrue
+#define FALSE kFalse
+
+#endif
diff --git a/source/exhumed/src/util.h b/source/exhumed/src/util.h
new file mode 100644
index 000000000..c4e12a59c
--- /dev/null
+++ b/source/exhumed/src/util.h
@@ -0,0 +1,21 @@
+
+#ifndef __util_h__
+#define __util_h__
+
+inline int Min(int a, int b)
+{
+ if (a < b)
+ return a;
+ else
+ return b;
+}
+
+inline int Max(int a, int b)
+{
+ if (a < b)
+ return b;
+ else
+ return a;
+}
+
+#endif
diff --git a/source/exhumed/src/version.cpp b/source/exhumed/src/version.cpp
new file mode 100644
index 000000000..e1d705b8d
--- /dev/null
+++ b/source/exhumed/src/version.cpp
@@ -0,0 +1,4 @@
+
+#include "version.h"
+
+const char *versionstr = "Mar 19 1997 17:31:18";
diff --git a/source/exhumed/src/version.h b/source/exhumed/src/version.h
new file mode 100644
index 000000000..fde2a8d92
--- /dev/null
+++ b/source/exhumed/src/version.h
@@ -0,0 +1,7 @@
+
+#ifndef __version_h__
+#define __version_h__
+
+extern const char *versionstr;
+
+#endif
diff --git a/source/exhumed/src/view.cpp b/source/exhumed/src/view.cpp
new file mode 100644
index 000000000..19a232657
--- /dev/null
+++ b/source/exhumed/src/view.cpp
@@ -0,0 +1,511 @@
+
+#include "types.h"
+#include "engine.h"
+#include "names.h"
+#include "view.h"
+#include "status.h"
+#include "exhumed.h"
+#include "player.h"
+#include "snake.h"
+#include "gun.h"
+#include "light.h"
+#include "init.h"
+#include "menu.h"
+#include "keyboard.h"
+#include "cd.h"
+#include "cdaudio.h"
+#include "typedefs.h"
+#include "move.h"
+#include "sound.h"
+#include "engine.h"
+#include "trigdat.h"
+#include "runlist.h"
+#include
+
+short bSubTitles = kTrue;
+
+int zbob;
+
+short nDestVertPan[kMaxPlayers] = { 0 };
+short dVertPan[kMaxPlayers];
+short nVertPan[kMaxPlayers];
+int nCamerax;
+int nCameray;
+int nCameraz;
+
+short bTouchFloor;
+
+short nQuake[kMaxPlayers] = { 0 };
+
+short nChunkTotal = 0;
+
+short nCameraa;
+short nCamerapan;
+short nViewTop;
+short bgpages = 0;
+short bClip = kFalse;
+short nViewBottom;
+short nViewRight;
+short besttarget;
+short nViewLeft;
+short bCamera = kFalse;
+
+short nViewy;
+
+int viewz;
+
+short enemy;
+
+short nEnemyPal = 0;
+
+
+void InitView()
+{
+ screensize = (short)xdim;
+}
+
+// NOTE - not to be confused with Ken's analyzesprites()
+static void analyzesprites()
+{
+ short nPlayerSprite = PlayerList[nLocalPlayer].nSprite;
+
+ int var_38 = 20;
+ int var_2C = 30000;
+
+ besttarget = -1;
+
+ int x = sprite[nPlayerSprite].x;
+ int y = sprite[nPlayerSprite].y;
+
+ int z = sprite[nPlayerSprite].z - (GetSpriteHeight(nPlayerSprite) / 2);
+
+ short nSector = sprite[nPlayerSprite].sectnum;
+
+ int nAngle = (2048 - sprite[nPlayerSprite].ang) & kAngleMask;
+
+ int edi = spritesortcnt;
+ int nSprite = spritesortcnt - 1;
+
+// int var_20 = var_24;
+
+ while (1)
+ {
+ edi--;
+ if (edi < 0)
+ {
+ if (besttarget != -1)
+ {
+ nCreepyTimer = 450;
+
+ if (!cansee(x, y, z, nSector, sprite[besttarget].x, sprite[besttarget].y, sprite[besttarget].z - GetSpriteHeight(besttarget), sprite[besttarget].sectnum))
+ {
+ besttarget = -1;
+ }
+ }
+
+ return;
+ }
+ else
+ {
+ int nSprite2 = tsprite[nSprite].owner;
+
+ if (sprite[nSprite2].statnum > 0)
+ {
+ runlist_SignalRun(sprite[nSprite2].lotag - 1, edi | 0x90000);
+
+ if ((sprite[nSprite2].statnum < 150) && (sprite[nSprite2].cstat & 0x101) && (nSprite2 != nPlayerSprite))
+ {
+ int xval = sprite[nSprite2].x - x;
+ int yval = sprite[nSprite2].y - y;
+
+ int var_40 = xval * Sin(nAngle + 512);
+ int var_44 = sintable[nAngle];
+
+
+ int edx = ((Sin(nAngle + 512) * yval) + (xval * var_44)) >> 14;
+
+
+ int eax = (var_40 - (yval * var_44)) >> 14;
+
+
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ int ebx = eax;
+ int ecx = eax;
+
+ if (eax)
+ {
+ eax = edx;
+
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ edx = (eax * 32) / ebx;
+
+ if (ebx >= 1000 || ebx >= var_2C || edx >= 10)
+ {
+ // loc_170A1
+ if (ecx < 30000)
+ {
+ eax = var_38 - edx;
+ if (eax <= 3)
+ {
+ if (ecx < var_2C)
+ {
+ if (eax < 0) {
+ eax = -eax;
+ }
+
+ if (eax < 5)
+ {
+ var_38 = edx;
+ var_2C = ecx;
+ besttarget = nSprite2;
+ }
+ }
+ }
+ else
+ {
+ var_38 = edx;
+ var_2C = ecx;
+ besttarget = nSprite2;
+ }
+ }
+ }
+ else
+ {
+ besttarget = nSprite2;
+ var_38 = edx;
+ var_2C = ebx;
+ }
+ }
+ }
+ }
+ }
+
+ nSprite--;
+ }
+}
+
+void ResetView()
+{
+ uchar blankPal[768];
+ memset(blankPal, 0, sizeof(blankPal));
+ MySetPalette(blankPal);
+
+ EraseScreen(0);
+
+ // FIXME
+#ifdef __WATCOMC__
+ setgamemode(2, 320, 200);
+#else
+ setgamemode(0, nScreenWidth, nScreenHeight, 8);
+#endif
+
+ MySetPalette(blankPal);
+
+ DoOverscanSet(overscanindex);
+ EraseScreen(overscanindex);
+
+ MySetPalette(kenpal);
+
+ LoadStatus();
+
+ screenpage = (short)numpages;
+}
+
+void SetView1()
+{
+ if (screenpage > 0) {
+ screenpage--;
+ }
+}
+
+void FlushMessageLine()
+{
+ int tileX = tilesizx[nBackgroundPic];
+ int nTileOffset = 0;
+
+ int xPos = 0;
+
+ while (xPos < nScreenWidth)
+ {
+ overwritesprite(xPos, 0, nBackgroundPic + nTileOffset, -32, 0, kPalNormal);
+
+ nTileOffset = nTileOffset == 0;
+
+ xPos += tileX;
+ }
+}
+
+void RefreshBackground()
+{
+ int nTileOffset = 0;
+ int tileX = tilesizx[nBackgroundPic];
+ int tileY = tilesizy[nBackgroundPic];
+
+ setview(0, 0, nScreenWidth - 1, nScreenHeight - 1);
+
+ MaskStatus();
+
+ for (int y = 0; y < nScreenHeight; y += tileY)
+ {
+ for (int x = 0; x < nScreenWidth; x += tileX)
+ {
+ overwritesprite(x, y, nBackgroundPic + nTileOffset, -32, 0, kPalNormal);
+ if (nTileOffset == 0) {
+ nTileOffset = 1;
+ }
+ else {
+ nTileOffset = 0;
+ }
+ }
+ }
+
+ setview(nViewLeft, nViewTop, nViewRight, nViewBottom);
+}
+
+void MySetView(int x1, int y1, int x2, int y2)
+{
+ if (!bFullScreen) {
+ MaskStatus();
+ }
+
+ nViewLeft = x1;
+ nViewTop = y1;
+ nViewRight = x2;
+ nViewBottom = y2;
+
+ setview(x1, y1, x2, y2);
+
+ nViewy = y1;
+ barpages = (short)numpages;
+ bgpages = (short)numpages;
+}
+
+// unused function
+void TestLava()
+{
+}
+
+void DrawView()
+{
+ long playerX;
+ long playerY;
+ long playerZ;
+ short nSector;
+ int nAngle;
+ short pan;
+
+ if (bgpages <= 0)
+ {
+ if (textpages > 0)
+ {
+ textpages--;
+ FlushMessageLine();
+ }
+ }
+ else
+ {
+ RefreshBackground();
+ bgpages--;
+ }
+
+ if (!bFullScreen) {
+ MaskStatus();
+ }
+
+ zbob = Sin(2 * bobangle) >> 3;
+
+ int nPlayerSprite = PlayerList[nLocalPlayer].nSprite;
+
+ if (nSnakeCam >= 0)
+ {
+ int nSprite = SnakeList[nSnakeCam].nSprites[0];
+
+ playerX = sprite[nSprite].x;
+ playerY = sprite[nSprite].y;
+ playerZ = sprite[nSprite].z;
+ nSector = sprite[nSprite].sectnum;
+ nAngle = sprite[nSprite].ang;
+
+ SetGreenPal();
+ UnMaskStatus();
+
+ enemy = SnakeList[nSnakeCam].nEnemy;
+
+ if (enemy <= -1 || totalmoves & 1)
+ {
+ nEnemyPal = -1;
+ }
+ else
+ {
+ nEnemyPal = sprite[enemy].pal;
+ sprite[enemy].pal = 5;
+ }
+ }
+ else
+ {
+ playerX = sprite[nPlayerSprite].x;
+ playerY = sprite[nPlayerSprite].y;
+ playerZ = sprite[nPlayerSprite].z + eyelevel[nLocalPlayer];
+ nSector = nPlayerViewSect[nLocalPlayer];
+ nAngle = sprite[nPlayerSprite].ang;
+ }
+
+ nCameraa = nAngle;
+
+ if (!bCamera || nFreeze)
+ {
+ if (nSnakeCam >= 0)
+ {
+ pan = 92;
+ viewz = playerZ;
+ }
+ else
+ {
+ viewz = playerZ + nQuake[nLocalPlayer];
+ int floorZ = sector[sprite[nPlayerSprite].sectnum].floorz;
+
+ pan = nVertPan[nLocalPlayer];
+
+ if (viewz > floorZ)
+ viewz = floorZ;
+
+ nCameraa += (nQuake[nLocalPlayer] >> 7) % 31;
+ }
+ }
+ else
+ {
+ clipmove(&playerX, &playerY, &playerZ, &nSector,
+ -2000 * Sin(inita + 512),
+ -2000 * Sin(inita),
+ 4, 0, 0, CLIPMASK1);
+
+ pan = 92;
+ viewz = playerZ;
+ }
+
+ nCamerax = playerX;
+ nCameray = playerY;
+ nCameraz = playerZ;
+
+ int Z = sector[nSector].ceilingz + 256;
+ if (Z <= viewz)
+ {
+ Z = sector[nSector].floorz - 256;
+
+ if (Z < viewz)
+ viewz = Z;
+ }
+ else {
+ viewz = Z;
+ }
+
+ nCamerapan = pan;
+
+ if (nFreeze == 2 || nFreeze == 1)
+ {
+ nSnakeCam = -1;
+ setview(0, 0, nScreenWidth - 1, nScreenHeight - 1);
+ UnMaskStatus();
+ }
+
+ if (nFreeze != 3)
+ {
+ drawrooms(nCamerax, nCameray, viewz, nCameraa, nCamerapan, nSector);
+ analyzesprites();
+ drawmasks();
+
+ if (nFreeze)
+ {
+ nSnakeCam = -1;
+
+ if (nFreeze == 2)
+ {
+ if (nHeadStage == 4)
+ {
+ nHeadStage = 5;
+
+ sprite[nPlayerSprite].cstat |= 0x8000;
+
+ int ang2 = nCameraa - sprite[nPlayerSprite].ang;
+ if (ang2 < 0)
+ ang2 = -ang2;
+
+ if (ang2 > 10)
+ {
+ inita -= (ang2 >> 3);
+ return;
+ }
+
+ if (bSubTitles)
+ {
+ if (levelnum == 1)
+ ReadyCinemaText(1);
+ else
+ ReadyCinemaText(5);
+ }
+ }
+ else
+ {
+ if ((bSubTitles && !AdvanceCinemaText()) || KB_KeyDown[sc_Escape] || KB_KeyDown[sc_Return] || KB_KeyDown[sc_Space])
+ {
+ levelnew = levelnum + 1;
+
+ if (CDplaying())
+ fadecdaudio();
+ }
+
+ setview(nViewLeft, nViewTop, nViewRight, nViewBottom);
+ }
+ }
+ }
+ else
+ {
+ if (nSnakeCam < 0)
+ {
+ DrawWeapons();
+ DrawStatus();
+ }
+ else
+ {
+ RestoreGreenPal();
+ if (nEnemyPal > -1) {
+ sprite[enemy].pal = nEnemyPal;
+ }
+
+ if (!bFullScreen) {
+ MaskStatus();
+ }
+ }
+ }
+ }
+ else
+ {
+ clearview(overscanindex);
+ DrawStatus();
+ }
+
+ flash = 0;
+}
+
+void NoClip()
+{
+ setview(0, 0, nScreenWidth - 1, nScreenHeight - 1);
+
+ bClip = kFalse;
+}
+
+void Clip()
+{
+ setview(nViewLeft, nViewTop, nViewRight, nViewBottom);
+ if (!bFullScreen) {
+ MaskStatus();
+ }
+
+ bClip = kTrue;
+}
diff --git a/source/exhumed/src/view.h b/source/exhumed/src/view.h
new file mode 100644
index 000000000..ed9417eb9
--- /dev/null
+++ b/source/exhumed/src/view.h
@@ -0,0 +1,37 @@
+
+#ifndef __view_h__
+#define __view_h__
+
+extern short bSubTitles;
+extern short nViewTop;
+extern short bgpages;
+extern short bClip;
+extern short nViewBottom;
+extern short nViewRight;
+extern short nViewLeft;
+extern short besttarget;
+extern short bCamera;
+
+void InitView();
+void SetView1();
+void RefreshBackground();
+void DrawView();
+void MySetView(int x1, int y1, int x2, int y2);
+void ResetView();
+void NoClip();
+void Clip();
+
+extern short nDestVertPan[];
+extern short dVertPan[];
+extern short nVertPan[];
+extern short nQuake[];
+
+extern int nCamerax;
+extern int nCameray;
+extern int nCameraz;
+
+extern short bTouchFloor;
+
+extern short nChunkTotal;
+
+#endif
diff --git a/source/exhumed/src/wasp.cpp b/source/exhumed/src/wasp.cpp
new file mode 100644
index 000000000..88f1b2a32
--- /dev/null
+++ b/source/exhumed/src/wasp.cpp
@@ -0,0 +1,398 @@
+
+#include "wasp.h"
+#include "engine.h"
+#include "runlist.h"
+#include "random.h"
+#include "exhumed.h"
+#include "sequence.h"
+#include "init.h"
+#include "move.h"
+#include "anims.h"
+#include "trigdat.h"
+#include
+
+#define kMaxWasps 100
+
+static short nVelShift = 0;
+short nWaspCount;
+
+struct Wasp
+{
+ short nHealth;
+ short field_2;
+ short nAction;
+ short nSprite;
+ short field_8;
+ short nTarget;
+ short field_C;
+ short field_E;
+ short field_10;
+ short field_12;
+ short field_14;
+ short field_16;
+};
+
+Wasp WaspList[kMaxWasps];
+
+static actionSeq ActionSeq[] = {{0,0}, {0,0}, {9,0}, {18,0}, {27,1}, {28,1}, {29,1}};
+
+
+void InitWasps()
+{
+ nWaspCount = 0;
+}
+
+void SetWaspVel(short nSprite)
+{
+ if (nVelShift < 0)
+ {
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) << -nVelShift;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) << -nVelShift;
+ }
+ else
+ {
+ sprite[nSprite].xvel = Sin(sprite[nSprite].ang + 512) >> nVelShift;
+ sprite[nSprite].yvel = Sin(sprite[nSprite].ang) >> nVelShift;
+ }
+
+}
+
+int BuildWasp(short nSprite, int x, int y, int z, short nSector, short nAngle)
+{
+ if (nWaspCount >= kMaxWasps) {
+ return -1;
+ }
+
+ short nWasp = nWaspCount;
+ nWaspCount++;
+
+ // TODO - CHECKME
+ BOOL bSomeType = kTrue;
+ if (nSprite == -2) {
+ bSomeType = kFalse;
+ }
+
+ if (nSprite < 0)
+ {
+ nSprite = insertsprite(nSector, 107);
+ assert(nSprite >= 0 && nSprite < kMaxSprites);
+
+ sprite[nSprite].x = x;
+ sprite[nSprite].y = y;
+ sprite[nSprite].z = z;
+ }
+ else
+ {
+ nAngle = sprite[nSprite].ang;
+ changespritestat(nSprite, 107);
+ }
+
+ sprite[nSprite].shade = -12;
+ sprite[nSprite].cstat = 0x101;
+ sprite[nSprite].pal = sector[sprite[nSprite].sectnum].ceilingpal;
+ sprite[nSprite].clipdist = 70;
+
+ if (bSomeType)
+ {
+ sprite[nSprite].yrepeat = 20;
+ sprite[nSprite].xrepeat = 20;
+ }
+ else
+ {
+ sprite[nSprite].xrepeat = 50;
+ sprite[nSprite].yrepeat = 50;
+ }
+
+ sprite[nSprite].xoffset = 0;
+ sprite[nSprite].yoffset = 0;
+ sprite[nSprite].picnum = 1;
+ sprite[nSprite].ang = nAngle;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].hitag = 0;
+ sprite[nSprite].lotag = runlist_HeadRun() + 1;
+ sprite[nSprite].extra = -1;
+
+// GrabTimeSlot(3);
+
+ WaspList[nWasp].nAction = 0;
+ WaspList[nWasp].field_2 = 0;
+ WaspList[nWasp].nSprite = nSprite;
+ WaspList[nWasp].nTarget = -1;
+ WaspList[nWasp].nHealth = 800;
+ WaspList[nWasp].field_16 = 10;
+
+ if (bSomeType)
+ {
+ WaspList[nWasp].field_C = 60;
+ WaspList[nWasp].field_16 = (WaspList[nWasp].field_16 - 1) >> 1;
+ }
+ else
+ {
+ WaspList[nWasp].field_C = RandomSize(5);
+ }
+
+ WaspList[nWasp].field_E = 0;
+ WaspList[nWasp].field_14 = 0;
+ WaspList[nWasp].field_12 = 0;
+ WaspList[nWasp].field_10 = RandomSize(7) + 127;
+
+ sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, nWasp | 0x1E0000);
+
+ WaspList[nWasp].field_8 = runlist_AddRunRec(NewRun, nWasp | 0x1E0000);
+
+ nCreaturesLeft++;
+ return nSprite;
+}
+
+void FuncWasp(int a, int nDamage, int nRun)
+{
+ short nWasp = RunData[nRun].nVal;
+
+ short nTarget = -1;
+
+ short nSprite = WaspList[nWasp].nSprite;
+ short nAction = WaspList[nWasp].nAction;
+
+ int someval = 0;
+
+ int nMessage = a & 0x7F0000;
+
+ switch (nMessage)
+ {
+ case 0x90000:
+ {
+ seq_PlotSequence(a & 0xFFFF, SeqOffsets[kSeqWasp] + ActionSeq[nAction].a, WaspList[nWasp].field_2, ActionSeq[nAction].b);
+ return;
+ }
+
+ case 0xA0000:
+ {
+ if (!(sprite[nSprite].cstat & 0x101))
+ return;
+
+ nDamage = runlist_CheckRadialDamage(nSprite);
+ // fall through to case 0x80000
+ }
+
+ case 0x80000:
+ {
+ if (!nDamage) {
+ return;
+ }
+
+ if (WaspList[nWasp].nHealth > 0)
+ {
+ WaspList[nWasp].nHealth -= nDamage;
+
+ if (WaspList[nWasp].nHealth > 0)
+ {
+ if (!RandomSize(4))
+ {
+ WaspList[nWasp].nAction = 3;
+ WaspList[nWasp].field_2 = 0;
+ }
+
+ WaspList[nWasp].nAction = 1;
+ sprite[nSprite].ang += RandomSize(9) + 768;
+ sprite[nSprite].ang &= kAngleMask;
+
+ WaspList[nWasp].field_12 = 3000;
+
+ sprite[nSprite].zvel = (-20) - RandomSize(6);
+ }
+ else
+ {
+ // Wasp is dead
+ WaspList[nWasp].nAction = 4;
+ WaspList[nWasp].field_2 = 0;
+
+ nVelShift = 0;
+
+ sprite[nSprite].cstat = 0;
+
+ nCreaturesLeft--;
+
+ sprite[nSprite].ang = (sprite[nSprite].ang + 1024) & kAngleMask;
+
+ SetWaspVel(nSprite);
+
+ sprite[nSprite].zvel = 512;
+ }
+ }
+ return;
+ }
+
+ case 0x20000:
+ {
+ short nSeq = SeqOffsets[kSeqWasp] + ActionSeq[nAction].a;
+
+ sprite[nSprite].picnum = seq_GetSeqPicnum2(nSeq, WaspList[nWasp].field_2);
+
+ seq_MoveSequence(nSprite, nSeq, WaspList[nWasp].field_2);
+
+ WaspList[nWasp].field_2++;
+ if (WaspList[nWasp].field_2 >= SeqSize[nSeq])
+ {
+ WaspList[nWasp].field_2 = 0;
+ someval = 1;
+ }
+
+ if (WaspList[nWasp].nHealth > 0)
+ {
+ nTarget = WaspList[nWasp].nTarget;
+
+ if (nTarget > -1 && (!(sprite[nTarget].cstat & 0x101) || (SectFlag[sprite[nTarget].sectnum] & kSectUnderwater)))
+ {
+ // goto pink
+ WaspList[nWasp].nTarget = -1;
+ WaspList[nWasp].nAction = 0;
+ WaspList[nWasp].field_C = RandomSize(6);
+ return;
+ }
+ }
+
+ switch (nAction)
+ {
+ case 0:
+ {
+ sprite[nSprite].zvel = Sin(WaspList[nWasp].field_E) >> 4;
+
+ WaspList[nWasp].field_E += WaspList[nWasp].field_10;
+ WaspList[nWasp].field_E &= kAngleMask;
+
+ MoveCreature(nSprite);
+
+ if (nTarget >= 0)
+ {
+ WaspList[nWasp].field_C--;
+ if (WaspList[nWasp].field_C > 0)
+ {
+ PlotCourseToSprite(nSprite, nTarget);
+ }
+ else
+ {
+ WaspList[nWasp].nAction = 1;
+ sprite[nSprite].zvel = 0;
+ WaspList[nWasp].field_2 = 0;
+ WaspList[nWasp].field_12 = 1500;
+ WaspList[nWasp].field_C = RandomSize(5) + 60;
+ }
+ }
+ else
+ {
+ if ((nWasp & 0x1F) == (totalmoves & 0x1F)) {
+ WaspList[nWasp].nTarget = FindPlayer(nSprite, 60);
+ }
+ }
+
+ return;
+ }
+
+ case 1:
+ {
+ WaspList[nWasp].field_C--;
+
+ if (WaspList[nWasp].field_C <= 0)
+ {
+ WaspList[nWasp].nAction = 0;
+ WaspList[nWasp].field_C = RandomSize(6);
+ return;
+ }
+
+ int nChaseVal = AngleChase(nSprite, nTarget, WaspList[nWasp].field_12, 0, 16);
+
+ switch (nChaseVal & 0xC000)
+ {
+ default:
+ return;
+
+ case 0x8000:
+ {
+ return;
+ }
+
+ case 0xC000:
+ {
+ short nSprite2 = (nChaseVal & 0x3FFF);
+ if (nSprite2 == nTarget)
+ {
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ runlist_DamageEnemy(nSprite2, nSprite, WaspList[nWasp].field_16);
+ WaspList[nWasp].nAction = 2;
+ WaspList[nWasp].field_2 = 0;
+ }
+ return;
+ }
+ }
+
+ return;
+ }
+
+ case 2:
+ case 3:
+ {
+ if (someval)
+ {
+ WaspList[nWasp].nAction = 1;
+ sprite[nSprite].ang = RandomSize(9) + 768;
+ sprite[nSprite].ang &= kAngleMask;
+
+ WaspList[nWasp].field_12 = 3000;
+
+ sprite[nSprite].zvel = (-20) - RandomSize(6);
+ }
+ return;
+ }
+ case 4:
+ {
+ int nMove = MoveCreature(nSprite) & 0x8000;
+ nMove |= 0xC000;
+
+ if (nMove)
+ {
+ sprite[nSprite].yvel = 0;
+ WaspList[nWasp].nAction = 5;
+ sprite[nSprite].xvel = 0;
+ WaspList[nWasp].field_2 = 0;
+ sprite[nSprite].zvel = 1024;
+ }
+
+ return;
+ }
+ case 5:
+ {
+ short nSector = sprite[nSprite].sectnum;
+
+ sprite[nSprite].z += sprite[nSprite].zvel;
+
+ if (sprite[nSprite].z >= sector[nSector].floorz)
+ {
+ if (SectBelow[nSector] > -1)
+ {
+ BuildSplash(nSprite, nSector);
+ sprite[nSprite].cstat |= 0x8000;
+ }
+
+ sprite[nSprite].zvel = 0;
+ sprite[nSprite].yvel = 0;
+ sprite[nSprite].xvel = 0;
+ WaspList[nWasp].nAction = 6;
+ WaspList[nWasp].field_2 = 0;
+ runlist_SubRunRec(WaspList[nWasp].field_8);
+ }
+
+ return;
+ }
+ default:
+ {
+ return;
+ }
+ }
+
+ break;
+ }
+ }
+}
diff --git a/source/exhumed/src/wasp.h b/source/exhumed/src/wasp.h
new file mode 100644
index 000000000..bd5fbc81e
--- /dev/null
+++ b/source/exhumed/src/wasp.h
@@ -0,0 +1,11 @@
+
+#ifndef __wasp_h__
+#define __wasp_h__
+
+extern short nWaspCount;
+
+void InitWasps();
+int BuildWasp(short nSprite, int x, int y, int z, short nSector, short nAngle);
+void FuncWasp(int eax, int edx, int nRun);
+
+#endif