CONVDB3.CPP 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <stdarg.h>
  5. #include <dos.h>
  6. #include <io.h>
  7. #include <fcntl.h>
  8. #include "db.h"
  9. #include "getopt.h"
  10. #include "engine.h"
  11. #include "error.h"
  12. #include "misc.h"
  13. #include <memcheck.h>
  14. #define kBloodMapSig "BLM\x1A"
  15. #define kBloodMapVersion 0x0300
  16. struct FNODE
  17. {
  18. FNODE *next;
  19. char name[1];
  20. };
  21. FNODE head = { &head, "" };
  22. FNODE *tail = &head;
  23. SECTOR sector[kMaxSectors];
  24. XSECTOR xsector[kMaxXSectors];
  25. WALL wall[kMaxWalls];
  26. XWALL xwall[kMaxXWalls];
  27. SPRITE sprite[kMaxSprites];
  28. XSPRITE xsprite[kMaxXSprites];
  29. uchar spriteSurf[kMaxSprites];
  30. uchar wallSurf[kMaxWalls];
  31. uchar floorSurf[kMaxSectors];
  32. uchar ceilingSurf[kMaxSectors];
  33. short pskyoff[kMaxSkyTiles];
  34. short pskybits;
  35. char gMapAuthor[64] = "";
  36. char gMapName[64] = "";
  37. ulong gMapCRC;
  38. int gSkyCount;
  39. short numsectors, numwalls;
  40. struct IOBuffer
  41. {
  42. int remain;
  43. char *p;
  44. IOBuffer( char *buffer, int l ) : p(buffer), remain(l) {};
  45. void Read(void *, int, int);
  46. void Write(void *, int, int);
  47. };
  48. void IOBuffer::Read(void *s, int size, int nError)
  49. {
  50. if (size <= remain)
  51. {
  52. memcpy(s, p, size);
  53. remain -= size;
  54. p += size;
  55. }
  56. else
  57. ThrowError("IOB", nError, "Read buffer overflow", ES_ERROR);
  58. }
  59. void IOBuffer::Write(void *s, int size, int nError)
  60. {
  61. if (size <= remain)
  62. {
  63. memcpy(p, s, size);
  64. remain -= size;
  65. p += size;
  66. }
  67. else
  68. ThrowError("IOB", nError, "Write buffer overflow", ES_ERROR);
  69. }
  70. struct OLDHEADER
  71. {
  72. long version;
  73. long x, y, z;
  74. short angle;
  75. short sectnum;
  76. };
  77. struct MPXHEADER
  78. {
  79. char signature[4];
  80. short version;
  81. short dummy;
  82. };
  83. struct HEADER
  84. {
  85. char signature[4];
  86. short version;
  87. };
  88. // version 2.x header
  89. struct INFO2
  90. {
  91. short xspriteSize;
  92. short xwallSize;
  93. short xsectorSize;
  94. char visibility;
  95. short xspriteCount;
  96. short xwallCount;
  97. short xsectorCount;
  98. short pskybits;
  99. char lenAuthor;
  100. char lenName;
  101. };
  102. // version 3.x header
  103. struct INFO3
  104. {
  105. long x, y, z;
  106. ushort angle;
  107. ushort sector;
  108. ushort pskybits;
  109. uchar visibility;
  110. int songId;
  111. uchar parallax;
  112. int mapRevisions;
  113. uchar lenName;
  114. uchar lenAuthor;
  115. ushort numsectors;
  116. ushort numwalls;
  117. ushort numsprites;
  118. };
  119. struct XSPRITE2
  120. {
  121. signed reference : 16;
  122. unsigned rxID : 10;
  123. unsigned difficulty : 2;
  124. unsigned detail : 2;
  125. unsigned map : 2;
  126. unsigned txID : 10;
  127. unsigned key : 3;
  128. unsigned command : 3;
  129. unsigned type : 10;
  130. unsigned state: 1;
  131. unsigned triggerOn : 1;
  132. unsigned triggerOff : 1;
  133. unsigned triggerOnce : 1;
  134. unsigned view : 2; // changed to : 3
  135. unsigned soundKit : 8;
  136. unsigned data : 16;
  137. };
  138. struct XWALL2
  139. {
  140. signed reference : 16;
  141. unsigned rxID : 10;
  142. unsigned surfType : 6;
  143. unsigned txID : 10;
  144. unsigned key : 3;
  145. unsigned command : 3;
  146. unsigned type : 10;
  147. unsigned map : 2;
  148. unsigned state: 1;
  149. unsigned triggerOn : 1;
  150. unsigned triggerOff : 1;
  151. unsigned data : 16;
  152. };
  153. struct XSECTOR2
  154. {
  155. signed reference : 16;
  156. unsigned rxID : 10;
  157. unsigned command : 3;
  158. unsigned triggerOn : 1;
  159. unsigned triggerOff : 1;
  160. unsigned triggerOnce : 1;
  161. signed ceilingShade0 : 8; // deleted
  162. signed floorShade0 : 8; // deleted
  163. signed amplitude : 8;
  164. unsigned freq : 8;
  165. unsigned wave : 8;
  166. unsigned phase : 8;
  167. unsigned state: 1;
  168. unsigned shadeFloor : 1;
  169. unsigned shadeCeiling : 1;
  170. unsigned shadeWalls : 1;
  171. unsigned panFloor : 1;
  172. unsigned panCeiling : 1;
  173. unsigned panDrag : 1;
  174. unsigned panWalls : 1;
  175. unsigned panAngle : 12;
  176. signed panSpeed : 8;
  177. signed shade : 8;
  178. unsigned surfType : 6; // deleted
  179. unsigned ceilSurf : 6;
  180. unsigned floorSurf : 6;
  181. unsigned txID : 10;
  182. unsigned key : 3;
  183. unsigned type : 10;
  184. unsigned underwater : 1;
  185. unsigned data : 16;
  186. };
  187. void ShowUsage(void)
  188. {
  189. printf("Usage:\n");
  190. printf(" CONVDB3 map1 map2 (wild cards ok)\n");
  191. printf("\nTECHNICAL INFO:\n sizeof(XSPRITE)=%d\n sizeof(XSECTOR)=%d\n sizeof(XWALL)=%d",
  192. sizeof(XSPRITE), sizeof(XSECTOR), sizeof(XWALL));
  193. exit(0);
  194. }
  195. void QuitMessage(char * fmt, ...)
  196. {
  197. char msg[80];
  198. va_list argptr;
  199. va_start( argptr, fmt );
  200. vsprintf( msg, fmt, argptr );
  201. va_end(argptr);
  202. printf(msg);
  203. exit(1);
  204. }
  205. void ProcessFile(char *filespec)
  206. {
  207. int hFile;
  208. int i;
  209. OLDHEADER oldHeader;
  210. MPXHEADER mpxheader;
  211. HEADER header;
  212. INFO2 info2;
  213. INFO3 info3;
  214. char filename[_MAX_PATH], bakfilename[_MAX_PATH];
  215. int x, y, z;
  216. short angle, nSector, numsprites;
  217. int length;
  218. char *buffer;
  219. strcpy(filename, filespec);
  220. printf("%s ", filename);
  221. hFile = open(filename, O_RDONLY | O_BINARY);
  222. if ( hFile == -1 )
  223. ThrowError( "MPX", 0, "unable to open MAP file", ES_ERROR);
  224. length = filelength(hFile);
  225. buffer = (char *)malloc(length);
  226. if (read(hFile, buffer, length) == length)
  227. {
  228. close(hFile);
  229. IOBuffer iob(buffer, length);
  230. iob.Read(&oldHeader, sizeof(OLDHEADER), 1);
  231. if (oldHeader.version != 6)
  232. {
  233. printf("not old format, skipping\n");
  234. return;
  235. }
  236. x = oldHeader.x;
  237. y = oldHeader.y;
  238. z = oldHeader.z;
  239. angle = oldHeader.angle;
  240. nSector = oldHeader.sectnum;
  241. iob.Read(&numsectors, sizeof(numsectors), 2);
  242. iob.Read(&sector[0], sizeof(SECTOR) * numsectors, 3);
  243. iob.Read(&numwalls, sizeof(numwalls), 4);
  244. iob.Read(&wall[0], sizeof(WALL) * numwalls, 5);
  245. iob.Read(&numsprites, sizeof(numsprites), 6);
  246. iob.Read(&sprite[0], sizeof(SPRITE) * numsprites, 7);
  247. }
  248. else
  249. ThrowError( "DB", 8, "Error reading map file", ES_ERROR);
  250. free(buffer);
  251. ChangeExtension(filename, "MPX");
  252. printf("%s ", filename);
  253. hFile = open(filename, O_RDONLY | O_BINARY);
  254. if ( hFile == -1 )
  255. ThrowError( "MPX", 9, "unable to open MPX file", ES_ERROR);
  256. length = filelength(hFile);
  257. buffer = (char *)malloc(length);
  258. if (read(hFile, buffer, length) == length)
  259. {
  260. close(hFile);
  261. IOBuffer iob(buffer, length);
  262. iob.Read(&mpxheader, sizeof(MPXHEADER), 10);
  263. if (memcmp(mpxheader.signature, "MPX\x1A", 4) != 0)
  264. {
  265. close(hFile);
  266. ThrowError( "MPX", 11, "MPX file corrupted", ES_ERROR);
  267. }
  268. if ( (mpxheader.version >> 8) != 2)
  269. ThrowError("MPX", 12, "Incorrect MPX version encounted.", ES_ERROR);
  270. iob.Read(&info2, sizeof(INFO2), 13);
  271. for (i = 0; i < info2.xspriteCount; i++)
  272. {
  273. XSPRITE2 xsprite2;
  274. iob.Read(&xsprite2, sizeof(XSPRITE2), 14);
  275. memset(&xsprite[i], 0, sizeof(XSPRITE));
  276. xsprite[i].reference = xsprite2.reference;
  277. xsprite[i].rxID = xsprite2.rxID;
  278. xsprite[i].difficulty = xsprite2.difficulty;
  279. xsprite[i].detail = xsprite2.detail;
  280. xsprite[i].map = xsprite2.map;
  281. xsprite[i].txID = xsprite2.txID;
  282. xsprite[i].key = xsprite2.key;
  283. xsprite[i].command = xsprite2.command;
  284. xsprite[i].type = xsprite2.type;
  285. xsprite[i].state = xsprite2.state;
  286. xsprite[i].triggerOn = xsprite2.triggerOn;
  287. xsprite[i].triggerOff = xsprite2.triggerOff;
  288. xsprite[i].triggerOnce = xsprite2.triggerOnce;
  289. xsprite[i].view = xsprite2.view;
  290. xsprite[i].soundKit = xsprite2.soundKit;
  291. xsprite[i].data = xsprite2.data;
  292. }
  293. for (i = 0; i < info2.xwallCount; i++)
  294. {
  295. XWALL2 xwall2;
  296. iob.Read(&xwall2, sizeof(XWALL2), 15);
  297. memset(&xwall[i], 0, sizeof(XWALL));
  298. xwall[i].reference = xwall2.reference;
  299. xwall[i].rxID = xwall2.rxID;
  300. xwall[i].txID = xwall2.txID;
  301. xwall[i].key = xwall2.key;
  302. xwall[i].command = xwall2.command;
  303. xwall[i].type = xwall2.type;
  304. xwall[i].map = xwall2.map;
  305. xwall[i].state = xwall2.state;
  306. xwall[i].triggerOn = xwall2.triggerOn;
  307. xwall[i].triggerOff = xwall2.triggerOff;
  308. xwall[i].data = xwall2.data;
  309. }
  310. for (i = 0; i < info2.xsectorCount; i++)
  311. {
  312. XSECTOR2 xsector2;
  313. iob.Read(&xsector2, sizeof(XSECTOR2), 16);
  314. memset(&xsector[i], 0, sizeof(XSECTOR));
  315. xsector[i].reference = xsector2.reference;
  316. xsector[i].rxID = xsector2.rxID;
  317. xsector[i].command = xsector2.command;
  318. xsector[i].triggerOn = xsector2.triggerOn;
  319. xsector[i].triggerOff = xsector2.triggerOff;
  320. xsector[i].triggerOnce = xsector2.triggerOnce;
  321. xsector[i].amplitude = xsector2.amplitude ;
  322. xsector[i].freq = xsector2.freq;
  323. xsector[i].wave = xsector2.wave;
  324. xsector[i].phase = xsector2.phase;
  325. xsector[i].state = xsector2.state;
  326. xsector[i].shadeFloor = xsector2.shadeFloor;
  327. xsector[i].shadeCeiling = xsector2.shadeCeiling;
  328. xsector[i].shadeWalls = xsector2.shadeWalls;
  329. xsector[i].panFloor = xsector2.panFloor;
  330. xsector[i].panCeiling = xsector2.panCeiling;
  331. xsector[i].panDrag = xsector2.panDrag;
  332. xsector[i].panAngle = xsector2.panAngle;
  333. xsector[i].panVel = xsector2.panSpeed;
  334. xsector[i].shade = xsector2.shade ;
  335. xsector[i].txID = xsector2.txID;
  336. xsector[i].key = xsector2.key;
  337. xsector[i].type = xsector2.type;
  338. xsector[i].underwater = xsector2.underwater;
  339. xsector[i].data = xsector2.data;
  340. }
  341. pskybits = info2.pskybits;
  342. gSkyCount = 1 << pskybits;
  343. iob.Read(pskyoff, gSkyCount * sizeof(pskyoff[0]), 17);
  344. iob.Read(gMapAuthor, info2.lenAuthor + 1, 18);
  345. iob.Read(gMapName, info2.lenName + 1, 19);
  346. }
  347. else
  348. ThrowError( "DB", 20, "Error reading MPX file", ES_ERROR);
  349. free(buffer);
  350. // remove sectors with a state of OFF
  351. for (i = 0; i < numsectors; i++)
  352. {
  353. if (sector[i].extra != -1)
  354. {
  355. if (!xsector[sector[i].extra].state)
  356. sector[i].extra = -1;
  357. }
  358. }
  359. // modify new hitscan bit for face,wall,floor sprites
  360. for (i = 0; i < numsprites; i++)
  361. {
  362. // skip invalid sprites
  363. if (sprite[i].statnum >= kMaxStatus)
  364. continue;
  365. // process valid sprites
  366. if (sprite[i].cstat & kSpriteBlocking) {
  367. if ((sprite[i].cstat & kSpriteRMask) == 0) {
  368. // set hitscan for all blocking face sprites
  369. sprite[i].cstat |= kSpriteHitscan;
  370. } else {
  371. // clear hitscan for all blocking wall and floor sprites
  372. // game should re-set these if they are switches
  373. sprite[i].cstat &= ~kSpriteHitscan;
  374. }
  375. }
  376. }
  377. // add up all the elements in the file to determine the size of the buffer
  378. length = 0;
  379. length += sizeof(HEADER);
  380. length += sizeof(INFO3);
  381. length += strlen(gMapName) + 1;
  382. length += strlen(gMapAuthor) + 1;
  383. length += gSkyCount * sizeof(pskyoff[0]);
  384. length += numsectors * sizeof(SECTOR);
  385. length += numsectors * sizeof(ceilingSurf[0]);
  386. length += numsectors * sizeof(floorSurf[0]);
  387. for (i = 0; i < numsectors; i++)
  388. {
  389. if (sector[i].extra > 0)
  390. length += sizeof(XSECTOR);
  391. }
  392. length += numwalls * sizeof(WALL);
  393. length += numwalls * sizeof(wallSurf[0]);
  394. for (i = 0; i < numwalls; i++)
  395. {
  396. if (wall[i].extra > 0)
  397. length += sizeof(XWALL);
  398. }
  399. for (i = 0; i < numsprites; i++)
  400. {
  401. if (sprite[i].extra > 0)
  402. length += sizeof(XSPRITE);
  403. }
  404. length += numsprites * sizeof(SPRITE);
  405. length += numsprites * sizeof(spriteSurf[0]);
  406. length += 4; // CRC
  407. buffer = (char *)malloc(length);
  408. IOBuffer iob(buffer, length);
  409. memcpy(header.signature, kBloodMapSig, 4);
  410. header.version = kBloodMapVersion;
  411. iob.Write(&header, sizeof(header), 1);
  412. info3.x = oldHeader.x;
  413. info3.y = oldHeader.y;
  414. info3.z = oldHeader.z;
  415. info3.angle = oldHeader.angle;
  416. info3.sector = oldHeader.sectnum;
  417. info3.pskybits = pskybits;
  418. info3.visibility = info2.visibility;
  419. info3.songId = 0;
  420. info3.parallax = 0;
  421. info3.mapRevisions = 0;
  422. info3.lenName = (char)strlen(gMapName);
  423. info3.lenAuthor = (char)strlen(gMapAuthor);
  424. info3.numsectors = numsectors;
  425. info3.numwalls = numwalls;
  426. info3.numsprites = (short)numsprites;
  427. iob.Write(&info3, sizeof(INFO3), 2);
  428. iob.Write(gMapName, info3.lenName + 1, 3);
  429. iob.Write(gMapAuthor, info3.lenAuthor + 1, 4);
  430. iob.Write(pskyoff, gSkyCount * sizeof(pskyoff[0]), 5);
  431. for (i = 0; i < numsectors; i++)
  432. {
  433. iob.Write(&sector[i], sizeof(SECTOR), 6);
  434. iob.Write(&ceilingSurf[i], sizeof(ceilingSurf[i]), 7);
  435. iob.Write(&floorSurf[i], sizeof(floorSurf[i]), 8);
  436. if (sector[i].extra > 0)
  437. iob.Write(&xsector[sector[i].extra], sizeof(XSECTOR), 9);
  438. }
  439. for (i = 0; i < numwalls; i++)
  440. {
  441. iob.Write(&wall[i], sizeof(WALL), 10);
  442. iob.Write(&wallSurf[i], sizeof(wallSurf[i]), 11);
  443. if (wall[i].extra > 0)
  444. iob.Write(&xwall[wall[i].extra], sizeof(XWALL), 12);
  445. }
  446. for (i = 0; i < numsprites; i++)
  447. {
  448. iob.Write(&sprite[i], sizeof(SPRITE), 13);
  449. iob.Write(&spriteSurf[i], sizeof(spriteSurf[i]), 14);
  450. if (sprite[i].extra > 0)
  451. iob.Write(&xsprite[sprite[i].extra], sizeof(XSPRITE), 15);
  452. }
  453. gMapCRC = CRC32(buffer, length - sizeof(gMapCRC));
  454. iob.Write(&gMapCRC, sizeof(gMapCRC), 16);
  455. // backup the map file
  456. strcpy(bakfilename, filename);
  457. ChangeExtension(filename, "MAP");
  458. ChangeExtension(bakfilename, "~AK");
  459. rename(filename, bakfilename);
  460. ChangeExtension(filename, "MPX");
  461. ChangeExtension(bakfilename, "~PX");
  462. rename(filename, bakfilename);
  463. ChangeExtension(filename, "MAP");
  464. printf("=> %s ", filename);
  465. hFile = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IWUSR);
  466. if ( hFile == -1 )
  467. ThrowError( "DB", 0, "Error opening MAP file", ES_ERROR);
  468. if (write(hFile, buffer, length) != length)
  469. ThrowError( "DB", 1, "Error write MAP file", ES_ERROR);
  470. close(hFile);
  471. free(buffer);
  472. printf("OK.\n");
  473. }
  474. void InsertFilename( char *fname )
  475. {
  476. FNODE *n = (FNODE *)malloc(sizeof(FNODE) + strlen(fname));
  477. strcpy(n->name, fname);
  478. // insert the node at the tail, so it stays in order
  479. n->next = tail->next;
  480. tail->next = n;
  481. tail = n;
  482. }
  483. void ProcessArgument(char *s)
  484. {
  485. char filespec[_MAX_PATH];
  486. char buffer[_MAX_PATH2];
  487. char path[_MAX_PATH];
  488. strcpy(filespec, s);
  489. ChangeExtension(filespec, ".MAP");
  490. char *drive, *dir;
  491. // separate the path from the filespec
  492. _splitpath2(s, buffer, &drive, &dir, NULL, NULL);
  493. _makepath(path, drive, dir, NULL, NULL);
  494. struct find_t fileinfo;
  495. unsigned r = _dos_findfirst(s, _A_NORMAL, &fileinfo);
  496. if (r != 0)
  497. printf("%s not found\n", s);
  498. while ( r == 0 )
  499. {
  500. strcpy(filespec, path);
  501. strcat(filespec, fileinfo.name);
  502. InsertFilename(filespec);
  503. r = _dos_findnext( &fileinfo );
  504. }
  505. _dos_findclose(&fileinfo);
  506. }
  507. /***********************************************************************
  508. * Process command line arguments
  509. **********************************************************************/
  510. void ParseOptions( int argc, char *argv[])
  511. {
  512. int c;
  513. while ( (c = GetOptions(argc, argv, "")) != GO_EOF ) {
  514. switch (c) {
  515. case GO_INVALID:
  516. QuitMessage("Invalid argument: %s", OptArgument);
  517. case GO_FULL:
  518. ProcessArgument(OptArgument);
  519. break;
  520. }
  521. }
  522. }
  523. void main(int argc, char *argv[])
  524. {
  525. printf("Blood Map 3 Converter Copyright (c) 1995 Q Studios Corporation\n");
  526. if (argc < 2) ShowUsage();
  527. ParseOptions(argc, argv);
  528. // process the file list
  529. for (FNODE *n = head.next; n != &head; n = n->next)
  530. ProcessFile(n->name);
  531. }