CONVDB5.CPP 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  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 "iob.h"
  14. #include "tile.h"
  15. #include <memcheck.h>
  16. #define kBloodMapSig "BLM\x1A"
  17. #define kBloodMapVersion 0x0501
  18. #define kBloodMapOldVersion 0x0401
  19. struct FNODE
  20. {
  21. FNODE *next;
  22. char name[1];
  23. };
  24. FNODE head = { &head, "" };
  25. FNODE *tail = &head;
  26. // Build globals
  27. SECTOR sector[kMaxSectors];
  28. WALL wall[kMaxWalls];
  29. SPRITE sprite[kMaxSprites];
  30. // Q globals
  31. XSECTOR xsector[kMaxXSectors];
  32. XWALL xwall[kMaxXWalls];
  33. XSPRITE xsprite[kMaxXSprites];
  34. short pskyoff[kMaxSkyTiles];
  35. PICANM picanm[kMaxTiles];
  36. uchar picsiz[kMaxTiles];
  37. short tilesizx[kMaxTiles];
  38. short tilesizy[kMaxTiles];
  39. short pskybits;
  40. ulong gMapCRC;
  41. int gSkyCount;
  42. short numsectors, numwalls;
  43. struct HEADER4
  44. {
  45. char signature[4];
  46. short version;
  47. };
  48. struct HEADER5
  49. {
  50. char signature[4];
  51. short version;
  52. };
  53. // version 4.x header
  54. struct INFO4
  55. {
  56. long x, y, z;
  57. ushort angle;
  58. ushort sector;
  59. ushort pskybits;
  60. long visibility;
  61. int songId;
  62. uchar parallax;
  63. int mapRevisions;
  64. uchar lenName;
  65. uchar lenAuthor;
  66. ushort numsectors;
  67. ushort numwalls;
  68. ushort numsprites;
  69. };
  70. struct INFO5
  71. {
  72. long x, y, z;
  73. ushort angle;
  74. ushort sector;
  75. ushort pskybits;
  76. long visibility;
  77. int songId;
  78. uchar parallax;
  79. int mapRevisions;
  80. ushort numsectors;
  81. ushort numwalls;
  82. ushort numsprites;
  83. };
  84. /***********************************************************************
  85. * Old version structures and typedefs
  86. **********************************************************************/
  87. struct XSPRITE4
  88. {
  89. signed reference : 16;
  90. unsigned state : 1;
  91. // trigger data
  92. unsigned busy : 17;
  93. unsigned type : 10;
  94. signed data : 16;
  95. unsigned txID : 10;
  96. unsigned rxID : 10;
  97. unsigned command : 3;
  98. unsigned triggerOn : 1;
  99. unsigned triggerOff : 1;
  100. unsigned triggerOnce : 1;
  101. unsigned restState : 1; // state to return to on callback
  102. unsigned key : 3;
  103. unsigned difficulty : 2;
  104. unsigned detail : 2;
  105. unsigned map : 2;
  106. unsigned view : 4; // OBSOLETE
  107. unsigned soundKit : 8;
  108. unsigned isTriggered : 1; // used for triggerOnce objects
  109. unsigned triggerPush : 1; // gates?
  110. unsigned triggerImpact : 1; // vector hits
  111. unsigned triggerPickup : 1; // secrets
  112. unsigned triggerTouch : 1; // sawblades, spikes, zaps?
  113. unsigned triggerSight : 1; // dunno, yet.
  114. unsigned triggerProximity : 1; // proximity bombs
  115. unsigned decoupled : 1;
  116. unsigned waitTime : 8;
  117. unsigned permanent : 1; // 0=not permanent, 1=permanent (respawn ignored)
  118. unsigned respawn : 2; // 0=never, 1=always, 2=optional never, 3=optional always
  119. unsigned respawnTime : 8; // 0=instant, >0=time in tenths of a second,
  120. unsigned launchMode : 2; // 0=all, 1=bloodbath, 2=ally, 3=ally&bloodbath,
  121. unsigned pad1 : 32;
  122. unsigned pad2 : 32;
  123. };
  124. struct XWALL4
  125. {
  126. signed reference : 16;
  127. unsigned state : 1;
  128. unsigned map : 2;
  129. // trigger data
  130. unsigned busy : 17;
  131. unsigned type : 10;
  132. signed data : 16;
  133. unsigned txID : 10;
  134. unsigned rxID : 10;
  135. unsigned command : 3;
  136. unsigned triggerOn : 1;
  137. unsigned triggerOff : 1;
  138. unsigned triggerOnce : 1;
  139. unsigned key : 3;
  140. // panning data
  141. signed panXVel : 8;
  142. signed panYVel : 8;
  143. unsigned isTriggered : 1; // used for triggerOnce objects
  144. unsigned triggerPush : 1;
  145. unsigned triggerImpact : 1;
  146. unsigned triggerRsvd1 : 1;
  147. unsigned triggerRsvd2 : 1;
  148. unsigned decoupled : 1;
  149. unsigned panAlways : 1;
  150. unsigned restState : 1; // state to return to on callback
  151. unsigned waitTime : 8; // delay before callback
  152. unsigned pad1 : 32;
  153. unsigned pad2 : 32;
  154. };
  155. struct XSECTOR4
  156. {
  157. signed reference : 16;
  158. unsigned state : 1;
  159. // trigger data
  160. unsigned busy : 17;
  161. unsigned type : 10;
  162. signed data : 16;
  163. unsigned txID : 10;
  164. unsigned rxID : 10;
  165. unsigned command : 3;
  166. unsigned triggerOn : 1;
  167. unsigned triggerOff : 1;
  168. unsigned triggerOnce : 1;
  169. unsigned restState : 1;
  170. unsigned key : 3;
  171. // lighting data
  172. signed amplitude : 8;
  173. unsigned freq : 8;
  174. unsigned wave : 4;
  175. unsigned shadeAlways : 1;
  176. unsigned phase : 8;
  177. unsigned shadeFloor : 1;
  178. unsigned shadeCeiling : 1;
  179. unsigned shadeWalls : 1;
  180. signed shade : 8;
  181. // panning data
  182. unsigned panFloor : 1;
  183. unsigned panCeiling : 1;
  184. unsigned panDrag : 1;
  185. unsigned waitTime : 8; // delay before callback
  186. unsigned panAlways : 1;
  187. unsigned busyTime : 8; // time to reach next state
  188. // wind/water stuff
  189. unsigned underwater : 1;
  190. unsigned depth : 2;
  191. unsigned panVel : 8;
  192. unsigned panAngle : 11;
  193. unsigned wind : 1;
  194. unsigned isTriggered : 1;
  195. unsigned triggerPush : 1;
  196. unsigned triggerImpact : 1;
  197. unsigned triggerEnter : 1;
  198. unsigned triggerExit : 1;
  199. unsigned decoupled : 1;
  200. unsigned triggerWPush : 1;
  201. signed offCeilZ : 32;
  202. signed onCeilZ : 32;
  203. signed offFloorZ : 32;
  204. signed onFloorZ : 32;
  205. unsigned pad1 : 32;
  206. unsigned pad2 : 32;
  207. };
  208. // stuff to get tile sizes from art
  209. static void CalcPicsiz( int nTile, int x, int y )
  210. {
  211. int i;
  212. uchar n = 0;
  213. for (i = 2; i <= x; i <<= 1)
  214. n += 0x01;
  215. for (i = 2; i <= y; i <<= 1)
  216. n += 0x10;
  217. picsiz[nTile] = n;
  218. }
  219. void artInit( void )
  220. {
  221. char filename[20];
  222. int i;
  223. int nTiles;
  224. int nFile, hFile;
  225. int tileStart, tileEnd;
  226. long artversion;
  227. long numtiles;
  228. memset(tilesizx, 0, sizeof(tilesizx));
  229. memset(tilesizy, 0, sizeof(tilesizy));
  230. memset(picanm, 0, sizeof(picanm));
  231. nFile = 0;
  232. while (1)
  233. {
  234. sprintf(filename, "TILES%03i.ART", nFile);
  235. hFile = open(filename, O_BINARY | O_RDWR);
  236. if ( hFile == -1 )
  237. break;
  238. read(hFile, &artversion, sizeof(artversion));
  239. if (artversion != 1)
  240. ThrowError("Bad art file", ES_ERROR);
  241. read(hFile, &numtiles, sizeof(numtiles));
  242. read(hFile, &tileStart, sizeof(tileStart));
  243. read(hFile, &tileEnd, sizeof(tileEnd));
  244. nTiles = tileEnd - tileStart + 1;
  245. read(hFile, &tilesizx[tileStart], nTiles * sizeof(tilesizx[0]));
  246. read(hFile, &tilesizy[tileStart], nTiles * sizeof(tilesizy[0]));
  247. read(hFile, &picanm[tileStart], nTiles * sizeof(picanm[0]));
  248. nFile++;
  249. }
  250. for (i = 0; i < kMaxTiles; i++)
  251. {
  252. // setup the tile size log 2 array for internal engine use
  253. CalcPicsiz(i, tilesizx[i], tilesizy[i]);
  254. }
  255. }
  256. void ShowUsage(void)
  257. {
  258. printf("Usage:\n");
  259. printf(" CONVDB4 map1 map2 (wild cards ok)\n");
  260. printf("\nTECHNICAL INFO:\n sizeof(XSPRITE)=%d\n sizeof(XSECTOR)=%d\n sizeof(XWALL)=%d",
  261. sizeof(XSPRITE), sizeof(XSECTOR), sizeof(XWALL));
  262. exit(0);
  263. }
  264. void QuitMessage(char * fmt, ...)
  265. {
  266. char msg[80];
  267. va_list argptr;
  268. va_start( argptr, fmt );
  269. vsprintf( msg, fmt, argptr );
  270. va_end(argptr);
  271. printf(msg);
  272. exit(1);
  273. }
  274. void ProcessFile(char *filespec)
  275. {
  276. int hFile;
  277. int i;
  278. HEADER4 header4;
  279. HEADER5 header5;
  280. INFO4 info4;
  281. INFO5 info5;
  282. char filename[_MAX_PATH], bakfilename[_MAX_PATH];
  283. short numsprites;
  284. int length;
  285. BYTE *buffer;
  286. strcpy(filename, filespec);
  287. ChangeExtension(filename, ".MAP");
  288. printf("%s ", filename);
  289. hFile = open(filename, O_RDONLY | O_BINARY);
  290. if ( hFile == -1 )
  291. ThrowError("unable to open MAP file", ES_ERROR);
  292. length = filelength(hFile);
  293. buffer = (BYTE *)malloc(length);
  294. if (read(hFile, buffer, length) == length)
  295. {
  296. close(hFile);
  297. IOBuffer iob(buffer, length);
  298. iob.Read(&header4, sizeof(HEADER4));
  299. // check signature and major version number
  300. if ( (memcmp(header4.signature, kBloodMapSig, sizeof(header4.signature)) != 0)
  301. || ((header4.version >> 8) != (kBloodMapOldVersion >> 8)) )
  302. {
  303. printf("not expected format, skipping\n");
  304. return;
  305. }
  306. iob.Read(&info4, sizeof(INFO4));
  307. numsectors = info4.numsectors;
  308. numwalls = info4.numwalls;
  309. numsprites = info4.numsprites;
  310. iob.Skip(info4.lenName + 1);
  311. iob.Skip(info4.lenAuthor + 1);
  312. pskybits = info4.pskybits;
  313. gSkyCount = 1 << pskybits;
  314. iob.Read(pskyoff, gSkyCount * sizeof(pskyoff[0]));
  315. for (i = 0; i < numsectors; i++)
  316. {
  317. iob.Read(&sector[i], sizeof(SECTOR));
  318. iob.Skip(sizeof(BYTE)); // old surface data
  319. iob.Skip(sizeof(BYTE)); // old surface data
  320. if (sector[i].extra > 0)
  321. {
  322. int j = sector[i].extra;
  323. XSECTOR4 xsector4;
  324. iob.Read(&xsector4, sizeof(XSECTOR4));
  325. memset(&xsector[j], 0, sizeof(XSECTOR));
  326. xsector[j].reference = xsector4.reference;
  327. xsector[j].state = xsector4.state;
  328. // trigger data
  329. xsector[j].busy = 0;
  330. xsector[j].data = xsector4.data;
  331. xsector[j].txID = xsector4.txID;
  332. xsector[j].rxID = xsector4.rxID;
  333. xsector[j].command = xsector4.command;
  334. xsector[j].triggerOn = xsector4.triggerOn;
  335. xsector[j].triggerOff = xsector4.triggerOff;
  336. xsector[j].busyTime = xsector4.busyTime;
  337. xsector[j].waitTime = xsector4.waitTime;
  338. xsector[j].restState = xsector4.restState;
  339. // lighting data
  340. xsector[j].amplitude = xsector4.amplitude;
  341. xsector[j].freq = xsector4.freq;
  342. xsector[j].wave = xsector4.wave;
  343. xsector[j].shadeAlways = xsector4.shadeAlways;
  344. xsector[j].phase = xsector4.phase;
  345. xsector[j].shadeFloor = xsector4.shadeFloor;
  346. xsector[j].shadeCeiling = xsector4.shadeCeiling;
  347. xsector[j].shadeWalls = xsector4.shadeWalls;
  348. xsector[j].shade = xsector4.shade;
  349. // panning data
  350. xsector[j].panFloor = xsector4.panFloor;
  351. xsector[j].panCeiling = xsector4.panCeiling;
  352. xsector[j].panDrag = xsector4.panDrag;
  353. xsector[j].panAlways = xsector4.panAlways;
  354. // wind/water stuff
  355. xsector[j].underwater = xsector4.underwater;
  356. xsector[j].depth = xsector4.depth;
  357. xsector[j].panVel = xsector4.panVel;
  358. xsector[j].panAngle = xsector4.panAngle;
  359. xsector[j].wind = xsector4.wind;
  360. // physical triggers
  361. xsector[j].decoupled = xsector4.decoupled;
  362. xsector[j].triggerOnce = xsector4.triggerOnce;
  363. xsector[j].isTriggered = 0;
  364. xsector[j].key = xsector4.key;
  365. xsector[j].triggerPush = xsector4.triggerPush;
  366. xsector[j].triggerImpact = xsector4.triggerImpact;
  367. xsector[j].triggerExplode = 0;
  368. xsector[j].triggerEnter = xsector4.triggerEnter;
  369. xsector[j].triggerExit = xsector4.triggerExit;
  370. xsector[j].triggerWPush = xsector4.triggerWPush;
  371. xsector[j].triggerReserved1 = 0;
  372. xsector[j].triggerReserved2 = 0;
  373. // movement data
  374. xsector[j].offCeilZ = xsector4.offCeilZ;
  375. xsector[j].onCeilZ = xsector4.onCeilZ;
  376. xsector[j].offFloorZ = xsector4.offFloorZ;
  377. xsector[j].onFloorZ = xsector4.onFloorZ;
  378. xsector[j].marker0 = sector[i].type; // former lotag
  379. xsector[j].marker1 = sector[i].hitag;
  380. sector[i].type = (ushort)xsector4.type;
  381. }
  382. }
  383. for (i = 0; i < numwalls; i++)
  384. {
  385. iob.Read(&wall[i], sizeof(WALL));
  386. iob.Skip(sizeof(BYTE)); // old surface data
  387. if (wall[i].extra > 0)
  388. {
  389. int j = wall[i].extra;
  390. XWALL4 xwall4;
  391. iob.Read(&xwall4, sizeof(XWALL4));
  392. memset(&xwall[j], 0, sizeof(XWALL));
  393. xwall[j].reference = xwall4.reference;
  394. xwall[j].state = xwall4.state;
  395. // trigger data
  396. xwall[j].busy = xwall4.busy;
  397. xwall[j].data = xwall4.data;
  398. xwall[j].txID = xwall4.txID;
  399. xwall[j].rxID = xwall4.rxID;
  400. xwall[j].command = xwall4.command;
  401. xwall[j].triggerOn = xwall4.triggerOn;
  402. xwall[j].triggerOff = xwall4.triggerOff;
  403. xwall[j].busyTime = 0;
  404. xwall[j].waitTime = xwall4.waitTime;
  405. xwall[j].restState = xwall4.restState;
  406. xwall[j].map = xwall4.map;
  407. // panning data
  408. xwall[j].panAlways = xwall4.panAlways;
  409. xwall[j].panXVel = xwall4.panXVel;
  410. xwall[j].panYVel = xwall4.panYVel;
  411. // physical triggers
  412. xwall[j].decoupled = xwall4.decoupled;
  413. xwall[j].triggerOnce = xwall4.triggerOnce;
  414. xwall[j].isTriggered = xwall4.isTriggered;
  415. xwall[j].key = xwall4.key;
  416. xwall[j].triggerPush = xwall4.triggerPush;
  417. xwall[j].triggerImpact = xwall4.triggerImpact;
  418. xwall[j].triggerExplode = 0;
  419. wall[i].type = (ushort)xwall4.type;
  420. }
  421. }
  422. for (i = 0; i < numsprites; i++)
  423. {
  424. iob.Read(&sprite[i], sizeof(SPRITE));
  425. iob.Skip(sizeof(BYTE)); // old surface data
  426. if (sprite[i].extra > 0)
  427. {
  428. int j = sprite[i].extra;
  429. XSPRITE4 xsprite4;
  430. iob.Read(&xsprite4, sizeof(XSPRITE4));
  431. memset(&xsprite[j], 0, sizeof(XSPRITE));
  432. xsprite[j].reference = xsprite4.reference;
  433. xsprite[j].state = xsprite4.state;
  434. // trigger data
  435. xsprite[j].busy = 0;
  436. xsprite[j].txID = xsprite4.txID;
  437. xsprite[j].rxID = xsprite4.rxID;
  438. xsprite[j].command = xsprite4.command;
  439. xsprite[j].triggerOn = xsprite4.triggerOn;
  440. xsprite[j].triggerOff = xsprite4.triggerOff;
  441. xsprite[j].restState = xsprite4.restState;
  442. xsprite[j].busyTime = 0;
  443. xsprite[j].waitTime = xsprite4.waitTime;
  444. xsprite[j].difficulty = xsprite4.difficulty;
  445. xsprite[j].map = xsprite4.map;
  446. xsprite[j].soundKit = xsprite4.soundKit;
  447. // physical triggers
  448. xsprite[j].decoupled = xsprite4.decoupled;
  449. xsprite[j].triggerOnce = xsprite4.triggerOnce;
  450. xsprite[j].isTriggered = 0;
  451. xsprite[j].key = xsprite4.key;
  452. xsprite[j].triggerPush = xsprite4.triggerPush;
  453. xsprite[j].triggerImpact = xsprite4.triggerImpact;
  454. xsprite[j].triggerExplode = 0;
  455. xsprite[j].triggerPickup = xsprite4.triggerPickup;
  456. xsprite[j].triggerTouch = xsprite4.triggerTouch;
  457. xsprite[j].triggerSight = xsprite4.triggerSight;
  458. xsprite[j].triggerProximity = xsprite4.triggerProximity;
  459. xsprite[j].data1 = xsprite4.data;
  460. xsprite[j].data2 = sprite[i].type; // former lotag
  461. xsprite[j].data3 = sprite[i].mass; // format hitag
  462. // respawn flags
  463. xsprite[j].respawn = xsprite4.respawn;
  464. xsprite[j].respawnTime = xsprite4.respawnTime;
  465. xsprite[j].launchMode = xsprite4.launchMode;
  466. // this stuff needed for dudes (probably initialized dynamically)
  467. xsprite[j].moveState = 0;
  468. xsprite[j].aiState = 0;
  469. xsprite[j].health = 0;
  470. xsprite[j].dudeDeaf = 0;
  471. xsprite[j].dudeAmbush = 0;
  472. xsprite[j].dudeFlag3 = 0;
  473. xsprite[j].dudeFlag4 = 0;
  474. xsprite[j].target = 0;
  475. xsprite[j].targetX = 0;
  476. xsprite[j].targetY = 0;
  477. xsprite[j].targetZ = 0;
  478. xsprite[j].avel = 0;
  479. xsprite[j].weaponTimer = 0;
  480. sprite[i].type = (ushort)xsprite4.type;
  481. // remove the xsprite if not necessary
  482. if (sprite[i].type >= kWeaponItemBase && sprite[i].type < kDudeBase)
  483. sprite[i].extra = -1;
  484. }
  485. // offset old marker type
  486. if ( sprite[i].statnum == kStatMarker )
  487. sprite[i].type += kMarkerOff;
  488. // fix relocated item enums
  489. if ( sprite[i].type >= kAmmoMax && sprite[i].type <= kItemMax )
  490. sprite[i].type += kItemBase - kAmmoMax;
  491. // make sure we use origin alignment
  492. if ( !(sprite[i].cstat & kSpriteOriginAlign) )
  493. {
  494. sprite[i].cstat |= kSpriteOriginAlign;
  495. // adjust z position for alignment change
  496. if ( (sprite[i].cstat & kSpriteRMask) != kSpriteFloor )
  497. {
  498. int nTile = sprite[i].picnum;
  499. sprite[i].z -= (tilesizy[nTile] - tilesizy[nTile] / 2 - picanm[nTile].ycenter) * sprite[i].yrepeat << 2;
  500. }
  501. }
  502. }
  503. }
  504. else
  505. ThrowError("Error reading map file", ES_ERROR);
  506. free(buffer);
  507. // add up all the elements in the file to determine the size of the buffer
  508. length = 0;
  509. length += sizeof(HEADER5);
  510. length += sizeof(INFO5);
  511. length += gSkyCount * sizeof(pskyoff[0]);
  512. length += numsectors * sizeof(SECTOR);
  513. for (i = 0; i < numsectors; i++)
  514. {
  515. if (sector[i].extra > 0)
  516. length += sizeof(XSECTOR);
  517. }
  518. length += numwalls * sizeof(WALL);
  519. for (i = 0; i < numwalls; i++)
  520. {
  521. if (wall[i].extra > 0)
  522. length += sizeof(XWALL);
  523. }
  524. length += numsprites * sizeof(SPRITE);
  525. for (i = 0; i < numsprites; i++)
  526. {
  527. if (sprite[i].extra > 0)
  528. length += sizeof(XSPRITE);
  529. }
  530. length += 4; // CRC
  531. buffer = (char *)malloc(length);
  532. IOBuffer iob(buffer, length);
  533. memcpy(header5.signature, kBloodMapSig, sizeof(header5.signature));
  534. header5.version = kBloodMapVersion;
  535. iob.Write(&header5, sizeof(header5));
  536. info5.x = info4.x;
  537. info5.y = info4.y;
  538. info5.z = info4.z;
  539. info5.angle = info4.angle;
  540. info5.sector = info4.sector;
  541. info5.pskybits = info4.pskybits;
  542. info5.visibility = info4.visibility;
  543. info5.songId = info4.songId;
  544. info5.parallax = info4.parallax;
  545. info5.mapRevisions = info4.mapRevisions;
  546. info5.numsectors = numsectors;
  547. info5.numwalls = numwalls;
  548. info5.numsprites = numsprites;
  549. iob.Write(&info5, sizeof(INFO5));
  550. iob.Write(pskyoff, gSkyCount * sizeof(pskyoff[0]));
  551. for (i = 0; i < numsectors; i++)
  552. {
  553. iob.Write(&sector[i], sizeof(SECTOR));
  554. if (sector[i].extra > 0)
  555. iob.Write(&xsector[sector[i].extra], sizeof(XSECTOR));
  556. }
  557. for (i = 0; i < numwalls; i++)
  558. {
  559. iob.Write(&wall[i], sizeof(WALL));
  560. if (wall[i].extra > 0)
  561. iob.Write(&xwall[wall[i].extra], sizeof(XWALL));
  562. }
  563. for (i = 0; i < numsprites; i++)
  564. {
  565. iob.Write(&sprite[i], sizeof(SPRITE));
  566. if (sprite[i].extra > 0)
  567. iob.Write(&xsprite[sprite[i].extra], sizeof(XSPRITE));
  568. }
  569. gMapCRC = CRC32(buffer, length - sizeof(gMapCRC));
  570. iob.Write(&gMapCRC, sizeof(gMapCRC));
  571. // backup the map file
  572. strcpy(bakfilename, filename);
  573. ChangeExtension(filename, "MAP");
  574. ChangeExtension(bakfilename, "MA4");
  575. rename(filename, bakfilename);
  576. ChangeExtension(filename, "MAP");
  577. printf("=> %s ", filename);
  578. hFile = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IWUSR);
  579. if ( hFile == -1 )
  580. ThrowError("Error opening MAP file", ES_ERROR);
  581. if (write(hFile, buffer, length) != length)
  582. ThrowError("Error writing MAP file", ES_ERROR);
  583. close(hFile);
  584. free(buffer);
  585. printf("OK.\n");
  586. }
  587. void InsertFilename( char *fname )
  588. {
  589. FNODE *n = (FNODE *)malloc(sizeof(FNODE) + strlen(fname));
  590. strcpy(n->name, fname);
  591. // insert the node at the tail, so it stays in order
  592. n->next = tail->next;
  593. tail->next = n;
  594. tail = n;
  595. }
  596. void ProcessArgument(char *s)
  597. {
  598. char filespec[_MAX_PATH];
  599. char buffer[_MAX_PATH2];
  600. char path[_MAX_PATH];
  601. strcpy(filespec, s);
  602. ChangeExtension(filespec, ".MAP");
  603. char *drive, *dir;
  604. // separate the path from the filespec
  605. _splitpath2(s, buffer, &drive, &dir, NULL, NULL);
  606. _makepath(path, drive, dir, NULL, NULL);
  607. struct find_t fileinfo;
  608. unsigned r = _dos_findfirst(s, _A_NORMAL, &fileinfo);
  609. if (r != 0)
  610. printf("%s not found\n", s);
  611. while ( r == 0 )
  612. {
  613. strcpy(filespec, path);
  614. strcat(filespec, fileinfo.name);
  615. InsertFilename(filespec);
  616. r = _dos_findnext( &fileinfo );
  617. }
  618. _dos_findclose(&fileinfo);
  619. }
  620. /***********************************************************************
  621. * Process command line arguments
  622. **********************************************************************/
  623. void ParseOptions( int argc, char *argv[])
  624. {
  625. int c;
  626. while ( (c = GetOptions(argc, argv, "")) != GO_EOF ) {
  627. switch (c) {
  628. case GO_INVALID:
  629. QuitMessage("Invalid argument: %s", OptArgument);
  630. case GO_FULL:
  631. ProcessArgument(OptArgument);
  632. break;
  633. }
  634. }
  635. }
  636. void main(int argc, char *argv[])
  637. {
  638. printf("Blood Map 5 Converter Copyright (c) 1995 Q Studios Corporation\n");
  639. if (argc < 2) ShowUsage();
  640. artInit(); // get tile size info
  641. ParseOptions(argc, argv);
  642. // process the file list
  643. for (FNODE *n = head.next; n != &head; n = n->next)
  644. ProcessFile(n->name);
  645. }