DB.CPP 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <io.h>
  4. #include <fcntl.h>
  5. #include "engine.h"
  6. #include "debug4g.h"
  7. #include "db.h"
  8. #include "error.h"
  9. #include "misc.h"
  10. #include "resource.h"
  11. #include "iob.h"
  12. #include "names.h"
  13. #include "globals.h"
  14. #include "trig.h"
  15. #include <memcheck.h>
  16. /***********************************************************************
  17. * Constants
  18. **********************************************************************/
  19. #define kBloodMapExt ".MAP"
  20. #define kBloodMapSig "BLM\x1A"
  21. #define kBloodMapVersion 0x0600
  22. #define kMajorVersionMask 0xFF00
  23. #define kMinorVersionMask 0x00FF
  24. #define kFreeHead 0
  25. /***********************************************************************
  26. * Structures and typedefs
  27. **********************************************************************/
  28. struct HEADER
  29. {
  30. char signature[4];
  31. short version;
  32. };
  33. // version 6.x header
  34. struct INFO
  35. {
  36. long x, y, z;
  37. ushort angle;
  38. ushort sector;
  39. ushort pskybits;
  40. long visibility;
  41. int songId;
  42. uchar parallax;
  43. int mapRevisions;
  44. ushort numsectors;
  45. ushort numwalls;
  46. ushort numsprites;
  47. };
  48. /*******************************************************************************
  49. File format:
  50. HEADER
  51. INFO
  52. name[]
  53. author[]
  54. sector[]
  55. wall[]
  56. sprite[]
  57. xsprite[]
  58. xwall[]
  59. xsector[]
  60. CRC
  61. *******************************************************************************/
  62. /***********************************************************************
  63. * Global Variables / MPX related strings
  64. **********************************************************************/
  65. char *gItemText[ kItemMax - kItemBase ] = {
  66. // items which will probably not change
  67. "Key 1", // kItemKey1
  68. "Key 2", // kItemKey2
  69. "Key 3", // kItemKey3
  70. "Key 4", // kItemKey4
  71. "Key 5", // kItemKey5
  72. "Key 6", // kItemKey6
  73. "Key 7", // kItemKey7
  74. "Doctor's Bag", // kItemDoctorBag
  75. "Medicine Pouch", // kItemMedPouch
  76. "Life Essence", // kItemLifeEssence
  77. "Life Seed", // kItemLifeSeed
  78. "Red Potion", // kItemPotion1
  79. "Feather Fall", // kItemFeatherFall
  80. "Limited Invisibility", // kItemLtdInvisibility
  81. "INVULNERABILITY", // kItemInvulnerability
  82. "Boots of Jumping", // kItemJumpBoots
  83. "Raven Flight", // kItemRavenFlight
  84. "Guns Akimbo", // kItemGunsAkimbo
  85. "Diving Suit", // kItemDivingSuit
  86. "Gas mask", // kItemGasMask
  87. "Clone", // kItemClone
  88. "Crystal Ball", // kItemCrystalBall
  89. "Decoy", // kItemDecoy
  90. "Doppleganger", // kItemDoppleganger
  91. "Reflective shots", // kItemReflectiveShots
  92. "Rose colored glasses", // kItemRoseGlasses
  93. "ShadowCloak", // kItemShadowCloak
  94. "Rage shroom", // kItemShroomRage
  95. "Delirium Shroom", // kItemShroomDelirium
  96. "Grow shroom", // kItemShroomGrow
  97. "Shrink shroom", // kItemShroomShrink
  98. "Death mask", // kItemDeathMask
  99. "Wine Goblet", // kItemWineGoblet
  100. "Wine Bottle", // kItemWineBottle
  101. "Skull Grail", // kItemSkullGrail
  102. "Silver Grail", // kItemSilverGrail
  103. "Tome", // kItemTome
  104. "Black Chest", // kItemBlackChest
  105. "Wooden Chest", // kItemWoodenChest
  106. "Asbestos Armor", // kItemAsbestosArmor
  107. };
  108. char *gAmmoText[kAmmoItemMax - kAmmoItemBase] = {
  109. "Spray can",
  110. "Stick of TNT",
  111. "Bundle of TNT",
  112. "Case of TNT",
  113. "Proximity Detonator",
  114. "Remote Detonator",
  115. "Timed Detonator",
  116. "4 shotgun shells",
  117. "Box of shotgun shells",
  118. "A few bullets",
  119. "Box of bullets",
  120. "Armor piercing bullets",
  121. "Full drum of bullets",
  122. "Speargun spear",
  123. "6 speargun spears",
  124. "Explosive spears",
  125. "Flares",
  126. "Explosive flares",
  127. "Burst flares",
  128. };
  129. char *gWeaponText[kWeaponItemMax - kWeaponItemBase] =
  130. {
  131. "RandomWeapon", // kWeaponItemRandom
  132. "SawedOff", // kWeaponItemShotgun
  133. "TommyGun", // kWeaponItemTommyGun
  134. "FlareGun", // kWeaponItemFlareGun
  135. "VoodooDoll", // kWeaponItemVoodooDoll
  136. "SpearGun", // kWeaponItemSpearGun
  137. "EctoBlaster", // kWeaponItemShadowGun
  138. "Pitchfork", // kWeaponItemPitchfork
  139. "SprayCan", // kWeaponItemSprayCan
  140. "TNT" // kWeaponItemTNT
  141. };
  142. /***********************************************************************
  143. * Variables
  144. **********************************************************************/
  145. XSPRITE xsprite[kMaxXSprites];
  146. XWALL xwall[kMaxXWalls];
  147. XSECTOR xsector[kMaxXSectors];
  148. ushort nextXSprite[kMaxXSprites];
  149. ushort nextXWall[kMaxXWalls];
  150. ushort nextXSector[kMaxXSectors];
  151. int gMapRev;
  152. int gSongId;
  153. ulong gMapCRC;
  154. int gSkyCount;
  155. /*******************************************************************************
  156. Replace engine sprite list functions
  157. *******************************************************************************/
  158. void InsertSpriteSect( short nSprite, short nSector )
  159. {
  160. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  161. dassert(nSector >= 0 && nSector < kMaxSectors);
  162. int nOldHead = headspritesect[nSector];
  163. if (nOldHead >= 0)
  164. {
  165. // insert sprite at the tail of the list
  166. prevspritesect[nSprite] = prevspritesect[nOldHead];
  167. nextspritesect[nSprite] = -1;
  168. nextspritesect[prevspritesect[nOldHead]] = nSprite;
  169. prevspritesect[nOldHead] = nSprite;
  170. }
  171. else
  172. {
  173. prevspritesect[nSprite] = nSprite;
  174. nextspritesect[nSprite] = -1;
  175. headspritesect[nSector] = nSprite;
  176. }
  177. sprite[nSprite].sectnum = nSector;
  178. }
  179. void RemoveSpriteSect( int nSprite )
  180. {
  181. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  182. int nSector = sprite[nSprite].sectnum;
  183. dassert(nSector >= 0 && nSector < kMaxSectors);
  184. if ( nextspritesect[nSprite] >= 0 )
  185. prevspritesect[nextspritesect[nSprite]] = prevspritesect[nSprite];
  186. else
  187. prevspritesect[headspritesect[nSector]] = prevspritesect[nSprite];
  188. if ( headspritesect[nSector] != nSprite )
  189. nextspritesect[prevspritesect[nSprite]] = nextspritesect[nSprite];
  190. else
  191. headspritesect[nSector] = nextspritesect[nSprite];
  192. sprite[nSprite].sectnum = -1;
  193. }
  194. void InsertSpriteStat( short nSprite, short nStat )
  195. {
  196. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  197. dassert(nStat >= 0 && nStat <= kMaxStatus);
  198. int nHead = headspritestat[nStat];
  199. if (nHead >= 0)
  200. {
  201. nextspritestat[nSprite] = -1;
  202. prevspritestat[nSprite] = prevspritestat[nHead];
  203. nextspritestat[prevspritestat[nHead]] = nSprite;
  204. prevspritestat[nHead] = nSprite;
  205. }
  206. else
  207. {
  208. prevspritestat[nSprite] = nSprite;
  209. nextspritestat[nSprite] = -1;
  210. headspritestat[nStat] = nSprite;
  211. }
  212. sprite[nSprite].statnum = nStat;
  213. }
  214. void RemoveSpriteStat( int nSprite )
  215. {
  216. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  217. int nStat = sprite[nSprite].statnum;
  218. dassert(nStat >= 0 && nStat <= kMaxStatus);
  219. if ( nextspritestat[nSprite] >= 0 )
  220. prevspritestat[nextspritestat[nSprite]] = prevspritestat[nSprite];
  221. else
  222. prevspritestat[headspritestat[nStat]] = prevspritestat[nSprite];
  223. if (headspritestat[nStat] != nSprite )
  224. nextspritestat[prevspritestat[nSprite]] = nextspritestat[nSprite];
  225. else
  226. headspritestat[nStat] = nextspritestat[nSprite];
  227. sprite[nSprite].statnum = -1;
  228. }
  229. void initspritelists()
  230. {
  231. short i;
  232. //Init doubly-linked sprite sector lists
  233. for (i = 0; i <= kMaxSectors; i++)
  234. headspritesect[i] = -1;
  235. for (i = 0; i <= kMaxStatus; i++)
  236. headspritestat[i] = -1;
  237. for (i = 0; i < kMaxSprites; i++)
  238. {
  239. sprite[i].sectnum = -1;
  240. InsertSpriteStat(i, kStatFree); // add to free list
  241. }
  242. }
  243. //long debugNumSprites = 0;
  244. short insertsprite( short nSector, short nStatus )
  245. {
  246. short nSprite;
  247. // debugNumSprites++;
  248. // dprintf("insertsprite: debugNumSprites=%i\n",debugNumSprites);
  249. nSprite = headspritestat[kStatFree];
  250. if (nSprite >= 0)
  251. {
  252. RemoveSpriteStat(nSprite);
  253. InsertSpriteStat(nSprite, nStatus);
  254. InsertSpriteSect(nSprite, nSector);
  255. sprite[nSprite].cstat = kSpriteOriginAlign;
  256. sprite[nSprite].shade = 0;
  257. sprite[nSprite].pal = 0;
  258. sprite[nSprite].clipdist = 32;
  259. sprite[nSprite].xrepeat = 64;
  260. sprite[nSprite].yrepeat = 64;
  261. sprite[nSprite].xoffset = 0;
  262. sprite[nSprite].yoffset = 0;
  263. sprite[nSprite].picnum = 0;
  264. sprite[nSprite].ang = 0;
  265. sprite[nSprite].xvel = 0;
  266. sprite[nSprite].yvel = 0;
  267. sprite[nSprite].zvel = 0;
  268. sprite[nSprite].owner = -1;
  269. sprite[nSprite].type = 0;
  270. sprite[nSprite].flags = 0;
  271. sprite[nSprite].extra = -1;
  272. }
  273. if ( nSprite < 0 )
  274. {
  275. dprintf("sprite status linked list:\n");
  276. for ( int i = 0; i <= kMaxStatus; i++ )
  277. dprintf("head[%4d]=%4d\n", i, headspritestat[i]);
  278. for ( i = 0; i <= kMaxSprites; i++ )
  279. dprintf("%4d: prev=%4d next=%4d\n", i, prevspritestat[i], nextspritestat[i]);
  280. dassert(nSprite >= 0);
  281. }
  282. return nSprite;
  283. }
  284. void deletesprite( short nSprite )
  285. {
  286. // debugNumSprites--;
  287. // dprintf("deletesprite: debugNumSprites=%i\n",debugNumSprites);
  288. if ( sprite[nSprite].extra > 0 )
  289. dbDeleteXSprite(sprite[nSprite].extra);
  290. dassert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus);
  291. RemoveSpriteStat(nSprite);
  292. dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors);
  293. RemoveSpriteSect(nSprite);
  294. InsertSpriteStat(nSprite, kStatFree);
  295. }
  296. int changespritesect( short nSprite, short nSector )
  297. {
  298. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  299. dassert(nSector >= 0 && nSector < kMaxSectors);
  300. dassert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus);
  301. dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors);
  302. // changing to same sector is a valid operation, and will put sprite at tail of list
  303. RemoveSpriteSect(nSprite);
  304. InsertSpriteSect(nSprite, nSector);
  305. return 0;
  306. }
  307. int changespritestat( short nSprite, short nStatus )
  308. {
  309. dassert(nSprite >= 0 && nSprite < kMaxSprites);
  310. dassert(nStatus >= 0 && nStatus < kMaxStatus);
  311. dassert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus);
  312. dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors);
  313. // changing to same status is a valid operation, and will put sprite at tail of list
  314. RemoveSpriteStat(nSprite);
  315. InsertSpriteStat(nSprite, nStatus);
  316. return 0;
  317. }
  318. /*******************************************************************************
  319. These functions are for manipulating the xobject lists
  320. *******************************************************************************/
  321. void InitFreeList( ushort xlist[], int xlistSize )
  322. {
  323. for (int i = 1; i < xlistSize; i++)
  324. xlist[i] = (ushort)(i - 1);
  325. xlist[kFreeHead] = (ushort)(xlistSize - 1);
  326. }
  327. inline ushort RemoveFree( ushort next[] )
  328. {
  329. ushort n = next[kFreeHead];
  330. next[kFreeHead] = next[n];
  331. return n;
  332. }
  333. inline void InsertFree( ushort next[], int n )
  334. {
  335. next[n] = next[kFreeHead];
  336. next[kFreeHead] = (ushort)n;
  337. }
  338. ushort dbInsertXSprite( int nSprite )
  339. {
  340. ushort nXSprite = RemoveFree(nextXSprite);
  341. if (nXSprite == 0)
  342. ThrowError("Out of free XSprites", ES_ERROR);
  343. memset(&xsprite[nXSprite], 0, sizeof(XSPRITE));
  344. sprite[nSprite].extra = nXSprite;
  345. xsprite[nXSprite].reference = nSprite;
  346. return nXSprite;
  347. }
  348. void dbDeleteXSprite( int nXSprite )
  349. {
  350. dassert(xsprite[nXSprite].reference >= 0);
  351. dassert(sprite[xsprite[nXSprite].reference].extra == nXSprite);
  352. InsertFree( nextXSprite, nXSprite );
  353. // clear the references
  354. sprite[xsprite[nXSprite].reference].extra = -1;
  355. xsprite[nXSprite].reference = -1;
  356. }
  357. ushort dbInsertXWall( int nWall )
  358. {
  359. ushort nXWall = RemoveFree(nextXWall);
  360. if (nXWall == 0)
  361. ThrowError("Out of free XWalls", ES_ERROR);
  362. memset(&xwall[nXWall], 0, sizeof(XWALL));
  363. wall[nWall].extra = nXWall;
  364. xwall[nXWall].reference = nWall;
  365. return nXWall;
  366. }
  367. void dbDeleteXWall( int nXWall )
  368. {
  369. dassert(xwall[nXWall].reference >= 0);
  370. InsertFree( nextXWall, nXWall );
  371. // clear the references
  372. wall[xwall[nXWall].reference].extra = -1;
  373. xwall[nXWall].reference = -1;
  374. }
  375. ushort dbInsertXSector( int nSector )
  376. {
  377. ushort nXSector = RemoveFree(nextXSector);
  378. if (nXSector == 0)
  379. ThrowError("Out of free XSectors", ES_ERROR);
  380. memset(&xsector[nXSector], 0, sizeof(XSECTOR));
  381. sector[nSector].extra = nXSector;
  382. xsector[nXSector].reference = nSector;
  383. return nXSector;
  384. }
  385. void dbDeleteXSector( int nXSector )
  386. {
  387. dassert(xsector[nXSector].reference >= 0);
  388. InsertFree( nextXSector, nXSector );
  389. // clear the references
  390. sector[xsector[nXSector].reference].extra = -1;
  391. xsector[nXSector].reference = -1; // clear the reference
  392. }
  393. /***********************************************************************
  394. * dbXSpriteClean()
  395. *
  396. * Clean up the xsprite list: clone duplicate references & delete orphans
  397. **********************************************************************/
  398. void dbXSpriteClean(void)
  399. {
  400. int nSprite, nXSprite;
  401. // clone duplicate references
  402. for ( nSprite = 0; nSprite < kMaxSprites; nSprite++ )
  403. {
  404. nXSprite = sprite[nSprite].extra;
  405. if (nXSprite == 0)
  406. sprite[nSprite].extra = -1;
  407. if ( sprite[nSprite].statnum < kMaxStatus && nXSprite > 0 )
  408. {
  409. dassert(nXSprite < kMaxXSprites);
  410. if ( xsprite[nXSprite].reference != nSprite )
  411. {
  412. // make a copy of the xsprite entry
  413. int newXSprite = dbInsertXSprite(nSprite);
  414. xsprite[newXSprite] = xsprite[nXSprite];
  415. xsprite[newXSprite].reference = nSprite; // fix reference after copying
  416. }
  417. }
  418. }
  419. // remove orphans
  420. for ( nXSprite = 1; nXSprite < kMaxXSprites; nXSprite++ )
  421. {
  422. nSprite = xsprite[nXSprite].reference;
  423. if (nSprite >= 0)
  424. {
  425. dassert(nSprite < kMaxSprites);
  426. if (sprite[nSprite].statnum >= kMaxStatus || sprite[nSprite].extra != nXSprite)
  427. {
  428. // delete manually so we don't assert from a mismatched reference
  429. InsertFree( nextXSprite, nXSprite );
  430. xsprite[nXSprite].reference = -1;
  431. }
  432. }
  433. }
  434. }
  435. /***********************************************************************
  436. * dbXWallClean()
  437. *
  438. * Clean up the xwall list: clone duplicate references & delete orphans
  439. **********************************************************************/
  440. void dbXWallClean(void)
  441. {
  442. int nWall, nXWall;
  443. // back propagate references
  444. for ( nWall = 0; nWall < numwalls; nWall++ )
  445. {
  446. nXWall = wall[nWall].extra;
  447. if (nXWall == 0)
  448. wall[nWall].extra = -1;
  449. if ( nXWall > 0 )
  450. {
  451. dassert(nXWall < kMaxXWalls);
  452. // wall points to a freed xwall
  453. if (xwall[nXWall].reference == -1)
  454. {
  455. wall[nWall].extra = -1;
  456. continue;
  457. }
  458. // probably just moved the wall around
  459. xwall[nXWall].reference = nWall;
  460. }
  461. }
  462. // clone duplicate references
  463. for ( nWall = 0; nWall < numwalls; nWall++ )
  464. {
  465. if ( wall[nWall].extra > 0 )
  466. {
  467. nXWall = wall[nWall].extra;
  468. dassert(nXWall < kMaxXWalls);
  469. if ( xwall[nXWall].reference != nWall )
  470. {
  471. // make a copy of the xwall entry
  472. int newXWall = dbInsertXWall(nWall);
  473. xwall[newXWall] = xwall[nXWall];
  474. xwall[newXWall].reference = nWall; // fix reference after copying
  475. }
  476. }
  477. }
  478. // remove orphans
  479. for ( nXWall = 1; nXWall < kMaxXWalls; nXWall++ )
  480. {
  481. nWall = xwall[nXWall].reference;
  482. if (nWall >= 0)
  483. {
  484. dassert(nWall < kMaxWalls);
  485. if ( nWall >= numwalls || wall[nWall].extra != nXWall )
  486. {
  487. // delete manually so we don't assert from a mismatched reference
  488. InsertFree( nextXWall, nXWall );
  489. xwall[nXWall].reference = -1;
  490. }
  491. }
  492. }
  493. }
  494. /***********************************************************************
  495. * dbXSectorClean()
  496. *
  497. * Clean up the xsector list: clone duplicate references & delete orphans
  498. **********************************************************************/
  499. void dbXSectorClean(void)
  500. {
  501. int nSector, nXSector;
  502. // back propagate references
  503. for ( nSector = 0; nSector < numsectors; nSector++ )
  504. {
  505. nXSector = sector[nSector].extra;
  506. if (nXSector == 0)
  507. sector[nSector].extra = -1;
  508. if ( nXSector > 0 )
  509. {
  510. dassert(nXSector < kMaxXSectors);
  511. // sector points to a freed xsector
  512. if (xsector[nXSector].reference == -1)
  513. {
  514. sector[nSector].extra = -1;
  515. continue;
  516. }
  517. // probably just moved the sector around
  518. xsector[nXSector].reference = nSector;
  519. }
  520. }
  521. // clone duplicate references
  522. for ( nSector = 0; nSector < numsectors; nSector++ )
  523. {
  524. if ( sector[nSector].extra > 0 )
  525. {
  526. nXSector = sector[nSector].extra;
  527. dassert(nXSector < kMaxXSectors);
  528. if ( xsector[nXSector].reference != nSector )
  529. {
  530. // make a copy of the xsector entry
  531. int newXSector = dbInsertXSector(nSector);
  532. xsector[newXSector] = xsector[nXSector];
  533. xsector[newXSector].reference = nSector; // fix reference after copying
  534. }
  535. }
  536. }
  537. // remove orphans
  538. for ( nXSector = 1; nXSector < kMaxXSectors; nXSector++ )
  539. {
  540. nSector = xsector[nXSector].reference;
  541. if (nSector >= 0)
  542. {
  543. dassert(nSector < kMaxSectors);
  544. if ( nSector >= numsectors || sector[nSector].extra != nXSector )
  545. {
  546. // delete manually so we don't assert from a mismatched reference
  547. InsertFree( nextXSector, nXSector );
  548. xsector[nXSector].reference = -1;
  549. }
  550. }
  551. }
  552. }
  553. void dbInit( void )
  554. {
  555. int i;
  556. // memset(sprite, 0, sizeof(sprite));
  557. // memset(wall, 0, sizeof(wall));
  558. // memset(sector, 0, sizeof(sector));
  559. InitFreeList(nextXSprite, kMaxXSprites);
  560. for (i = 1; i < kMaxXSprites; i++)
  561. xsprite[i].reference = -1;
  562. InitFreeList(nextXWall, kMaxXWalls);
  563. for (i = 1; i < kMaxXWalls; i++)
  564. xwall[i].reference = -1;
  565. InitFreeList(nextXSector, kMaxXSectors);
  566. for (i = 1; i < kMaxXSectors; i++)
  567. xsector[i].reference = -1;
  568. initspritelists();
  569. // initialize default cstat for sprites
  570. for (i = 0; i < kMaxSprites; i++)
  571. sprite[i].cstat = kSpriteOriginAlign;
  572. }
  573. /*******************************************************************************
  574. FUNCTION: PropagateMarkerReferences()
  575. DESCRIPTION: Fixed sector references based on marker sprite references.
  576. NOTES: This function assumes that the owner references in the
  577. marker sprites are correct. This function should be called
  578. from loadboard, where we know that sprites are rearranged.
  579. *******************************************************************************/
  580. void PropagateMarkerReferences( void )
  581. {
  582. int nSprite, j;
  583. int nSector, nXSector;
  584. for (nSprite = headspritestat[kStatMarker]; nSprite != -1; nSprite = j)
  585. {
  586. j = nextspritestat[nSprite];
  587. switch (sprite[nSprite].type)
  588. {
  589. case kMarkerWarpDest:
  590. nSector = sprite[nSprite].owner;
  591. if (nSector < 0 || nSector >= numsectors)
  592. break;
  593. nXSector = sector[nSector].extra;
  594. if (nXSector <= 0 || nXSector >= kMaxXSectors)
  595. break;
  596. xsector[nXSector].marker0 = nSprite;
  597. continue;
  598. case kMarkerOff:
  599. nSector = sprite[nSprite].owner;
  600. if (nSector < 0 || nSector >= numsectors)
  601. break;
  602. nXSector = sector[nSector].extra;
  603. if (nXSector <= 0 || nXSector >= kMaxXSectors)
  604. break;
  605. xsector[nXSector].marker0 = nSprite;
  606. continue;
  607. case kMarkerOn:
  608. nSector = sprite[nSprite].owner;
  609. if (nSector < 0 || nSector >= numsectors)
  610. break;
  611. nXSector = sector[nSector].extra;
  612. if (nXSector <= 0 || nXSector >= kMaxXSectors)
  613. break;
  614. xsector[nXSector].marker1 = nSprite;
  615. continue;
  616. case kMarkerAxis:
  617. nSector = sprite[nSprite].owner;
  618. if (nSector < 0 || nSector >= numsectors)
  619. break;
  620. nXSector = sector[nSector].extra;
  621. if (nXSector <= 0 || nXSector >= kMaxXSectors)
  622. break;
  623. xsector[nXSector].marker0 = nSprite;
  624. continue;
  625. }
  626. dprintf("Deleting invalid marker sprite\n");
  627. deletesprite((short)nSprite);
  628. }
  629. }
  630. /***********************************************************************
  631. * dbLoadMap()
  632. **********************************************************************/
  633. void dbLoadMap(const char *mapname, long *x, long *y, long *z, short *angle, short *nSector)
  634. {
  635. char filename[_MAX_PATH];
  636. int i, numsprites;
  637. int length;
  638. HEADER header;
  639. INFO info;
  640. BYTE *buffer;
  641. // these eventually need to be added to the save game format
  642. // memset(show2dsector, 0, sizeof(show2dsector));
  643. // memset(show2dwall, 0, sizeof(show2dwall));
  644. // memset(show2dsprite, 0, sizeof(show2dsprite));
  645. strcpy(filename, mapname);
  646. // clear any extension
  647. char *p = strchr(filename, '.');
  648. if ( p != NULL)
  649. *p = '\0';
  650. RESHANDLE hMap = gSysRes.Lookup(filename, ".MAP");
  651. if ( hMap == NULL )
  652. ThrowError("Error opening map file", ES_ERROR);
  653. length = gSysRes.Size(hMap);
  654. buffer = (BYTE *)gSysRes.Lock(hMap);
  655. IOBuffer iob(buffer, length);
  656. iob.Read(&header, sizeof(HEADER));
  657. if (memcmp(header.signature, kBloodMapSig, sizeof(header.signature)) != 0)
  658. ThrowError("Map file corrupted", ES_ERROR);
  659. if ( (header.version & kMajorVersionMask) != (kBloodMapVersion & kMajorVersionMask) )
  660. ThrowError("Map file is wrong version", ES_ERROR);
  661. iob.Read(&info, sizeof(INFO));
  662. *x = info.x;
  663. *y = info.y;
  664. *z = info.z;
  665. *angle = info.angle;
  666. *nSector = info.sector;
  667. pskybits = info.pskybits;
  668. visibility = info.visibility;
  669. gSongId = info.songId;
  670. parallaxtype = info.parallax;
  671. gMapRev = info.mapRevisions;
  672. numsectors = info.numsectors;
  673. numwalls = info.numwalls;
  674. numsprites = info.numsprites;
  675. dbInit();
  676. gSkyCount = 1 << pskybits;
  677. iob.Read(pskyoff, gSkyCount * sizeof(pskyoff[0]));
  678. for (i = 0; i < numsectors; i++)
  679. {
  680. SECTOR *pSector = &sector[i];
  681. iob.Read(&sector[i], sizeof(SECTOR));
  682. if (sector[i].extra > 0)
  683. {
  684. iob.Read(&xsector[dbInsertXSector(i)], sizeof(XSECTOR));
  685. xsector[sector[i].extra].reference = i;
  686. xsector[sector[i].extra].busy = xsector[sector[i].extra].state << 16;
  687. }
  688. }
  689. for (i = 0; i < numwalls; i++)
  690. {
  691. iob.Read(&wall[i], sizeof(WALL));
  692. if (wall[i].extra > 0)
  693. {
  694. iob.Read(&xwall[dbInsertXWall(i)], sizeof(XWALL));
  695. xwall[wall[i].extra].reference = i;
  696. xwall[wall[i].extra].busy = xwall[wall[i].extra].state << 16;
  697. }
  698. }
  699. initspritelists();
  700. for (i = 0; i < numsprites; i++)
  701. {
  702. RemoveSpriteStat((short)i); // remove it from the free list
  703. iob.Read(&sprite[i], sizeof(SPRITE));
  704. // insert sprite on appropriate lists
  705. InsertSpriteSect((short)i, sprite[i].sectnum);
  706. InsertSpriteStat((short)i, sprite[i].statnum);
  707. // debugNumSprites++;
  708. if (sprite[i].extra > 0)
  709. {
  710. iob.Read(&xsprite[dbInsertXSprite(i)], sizeof(XSPRITE));
  711. xsprite[sprite[i].extra].reference = i;
  712. xsprite[sprite[i].extra].busy = xsprite[sprite[i].extra].state << 16;
  713. }
  714. }
  715. iob.Read(&gMapCRC, sizeof(gMapCRC));
  716. if ( gMapCRC != CRC32(buffer, length - sizeof(gMapCRC)) )
  717. ThrowError("File does not match CRC", ES_ERROR);
  718. gSysRes.Unlock(hMap);
  719. PropagateMarkerReferences();
  720. }
  721. /***********************************************************************
  722. * dbSaveMap()
  723. **********************************************************************/
  724. void dbSaveMap(const char *mapname, long x, long y, long z, short angle, short nSector)
  725. {
  726. char filename[_MAX_PATH];
  727. char bakfilename[_MAX_PATH];
  728. int hFile;
  729. HEADER header;
  730. INFO info;
  731. int length;
  732. BYTE *buffer;
  733. int numsprites = 0;
  734. int i;
  735. gSkyCount = 1 << pskybits;
  736. gMapRev++;
  737. strcpy(filename, mapname);
  738. strcpy(bakfilename, mapname);
  739. ChangeExtension(filename, kBloodMapExt);
  740. ChangeExtension(bakfilename, ".BAK");
  741. // add up all the elements in the file to determine the size of the buffer
  742. length = 0;
  743. length += sizeof(HEADER);
  744. length += sizeof(INFO);
  745. length += gSkyCount * sizeof(pskyoff[0]);
  746. length += numsectors * sizeof(SECTOR);
  747. for (i = 0; i < numsectors; i++)
  748. {
  749. if (sector[i].extra > 0)
  750. length += sizeof(XSECTOR);
  751. }
  752. length += numwalls * sizeof(WALL);
  753. for (i = 0; i < numwalls; i++)
  754. {
  755. if (wall[i].extra > 0)
  756. length += sizeof(XWALL);
  757. }
  758. for (i = 0; i < kMaxSprites; i++)
  759. {
  760. if (sprite[i].statnum < kMaxStatus)
  761. {
  762. numsprites++;
  763. if (sprite[i].extra > 0)
  764. length += sizeof(XSPRITE);
  765. }
  766. }
  767. length += numsprites * sizeof(SPRITE);
  768. length += 4; // CRC
  769. buffer = (BYTE *)Resource::Alloc(length);
  770. IOBuffer iob(buffer, length);
  771. memcpy(header.signature, kBloodMapSig, sizeof(header.signature));
  772. header.version = kBloodMapVersion;
  773. iob.Write(&header, sizeof(header));
  774. info.x = x;
  775. info.y = y;
  776. info.z = z;
  777. info.angle = angle;
  778. info.sector = nSector;
  779. info.pskybits = pskybits;
  780. info.visibility = visibility;
  781. info.songId = gSongId;
  782. info.parallax = parallaxtype;
  783. info.mapRevisions = gMapRev;
  784. info.numsectors = numsectors;
  785. info.numwalls = numwalls;
  786. info.numsprites = (short)numsprites;
  787. iob.Write(&info, sizeof(INFO));
  788. iob.Write(pskyoff, gSkyCount * sizeof(pskyoff[0]));
  789. for (i = 0; i < numsectors; i++)
  790. {
  791. iob.Write(&sector[i], sizeof(SECTOR));
  792. if (sector[i].extra > 0)
  793. iob.Write(&xsector[sector[i].extra], sizeof(XSECTOR));
  794. }
  795. for (i = 0; i < numwalls; i++)
  796. {
  797. iob.Write(&wall[i], sizeof(WALL));
  798. if (wall[i].extra > 0)
  799. iob.Write(&xwall[wall[i].extra], sizeof(XWALL));
  800. }
  801. for (i = 0; i < kMaxSprites; i++)
  802. {
  803. if (sprite[i].statnum < kMaxStatus)
  804. {
  805. iob.Write(&sprite[i], sizeof(SPRITE));
  806. if (sprite[i].extra > 0)
  807. iob.Write(&xsprite[sprite[i].extra], sizeof(XSPRITE));
  808. }
  809. }
  810. gMapCRC = CRC32(buffer, length - sizeof(gMapCRC));
  811. iob.Write(&gMapCRC, sizeof(gMapCRC));
  812. // backup the map file
  813. unlink(bakfilename);
  814. rename(filename, bakfilename);
  815. hFile = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IWUSR);
  816. if ( hFile == -1 )
  817. ThrowError("Error opening MAP file", ES_ERROR);
  818. if (write(hFile, buffer, length) != length)
  819. ThrowError("Error writing MAP file", ES_ERROR);
  820. close(hFile);
  821. Resource::Free(buffer);
  822. // make sure we don't leave a stale copy of the map on the heap
  823. char *p = strchr(filename, '.');
  824. if ( p != NULL)
  825. *p = '\0';
  826. gSysRes.AddExternalResource(filename, ".MAP", length);
  827. }