cstuff.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. /*
  2. * This file is part of XDRE.
  3. *
  4. * XDRE is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * XDRE is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with XDRE. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. * Этот файл — часть XDRE.
  18. *
  19. * XDRE — свободная программа: вы можете перераспространять её и/или
  20. * изменять её на условиях Стандартной общественной лицензии GNU в том виде,
  21. * в каком она была опубликована Фондом свободного программного обеспечения;
  22. * либо версии 2 лицензии, либо (по вашему выбору) любой более поздней
  23. * версии.
  24. *
  25. * XDRE распространяется в надежде, что она будет полезной,
  26. * но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
  27. * или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
  28. * общественной лицензии GNU.
  29. *
  30. * Вы должны были получить копию Стандартной общественной лицензии GNU
  31. * вместе с этой программой. Если это не так, см.
  32. * <http://www.gnu.org/licenses/>.
  33. *
  34. * Description: C stuff.
  35. */
  36. #include "cstuff.h"
  37. #include "doomtype.h"
  38. #include "doomstat.h"
  39. #include "m_random.h"
  40. #include "d_player.h"
  41. #include "g_game.h"
  42. #include "lprintf.h"
  43. #include "p_saveg.h"
  44. #include "p_map.h"
  45. #include "p_mobj.h"
  46. #include "r_demo.h"
  47. #include "r_draw.h"
  48. #include "r_fps.h"
  49. #include "r_main.h"
  50. #include "s_sound.h"
  51. #include "s_advsound.h"
  52. #include "stdio.h"
  53. #include "p_tick.h"
  54. #include "p_setup.h"
  55. extern void RecalculateDrawnSubsectors(void);
  56. extern int totalleveltimes;
  57. extern dboolean setsizeneeded;
  58. extern byte* savebuffer;
  59. extern size_t savegamesize;
  60. extern int numsectors;
  61. extern sector_t* sectors;
  62. int secID;
  63. int xSectorInfo[3];
  64. extern int numthings;
  65. extern mobj_t **mobj_ptrs;
  66. int thingID;
  67. int xThingInfo[8];
  68. extern int numlines;
  69. extern line_t* lines;
  70. extern int xLineId;
  71. extern int xLineCrossed;
  72. extern int xLineVertexes[2][2];
  73. float angles = 16384.0;
  74. typedef struct {
  75. int tic;
  76. byte* save;
  77. } xSavepoint_t;
  78. #define MAXSSP 100
  79. static xSavepoint_t savepoints[MAXSSP]; //autosavepoint at 0
  80. int playeringameGet(int plr) {
  81. if(plr < 0 || plr > 3) return 0;
  82. return playeringame[plr];
  83. }
  84. void playeringameSet(int plr, int val) {
  85. if(plr < 0 || plr > 3) return;
  86. playeringame[plr] = val == 0 ? 0 : 1;
  87. }
  88. void x_setLinedefCheck(int linedef) {
  89. int i;
  90. if(linedef == -1) linedef = xLineId;
  91. xLineId = -1;
  92. for(int i = 0; i < numlines; ++i) {
  93. if(linedef == lines[i].iLineID) {
  94. xLineId = lines[i].iLineID;
  95. xLineVertexes[0][0] = lines[i].v1->x;
  96. xLineVertexes[0][1] = lines[i].v1->y;
  97. xLineVertexes[1][0] = lines[i].v2->x;
  98. xLineVertexes[1][1] = lines[i].v2->y;
  99. break;
  100. }
  101. }
  102. if(xLineId == -1) {
  103. xLineVertexes[0][0] = 0;
  104. xLineVertexes[0][1] = 0;
  105. xLineVertexes[1][0] = 0;
  106. xLineVertexes[1][1] = 0;
  107. }
  108. }
  109. void x_setSectorCheck(int sector) {
  110. int i;
  111. if(sector == -1) sector = secID;
  112. secID = -1;
  113. for(i = 0; i < numsectors; ++i) {
  114. if(sector == sectors[i].iSectorID) {
  115. secID = sectors[i].iSectorID;
  116. xSectorInfo[0] = sectors[i].floorheight;
  117. xSectorInfo[1] = sectors[i].ceilingheight;
  118. xSectorInfo[2] = sectors[i].special;
  119. break;
  120. }
  121. }
  122. if(secID == -1)
  123. for(i = 0; i < 3; ++i)
  124. xSectorInfo[i] = 0;
  125. }
  126. //mobj_ptrs is in src/prboom-plus/src/p_setup.c
  127. void x_setThingCheck(int index) {
  128. if(index == -1) index = thingID;
  129. if(index < numthings && mobj_ptrs[index] != NULL) {
  130. thingID = index;
  131. xThingInfo[0] = mobj_ptrs[index]->x;
  132. xThingInfo[1] = mobj_ptrs[index]->y;
  133. xThingInfo[2] = mobj_ptrs[index]->z;
  134. xThingInfo[3] = mobj_ptrs[index]->radius;
  135. xThingInfo[4] = mobj_ptrs[index]->tics; //state tic counter
  136. xThingInfo[5] = mobj_ptrs[index]->health;
  137. xThingInfo[6] = mobj_ptrs[index]->reactiontime;
  138. xThingInfo[7] = mobj_ptrs[index]->threshold;
  139. }
  140. else
  141. for(index = 0; index < 8; ++index)
  142. xThingInfo[index] = 0;
  143. }
  144. int x_getRngIndex(void) {return rng.rndindex;}
  145. double x_getXPos(void) {
  146. if(gamestate != GS_LEVEL) return 0;
  147. return players[displayplayer].mo->x / (double)FRACUNIT;
  148. }
  149. double x_getYPos(void) {
  150. if(gamestate != GS_LEVEL) return 0;
  151. return players[displayplayer].mo->y / (double)FRACUNIT;
  152. }
  153. double x_getZPos(void) {
  154. if(gamestate != GS_LEVEL) return 0;
  155. return players[displayplayer].mo->z / (double)FRACUNIT;
  156. }
  157. double x_getPrevXPos(void) {
  158. if(gamestate != GS_LEVEL) return 0;
  159. return players[displayplayer].mo->PrevX / (double)FRACUNIT;
  160. }
  161. double x_getPrevYPos(void) {
  162. if(gamestate != GS_LEVEL) return 0;
  163. return players[displayplayer].mo->PrevY / (double)FRACUNIT;
  164. }
  165. double x_getPrevZPos(void) {
  166. if(gamestate != GS_LEVEL) return 0;
  167. return players[displayplayer].mo->PrevZ / (double)FRACUNIT;
  168. }
  169. double x_getXMom(void) {
  170. if(gamestate != GS_LEVEL) return 0;
  171. return players[displayplayer].mo->momx / (double)FRACUNIT;
  172. }
  173. double x_getYMom(void) {
  174. if(gamestate != GS_LEVEL) return 0;
  175. return players[displayplayer].mo->momy / (double)FRACUNIT;
  176. }
  177. void x_setAngleType(int type) { //moved from xdre.cpp because of accuracy
  178. switch(type) {
  179. case 0: angles = 16384.0; break; //longtics
  180. case 1: angles = 2048.0; break; //fine angles
  181. case 2: angles = 90.0; break; //degrees
  182. case 3: angles = 64.0; break; //byte angles
  183. }
  184. }
  185. unsigned int x_getAngle(short type) {
  186. if(gamestate != GS_LEVEL) return 0;
  187. //zero is east, the values increase anti-clockwise. Also changed to unsigned
  188. return players[displayplayer].mo->angle * (angles / ANG90);
  189. }
  190. /*
  191. 1. comp_telefrag = 1
  192. 2. comp_dropoff = 2
  193. 3. comp_vile = 4
  194. 4. comp_pain = 8
  195. 5. comp_skull = 16
  196. 6. comp_blazing = 32
  197. 7. comp_doorlight = 64
  198. 8. comp_model = 128
  199. 9. comp_god = 256
  200. 10. comp_falloff = 512
  201. 11. comp_floors = 1024
  202. 12. comp_skymap = 2048
  203. 13. comp_pursuit = 4096
  204. 14. comp_doorstuck = 8192
  205. 15. comp_staylift = 16384
  206. 16. comp_zombie = 32768
  207. 17. comp_stairs = 65536
  208. 18. comp_infcheat = 131072
  209. 19. comp_zerotags = 262144
  210. 20. comp_moveblock = 524288
  211. 21. comp_respawn = 1048576
  212. 22. comp_sound = 2097152
  213. 23. comp_666 = 4194304
  214. 24. comp_soul = 8388608
  215. 25. comp_maskedanim = 16777216
  216. 26. comp_ouchface = 33554432
  217. 27. comp_maxhealth = 67108864
  218. 28. comp_translucency = 134217728
  219. I don't think this will be useful, but you can always add flags below.
  220. 1. monsters_remember = 1
  221. 2. variable_friction = 2
  222. 3. weapon_recoil = 4
  223. 4. allow_pushers = 8
  224. 5. player_bobbing = 16
  225. 6. demo_insurance = 32
  226. 7. monster_infighting = 64
  227. 8. monster_backing = 128
  228. 9. monster_avoid_hazards = 256
  229. 10. monster_friction = 512
  230. 11. help_friends = 1024
  231. 12. dog_jumping = 2048
  232. 13. monkeys = 4096
  233. */
  234. int x_GetCompatibility(void) {
  235. int compatflags = 0;
  236. for(int i = 0; i < COMP_NUM; i++) compatflags += comp[i] << i; //no need for 4 extra values yet
  237. return compatflags;
  238. }
  239. void x_SetCompatibility(int compatflags) {
  240. for(int i = 0; i < COMP_NUM; i++)
  241. comp[i] = compatflags & (1 << i);
  242. }
  243. dboolean x_longtics = 0; //avoid demo errors
  244. dboolean usedHeader = false;
  245. //get options, for HeaderDialog
  246. void x_getOptions(int options[]) {
  247. options[0] = compatibility_level;
  248. options[1] = gameskill + 1;
  249. options[2] = gameepisode;
  250. options[3] = gamemap;
  251. options[4] = deathmatch;
  252. options[5] = respawnparm;
  253. options[6] = fastparm;
  254. options[7] = nomonsters;
  255. options[8] = consoleplayer;
  256. options[9] = 0;
  257. for(int i = 0; i < 4; i++)
  258. options[9] += playeringameGet(i) << i;
  259. options[10] = monsters_remember; //didn't really want bit flags here
  260. options[11] = variable_friction;
  261. options[12] = weapon_recoil;
  262. options[13] = allow_pushers;
  263. options[14] = player_bobbing;
  264. options[15] = demo_insurance;
  265. options[16] = rngseed;
  266. options[17] = monster_infighting;
  267. options[18] = dogs;
  268. options[19] = distfriend;
  269. options[20] = monster_backing;
  270. options[21] = monster_avoid_hazards;
  271. options[22] = monster_friction;
  272. options[23] = help_friends;
  273. options[24] = dog_jumping;
  274. options[25] = monkeys;
  275. options[26] = x_GetCompatibility();
  276. options[27] = longtics;
  277. }
  278. //set
  279. void x_changeOptions(int options[]) {
  280. compatibility_level = options[0];
  281. gameskill = (skill_t)options[1] - 1;
  282. gameepisode = options[2];
  283. gamemap = options[3];
  284. deathmatch = options[4];
  285. respawnparm = options[5];
  286. fastparm = options[6];
  287. nomonsters = options[7];
  288. displayplayer = consoleplayer = options[8];
  289. dboolean players[4];
  290. int lastplayer;
  291. for(int i = 0; i < 4; i++) {
  292. players[i] = options[9] & (1 << i);
  293. playeringameSet(i, players[i]);
  294. if(players[i])
  295. lastplayer = i;
  296. }
  297. //avoid segfaults
  298. for(int i = 0; i < 4; i++) {
  299. if(!players[i] && consoleplayer == i) {
  300. displayplayer = consoleplayer = lastplayer;
  301. }
  302. }
  303. monsters_remember = options[10];
  304. variable_friction = options[11];
  305. weapon_recoil = options[12];
  306. allow_pushers = options[13];
  307. player_bobbing = options[14];
  308. demo_insurance = options[15];
  309. rngseed = options[16];
  310. monster_infighting = options[17];
  311. dogs = options[18];
  312. distfriend = options[19];
  313. monster_backing = options[20];
  314. monster_avoid_hazards = options[21];
  315. monster_friction = options[22];
  316. help_friends = options[23];
  317. dog_jumping = options[24];
  318. monkeys = options[25];
  319. x_SetCompatibility(options[26]);
  320. x_longtics = options[27];
  321. usedHeader = true;
  322. }
  323. #define MIN_MAXPLAYERS 32
  324. void x_initHeader(unsigned char* demo_p) //modified from G_BeginRecording
  325. {
  326. int i;
  327. /* cph - 3 demo record formats supported: MBF+, BOOM, and Doom v1.9 */
  328. if (mbf_features) {
  329. { /* Write version code into demo */
  330. unsigned char v = 0;
  331. switch(compatibility_level) {
  332. case mbf_compatibility: v = 203; break; // e6y: Bug in MBF compatibility mode fixed
  333. case prboom_2_compatibility: v = 210; break;
  334. case prboom_3_compatibility: v = 211; break;
  335. case prboom_4_compatibility: v = 212; break;
  336. case prboom_5_compatibility: v = 213; break;
  337. case prboom_6_compatibility: v = 214; longtics = 1; break;
  338. default: I_Error("x_initHeader: PrBoom compatibility level unrecognised?");
  339. }
  340. *demo_p++ = v;
  341. }
  342. // signature
  343. *demo_p++ = 0x1d;
  344. *demo_p++ = 'M';
  345. *demo_p++ = 'B';
  346. *demo_p++ = 'F';
  347. *demo_p++ = 0xe6;
  348. *demo_p++ = '\0';
  349. /* killough 2/22/98: save compatibility flag in new demos
  350. * cph - FIXME? MBF demos will always be not in compat. mode */
  351. *demo_p++ = 0;
  352. *demo_p++ = gameskill;
  353. *demo_p++ = gameepisode;
  354. *demo_p++ = gamemap;
  355. *demo_p++ = deathmatch;
  356. *demo_p++ = consoleplayer;
  357. demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options
  358. for (i=0 ; i<MAXPLAYERS ; i++)
  359. *demo_p++ = playeringame[i];
  360. // killough 2/28/98:
  361. // We always store at least MIN_MAXPLAYERS bytes in demo, to
  362. // support enhancements later w/o losing demo compatibility
  363. for (; i<32; i++)
  364. *demo_p++ = 0;
  365. } else if (compatibility_level >= boom_compatibility_compatibility) { //they still desync, though
  366. byte v = 0, c = 0; /* Nominally, version and compatibility bits */
  367. switch (compatibility_level) {
  368. case boom_compatibility_compatibility: v = 202, c = 1; break;
  369. case boom_201_compatibility: v = 201; c = 0; break;
  370. case boom_202_compatibility: v = 202, c = 0; break;
  371. default: I_Error("x_initHeader: Boom compatibility level unrecognised?");
  372. }
  373. *demo_p++ = v;
  374. // signature
  375. *demo_p++ = 0x1d;
  376. *demo_p++ = 'B';
  377. *demo_p++ = 'o';
  378. *demo_p++ = 'o';
  379. *demo_p++ = 'm';
  380. *demo_p++ = 0xe6;
  381. /* CPhipps - save compatibility level in demos */
  382. *demo_p++ = c;
  383. *demo_p++ = gameskill;
  384. *demo_p++ = gameepisode;
  385. *demo_p++ = gamemap;
  386. *demo_p++ = deathmatch;
  387. *demo_p++ = consoleplayer;
  388. demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options
  389. for (i=0; i<MAXPLAYERS; i++)
  390. *demo_p++ = playeringame[i];
  391. // killough 2/28/98:
  392. // We always store at least MIN_MAXPLAYERS bytes in demo, to
  393. // support enhancements later w/o losing demo compatibility
  394. for (; i<32; i++)
  395. *demo_p++ = 0;
  396. } else { // cph - write old v1.9 demos (might even sync)
  397. unsigned char v = 109;
  398. if(!usedHeader) longtics = M_CheckParm("-longtics");
  399. else longtics = x_longtics;
  400. if (longtics)
  401. {
  402. v = 111;
  403. }
  404. else
  405. {
  406. switch (compatibility_level)
  407. {
  408. case doom_1666_compatibility:
  409. v = 106;
  410. break;
  411. case tasdoom_compatibility:
  412. v = 110;
  413. break;
  414. }
  415. }
  416. *demo_p++ = v;
  417. *demo_p++ = gameskill;
  418. *demo_p++ = gameepisode;
  419. *demo_p++ = gamemap;
  420. *demo_p++ = deathmatch;
  421. *demo_p++ = respawnparm;
  422. *demo_p++ = fastparm;
  423. *demo_p++ = nomonsters;
  424. *demo_p++ = consoleplayer;
  425. for (i=0; i<4; i++) // intentionally hard-coded 4 -- killough
  426. *demo_p++ = playeringame[i];
  427. }
  428. }
  429. void x_clearMapSavepoints(void) {
  430. int i;
  431. for(i = 1; i < MAXSSP; ++i) {
  432. free(savepoints[i].save);
  433. savepoints[i].save = NULL;
  434. savepoints[i].tic = 0;
  435. }
  436. }
  437. void x_clearUserSavepoint() {
  438. free(savepoints[0].save);
  439. savepoints[0].save = NULL;
  440. savepoints[0].tic = 0;
  441. }
  442. static int x_getSavepointIndex(int dest) {
  443. int index = -1;
  444. int savetic = 0;
  445. int map = gamemap;
  446. if(map > MAXSSP-1) map = MAXSSP-1;
  447. if(savepoints[0].save && savepoints[0].tic < dest) {
  448. index = 0;
  449. savetic = savepoints[0].tic;
  450. }
  451. for(; map > 0; --map) {
  452. if(savetic < savepoints[map].tic && savepoints[map].tic < dest) {
  453. index = map;
  454. break;
  455. }
  456. }
  457. return index;
  458. }
  459. int x_getSavepointTic(int dest) {
  460. int index = x_getSavepointIndex(dest);
  461. if(index < 0) return 0;
  462. return savepoints[index].tic;
  463. }
  464. int x_setSavepoint(int isUserSave) {
  465. int map = gamemap;
  466. if(map < 0 || map > MAXSSP-1 || gamestate != GS_LEVEL || gameaction != ga_nothing) return 1;
  467. if(leveltime != 1 || isUserSave != 0) map = 0;
  468. if(savepoints[map].save) {
  469. free(savepoints[map].save);
  470. savepoints[map].save = NULL;
  471. }
  472. savepoints[map].save = malloc(savegamesize);
  473. savepoints[map].tic = gametic;
  474. save_p = savebuffer = savepoints[map].save;
  475. // do save
  476. {
  477. int i;
  478. *save_p++ = compatibility_level;
  479. *save_p++ = gameskill;
  480. *save_p++ = gameepisode;
  481. *save_p++ = gamemap;
  482. for(i = 0; i < MAXPLAYERS; ++i) *save_p++ = playeringame[i];
  483. for(; i < MIN_MAXPLAYERS; ++i) *save_p++ = 0;
  484. *save_p++ = idmusnum;
  485. save_p = G_WriteOptions(save_p);
  486. memcpy(save_p, &leveltime, sizeof leveltime);
  487. save_p += sizeof leveltime;
  488. memcpy(save_p, &totalleveltimes, sizeof totalleveltimes);
  489. save_p += sizeof totalleveltimes;
  490. *save_p++ = (gametic - basetic) & 255;
  491. Z_CheckHeap();
  492. P_ArchivePlayers();
  493. Z_CheckHeap();
  494. P_ThinkerToIndex();
  495. P_ArchiveWorld();
  496. Z_CheckHeap();
  497. P_ArchiveThinkers();
  498. Z_CheckHeap();
  499. P_ArchiveSpecials();
  500. P_IndexToThinker();
  501. P_ArchiveRNG();
  502. Z_CheckHeap();
  503. P_ArchiveMap();
  504. *save_p++ = 0xe6;
  505. Z_CheckHeap();
  506. }
  507. // done
  508. savepoints[map].save = savebuffer; //incase checksavegame reallocated savebuffer
  509. save_p = savebuffer = NULL;
  510. return 0;
  511. }
  512. //modified G_DoLoadGame
  513. int x_loadSavepoint(int dest) {
  514. int i;
  515. save_p = NULL;
  516. int map = x_getSavepointIndex(dest);
  517. if(map < 0) return 1;
  518. if(map != 0) x_clearUserSavepoint();
  519. save_p = savepoints[map].save;
  520. gametic = savepoints[map].tic;
  521. gameaction = ga_nothing;
  522. compatibility_level = *save_p++;
  523. gameskill = *save_p++;
  524. gameepisode = *save_p++;
  525. gamemap = *save_p++;
  526. for(i = 0; i < MAXPLAYERS; ++i) playeringame[i] = *save_p++;
  527. save_p += 28; //28 = MIN_MAXPLAYERS - MAXPLAYERS in g_game.c
  528. idmusnum = *save_p++;
  529. if(idmusnum == 255) idmusnum = -1;
  530. save_p += (G_ReadOptions(save_p) - save_p);
  531. G_InitNew(gameskill, gameepisode, gamemap);
  532. memcpy(&leveltime, save_p, sizeof leveltime);
  533. save_p += sizeof leveltime;
  534. memcpy(&totalleveltimes, save_p, sizeof totalleveltimes);
  535. save_p += sizeof totalleveltimes;
  536. basetic = gametic - *save_p++;
  537. P_MapStart();
  538. P_UnArchivePlayers();
  539. P_UnArchiveWorld();
  540. P_UnarchiveThinkersAndSpecials();
  541. P_UnArchiveRNG();
  542. P_UnArchiveMap();
  543. P_MapEnd();
  544. R_ActivateSectorInterpolations();
  545. R_SmoothPlaying_Reset(NULL);
  546. if(musinfo.current_item != -1) S_ChangeMusInfoMusic(musinfo.current_item, true);
  547. RecalculateDrawnSubsectors();
  548. if(*save_p != 0xe6) I_Error("x_loadSavepoint: Bad savepoint on map %i", map);
  549. if(setsizeneeded) R_ExecuteSetViewSize();
  550. R_FillBackScreen();
  551. save_p = NULL;
  552. return 0;
  553. }