demo.cpp
1 //------------------------------------------------------------------------- 2 /* 3 Copyright (C) 2010-2019 EDuke32 developers and contributors 4 Copyright (C) 2019 Nuke.YKT 5 6 This file is part of NBlood. 7 8 NBlood is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License version 2 10 as published by the Free Software Foundation. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 16 See the GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 */ 22 //------------------------------------------------------------------------- 23 #include <stdio.h> 24 #include <string.h> 25 #include "common.h" 26 #include "common_game.h" 27 #include "keyboard.h" 28 #include "control.h" 29 #include "osd.h" 30 #include "mmulti.h" 31 32 #include "blood.h" 33 #include "controls.h" 34 #include "demo.h" 35 #include "fire.h" 36 #include "gamemenu.h" 37 #include "globals.h" 38 #include "levels.h" 39 #include "menu.h" 40 #include "messages.h" 41 #include "misc.h" 42 #include "music.h" 43 #include "network.h" 44 #include "player.h" 45 #include "screen.h" 46 #include "sound.h" 47 #include "view.h" 48 49 bool gDemoRunValidation = false; 50 51 struct DEMOVALIDATE { 52 const char *zName; 53 int32_t nInputTicks; 54 uint32_t wrandomseed; 55 uint32_t health; 56 vec3_t xyz; 57 int nAutoAim; 58 }; 59 60 const char *gDemoInvalid[] = { // compiler hall of shame 61 #if defined(__GNUC__) && __GNUC__ >= 15 62 "TEST085.DEM", 63 "TEST096.DEM", 64 "TEST098.DEM", 65 #else 66 "" 67 #endif 68 }; 69 70 const DEMOVALIDATE gDemoValidate[] = { 71 {"/validatedemos/TEST000.DEM", (int32_t)0x00000DB1, 0x68E811AD, 0x00000000, {(int32_t)0x00002239, (int32_t)0x00006A75, (int32_t)0x000029A4}, 1}, 72 {"/validatedemos/TEST001.DEM", (int32_t)0x000008E3, 0x898BFCFE, 0x00000000, {(int32_t)0x00001AC0, (int32_t)0x00003F49, (int32_t)0x000025A4}, 1}, 73 {"/validatedemos/TEST002.DEM", (int32_t)0x00000CE0, 0xCAF89634, 0x00000000, {(int32_t)0x0000C8ED, (int32_t)0x00009AF9, (int32_t)0x000159A4}, 1}, 74 {"/validatedemos/TEST003.DEM", (int32_t)0x00000B87, 0x4488E1A6, 0x00000000, {(int32_t)0xFFFFD54C, (int32_t)0xFFFFD41F, (int32_t)0x000019A4}, 1}, 75 // custom validation demos below 76 {"/validatedemos/TEST004.DEM", (int32_t)0x00000C14, 0x6E8F8936, 0x00000000, {(int32_t)0x00003D02, (int32_t)0x00009F6E, (int32_t)0x000069A4}, 1}, 77 {"/validatedemos/TEST005.DEM", (int32_t)0x00001BF9, 0xE8B80FD0, 0x00000000, {(int32_t)0x00000162, (int32_t)0x00007AE0, (int32_t)0xFFFEFDA4}, 1}, 78 {"/validatedemos/TEST006.DEM", (int32_t)0x000036C8, 0xABF22136, 0x00000000, {(int32_t)0xFFFF2181, (int32_t)0x000091B1, (int32_t)0x000083CE}, 1}, 79 {"/validatedemos/TEST007.DEM", (int32_t)0x00004DA6, 0xB7FB11EB, 0x00000000, {(int32_t)0x0000F4DC, (int32_t)0x000053C9, (int32_t)0x000125A4}, 1}, 80 {"/validatedemos/TEST008.DEM", (int32_t)0x0000347B, 0x02CB1319, 0x00000BED, {(int32_t)0xFFFF8138, (int32_t)0xFFFED30A, (int32_t)0xFFFF7D50}, 1}, 81 {"/validatedemos/TEST009.DEM", (int32_t)0x000026AF, 0x4F91391D, 0x00000000, {(int32_t)0xFFFF3824, (int32_t)0xFFFF91BF, (int32_t)0x00007BA4}, 1}, 82 {"/validatedemos/TEST010.DEM", (int32_t)0x00000E96, 0xFF23FAE8, 0x00000000, {(int32_t)0xFFFF23DD, (int32_t)0xFFFF9EE0, (int32_t)0x00006DA4}, 1}, 83 {"/validatedemos/TEST011.DEM", (int32_t)0x00001706, 0x3A7DD0B0, 0x00000000, {(int32_t)0x0000CD98, (int32_t)0x00004C0A, (int32_t)0x00011DF5}, 1}, 84 {"/validatedemos/TEST012.DEM", (int32_t)0x00003D72, 0xE4A69539, 0x00000000, {(int32_t)0xFFFF8745, (int32_t)0xFFFED4C6, (int32_t)0xFFFF99A4}, 1}, 85 {"/validatedemos/TEST013.DEM", (int32_t)0x000028CE, 0x93096ADB, 0x0000046A, {(int32_t)0xFFFF826E, (int32_t)0xFFFED2C1, (int32_t)0xFFFF7D50}, 1}, 86 {"/validatedemos/TEST014.DEM", (int32_t)0x00000F77, 0xA8160C3C, 0x00000000, {(int32_t)0xFFFFC8D7, (int32_t)0xFFFF930F, (int32_t)0xFFFFA5A4}, 1}, 87 {"/validatedemos/TEST015.DEM", (int32_t)0x000016CB, 0xF6F9315E, 0x00000000, {(int32_t)0xFFFFF7A1, (int32_t)0x00007494, (int32_t)0xFFFE6651}, 1}, 88 {"/validatedemos/TEST016.DEM", (int32_t)0x0000165C, 0x45F41D2E, 0x00000000, {(int32_t)0x00001A1C, (int32_t)0x00008D3F, (int32_t)0xFFFF39A4}, 1}, 89 {"/validatedemos/TEST017.DEM", (int32_t)0x000033F7, 0x52634976, 0x00000640, {(int32_t)0x0000AC77, (int32_t)0x000012AB, (int32_t)0xFFFFFD50}, 1}, 90 {"/validatedemos/TEST018.DEM", (int32_t)0x00002D0C, 0x60DCE40A, 0x00000000, {(int32_t)0x0000645F, (int32_t)0x0000CB1B, (int32_t)0xFFFFC9A4}, 1}, 91 {"/validatedemos/TEST019.DEM", (int32_t)0x00000337, 0x4A0013E6, 0x00000640, {(int32_t)0xFFFF9FCC, (int32_t)0x00003E52, (int32_t)0xFFFF63D4}, 1}, 92 {"/validatedemos/TEST020.DEM", (int32_t)0x000009DE, 0xC0725AF1, 0x00000000, {(int32_t)0xFFFFC1CF, (int32_t)0x000064AD, (int32_t)0x000061A4}, 1}, 93 {"/validatedemos/TEST021.DEM", (int32_t)0x000019A4, 0x8BE81A09, 0x00000000, {(int32_t)0xFFFF161C, (int32_t)0x00004DB3, (int32_t)0xFFFFEEFE}, 1}, 94 {"/validatedemos/TEST022.DEM", (int32_t)0x00000EB3, 0x37E4D6D6, 0x00000000, {(int32_t)0x00004869, (int32_t)0x0000170D, (int32_t)0x000129A4}, 1}, 95 {"/validatedemos/TEST023.DEM", (int32_t)0x00001F68, 0x19B46535, 0x00000000, {(int32_t)0xFFFFDE10, (int32_t)0xFFFFD970, (int32_t)0xFFFFE9A4}, 1}, 96 {"/validatedemos/TEST024.DEM", (int32_t)0x00003C97, 0x7F3AE994, 0x00000640, {(int32_t)0xFFFFD2F2, (int32_t)0xFFFF8DD4, (int32_t)0xFFFF0950}, 1}, 97 {"/validatedemos/TEST025.DEM", (int32_t)0x0000182B, 0x330C60F2, 0x00000000, {(int32_t)0xFFFF94C1, (int32_t)0xFFFFAA81, (int32_t)0x000019A4}, 1}, 98 {"/validatedemos/TEST026.DEM", (int32_t)0x00002364, 0x37059BD3, 0x00000000, {(int32_t)0x0000456F, (int32_t)0xFFFFF8B8, (int32_t)0x000099A4}, 1}, 99 {"/validatedemos/TEST027.DEM", (int32_t)0x00001731, 0x250E075B, 0x00000000, {(int32_t)0x0000043F, (int32_t)0xFFFFD0C1, (int32_t)0x000119A4}, 1}, 100 {"/validatedemos/TEST028.DEM", (int32_t)0x00002FB4, 0xDF294819, 0x00000842, {(int32_t)0x000056A8, (int32_t)0xFFFFD628, (int32_t)0xFFFFFD9F}, 1}, 101 {"/validatedemos/TEST029.DEM", (int32_t)0x000017BB, 0xD184192B, 0x00000A1A, {(int32_t)0xFFFFAD5B, (int32_t)0xFFFF4573, (int32_t)0xFFFFE550}, 1}, 102 {"/validatedemos/TEST030.DEM", (int32_t)0x0000396B, 0x5031BC75, 0x00000000, {(int32_t)0x0000B326, (int32_t)0x000074C4, (int32_t)0x0000D9A4}, 1}, 103 {"/validatedemos/TEST031.DEM", (int32_t)0x000023D1, 0xC5DCAC81, 0x00000640, {(int32_t)0x00009BEE, (int32_t)0x00006CC8, (int32_t)0x00003550}, 1}, 104 {"/validatedemos/TEST032.DEM", (int32_t)0x000013BC, 0xCA389D8F, 0x00000000, {(int32_t)0x00009B71, (int32_t)0x000092A4, (int32_t)0x000159A4}, 1}, 105 {"/validatedemos/TEST033.DEM", (int32_t)0x00000BA4, 0xB06865D4, 0x00000000, {(int32_t)0x00009415, (int32_t)0x00007E5D, (int32_t)0x000159A4}, 1}, 106 {"/validatedemos/TEST034.DEM", (int32_t)0x000019C7, 0x7F7D0178, 0x00000640, {(int32_t)0x00009B90, (int32_t)0x00006CF1, (int32_t)0x000035E4}, 1}, 107 {"/validatedemos/TEST035.DEM", (int32_t)0x0000066A, 0xD7607579, 0x00000000, {(int32_t)0x0000B31C, (int32_t)0x0000B03F, (int32_t)0x000159A4}, 1}, 108 {"/validatedemos/TEST036.DEM", (int32_t)0x000016DC, 0x79095E8C, 0x00000000, {(int32_t)0x0000C2AB, (int32_t)0x000094C1, (int32_t)0x000059A4}, 1}, 109 {"/validatedemos/TEST037.DEM", (int32_t)0x00000B4A, 0xF9F76876, 0x00000000, {(int32_t)0x0000D00B, (int32_t)0x0000ACC8, (int32_t)0x000159A4}, 1}, 110 {"/validatedemos/TEST038.DEM", (int32_t)0x0000384B, 0x46086DB2, 0x0000032F, {(int32_t)0x000103E8, (int32_t)0xFFFFC601, (int32_t)0x000005E4}, 1}, // at this point msvc created binaries will desync for some weird reason 111 {"/validatedemos/TEST039.DEM", (int32_t)0x000034D7, 0xC6E9D184, 0x00000000, {(int32_t)0x0000FA87, (int32_t)0x00006C32, (int32_t)0x000025A4}, 1}, 112 {"/validatedemos/TEST040.DEM", (int32_t)0x0000385B, 0x246696C4, 0x00000000, {(int32_t)0x00010BC8, (int32_t)0x00005F46, (int32_t)0xFFFFC1A4}, 1}, 113 {"/validatedemos/TEST041.DEM", (int32_t)0x00001BA1, 0x8377D75C, 0x00000000, {(int32_t)0x00006EBF, (int32_t)0x0000463F, (int32_t)0x00079DA4}, 1}, 114 {"/validatedemos/TEST042.DEM", (int32_t)0x00000A75, 0x61288D5E, 0x00000000, {(int32_t)0x0000A14F, (int32_t)0x00005D22, (int32_t)0x000069A4}, 1}, 115 {"/validatedemos/TEST043.DEM", (int32_t)0x000036FF, 0xD89DFDDD, 0x00000000, {(int32_t)0x00008B93, (int32_t)0x0000873F, (int32_t)0x000099A4}, 1}, 116 {"/validatedemos/TEST044.DEM", (int32_t)0x000012BD, 0xD53A7E17, 0x00000000, {(int32_t)0x0000BF3F, (int32_t)0x000079F1, (int32_t)0xFFFFC9A4}, 1}, 117 {"/validatedemos/TEST045.DEM", (int32_t)0x00000579, 0xDCE04A38, 0x00000000, {(int32_t)0x0000CA14, (int32_t)0x000081E9, (int32_t)0x000159A4}, 1}, 118 {"/validatedemos/TEST046.DEM", (int32_t)0x00000106, 0x363D780D, 0x00000000, {(int32_t)0xFFFFFF64, (int32_t)0x00009418, (int32_t)0xFFFFE1A4}, 1}, 119 {"/validatedemos/TEST047.DEM", (int32_t)0x00000B5F, 0x11F8A1D5, 0x000003BD, {(int32_t)0x00009A45, (int32_t)0x0000847F, (int32_t)0x0000BD50}, 1}, 120 {"/validatedemos/TEST048.DEM", (int32_t)0x00000AF3, 0x6E949D93, 0x00000000, {(int32_t)0xFFFF3468, (int32_t)0xFFFFD441, (int32_t)0x000061A4}, 1}, 121 {"/validatedemos/TEST049.DEM", (int32_t)0x00000C8F, 0x4E28530B, 0x00000000, {(int32_t)0xFFFFED7C, (int32_t)0x0000C8C0, (int32_t)0x000009A4}, 1}, 122 {"/validatedemos/TEST050.DEM", (int32_t)0x0000230B, 0xEA61B563, 0x00000000, {(int32_t)0x000029C1, (int32_t)0x00002C3F, (int32_t)0x000071A4}, 1}, 123 {"/validatedemos/TEST051.DEM", (int32_t)0x00002EA8, 0x19510828, 0x00000000, {(int32_t)0x00001FE4, (int32_t)0x000031D9, (int32_t)0x00000DA4}, 1}, 124 {"/validatedemos/TEST052.DEM", (int32_t)0x00005088, 0x04A4F873, 0x00000C80, {(int32_t)0x0000C0F4, (int32_t)0x0000B5ED, (int32_t)0xFFFF9F3F}, 1}, 125 {"/validatedemos/TEST053.DEM", (int32_t)0x000022BA, 0x93F42352, 0x00000000, {(int32_t)0x00001B69, (int32_t)0x000045D8, (int32_t)0x000011A4}, 1}, 126 {"/validatedemos/TEST054.DEM", (int32_t)0x00002C67, 0xE914FDC5, 0x00000000, {(int32_t)0xFFFF66E4, (int32_t)0x000049FF, (int32_t)0x000012E4}, 1}, 127 {"/validatedemos/TEST055.DEM", (int32_t)0x00001F8B, 0x1B5F1C0F, 0x00000000, {(int32_t)0xFFFFDD1F, (int32_t)0x00003A35, (int32_t)0x000059A4}, 1}, 128 {"/validatedemos/TEST056.DEM", (int32_t)0x00003EE5, 0xD02F860D, 0x00000000, {(int32_t)0xFFFF8824, (int32_t)0x0000543E, (int32_t)0x0000C1A4}, 1}, 129 {"/validatedemos/TEST057.DEM", (int32_t)0x00006979, 0xD9EC81A9, 0x00000000, {(int32_t)0xFFFF9197, (int32_t)0x000063D2, (int32_t)0x000061A4}, 1}, 130 {"/validatedemos/TEST058.DEM", (int32_t)0x00001C16, 0xD85F3129, 0x0000082F, {(int32_t)0xFFFFADAA, (int32_t)0xFFFF67D4, (int32_t)0xFFFFDD50}, 1}, 131 {"/validatedemos/TEST059.DEM", (int32_t)0x0000244B, 0x1E82B956, 0x00000000, {(int32_t)0x000000A4, (int32_t)0x00001F09, (int32_t)0x000219A4}, 1}, 132 {"/validatedemos/TEST060.DEM", (int32_t)0x000067CF, 0x086B69C7, 0x00000315, {(int32_t)0xFFFFA704, (int32_t)0x0000D1A8, (int32_t)0xFFFFFD50}, 1}, 133 {"/validatedemos/TEST061.DEM", (int32_t)0x000014BB, 0x89393200, 0x00000000, {(int32_t)0xFFFFC242, (int32_t)0xFFFF7FAD, (int32_t)0xFFFFCDA4}, 1}, 134 {"/validatedemos/TEST062.DEM", (int32_t)0x00002180, 0xB2F4CC77, 0x00000000, {(int32_t)0xFFFFB4AD, (int32_t)0x0000137E, (int32_t)0x000061A4}, 1}, 135 {"/validatedemos/TEST063.DEM", (int32_t)0x00000736, 0xB077ACC3, 0x00000000, {(int32_t)0xFFFF61FF, (int32_t)0xFFFFE7BA, (int32_t)0x000119A4}, 1}, 136 {"/validatedemos/TEST064.DEM", (int32_t)0x0000443E, 0x5FE50A44, 0x00000000, {(int32_t)0xFFFFF382, (int32_t)0x000086A6, (int32_t)0x000235A4}, 1}, 137 {"/validatedemos/TEST065.DEM", (int32_t)0x00003EBD, 0xA7A0D9C5, 0x00000247, {(int32_t)0xFFFF6B20, (int32_t)0xFFFFC641, (int32_t)0xFFFE1950}, 1}, 138 {"/validatedemos/TEST066.DEM", (int32_t)0x00003229, 0xAD1A9240, 0x00000000, {(int32_t)0xFFFF2809, (int32_t)0x0000A21E, (int32_t)0xFFFF59A4}, 1}, 139 {"/validatedemos/TEST067.DEM", (int32_t)0x0000374C, 0x19C88BDF, 0x00000615, {(int32_t)0xFFFFBC69, (int32_t)0xFFFF71B6, (int32_t)0xFFF9B97D}, 1}, 140 {"/validatedemos/TEST068.DEM", (int32_t)0x000045FF, 0x06B9C43C, 0x000004B9, {(int32_t)0xFFFEFF2E, (int32_t)0xFFFEE747, (int32_t)0xFFFE7950}, 1}, 141 {"/validatedemos/TEST069.DEM", (int32_t)0x00004B51, 0x1806DD38, 0x00000000, {(int32_t)0xFFFF430F, (int32_t)0x0000CF3F, (int32_t)0x000211A4}, 1}, 142 {"/validatedemos/TEST070.DEM", (int32_t)0x00001070, 0xA2B9B378, 0x00000000, {(int32_t)0x0000D06B, (int32_t)0x0001176F, (int32_t)0x000189A4}, 1}, 143 {"/validatedemos/TEST071.DEM", (int32_t)0x000082E6, 0xC74AB5A2, 0x0000016C, {(int32_t)0xFFFF80A0, (int32_t)0x00005BA3, (int32_t)0x00002950}, 1}, 144 {"/validatedemos/TEST072.DEM", (int32_t)0x000047C6, 0xA4405651, 0x00000000, {(int32_t)0x000099B6, (int32_t)0x000064BE, (int32_t)0x00006DA4}, 1}, 145 {"/validatedemos/TEST073.DEM", (int32_t)0x00002FD7, 0x11377903, 0x00000000, {(int32_t)0xFFFF7EC1, (int32_t)0xFFFEEF5F, (int32_t)0xFFF701A4}, 1}, 146 {"/validatedemos/TEST074.DEM", (int32_t)0x0000287A, 0xACAC602D, 0x00000000, {(int32_t)0x0000D43F, (int32_t)0x000092C1, (int32_t)0x00002844}, 1}, 147 {"/validatedemos/TEST075.DEM", (int32_t)0x000013DD, 0x78D2DFA4, 0x00000000, {(int32_t)0x00002362, (int32_t)0x00013B0D, (int32_t)0x000069A4}, 1}, 148 {"/validatedemos/TEST076.DEM", (int32_t)0x0000368A, 0x99FF70C3, 0x00000094, {(int32_t)0x00005624, (int32_t)0xFFFFD547, (int32_t)0x000000CE}, 1}, 149 {"/validatedemos/TEST077.DEM", (int32_t)0x00000837, 0x731125E0, 0x00000536, {(int32_t)0xFFFF8914, (int32_t)0xFFFF7F20, (int32_t)0x00002AEA}, 1}, 150 {"/validatedemos/TEST078.DEM", (int32_t)0x000004BB, 0x40CD5E4D, 0x00000640, {(int32_t)0x0001FCBB, (int32_t)0x0000412E, (int32_t)0x0004BAB4}, 1}, 151 {"/validatedemos/TEST079.DEM", (int32_t)0x000019E3, 0x4B34312A, 0x00000000, {(int32_t)0x000144F5, (int32_t)0x000143BE, (int32_t)0x00006DA4}, 1}, 152 {"/validatedemos/TEST080.DEM", (int32_t)0x00001169, 0xF488E48C, 0x00000000, {(int32_t)0x00008898, (int32_t)0xFFFF5BCD, (int32_t)0x00005DA4}, 1}, 153 {"/validatedemos/TEST081.DEM", (int32_t)0x00000864, 0xC181DEFE, 0x00000442, {(int32_t)0x00007927, (int32_t)0x00009CD7, (int32_t)0x00013D50}, 1}, 154 {"/validatedemos/TEST082.DEM", (int32_t)0x0000147B, 0x52769222, 0x000005EC, {(int32_t)0x00009BC9, (int32_t)0x00006EF9, (int32_t)0x00003550}, 1}, 155 {"/validatedemos/TEST083.DEM", (int32_t)0x00005D8D, 0xB9847039, 0x00000000, {(int32_t)0xFFFFC05A, (int32_t)0x0000AADA, (int32_t)0x000035A4}, 1}, 156 {"/validatedemos/TEST084.DEM", (int32_t)0x00004328, 0x74A65BA3, 0x0000009E, {(int32_t)0x000089F0, (int32_t)0xFFFF861C, (int32_t)0xFFFFF950}, 1}, 157 {"/validatedemos/TEST085.DEM", (int32_t)0x0000561D, 0x759EAFB7, 0x00000A6E, {(int32_t)0xFFFFF591, (int32_t)0x000059D9, (int32_t)0x00001DE4}, 1}, 158 {"/validatedemos/TEST086.DEM", (int32_t)0x00002820, 0x3701B79E, 0x00000000, {(int32_t)0x000018C5, (int32_t)0xFFFFC8C1, (int32_t)0x000019A4}, 0}, 159 {"/validatedemos/TEST087.DEM", (int32_t)0x000068CF, 0x0112953A, 0x00000640, {(int32_t)0x00000913, (int32_t)0x00005B0A, (int32_t)0x0001C150}, 0}, 160 {"/validatedemos/TEST088.DEM", (int32_t)0x000023DF, 0x4F0E5AB3, 0x00000000, {(int32_t)0xFFFF99A5, (int32_t)0xFFFFE2E1, (int32_t)0x000021A4}, 0}, 161 {"/validatedemos/TEST089.DEM", (int32_t)0x00005437, 0x5DEE1B13, 0x00000405, {(int32_t)0xFFFF65C1, (int32_t)0xFFFFA4A3, (int32_t)0xFFFEF550}, 1}, 162 {"/validatedemos/TEST090.DEM", (int32_t)0x0000258B, 0xFD21283F, 0x00000AF9, {(int32_t)0x0000A0C1, (int32_t)0x0000A10A, (int32_t)0x00020DE4}, 1}, 163 {"/validatedemos/TEST091.DEM", (int32_t)0x000034C5, 0x8893658D, 0x00000958, {(int32_t)0x0000AB42, (int32_t)0x00001360, (int32_t)0xFFFFFD50}, 1}, 164 {"/validatedemos/TEST092.DEM", (int32_t)0x00000D99, 0xF75E793F, 0x00000000, {(int32_t)0x00003C9D, (int32_t)0x0000D7BB, (int32_t)0xFFFF99A4}, 1}, 165 {"/validatedemos/TEST093.DEM", (int32_t)0x000075C7, 0xB1752688, 0x00000640, {(int32_t)0x00006693, (int32_t)0xFFFF226B, (int32_t)0xFFFD79E4}, 1}, 166 {"/validatedemos/TEST094.DEM", (int32_t)0x00005264, 0x119CF6D1, 0x00000000, {(int32_t)0x0000AE5B, (int32_t)0x00005036, (int32_t)0x000025A4}, 1}, 167 {"/validatedemos/TEST095.DEM", (int32_t)0x00002C7D, 0x6E7B8D97, 0x00000000, {(int32_t)0xFFFFEF48, (int32_t)0xFFFF9643, (int32_t)0x000099A4}, 1}, 168 {"/validatedemos/TEST096.DEM", (int32_t)0x00003647, 0xC2DE5F9B, 0x00000000, {(int32_t)0xFFFFF402, (int32_t)0x00000096, (int32_t)0x000389A4}, 1}, 169 {"/validatedemos/TEST097.DEM", (int32_t)0x00003902, 0x04ADDBE5, 0x00000000, {(int32_t)0x00014C09, (int32_t)0x00011CC1, (int32_t)0x000005A4}, 1}, // this demo crashes DOS v1.21 (ERROR (1344) src\ai.cpp) 170 {"/validatedemos/TEST098.DEM", (int32_t)0x00003061, 0xB813201F, 0x0000043C, {(int32_t)0x0000957B, (int32_t)0x0001362C, (int32_t)0xFFFFE9E4}, 1}, 171 {"/validatedemos/TEST099.DEM", (int32_t)0x00000D8E, 0xCC24C186, 0x00000000, {(int32_t)0x0000143E, (int32_t)0x0000F753, (int32_t)0x0001F5A4}, 1}, 172 {"/validatedemos/TEST100.DEM", (int32_t)0x000050EE, 0x4A970C28, 0x00000128, {(int32_t)0x00001872, (int32_t)0x0000B208, (int32_t)0xFFFF0D50}, 1}, 173 {"/validatedemos/TEST101.DEM", (int32_t)0x00000DF2, 0x6059C7F7, 0x000004A4, {(int32_t)0x000017EB, (int32_t)0x000035CA, (int32_t)0xFFFFF1E4}, 1}, 174 {"/validatedemos/TEST102.DEM", (int32_t)0x000018C9, 0x972B0857, 0x00000053, {(int32_t)0x000016CF, (int32_t)0x00003540, (int32_t)0xFFFFF150}, 1}, 175 {"/validatedemos/TEST103.DEM", (int32_t)0x000005D9, 0x79F3760B, 0x00000000, {(int32_t)0x00001B3F, (int32_t)0xFFFFAC41, (int32_t)0x000041A4}, 0}, 176 {"/validatedemos/TEST104.DEM", (int32_t)0x00000ED3, 0xC1E67725, 0x00000000, {(int32_t)0x000029C1, (int32_t)0x000054BD, (int32_t)0x000069A4}, 0}, 177 {"/validatedemos/TEST105.DEM", (int32_t)0x000007A2, 0x48007932, 0x00000000, {(int32_t)0x0000267F, (int32_t)0xFFFFFC17, (int32_t)0x000041A4}, 0}, 178 {"/validatedemos/TEST106.DEM", (int32_t)0x000008E5, 0x195F6658, 0x00000000, {(int32_t)0x0000113F, (int32_t)0x000034C1, (int32_t)0x000019A4}, 0}, 179 {"/validatedemos/TEST107.DEM", (int32_t)0x000017D4, 0x5C2E2774, 0x00000000, {(int32_t)0x0000180D, (int32_t)0x000021C1, (int32_t)0xFFFFD9A4}, 0}, 180 {"/validatedemos/TEST108.DEM", (int32_t)0x000045C3, 0x79AE9FDD, 0x0000029D, {(int32_t)0x000011AD, (int32_t)0xFFFFB247, (int32_t)0x00002550}, 0}, 181 {"/validatedemos/TEST109.DEM", (int32_t)0x000038B4, 0x2197456B, 0x00000000, {(int32_t)0x0000196A, (int32_t)0xFFFF5C13, (int32_t)0xFFFFF9A4}, 1}, 182 {"/validatedemos/TEST110.DEM", (int32_t)0x00004ACC, 0xB2E036DC, 0x00000000, {(int32_t)0x000102C5, (int32_t)0x00004CC3, (int32_t)0x000031A4}, 1}, 183 {"/validatedemos/TEST111.DEM", (int32_t)0x000018A1, 0x7E4E907C, 0x00000000, {(int32_t)0x0000BDC1, (int32_t)0x0000583F, (int32_t)0x000019A4}, 1}, 184 {"/validatedemos/TEST112.DEM", (int32_t)0x00003F4C, 0x50D29210, 0x00000000, {(int32_t)0x0000F6A1, (int32_t)0xFFFED26B, (int32_t)0x00024DA4}, 1}, 185 {"/validatedemos/TEST113.DEM", (int32_t)0x000025DC, 0xCD2519A0, 0x0000001F, {(int32_t)0xFFFFFA41, (int32_t)0xFFFFD353, (int32_t)0x0000FD50}, 0}, 186 {"/validatedemos/TEST114.DEM", (int32_t)0x00001664, 0x62DBFA86, 0x00000000, {(int32_t)0x0000787B, (int32_t)0xFFFFDB53, (int32_t)0x000019A4}, 1}, 187 {"/validatedemos/TEST115.DEM", (int32_t)0x00001B5E, 0xB8CFF3D2, 0x00000000, {(int32_t)0xFFFF37FF, (int32_t)0xFFFFDB3F, (int32_t)0x0000E9A4}, 1}, 188 {"/validatedemos/TEST116.DEM", (int32_t)0x0000638C, 0xBB29CB40, 0x00000405, {(int32_t)0xFFFF7632, (int32_t)0x000053F7, (int32_t)0xFFFF8D50}, 1}, 189 {"/validatedemos/TEST117.DEM", (int32_t)0x00001549, 0xABD36DE5, 0x00000640, {(int32_t)0x00009ACB, (int32_t)0x00006CC1, (int32_t)0x00003550}, 1}, // this demo crashes DOS v1.21 (ERROR (3339) src\actor.cpp Bad Dude Failed: initial=0 type=0 NORMAL) 190 {"/validatedemos/TEST118.DEM", (int32_t)0x00001B56, 0xF88C22B7, 0x00000640, {(int32_t)0x00009C57, (int32_t)0x00006F1B, (int32_t)0x00003550}, 1}, 191 {"/validatedemos/TEST119.DEM", (int32_t)0x00000E93, 0x499EF35B, 0x00000000, {(int32_t)0x00009AD5, (int32_t)0x000096BC, (int32_t)0x000159A4}, 1}, 192 {"/validatedemos/TEST120.DEM", (int32_t)0x000022A5, 0xC323F11D, 0x00000000, {(int32_t)0xFFFFAF9D, (int32_t)0xFFFF93D4, (int32_t)0x000009A4}, 1}, 193 {"/validatedemos/TEST121.DEM", (int32_t)0x0000349D, 0x2A8C0171, 0x00000000, {(int32_t)0xFFFFC62C, (int32_t)0xFFFFA38D, (int32_t)0x000009A4}, 1}, 194 {"/validatedemos/TEST122.DEM", (int32_t)0x00001205, 0xFBAFA0C9, 0x00000000, {(int32_t)0x0000399A, (int32_t)0x0000033F, (int32_t)0x0000B9A4}, 1}, 195 {"/validatedemos/TEST123.DEM", (int32_t)0x00002672, 0x5660A5AA, 0x00000AF6, {(int32_t)0xFFFFFAD0, (int32_t)0xFFFFD48D, (int32_t)0x0000FDE4}, 1}, 196 {"/validatedemos/TEST124.DEM", (int32_t)0x000015A5, 0xFC3CC30B, 0x00000000, {(int32_t)0xFFFF9DE6, (int32_t)0xFFFF907D, (int32_t)0x000009A4}, 1}, 197 {"/validatedemos/TEST125.DEM", (int32_t)0x000009AB, 0x68DB200E, 0x00000000, {(int32_t)0xFFFFF93C, (int32_t)0x00006C0C, (int32_t)0xFFFEFDA4}, 1}, 198 {"/validatedemos/TEST126.DEM", (int32_t)0x000008F7, 0xC60781A6, 0x00000000, {(int32_t)0x000026A0, (int32_t)0x00004087, (int32_t)0xFFFFC9A4}, 0}, 199 {"/validatedemos/TEST127.DEM", (int32_t)0x00001BD3, 0xA53BC5B3, 0x00000C21, {(int32_t)0x000017E7, (int32_t)0x000036A7, (int32_t)0xFFFFF1E4}, 0}, 200 {"/validatedemos/TEST128.DEM", (int32_t)0x000022CE, 0x1F4DC465, 0x00000640, {(int32_t)0x000016D6, (int32_t)0x00003526, (int32_t)0xFFFFF1E4}, 0}, 201 {"/validatedemos/TEST129.DEM", (int32_t)0x00000B4C, 0x4A2A6308, 0x00000000, {(int32_t)0x0000393F, (int32_t)0x00005E42, (int32_t)0x000051A4}, 0}, 202 {"/validatedemos/TEST130.DEM", (int32_t)0x00002B93, 0xF4B28CC5, 0x00000000, {(int32_t)0x000093EF, (int32_t)0x00001244, (int32_t)0x000119A4}, 1}, 203 {"/validatedemos/TEST131.DEM", (int32_t)0x0000633B, 0x169354F2, 0x0000048F, {(int32_t)0x0000BDC6, (int32_t)0x00005363, (int32_t)0x000009E4}, 1}, 204 {"/validatedemos/TEST132.DEM", (int32_t)0x000044A2, 0x9AB1E4C7, 0x00000640, {(int32_t)0xFFFFB6EA, (int32_t)0xFFFF87BA, (int32_t)0x00005D50}, 1}, 205 {"/validatedemos/TEST133.DEM", (int32_t)0x00001075, 0x090AEA76, 0x00000000, {(int32_t)0xFFFF327B, (int32_t)0x00009CEB, (int32_t)0x00003EE4}, 1}, 206 {"/validatedemos/TEST134.DEM", (int32_t)0x000008E1, 0xB172DEB5, 0x00000000, {(int32_t)0x00000482, (int32_t)0x000078C1, (int32_t)0xFFFF39A4}, 1}, 207 {"/validatedemos/TEST135.DEM", (int32_t)0x00002B13, 0xED1F723F, 0x000002FF, {(int32_t)0x0000A241, (int32_t)0x0000A067, (int32_t)0x00020D50}, 1}, 208 {"/validatedemos/TEST136.DEM", (int32_t)0x00003419, 0x5BD6E490, 0x00000B1B, {(int32_t)0x0000A245, (int32_t)0x00009F55, (int32_t)0x00020DE4}, 1}, 209 {"/validatedemos/TEST137.DEM", (int32_t)0x00004077, 0x9C07094D, 0x00000330, {(int32_t)0x00005CCD, (int32_t)0x00009154, (int32_t)0x00003D50}, 1}, 210 {"/validatedemos/TEST138.DEM", (int32_t)0x00002C1A, 0x0E08B278, 0x000006AC, {(int32_t)0x00005DBF, (int32_t)0x000092B4, (int32_t)0x00003D50}, 0}, 211 {"/validatedemos/TEST139.DEM", (int32_t)0x000005EE, 0x1E12503F, 0x00000000, {(int32_t)0xFFFFFE24, (int32_t)0xFFFFDB4E, (int32_t)0xFFFFF9A4}, 1}, 212 {"/validatedemos/TEST140.DEM", (int32_t)0x0000AFAA, 0x49A8C956, 0x00000479, {(int32_t)0xFFFFB6DD, (int32_t)0xFFFF8798, (int32_t)0x00005D50}, 1}, 213 {"/validatedemos/TEST141.DEM", (int32_t)0x00003B15, 0xBBFDA9CB, 0x00000B15, {(int32_t)0x00001A89, (int32_t)0x00001EE2, (int32_t)0x00002550}, 1}, 214 {"/validatedemos/TEST142.DEM", (int32_t)0x0000452E, 0x0980D36B, 0x000008DB, {(int32_t)0x0000273F, (int32_t)0x00004E87, (int32_t)0xFFFFFD50}, 1}, 215 {"/validatedemos/TEST143.DEM", (int32_t)0x000020B1, 0x23CF6A95, 0x00000000, {(int32_t)0x00001C53, (int32_t)0x00004932, (int32_t)0x000019A4}, 1}, 216 }; 217 218 int nBuild = 0; 219 220 void ReadGameOptionsLegacy(GAMEOPTIONS &gameOptions, GAMEOPTIONSLEGACY &gameOptionsLegacy) 221 { 222 gameOptions.nGameType = gameOptionsLegacy.nGameType; 223 gameOptions.nDifficulty = gameOptionsLegacy.nDifficulty; 224 gameOptions.nEpisode = gameOptionsLegacy.nEpisode; 225 gameOptions.nLevel = gameOptionsLegacy.nLevel; 226 strcpy(gameOptions.zLevelName, gameOptionsLegacy.zLevelName); 227 strcpy(gameOptions.zLevelSong, gameOptionsLegacy.zLevelSong); 228 gameOptions.nTrackNumber = gameOptionsLegacy.nTrackNumber; 229 //strcpy(gameOptions.szSaveGameName, gameOptionsLegacy.szSaveGameName); 230 //strcpy(gameOptions.szUserGameName, gameOptionsLegacy.szUserGameName); 231 gameOptions.nSaveGameSlot = gameOptionsLegacy.nSaveGameSlot; 232 gameOptions.picEntry = gameOptionsLegacy.picEntry; 233 gameOptions.uMapCRC = gameOptionsLegacy.uMapCRC; 234 gameOptions.nMonsterSettings = gameOptionsLegacy.nMonsterSettings; 235 gameOptions.uGameFlags = gameOptionsLegacy.uGameFlags; 236 gameOptions.uNetGameFlags = gameOptionsLegacy.uNetGameFlags; 237 gameOptions.nWeaponSettings = gameOptionsLegacy.nWeaponSettings; 238 gameOptions.nItemSettings = gameOptionsLegacy.nItemSettings; 239 gameOptions.nRespawnSettings = gameOptionsLegacy.nRespawnSettings; 240 gameOptions.nTeamSettings = gameOptionsLegacy.nTeamSettings; 241 gameOptions.nMonsterRespawnTime = gameOptionsLegacy.nMonsterRespawnTime; 242 gameOptions.nWeaponRespawnTime = gameOptionsLegacy.nWeaponRespawnTime; 243 gameOptions.nItemRespawnTime = gameOptionsLegacy.nItemRespawnTime; 244 gameOptions.nSpecialRespawnTime = gameOptionsLegacy.nSpecialRespawnTime; 245 gameOptions.nEnemyQuantity = gameOptions.nDifficulty; 246 gameOptions.nEnemyHealth = gameOptions.nDifficulty; 247 gameOptions.nEnemySpeed = 0; 248 gameOptions.nPlayerSpeed = 0; 249 gameOptions.bEnemyShuffle = false; 250 gameOptions.bPitchforkOnly = false; 251 gameOptions.bPermaDeath = false; 252 gameOptions.bFriendlyFire = true; 253 gameOptions.nKeySettings = 0; 254 gameOptions.bItemWeaponSettings = 0; 255 gameOptions.bAutoTeams = 1; 256 gameOptions.nSpawnProtection = 0; 257 gameOptions.nSpawnWeapon = 0; 258 gameOptions.uSpriteBannedFlags = BANNED_NONE; 259 } 260 261 void WriteGameOptionsLegacy(GAMEOPTIONSLEGACY &gameOptionsLegacy, GAMEOPTIONS &gameOptions) 262 { 263 gameOptionsLegacy.nGameType = gameOptions.nGameType; 264 gameOptionsLegacy.nDifficulty = gameOptions.nDifficulty; 265 gameOptionsLegacy.nEpisode = gameOptions.nEpisode; 266 gameOptionsLegacy.nLevel = gameOptions.nLevel; 267 memset(gameOptionsLegacy.zLevelName, '\0', sizeof(gameOptionsLegacy.zLevelName)); 268 memset(gameOptionsLegacy.zLevelSong, '\0', sizeof(gameOptionsLegacy.zLevelSong)); 269 strncpy(gameOptionsLegacy.zLevelName, gameOptions.zLevelName, sizeof(gameOptionsLegacy.zLevelName)); 270 strncpy(gameOptionsLegacy.zLevelSong, gameOptions.zLevelSong, sizeof(gameOptionsLegacy.zLevelSong)); 271 gameOptionsLegacy.nTrackNumber = gameOptions.nTrackNumber; 272 memset(gameOptionsLegacy.szSaveGameName, '\0', sizeof(gameOptionsLegacy.szSaveGameName)); 273 memset(gameOptionsLegacy.szUserGameName, '\0', sizeof(gameOptionsLegacy.szUserGameName)); 274 gameOptionsLegacy.nSaveGameSlot = gameOptionsLegacy.nSaveGameSlot; 275 gameOptionsLegacy.picEntry = gameOptionsLegacy.picEntry; 276 gameOptionsLegacy.uMapCRC = gameOptionsLegacy.uMapCRC; 277 gameOptionsLegacy.nMonsterSettings = gameOptions.nMonsterSettings; 278 gameOptionsLegacy.uGameFlags = gameOptions.uGameFlags; 279 gameOptionsLegacy.uNetGameFlags = gameOptions.uNetGameFlags; 280 gameOptionsLegacy.nWeaponSettings = gameOptions.nWeaponSettings; 281 gameOptionsLegacy.nItemSettings = gameOptions.nItemSettings; 282 gameOptionsLegacy.nRespawnSettings = gameOptions.nRespawnSettings; 283 gameOptionsLegacy.nTeamSettings = gameOptions.nTeamSettings; 284 gameOptionsLegacy.nMonsterRespawnTime = gameOptions.nMonsterRespawnTime; 285 gameOptionsLegacy.nWeaponRespawnTime = gameOptions.nWeaponRespawnTime; 286 gameOptionsLegacy.nItemRespawnTime = gameOptions.nItemRespawnTime; 287 gameOptionsLegacy.nSpecialRespawnTime = gameOptions.nSpecialRespawnTime; 288 } 289 290 CDemo gDemo; 291 292 CDemo::CDemo() 293 { 294 nBuild = 4; 295 bRecording = 0; 296 bPlaying = 0; 297 at3 = 0; 298 hPFile = -1; 299 hRFile = NULL; 300 nInputTicks = 0; 301 pFirstDemo = NULL; 302 pCurrentDemo = NULL; 303 nDemosFound = 0; 304 at2 = 0; 305 memset(&atf, 0, sizeof(atf)); 306 } 307 308 CDemo::~CDemo() 309 { 310 bRecording = 0; 311 bPlaying = 0; 312 at3 = 0; 313 nInputTicks = 0; 314 memset(&atf, 0, sizeof(atf)); 315 if (hPFile >= 0) 316 { 317 kclose(hPFile); 318 hPFile = -1; 319 } 320 if (hRFile != NULL) 321 { 322 fclose(hRFile); 323 hRFile = NULL; 324 } 325 auto pNextDemo = pFirstDemo; 326 for (auto pDemo = pFirstDemo; pDemo != NULL; pDemo = pNextDemo) 327 { 328 pNextDemo = pDemo->pNext; 329 delete pDemo; 330 } 331 pFirstDemo = NULL; 332 pCurrentDemo = NULL; 333 nDemosFound = 0; 334 } 335 336 bool CDemo::Create(const char *pzFile) 337 { 338 char buffer[BMAX_PATH]; 339 char vc = 0; 340 if (bRecording || bPlaying) 341 ThrowError("CDemo::Create called during demo record/playback process."); 342 if (!pzFile) 343 { 344 for (int i = 0; i < 8 && !vc; i++) 345 { 346 if (G_ModDirSnprintf(buffer, BMAX_PATH, "%s0%02d.dem", BloodIniPre, i)) 347 return false; 348 if (access(buffer, F_OK) != -1) 349 vc = 1; 350 } 351 if (vc == 1) 352 { 353 hRFile = fopen(buffer, "wb"); 354 if (hRFile == NULL) 355 return false; 356 } 357 } 358 else 359 { 360 G_ModDirSnprintfLite(buffer, BMAX_PATH, pzFile); 361 hRFile = fopen(buffer, "wb"); 362 if (hRFile == NULL) 363 return false; 364 } 365 bRecording = 1; 366 nInputTicks = 0; 367 return true; 368 } 369 370 void CDemo::Write(GINPUT *pPlayerInputs) 371 { 372 dassert(pPlayerInputs != NULL); 373 if (!bRecording) 374 return; 375 if (nInputTicks == 0) 376 { 377 atf.signature = 0x1a4d4544; // '\x1aMED'; 378 atf.nVersion = BloodVersion; 379 atf.nBuild = nBuild; 380 atf.nInputCount = 0; 381 atf.nNetPlayers = gNetPlayers; 382 atf.nMyConnectIndex = myconnectindex; 383 atf.nConnectHead = connecthead; 384 memcpy(atf.connectPoints, connectpoint2, sizeof(atf.connectPoints)); 385 GAMEOPTIONSLEGACY gameOptions; 386 memset(&gameOptions, 0, sizeof(gameOptions)); 387 WriteGameOptionsLegacy(gameOptions, gGameOptions); 388 #if B_BIG_ENDIAN == 1 389 atf.signature = B_LITTLE32(atf.signature); 390 atf.nVersion = B_LITTLE16(atf.nVersion); 391 atf.nBuild = B_LITTLE32(atf.nBuild); 392 atf.nInputCount = B_LITTLE32(atf.nInputCount); 393 atf.nNetPlayers = B_LITTLE32(atf.nNetPlayers); 394 atf.nMyConnectIndex = B_LITTLE16(atf.nMyConnectIndex); 395 atf.nConnectHead = B_LITTLE16(atf.nConnectHead); 396 for (int i = 0; i < 8; i++) 397 atf.connectPoints[i] = B_LITTLE16(atf.connectPoints[i]); 398 #endif 399 fwrite(&atf, sizeof(DEMOHEADER), 1, hRFile); 400 #if B_BIG_ENDIAN == 1 401 gameOptions.nEpisode = B_LITTLE32(gameOptions.nEpisode); 402 gameOptions.nLevel = B_LITTLE32(gameOptions.nLevel); 403 gameOptions.nTrackNumber = B_LITTLE32(gameOptions.nTrackNumber); 404 gameOptions.nSaveGameSlot = B_LITTLE16(gameOptions.nSaveGameSlot); 405 gameOptions.picEntry = B_LITTLE32(gameOptions.picEntry); 406 gameOptions.uMapCRC = B_LITTLE32(gameOptions.uMapCRC); 407 gameOptions.uGameFlags = B_LITTLE32(gameOptions.uGameFlags); 408 gameOptions.uNetGameFlags = B_LITTLE32(gameOptions.uNetGameFlags); 409 gameOptions.nMonsterRespawnTime = B_LITTLE32(gameOptions.nMonsterRespawnTime); 410 gameOptions.nWeaponRespawnTime = B_LITTLE32(gameOptions.nWeaponRespawnTime); 411 gameOptions.nItemRespawnTime = B_LITTLE32(gameOptions.nItemRespawnTime); 412 gameOptions.nSpecialRespawnTime = B_LITTLE32(gameOptions.nSpecialRespawnTime); 413 #endif 414 fwrite(&gameOptions, sizeof(GAMEOPTIONSLEGACY), 1, hRFile); 415 } 416 for (int p = connecthead; p >= 0; p = connectpoint2[p]) 417 { 418 memcpy(&at1aa[nInputTicks&1023], &pPlayerInputs[p], sizeof(GINPUT)); 419 nInputTicks++; 420 if ((nInputTicks&(kInputBufferSize-1))==0) 421 FlushInput(kInputBufferSize); 422 } 423 } 424 425 void CDemo::Close(void) 426 { 427 if (bRecording) 428 { 429 if (nInputTicks&(kInputBufferSize-1)) 430 FlushInput(nInputTicks&(kInputBufferSize-1)); 431 atf.nInputCount = nInputTicks; 432 #if B_BIG_ENDIAN == 1 433 atf.nInputCount = B_LITTLE32(atf.nInputCount); 434 #endif 435 fseek(hRFile, 0, SEEK_SET); 436 fwrite(&atf, sizeof(DEMOHEADER), 1, hRFile); 437 } 438 if (hPFile >= 0) 439 { 440 kclose(hPFile); 441 hPFile = -1; 442 } 443 if (hRFile != NULL) 444 { 445 fclose(hRFile); 446 hRFile = NULL; 447 } 448 bRecording = 0; 449 bPlaying = 0; 450 } 451 452 bool CDemo::SetupPlayback(const char *pzFile) 453 { 454 bRecording = 0; 455 bPlaying = 0; 456 if (pzFile) 457 { 458 hPFile = kopen4loadfrommod(pzFile, 0); 459 if (hPFile == -1) 460 return false; 461 } 462 else 463 { 464 if (!pCurrentDemo) 465 return false; 466 hPFile = kopen4loadfrommod(pCurrentDemo->zName, 0); 467 if (hPFile == -1) 468 return false; 469 } 470 kread(hPFile, &atf, sizeof(DEMOHEADER)); 471 #if B_BIG_ENDIAN == 1 472 atf.signature = B_LITTLE32(atf.signature); 473 atf.nVersion = B_LITTLE16(atf.nVersion); 474 atf.nBuild = B_LITTLE32(atf.nBuild); 475 atf.nInputCount = B_LITTLE32(atf.nInputCount); 476 atf.nNetPlayers = B_LITTLE32(atf.nNetPlayers); 477 atf.nMyConnectIndex = B_LITTLE16(atf.nMyConnectIndex); 478 atf.nConnectHead = B_LITTLE16(atf.nConnectHead); 479 for (int i = 0; i < 8; i++) 480 atf.connectPoints[i] = B_LITTLE16(atf.connectPoints[i]); 481 #endif 482 if (atf.signature != 0x1a4d4544) 483 return 0; 484 if (BloodVersion != atf.nVersion) 485 return 0; 486 m_gameOptions = gGameOptions; 487 GAMEOPTIONSLEGACY gameOptions; 488 kread(hPFile, &gameOptions, sizeof(GAMEOPTIONSLEGACY)); 489 ReadGameOptionsLegacy(m_gameOptions, gameOptions); 490 #if B_BIG_ENDIAN == 1 491 m_gameOptions.nEpisode = B_LITTLE32(m_gameOptions.nEpisode); 492 m_gameOptions.nLevel = B_LITTLE32(m_gameOptions.nLevel); 493 m_gameOptions.nTrackNumber = B_LITTLE32(m_gameOptions.nTrackNumber); 494 m_gameOptions.nSaveGameSlot = B_LITTLE16(m_gameOptions.nSaveGameSlot); 495 m_gameOptions.picEntry = B_LITTLE32(m_gameOptions.picEntry); 496 m_gameOptions.uMapCRC = B_LITTLE32(m_gameOptions.uMapCRC); 497 m_gameOptions.uGameFlags = B_LITTLE32(m_gameOptions.uGameFlags); 498 m_gameOptions.uNetGameFlags = B_LITTLE32(m_gameOptions.uNetGameFlags); 499 m_gameOptions.nMonsterRespawnTime = B_LITTLE32(m_gameOptions.nMonsterRespawnTime); 500 m_gameOptions.nWeaponRespawnTime = B_LITTLE32(m_gameOptions.nWeaponRespawnTime); 501 m_gameOptions.nItemRespawnTime = B_LITTLE32(m_gameOptions.nItemRespawnTime); 502 m_gameOptions.nSpecialRespawnTime = B_LITTLE32(m_gameOptions.nSpecialRespawnTime); 503 #endif 504 bRecording = 0; 505 bPlaying = 1; 506 if (gDemoRunValidation) 507 { 508 timerInit(CLOCKTICKSPERSECOND*500); 509 SoundToggle = MusicToggle = 0; // mute audio while we speedrun demos 510 } 511 return 1; 512 } 513 514 void CDemo::ProcessKeys(void) 515 { 516 switch (gInputMode) 517 { 518 case INPUT_MODE_1: 519 gGameMenuMgr.Process(); 520 break; 521 case INPUT_MODE_2: 522 gPlayerMsg.ProcessKeys(); 523 break; 524 case INPUT_MODE_0: 525 { 526 char nKey; 527 while ((nKey = keyGetScan()) != 0) 528 { 529 char UNUSED(alt) = keystatus[sc_LeftAlt] | keystatus[sc_RightAlt]; 530 char UNUSED(ctrl) = keystatus[sc_LeftControl] | keystatus[sc_RightControl]; 531 switch (nKey) 532 { 533 case sc_Escape: 534 if (!CGameMenuMgr::m_bActive) 535 { 536 gGameMenuMgr.Push(&menuMain, -1); 537 at2 = 1; 538 } 539 break; 540 case sc_F12: 541 gViewIndex = connectpoint2[gViewIndex]; 542 if (gViewIndex == -1) 543 gViewIndex = connecthead; 544 gView = &gPlayer[gViewIndex]; 545 break; 546 } 547 } 548 if (!nKey && CONTROL_JoystickEnabled) 549 { 550 static int32_t joyold = 0; 551 int32_t joy = JOYSTICK_GetControllerButtons() == (1 << CONTROLLER_BUTTON_START); 552 if (joy && !joyold) 553 { 554 JOYSTICK_ClearAllButtons(); 555 if (!CGameMenuMgr::m_bActive) 556 { 557 gGameMenuMgr.Push(&menuMain, -1); 558 at2 = 1; 559 } 560 } 561 joyold = joy; 562 } 563 break; 564 default: 565 gInputMode = INPUT_MODE_0; 566 break; 567 } 568 } 569 } 570 571 void CDemo::Playback(void) 572 { 573 const DEMOVALIDATE *pValidateInfo; 574 CONTROL_BindsEnabled = false; 575 ready2send = 0; 576 int v4 = 0; 577 if (!CGameMenuMgr::m_bActive) 578 { 579 gGameMenuMgr.Push(&menuMain, -1); 580 if (gSetup.firstlaunch) 581 gGameMenuMgr.Push(&menuFirstLaunch, -1); 582 at2 = 1; 583 } 584 gNetFifoClock = totalclock; 585 gViewMode = 3; 586 _DEMOPLAYBACK: 587 pValidateInfo = NULL; 588 while (bPlaying && !gQuitGame) 589 { 590 while (totalclock >= gNetFifoClock && !gQuitGame) 591 { 592 if (!v4) 593 { 594 viewResizeView(gViewSize); 595 viewSetMessage(""); 596 gNetPlayers = atf.nNetPlayers; 597 nInputTicks = atf.nInputCount; 598 myconnectindex = atf.nMyConnectIndex; 599 connecthead = atf.nConnectHead; 600 for (int i = 0; i < 8; i++) 601 connectpoint2[i] = atf.connectPoints[i]; 602 memset(gNetFifoHead, 0, sizeof(gNetFifoHead)); 603 gNetFifoTail = 0; 604 //memcpy(connectpoint2, aimHeight.connectPoints, sizeof(aimHeight.connectPoints)); 605 memcpy(&gGameOptions, &m_gameOptions, sizeof(GAMEOPTIONS)); 606 gGameOptions.uGameFlags &= ~kGameFlagContinuing; // don't let demo attempt to load player health from gHealthTemp 607 playerSetSkill(gGameOptions.nDifficulty); // set skill to same value as current difficulty 608 for (int i = 0; i < kMaxPlayers; i++) 609 playerInit(i, 0); 610 StartLevel(&gGameOptions); 611 for (int i = 0; i < kMaxPlayers; i++) // force player settings for demos 612 { 613 gProfile[i].nAutoAim = 1; 614 gProfile[i].nWeaponSwitch = 1; 615 gProfile[i].bWeaponFastSwitch = 0; 616 gProfile[i].nWeaponHBobbing = 1; 617 gProfileNet[i] = gProfile[i]; 618 } 619 if (gDemoRunValidation) // if we're executing validation test 620 { 621 for (int index = 0; index < ARRAY_SSIZE(gDemoValidate); index++) // search for current demo in list of known valid results 622 { 623 if (nInputTicks != gDemoValidate[index].nInputTicks) // demo ticks not matching/demo name does not exist, skip 624 continue; 625 if (!pCurrentDemo || Bstrcasecmp(pCurrentDemo->zName, gDemoValidate[index].zName)) // demo name does not match, skip 626 continue; 627 pValidateInfo = &gDemoValidate[index]; // found demo's verified results, set as validate info 628 gProfile[myconnectindex].nAutoAim = pValidateInfo->nAutoAim; // assign auto aim setting from validate info 629 break; 630 } 631 if (!pValidateInfo) // run newly added verify demos at a slower speed for visual verification 632 timerInit(CLOCKTICKSPERSECOND*5); 633 } 634 } 635 ready2send = 0; 636 OSD_DispatchQueued(); 637 if (!gDemo.bPlaying) 638 break; 639 ProcessKeys(); 640 for (int p = connecthead; p >= 0; p = connectpoint2[p]) 641 { 642 if ((v4&1023) == 0) 643 { 644 unsigned int nSize = nInputTicks-v4; 645 if (nSize > kInputBufferSize) 646 nSize = kInputBufferSize; 647 ReadInput(nSize); 648 } 649 memcpy(&gFifoInput[gNetFifoHead[p]&255], &at1aa[v4&1023], sizeof(GINPUT)); 650 gNetFifoHead[p]++; 651 v4++; 652 if (v4 >= atf.nInputCount) 653 { 654 ready2send = 0; 655 if (pValidateInfo) // if validate demo info are known, run checks 656 { 657 char bInvalid = 0; 658 if (wrandomseed != pValidateInfo->wrandomseed) 659 { 660 bInvalid = 1; 661 OSD_Printf("Error: Random seed desync\n"); 662 } 663 if (gPlayer[myconnectindex].pSprite->xyz != pValidateInfo->xyz) 664 { 665 bInvalid = 1; 666 OSD_Printf("Error: Player position desync\n"); 667 } 668 if (xsprite[gPlayer[myconnectindex].pSprite->extra].health != pValidateInfo->health) 669 { 670 bInvalid = 1; 671 OSD_Printf("Error: Player health desync\n"); 672 } 673 if (bInvalid) 674 { 675 OSD_Printf("Error: %s desync (see log for detail)\n", pCurrentDemo->zName); 676 ThrowError("Error: %s desync (see log for detail)", pCurrentDemo->zName); 677 gQuitGame = true; 678 } 679 else 680 { 681 OSD_Printf("Demo Synced\n"); 682 } 683 } 684 else if (gDemoRunValidation && pCurrentDemo) // print validation result for new demo 685 { 686 OSD_Printf("{\"%s\", (int32_t)0x%08X, 0x%08X, 0x%08X, {(int32_t)0x%08X, (int32_t)0x%08X, (int32_t)0x%08X}, %d},", pCurrentDemo->zName, nInputTicks, wrandomseed, (unsigned int)xsprite[gPlayer[myconnectindex].pSprite->extra].health, (unsigned int)gPlayer[myconnectindex].pSprite->x, (unsigned int)gPlayer[myconnectindex].pSprite->y, (unsigned int)gPlayer[myconnectindex].pSprite->z, gProfile[myconnectindex].nAutoAim); 687 } 688 if (nDemosFound > 1) 689 { 690 v4 = 0; 691 Close(); 692 if (gDemoRunValidation && pCurrentDemo && !pCurrentDemo->pNext) // finished validation, abort 693 { 694 uint32_t nTotalTicks = 0; 695 for (int index = 0; index < ARRAY_SSIZE(gDemoValidate); index++) 696 nTotalTicks += (uint32_t)gDemoValidate[index].nInputTicks; 697 OSD_Printf("1.21 Validation Successful!\nTotal Demo Hours: %02d:%02d", nTotalTicks/(kTicsPerSec*60)/60, nTotalTicks/(kTicsPerSec*60)%60); 698 gQuitGame = true; 699 break; 700 } 701 NextDemo(); 702 gNetFifoClock = totalclock; 703 goto _DEMOPLAYBACK; 704 } 705 else 706 { 707 int const nOffset = sizeof(DEMOHEADER)+sizeof(GAMEOPTIONSLEGACY); 708 klseek(hPFile, nOffset, SEEK_SET); 709 v4 = 0; 710 } 711 } 712 } 713 gNetFifoClock += kTicsPerFrame; 714 if (!gQuitGame) 715 ProcessFrame(); 716 ready2send = 0; 717 } 718 if (engineFPSLimit()) 719 { 720 if (handleevents() && quitevent) 721 { 722 KB_KeyDown[sc_Escape] = 1; 723 quitevent = 0; 724 } 725 if (!gDemoRunValidation) 726 MUSIC_Update(); 727 viewDrawScreen(); 728 if ((gInputMode == INPUT_MODE_1) && CGameMenuMgr::m_bActive && !gDemoRunValidation) 729 { 730 if (gGameStarted && gViewDim) // dim background 731 viewDimScreen(); 732 gGameMenuMgr.Draw(); 733 } 734 else if (gDemoRunValidation) // keep game locked 735 gInputMode = INPUT_MODE_1; 736 videoNextPage(); 737 } 738 if (TestBitString(gotpic, 2342)) 739 { 740 FireProcess(); 741 ClearBitString(gotpic, 2342); 742 } 743 } 744 Close(); 745 } 746 747 void CDemo::StopPlayback(void) 748 { 749 bPlaying = 0; 750 } 751 752 void CDemo::LoadDemoInfo(void) 753 { 754 auto pDemo = &pFirstDemo; 755 const int opsm = pathsearchmode; 756 nDemosFound = 0; 757 pathsearchmode = 0; 758 char zFN[BMAX_PATH]; 759 Bsnprintf(zFN, BMAX_PATH, "%s*.dem", BloodIniPre); 760 auto pList = klistpath(!gDemoRunValidation ? "/" : "/validatedemos/", zFN, BUILDVFS_FIND_FILE); 761 auto pIterator = pList; 762 while (pIterator != NULL) 763 { 764 int hFile; 765 if (gDemoRunValidation) 766 { 767 char bSkipBadDemo = 0; 768 for (size_t i = 0; i < ARRAY_SIZE(gDemoInvalid); i++) 769 { 770 if (!strcmp(pIterator->name, gDemoInvalid[i])) 771 { 772 bSkipBadDemo = 1; 773 break; 774 } 775 } 776 if (bSkipBadDemo) 777 { 778 pIterator = pIterator->next; 779 continue; 780 } 781 Bsnprintf(zFN, BMAX_PATH, "/validatedemos/%s", pIterator->name); 782 hFile = kopen4loadfrommod(zFN, 0); 783 } 784 else 785 { 786 hFile = kopen4loadfrommod(pIterator->name, 0); 787 } 788 if (hFile == -1) 789 ThrowError("Error loading demo file header."); 790 kread(hFile, &atf, sizeof(atf)); 791 kclose(hFile); 792 #if B_BIG_ENDIAN == 1 793 atf.signature = B_LITTLE32(atf.signature); 794 atf.nVersion = B_LITTLE16(atf.nVersion); 795 #endif 796 if ((atf.signature == 0x1a4d4544 /* '\x1aMED' */&& atf.nVersion == BloodVersion)) 797 { 798 *pDemo = new DEMOCHAIN; 799 (*pDemo)->pNext = NULL; 800 Bstrncpy((*pDemo)->zName, !gDemoRunValidation ? pIterator->name : zFN, BMAX_PATH); 801 nDemosFound++; 802 pDemo = &(*pDemo)->pNext; 803 } 804 pIterator = pIterator->next; 805 } 806 klistfree(pList); 807 pathsearchmode = opsm; 808 pCurrentDemo = pFirstDemo; 809 } 810 811 void CDemo::NextDemo(void) 812 { 813 pCurrentDemo = pCurrentDemo->pNext ? pCurrentDemo->pNext : pFirstDemo; 814 SetupPlayback(NULL); 815 } 816 817 #define kInputSize 22 818 static char pBuffer[kInputSize*kInputBufferSize]; 819 820 void CDemo::FlushInput(int nCount) 821 { 822 BitWriter bitWriter(pBuffer, sizeof(pBuffer)); 823 for (int i = 0; i < nCount; i++) 824 { 825 GINPUT *pInput = &at1aa[i]; 826 bitWriter.writeBit(pInput->syncFlags.buttonChange); 827 bitWriter.writeBit(pInput->syncFlags.keyChange); 828 bitWriter.writeBit(pInput->syncFlags.useChange); 829 bitWriter.writeBit(pInput->syncFlags.weaponChange); 830 bitWriter.writeBit(pInput->syncFlags.mlookChange); 831 bitWriter.writeBit(pInput->syncFlags.run); 832 bitWriter.skipBits(26); 833 bitWriter.write(pInput->forward>>8, 8); 834 bitWriter.write(fix16_to_int(pInput->q16turn<<2), 16); 835 bitWriter.write(pInput->strafe>>8, 8); 836 bitWriter.writeBit(pInput->buttonFlags.jump); 837 bitWriter.writeBit(pInput->buttonFlags.crouch); 838 bitWriter.writeBit(pInput->buttonFlags.shoot); 839 bitWriter.writeBit(pInput->buttonFlags.shoot2); 840 bitWriter.writeBit(pInput->buttonFlags.lookUp); 841 bitWriter.writeBit(pInput->buttonFlags.lookDown); 842 bitWriter.skipBits(26); 843 bitWriter.writeBit(pInput->keyFlags.action); 844 //bitWriter.writeBit(pInput->keyFlags.jab); // unused 845 bitWriter.skipBits(1); 846 bitWriter.writeBit(pInput->keyFlags.prevItem); 847 bitWriter.writeBit(pInput->keyFlags.nextItem); 848 bitWriter.writeBit(pInput->keyFlags.useItem); 849 bitWriter.writeBit(pInput->keyFlags.prevWeapon); 850 bitWriter.writeBit(pInput->keyFlags.nextWeapon); 851 bitWriter.writeBit(pInput->keyFlags.holsterWeapon); 852 bitWriter.writeBit(pInput->keyFlags.lookCenter); 853 bitWriter.writeBit(pInput->keyFlags.lookLeft); 854 bitWriter.writeBit(pInput->keyFlags.lookRight); 855 bitWriter.writeBit(pInput->keyFlags.spin180); 856 bitWriter.writeBit(pInput->keyFlags.pause); 857 bitWriter.writeBit(pInput->keyFlags.quit); 858 bitWriter.writeBit(pInput->keyFlags.restart); 859 bitWriter.skipBits(17); 860 bitWriter.writeBit(pInput->useFlags.useBeastVision); 861 bitWriter.writeBit(pInput->useFlags.useCrystalBall); 862 bitWriter.writeBit(pInput->useFlags.useJumpBoots); 863 bitWriter.writeBit(pInput->useFlags.useMedKit); 864 bitWriter.skipBits(28); 865 bitWriter.write(pInput->newWeapon, 8); 866 bitWriter.write(fix16_to_int(pInput->q16mlook*4), 8); 867 } 868 fwrite(pBuffer, 1, kInputSize*nCount, hRFile); 869 } 870 871 void CDemo::ReadInput(int nCount) 872 { 873 kread(hPFile, pBuffer, kInputSize*nCount); 874 BitReader bitReader(pBuffer, sizeof(pBuffer)); 875 memset(at1aa, 0, nCount * sizeof(GINPUT)); 876 for (int i = 0; i < nCount; i++) 877 { 878 GINPUT *pInput = &at1aa[i]; 879 pInput->syncFlags.buttonChange = bitReader.readBit(); 880 pInput->syncFlags.keyChange = bitReader.readBit(); 881 pInput->syncFlags.useChange = bitReader.readBit(); 882 pInput->syncFlags.weaponChange = bitReader.readBit(); 883 pInput->syncFlags.mlookChange = bitReader.readBit(); 884 pInput->syncFlags.run = bitReader.readBit(); 885 bitReader.skipBits(26); 886 pInput->forward = bitReader.readSigned(8) << 8; 887 pInput->q16turn = fix16_from_int(bitReader.readSigned(16)) >> 2; 888 pInput->strafe = bitReader.readSigned(8) << 8; 889 pInput->buttonFlags.jump = bitReader.readBit(); 890 pInput->buttonFlags.crouch = bitReader.readBit(); 891 pInput->buttonFlags.shoot = bitReader.readBit(); 892 pInput->buttonFlags.shoot2 = bitReader.readBit(); 893 pInput->buttonFlags.lookUp = bitReader.readBit(); 894 pInput->buttonFlags.lookDown = bitReader.readBit(); 895 bitReader.skipBits(26); 896 pInput->keyFlags.action = bitReader.readBit(); 897 //pInput->keyFlags.jab = bitReader.readBit(); // unused 898 pInput->keyFlags.isTyping = 0; 899 bitReader.skipBits(1); 900 pInput->keyFlags.prevItem = bitReader.readBit(); 901 pInput->keyFlags.nextItem = bitReader.readBit(); 902 pInput->keyFlags.useItem = bitReader.readBit(); 903 pInput->keyFlags.prevWeapon = bitReader.readBit(); 904 pInput->keyFlags.nextWeapon = bitReader.readBit(); 905 pInput->keyFlags.holsterWeapon = bitReader.readBit(); 906 pInput->keyFlags.lookCenter = bitReader.readBit(); 907 pInput->keyFlags.lookLeft = bitReader.readBit(); 908 pInput->keyFlags.lookRight = bitReader.readBit(); 909 pInput->keyFlags.spin180 = bitReader.readBit(); 910 pInput->keyFlags.pause = bitReader.readBit(); 911 pInput->keyFlags.quit = bitReader.readBit(); 912 pInput->keyFlags.restart = bitReader.readBit(); 913 pInput->keyFlags.lastWeapon = 0; 914 bitReader.skipBits(17); 915 pInput->useFlags.useBeastVision = bitReader.readBit(); 916 pInput->useFlags.useCrystalBall = bitReader.readBit(); 917 pInput->useFlags.useJumpBoots = bitReader.readBit(); 918 pInput->useFlags.useMedKit = bitReader.readBit(); 919 bitReader.skipBits(28); 920 pInput->newWeapon = bitReader.readUnsigned(8); 921 int mlook = bitReader.readSigned(8); 922 pInput->q16mlook = fix16_from_int(mlook / 4); 923 } 924 }