MAPINFO.CPP 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  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. /***********************************************************************
  15. * Structures and typedefs
  16. **********************************************************************/
  17. struct XSPRITE4
  18. {
  19. signed reference : 16;
  20. unsigned type : 10;
  21. // trigger data
  22. unsigned state : 1;
  23. unsigned busy : 16;
  24. unsigned txID : 10;
  25. unsigned rxID : 10;
  26. unsigned command : 3;
  27. unsigned triggerOn : 1;
  28. unsigned triggerOff : 1;
  29. unsigned key : 3;
  30. signed data : 16;
  31. unsigned restState : 1; // state to return to on callback
  32. unsigned waitTime : 8;
  33. unsigned triggerPush : 1; // gates?
  34. unsigned triggerImpact : 1; // exploding things, etc.
  35. unsigned triggerPickup : 1; // secrets
  36. unsigned triggerTouch : 1; // sawblades, spikes, zaps?
  37. unsigned triggerSight : 1; // dunno, yet.
  38. unsigned triggerProximity : 1; // proximity bombs
  39. unsigned decoupled : 1;
  40. unsigned triggerOnce : 1;
  41. unsigned isTriggered : 1; // used for triggerOnce objects
  42. unsigned difficulty : 2;
  43. unsigned detail : 2;
  44. unsigned view : 4;
  45. unsigned soundKit : 8;
  46. unsigned map : 2;
  47. unsigned permanent : 1; // 0=not permanent, 1=permanent (respawn ignored)
  48. unsigned respawn : 2; // 0=never, 1=always, 2=optional never, 3=optional always
  49. unsigned respawnTime : 8; // 0=instant, >0=time in tenths of a second,
  50. unsigned launchMode : 2; // 0=all, 1=bloodbath, 2=ally, 3=ally&bloodbath,
  51. };
  52. struct XWALL4
  53. {
  54. signed reference : 16;
  55. unsigned type : 10;
  56. // trigger data
  57. unsigned state : 1;
  58. unsigned busy : 16;
  59. unsigned txID : 10;
  60. unsigned rxID : 10;
  61. unsigned command : 3;
  62. unsigned triggerOn : 1;
  63. unsigned triggerOff : 1;
  64. unsigned key : 3;
  65. signed data : 16;
  66. unsigned waitTime : 8; // delay before callback
  67. unsigned restState : 1; // state to return to on callback
  68. unsigned triggerPush : 1;
  69. unsigned triggerImpact : 1;
  70. unsigned triggerRsvd1 : 1;
  71. unsigned triggerRsvd2 : 1;
  72. unsigned decoupled : 1;
  73. unsigned triggerOnce : 1;
  74. unsigned isTriggered : 1; // used for triggerOnce objects
  75. // panning data
  76. signed panXVel : 8;
  77. signed panYVel : 8;
  78. unsigned panAlways : 1;
  79. unsigned map : 2;
  80. };
  81. struct XSECTOR4
  82. {
  83. signed reference : 16;
  84. unsigned type : 10;
  85. // trigger data
  86. unsigned state : 1;
  87. unsigned busy : 16;
  88. unsigned txID : 10;
  89. unsigned rxID : 10;
  90. unsigned command : 3;
  91. unsigned triggerOn : 1;
  92. unsigned triggerOff : 1;
  93. unsigned key : 3;
  94. signed data : 16;
  95. unsigned busyTime : 8; // time to reach next state
  96. unsigned waitTime : 8; // delay before callback
  97. unsigned restState : 1; // state to return to on callback
  98. unsigned triggerPush : 1;
  99. unsigned triggerImpact : 1;
  100. unsigned triggerEnter : 1;
  101. unsigned triggerExit : 1;
  102. unsigned triggerWPush : 1;
  103. unsigned decoupled : 1;
  104. unsigned triggerOnce : 1;
  105. unsigned isTriggered : 1;
  106. // lighting data
  107. signed shade : 8;
  108. signed amplitude : 8;
  109. unsigned freq : 8;
  110. unsigned phase : 8;
  111. unsigned wave : 4;
  112. unsigned shadeFloor : 1;
  113. unsigned shadeCeiling : 1;
  114. unsigned shadeWalls : 1;
  115. unsigned shadeAlways : 1;
  116. // panning data
  117. unsigned panFloor : 1;
  118. unsigned panCeiling : 1;
  119. unsigned Drag : 1;
  120. unsigned panAlways : 1;
  121. // wind/water stuff
  122. unsigned depth : 2;
  123. unsigned panVel : 8;
  124. unsigned panAngle : 11;
  125. unsigned underwater : 1;
  126. unsigned wind : 1;
  127. signed ceilingOffZ : 32;
  128. signed ceilingOnZ : 32;
  129. signed floorOffZ : 32;
  130. signed floorOnZ : 32;
  131. };
  132. #define kBloodMapSig "BLM\x1A"
  133. #define kBloodMapVersion 0x0400
  134. struct FNODE
  135. {
  136. FNODE *next;
  137. char name[1];
  138. };
  139. FNODE head = { &head, "" };
  140. FNODE *tail = &head;
  141. // Build globals
  142. SECTOR sector[kMaxSectors];
  143. WALL wall[kMaxWalls];
  144. SPRITE sprite[kMaxSprites];
  145. // Q globals
  146. XSECTOR4 xsector4[kMaxXSectors];
  147. XWALL4 xwall4[kMaxXWalls];
  148. XSPRITE4 xsprite4[kMaxXSprites];
  149. uchar spriteSurf[kMaxSprites];
  150. uchar wallSurf[kMaxWalls];
  151. uchar floorSurf[kMaxSectors];
  152. uchar ceilingSurf[kMaxSectors];
  153. short pskyoff[kMaxSkyTiles];
  154. short pskybits;
  155. char gMapAuthor[64] = "";
  156. char gMapName[64] = "";
  157. ulong gMapCRC;
  158. int gSkyCount;
  159. short numsectors, numwalls;
  160. struct IOBuffer
  161. {
  162. int remain;
  163. char *p;
  164. IOBuffer( char *buffer, int l ) : p(buffer), remain(l) {};
  165. void Read(void *, int, int);
  166. void Write(void *, int, int);
  167. };
  168. void IOBuffer::Read(void *s, int size, int nError)
  169. {
  170. if (size <= remain)
  171. {
  172. memcpy(s, p, size);
  173. remain -= size;
  174. p += size;
  175. }
  176. else
  177. ThrowError("Read buffer overflow", ES_ERROR);
  178. }
  179. void IOBuffer::Write(void *s, int size, int nError)
  180. {
  181. if (size <= remain)
  182. {
  183. memcpy(p, s, size);
  184. remain -= size;
  185. p += size;
  186. }
  187. else
  188. ThrowError("Write buffer overflow", ES_ERROR);
  189. }
  190. struct HEADER4
  191. {
  192. char signature[4];
  193. short version;
  194. };
  195. // version 4.x header
  196. struct INFO4
  197. {
  198. long x, y, z;
  199. ushort angle;
  200. ushort sector;
  201. ushort pskybits;
  202. long visibility;
  203. int songId;
  204. uchar parallax;
  205. int mapRevisions;
  206. uchar lenName;
  207. uchar lenAuthor;
  208. ushort numsectors;
  209. ushort numwalls;
  210. ushort numsprites;
  211. };
  212. void ShowUsage(void)
  213. {
  214. printf("Usage:\n");
  215. printf(" MAPINFO map1 map2 (wild cards ok)\n");
  216. exit(0);
  217. }
  218. void QuitMessage(char * fmt, ...)
  219. {
  220. char msg[80];
  221. va_list argptr;
  222. va_start( argptr, fmt );
  223. vsprintf( msg, fmt, argptr );
  224. va_end(argptr);
  225. printf(msg);
  226. exit(1);
  227. }
  228. void ProcessFile(char *filespec)
  229. {
  230. int hFile;
  231. int i;
  232. HEADER3 header3;
  233. HEADER4 header4;
  234. INFO3 info3;
  235. INFO4 info4;
  236. char filename[_MAX_PATH], bakfilename[_MAX_PATH];
  237. short nSector, numsprites;
  238. int length;
  239. char *buffer;
  240. strcpy(filename, filespec);
  241. printf("%s ", filename);
  242. hFile = open(filename, O_RDONLY | O_BINARY);
  243. if ( hFile == -1 )
  244. ThrowError( "unable to open MAP file", ES_ERROR);
  245. length = filelength(hFile);
  246. buffer = (char *)malloc(length);
  247. if (read(hFile, buffer, length) == length)
  248. {
  249. close(hFile);
  250. IOBuffer iob(buffer, length);
  251. iob.Read(&header3, sizeof(HEADER3), 1);
  252. // check signature and major version number
  253. if ( strncmp(header3.signature, kBloodMapSig, sizeof(header3.signature))
  254. || header3.version & 0xFF00 != kBloodMapOldVersion & 0xFF00 )
  255. {
  256. printf("not expected format, skipping\n");
  257. return;
  258. }
  259. iob.Read(&info3, sizeof(INFO3), 2);
  260. numsectors = info3.numsectors;
  261. numwalls = info3.numwalls;
  262. numsprites = info3.numsprites;
  263. iob.Read(gMapName, info3.lenName + 1, 3);
  264. iob.Read(gMapAuthor, info3.lenAuthor + 1, 4);
  265. pskybits = info3.pskybits;
  266. gSkyCount = 1 << pskybits;
  267. iob.Read(pskyoff, gSkyCount * sizeof(pskyoff[0]), 5);
  268. for (i = 0; i < numsectors; i++)
  269. {
  270. iob.Read(&sector[i], sizeof(SECTOR), 6);
  271. iob.Read(&ceilingSurf[i], sizeof(ceilingSurf[i]), 7);
  272. iob.Read(&floorSurf[i], sizeof(floorSurf[i]), 8);
  273. // expand sector shade range
  274. sector[i].ceilingshade = (schar)ClipRange(sector[i].ceilingshade << 1, -128, 127);
  275. sector[i].floorshade = (schar)ClipRange(sector[i].floorshade << 1, -128, 127);
  276. if (sector[i].extra > 0)
  277. {
  278. XSECTOR3 xsector3;
  279. iob.Read(&xsector3, sizeof(XSECTOR3), 9);
  280. memset(&xsector4[i], 0, sizeof(XSECTOR));
  281. xsector4[i].reference = xsector3.reference;
  282. xsector4[i].state = xsector3.state;
  283. xsector4[i].busy = 0;
  284. xsector4[i].type = xsector3.type;
  285. xsector4[i].data = xsector3.data;
  286. xsector4[i].txID = xsector3.txID;
  287. xsector4[i].rxID = xsector3.rxID;
  288. xsector4[i].command = xsector3.command;
  289. xsector4[i].triggerOn = xsector3.triggerOn;
  290. xsector4[i].triggerOff = xsector3.triggerOff;
  291. xsector4[i].triggerOnce = xsector3.triggerOnce;
  292. xsector4[i].restState = xsector3.restState;
  293. xsector4[i].key = xsector3.key;
  294. xsector4[i].amplitude = ClipRange(xsector3.amplitude << 1, -128, 127);
  295. xsector4[i].freq = xsector3.freq;
  296. xsector4[i].wave = xsector3.wave;
  297. xsector4[i].shadeAlways = xsector3.shadeAlways;
  298. xsector4[i].phase = xsector3.phase;
  299. xsector4[i].shadeFloor = xsector3.shadeFloor;
  300. xsector4[i].shadeCeiling = xsector3.shadeCeiling;
  301. xsector4[i].shadeWalls = xsector3.shadeWalls;
  302. xsector4[i].shade = xsector3.shade;
  303. xsector4[i].panFloor = xsector3.panFloor;
  304. xsector4[i].panCeiling = xsector3.panCeiling;
  305. xsector4[i].panDrag = xsector3.panDrag;
  306. xsector4[i].waitTime = xsector3.waitTime;
  307. xsector4[i].panAlways = xsector3.panAlways;
  308. xsector4[i].busyTime = xsector3.busyTime;
  309. xsector4[i].underwater = xsector3.underwater;
  310. xsector4[i].depth = xsector3.depth;
  311. xsector4[i].panVel = xsector3.panVel;
  312. xsector4[i].panAngle = xsector3.panAngle;
  313. xsector4[i].wind = xsector3.wind ? 1 : 0;
  314. xsector4[i].isTriggered = 0;
  315. xsector4[i].triggerPush = xsector3.triggerPush;
  316. xsector4[i].triggerImpact = xsector3.triggerImpact;
  317. xsector4[i].triggerEnter = xsector3.triggerEnter;
  318. xsector4[i].triggerExit = xsector3.triggerExit;
  319. xsector4[i].triggerWPush = xsector3.triggerWPush;
  320. xsector4[i].decoupled = xsector3.decoupled;
  321. // zero all onZ offZ values
  322. xsector4[i].ceilingOffZ = 0;
  323. xsector4[i].ceilingOnZ = 0;
  324. xsector4[i].floorOffZ = 0;
  325. xsector4[i].floorOnZ = 0;
  326. switch( xsector4[i].type )
  327. {
  328. case kSectorTopDoor:
  329. xsector4[i].ceilingOffZ = sector[nSector].floorz;
  330. xsector4[i].ceilingOnZ = sector[nSector].ceilingz;
  331. // open or close door as necessary for initial state
  332. if ( xsector4[i].state == 0 )
  333. sector[nSector].ceilingz = xsector4[i].ceilingOffZ;
  334. break;
  335. case kSectorBottomDoor:
  336. xsector4[i].ceilingOffZ = sector[nSector].ceilingz;
  337. xsector4[i].ceilingOnZ = sector[nSector].floorz;
  338. // open or close door as necessary for initial state
  339. if ( xsector4[i].state == 0 )
  340. sector[nSector].floorz = xsector4[i].ceilingOffZ;
  341. break;
  342. case kSectorHSplitDoor:
  343. xsector4[i].ceilingOffZ = (sector[nSector].ceilingz + sector[nSector].floorz) / 2;
  344. xsector4[i].ceilingOnZ = sector[nSector].floorz;
  345. xsector4[i].ceilingOnZ = sector[nSector].ceilingz;
  346. // open or close door as necessary for initial state
  347. if ( xsector4[i].state == 0 )
  348. {
  349. sector[nSector].floorz = xsector4[i].ceilingOffZ;
  350. sector[nSector].ceilingz = xsector4[i].ceilingOffZ;
  351. }
  352. break;
  353. default:
  354. break;
  355. }
  356. }
  357. }
  358. for (i = 0; i < numwalls; i++)
  359. {
  360. iob.Read(&wall[i], sizeof(WALL), 10);
  361. iob.Read(&wallSurf[i], sizeof(wallSurf[i]), 11);
  362. // expand wall shade range
  363. wall[i].shade = (schar)ClipRange(wall[i].shade << 1, -128, 127);
  364. if (wall[i].extra > 0)
  365. {
  366. XWALL3 xwall3;
  367. iob.Read(&xwall3, sizeof(XWALL3), 12);
  368. memset(&xwall4[i], 0, sizeof(XWALL));
  369. xwall4[i].reference = xwall3.reference;
  370. xwall4[i].type = xwall3.type;
  371. xwall4[i].state = xwall3.state;
  372. xwall4[i].busy = xwall3.busy;
  373. xwall4[i].txID = xwall3.txID;
  374. xwall4[i].rxID = xwall3.rxID;
  375. xwall4[i].command = xwall3.command;
  376. xwall4[i].triggerOn = xwall3.triggerOn;
  377. xwall4[i].triggerOff = xwall3.triggerOff;
  378. xwall4[i].key = xwall3.key;
  379. xwall4[i].data = xwall3.data;
  380. xwall4[i].waitTime = xwall3.waitTime;
  381. xwall4[i].restState = xwall3.restState;
  382. xwall4[i].triggerPush = xwall3.triggerPush;
  383. xwall4[i].triggerImpact = xwall3.triggerImpact;
  384. xwall4[i].triggerRsvd1 = xwall3.triggerRsvd1;
  385. xwall4[i].triggerRsvd2 = xwall3.triggerRsvd2;
  386. xwall4[i].decoupled = xwall3.decoupled;
  387. xwall4[i].triggerOnce = xwall3.triggerOnce;
  388. xwall4[i].isTriggered = xwall3.isTriggered;
  389. xwall4[i].panXVel = xwall3.panXVel;
  390. xwall4[i].panYVel = xwall3.panYVel;
  391. xwall4[i].panAlways = xwall3.panAlways;
  392. xwall4[i].map = xwall3.map;
  393. }
  394. }
  395. for (i = 0; i < numsprites; i++)
  396. {
  397. iob.Read(&sprite[i], sizeof(SPRITE), 13);
  398. iob.Read(&spriteSurf[i], sizeof(spriteSurf[i]), 14);
  399. // expand sprite shade range
  400. if ( sprite[i].statnum < kMaxStatus )
  401. sprite[i].shade = (schar)ClipRange(sprite[i].shade << 1, -128, 127);
  402. if (sprite[i].extra > 0)
  403. {
  404. XSPRITE3 xsprite3;
  405. iob.Read(&xsprite3, sizeof(XSPRITE3), 15);
  406. memset(&xsprite4[i], 0, sizeof(XSPRITE));
  407. xsprite4[i].reference = xsprite3.reference;
  408. xsprite4[i].state = xsprite3.state;
  409. xsprite4[i].type = xsprite3.type;
  410. xsprite4[i].txID = xsprite3.txID;
  411. xsprite4[i].rxID = xsprite3.rxID;
  412. xsprite4[i].command = xsprite3.command;
  413. xsprite4[i].triggerOn = xsprite3.triggerOn;
  414. xsprite4[i].triggerOff = xsprite3.triggerOff;
  415. xsprite4[i].triggerOnce = xsprite3.triggerOnce;
  416. xsprite4[i].restState = xsprite3.restState;
  417. xsprite4[i].key = xsprite3.key;
  418. xsprite4[i].difficulty = xsprite3.difficulty;
  419. xsprite4[i].detail = xsprite3.detail;
  420. xsprite4[i].map = xsprite3.map;
  421. xsprite4[i].view = xsprite3.view;
  422. xsprite4[i].soundKit = xsprite3.soundKit;
  423. xsprite4[i].data = xsprite3.data;
  424. xsprite4[i].isTriggered = 0;
  425. xsprite4[i].triggerPush = xsprite3.isTriggered;
  426. xsprite4[i].triggerImpact = xsprite3.triggerImpact;
  427. xsprite4[i].triggerPickup = xsprite3.triggerPickup;
  428. xsprite4[i].triggerTouch = xsprite3.triggerTouch;
  429. xsprite4[i].triggerSight = xsprite3.triggerSight;
  430. xsprite4[i].triggerProximity = xsprite3.triggerProximity;
  431. xsprite4[i].decoupled = xsprite3.decoupled;
  432. xsprite4[i].waitTime = xsprite3.waitTime;
  433. xsprite4[i].permanent = 0;
  434. xsprite4[i].respawn = 0;
  435. xsprite4[i].respawnTime = 0;
  436. xsprite4[i].launchMode = 0;
  437. }
  438. }
  439. }
  440. else
  441. ThrowError("Error reading map file", ES_ERROR);
  442. free(buffer);
  443. // add up all the elements in the file to determine the size of the buffer
  444. length = 0;
  445. length += sizeof(HEADER4);
  446. length += sizeof(INFO4);
  447. length += strlen(gMapName) + 1;
  448. length += strlen(gMapAuthor) + 1;
  449. length += gSkyCount * sizeof(pskyoff[0]);
  450. length += numsectors * sizeof(SECTOR);
  451. length += numsectors * sizeof(ceilingSurf[0]);
  452. length += numsectors * sizeof(floorSurf[0]);
  453. for (i = 0; i < numsectors; i++)
  454. {
  455. if (sector[i].extra > 0)
  456. length += sizeof(XSECTOR4);
  457. }
  458. length += numwalls * sizeof(WALL);
  459. length += numwalls * sizeof(wallSurf[0]);
  460. for (i = 0; i < numwalls; i++)
  461. {
  462. if (wall[i].extra > 0)
  463. length += sizeof(XWALL4);
  464. }
  465. length += numsprites * sizeof(SPRITE);
  466. length += numsprites * sizeof(spriteSurf[0]);
  467. for (i = 0; i < numsprites; i++)
  468. {
  469. if (sprite[i].extra > 0)
  470. length += sizeof(XSPRITE4);
  471. }
  472. length += 4; // CRC
  473. buffer = (char *)malloc(length);
  474. IOBuffer iob(buffer, length);
  475. memcpy(header4.signature, kBloodMapSig, sizeof(header4.signature));
  476. header4.version = kBloodMapVersion;
  477. iob.Write(&header4, sizeof(header4), 1);
  478. info4.x = info3.x;
  479. info4.y = info3.y;
  480. info4.z = info3.z;
  481. info4.angle = info3.angle;
  482. info4.sector = info3.sector;
  483. info4.pskybits = info3.pskybits;
  484. info4.visibility = 1 << (22 - info3.visibility);
  485. info4.songId = info3.songId;
  486. info4.parallax = info3.parallax;
  487. info4.mapRevisions = info3.mapRevisions;
  488. info4.lenName = (char)strlen(gMapName);
  489. info4.lenAuthor = (char)strlen(gMapAuthor);
  490. info4.numsectors = numsectors;
  491. info4.numwalls = numwalls;
  492. info4.numsprites = numsprites;
  493. iob.Write(&info4, sizeof(INFO3), 2);
  494. iob.Write(gMapName, info4.lenName + 1, 3);
  495. iob.Write(gMapAuthor, info4.lenAuthor + 1, 4);
  496. iob.Write(pskyoff, gSkyCount * sizeof(pskyoff[0]), 5);
  497. for (i = 0; i < numsectors; i++)
  498. {
  499. iob.Write(&sector[i], sizeof(SECTOR), 6);
  500. iob.Write(&ceilingSurf[i], sizeof(ceilingSurf[i]), 7);
  501. iob.Write(&floorSurf[i], sizeof(floorSurf[i]), 8);
  502. if (sector[i].extra > 0)
  503. iob.Write(&xsector4[sector[i].extra], sizeof(XSECTOR), 9);
  504. }
  505. for (i = 0; i < numwalls; i++)
  506. {
  507. iob.Write(&wall[i], sizeof(WALL), 10);
  508. iob.Write(&wallSurf[i], sizeof(wallSurf[i]), 11);
  509. if (wall[i].extra > 0)
  510. iob.Write(&xwall4[wall[i].extra], sizeof(XWALL), 12);
  511. }
  512. for (i = 0; i < numsprites; i++)
  513. {
  514. iob.Write(&sprite[i], sizeof(SPRITE), 13);
  515. iob.Write(&spriteSurf[i], sizeof(spriteSurf[i]), 14);
  516. if (sprite[i].extra > 0)
  517. iob.Write(&xsprite4[sprite[i].extra], sizeof(XSPRITE), 15);
  518. }
  519. gMapCRC = CRC32(buffer, length - sizeof(gMapCRC));
  520. iob.Write(&gMapCRC, sizeof(gMapCRC), 16);
  521. // backup the map file
  522. strcpy(bakfilename, filename);
  523. ChangeExtension(filename, "MAP");
  524. ChangeExtension(bakfilename, "~AK");
  525. rename(filename, bakfilename);
  526. ChangeExtension(filename, "MPX");
  527. ChangeExtension(bakfilename, "~PX");
  528. rename(filename, bakfilename);
  529. ChangeExtension(filename, "MAP");
  530. printf("=> %s ", filename);
  531. hFile = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IWUSR);
  532. if ( hFile == -1 )
  533. ThrowError("Error opening MAP file", ES_ERROR);
  534. if (write(hFile, buffer, length) != length)
  535. ThrowError("Error write MAP file", ES_ERROR);
  536. close(hFile);
  537. free(buffer);
  538. printf("OK.\n");
  539. }
  540. void InsertFilename( char *fname )
  541. {
  542. FNODE *n = (FNODE *)malloc(sizeof(FNODE) + strlen(fname));
  543. strcpy(n->name, fname);
  544. // insert the node at the tail, so it stays in order
  545. n->next = tail->next;
  546. tail->next = n;
  547. tail = n;
  548. }
  549. void ProcessArgument(char *s)
  550. {
  551. char filespec[_MAX_PATH];
  552. char buffer[_MAX_PATH2];
  553. char path[_MAX_PATH];
  554. strcpy(filespec, s);
  555. ChangeExtension(filespec, ".MAP");
  556. char *drive, *dir;
  557. // separate the path from the filespec
  558. _splitpath2(s, buffer, &drive, &dir, NULL, NULL);
  559. _makepath(path, drive, dir, NULL, NULL);
  560. struct find_t fileinfo;
  561. unsigned r = _dos_findfirst(s, _A_NORMAL, &fileinfo);
  562. if (r != 0)
  563. printf("%s not found\n", s);
  564. while ( r == 0 )
  565. {
  566. strcpy(filespec, path);
  567. strcat(filespec, fileinfo.name);
  568. InsertFilename(filespec);
  569. r = _dos_findnext( &fileinfo );
  570. }
  571. _dos_findclose(&fileinfo);
  572. }
  573. /***********************************************************************
  574. * Process command line arguments
  575. **********************************************************************/
  576. void ParseOptions( int argc, char *argv[])
  577. {
  578. int c;
  579. while ( (c = GetOptions(argc, argv, "")) != GO_EOF ) {
  580. switch (c) {
  581. case GO_INVALID:
  582. QuitMessage("Invalid argument: %s", OptArgument);
  583. case GO_FULL:
  584. ProcessArgument(OptArgument);
  585. break;
  586. }
  587. }
  588. }
  589. void main(int argc, char *argv[])
  590. {
  591. printf("Blood Map 3 Converter Copyright (c) 1995 Q Studios Corporation\n");
  592. if (argc < 2) ShowUsage();
  593. ParseOptions(argc, argv);
  594. // process the file list
  595. for (FNODE *n = head.next; n != &head; n = n->next)
  596. ProcessFile(n->name);
  597. }