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