QAVEDIT.CPP 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  1. /*******************************************************************************
  2. FILE: QAVEDIT.CPP
  3. DESCRIPTION: Allows editing of 2D animation sequences
  4. AUTHOR: Peter M. Freese
  5. CREATED: 02-26-95
  6. COPYRIGHT: Copyright (c) 1995 Q Studios Corporation
  7. *******************************************************************************/
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <helix.h>
  11. #include <string.h>
  12. #include <io.h>
  13. #include <fcntl.h>
  14. #include <dos.h>
  15. #include "typedefs.h"
  16. #include "engine.h"
  17. #include "key.h"
  18. #include "misc.h"
  19. #include "gameutil.h"
  20. #include "gfx.h"
  21. #include "bstub.h"
  22. #include "globals.h"
  23. #include "debug4g.h"
  24. #include "error.h"
  25. #include "gui.h"
  26. #include "tile.h"
  27. #include "qav.h"
  28. #include "screen.h"
  29. #include "textio.h"
  30. #include "inifile.h"
  31. #include "options.h"
  32. #include "timer.h"
  33. #include "mouse.h"
  34. #include "trig.h"
  35. #include "getopt.h"
  36. #define kMaxFrames 1024
  37. #define kAttrTitle (kColorGreen * 16 + kColorWhite)
  38. struct FRAME1
  39. {
  40. long timeStart;
  41. long timeStop;
  42. int type;
  43. int id;
  44. int flags;
  45. union
  46. {
  47. // type = kQFrameTile
  48. struct
  49. {
  50. int x, y;
  51. int layer;
  52. int shade;
  53. int pal;
  54. };
  55. // type = kQFrameSound
  56. struct
  57. {
  58. int priority;
  59. int volume;
  60. int soundID;
  61. };
  62. // type = kQFrameTrigger
  63. struct {
  64. int trigger;
  65. };
  66. };
  67. };
  68. struct QAV1
  69. {
  70. char signature[4];
  71. short version;
  72. char dummy[2];
  73. int frames;
  74. long duration;
  75. int backTile;
  76. Point origin;
  77. FRAME1 frame[1];
  78. };
  79. struct EditQAV : public QAV
  80. {
  81. void ClipTileFrame( TILE_FRAME *f );
  82. void SetOrigin( int x, int y );
  83. void DrawOrigin( int nColor );
  84. void HighlightFrame( TILE_FRAME *f );
  85. };
  86. char gQAVName[128] = "";
  87. int lastTile = 2052;
  88. char buffer[256];
  89. EditQAV *gQAV = NULL;
  90. static BOOL isModified;
  91. EHF prevErrorHandler;
  92. void faketimerhandler( void )
  93. { }
  94. struct FNODE
  95. {
  96. FNODE *next;
  97. char name[1];
  98. };
  99. FNODE head = { &head, "" };
  100. FNODE *tail = &head;
  101. /*******************************************************************************
  102. FUNCTION: ShowBanner()
  103. DESCRIPTION: Show application banner
  104. *******************************************************************************/
  105. void ShowBanner( void )
  106. {
  107. printf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n");
  108. printf(" QAV Editor Version 2.0 Copyright (c) 1995 Q Studios Corporation\n");
  109. printf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n");
  110. }
  111. /*******************************************************************************
  112. FUNCTION: ShowUsage()
  113. DESCRIPTION: Display command-line parameter usage, then exit
  114. *******************************************************************************/
  115. void ShowUsage(void)
  116. {
  117. printf("Syntax: QAVEDIT [options] files[.qav]\n");
  118. printf("-c Batch convert files to current verson\n");
  119. printf("-? This help\n");
  120. exit(0);
  121. }
  122. /*******************************************************************************
  123. FUNCTION: QuitMessage()
  124. DESCRIPTION: Display a printf() style message, the exit with code 1
  125. *******************************************************************************/
  126. void QuitMessage(char * fmt, ...)
  127. {
  128. char msg[80];
  129. va_list argptr;
  130. va_start( argptr, fmt );
  131. vsprintf( msg, fmt, argptr );
  132. va_end(argptr);
  133. printf(msg);
  134. exit(1);
  135. }
  136. /***********************************************************************
  137. * EditorErrorHandler()
  138. *
  139. * Terminate from error condition, displaying a message in text mode.
  140. *
  141. **********************************************************************/
  142. ErrorResult EditorErrorHandler( const Error& error )
  143. {
  144. uninitengine();
  145. keyRemove();
  146. setvmode(gOldDisplayMode);
  147. // chain to the default error handler
  148. return prevErrorHandler(error);
  149. };
  150. /***********************************************************************
  151. * Ensure that the tile location isn't off the screen
  152. **********************************************************************/
  153. void EditQAV::ClipTileFrame( TILE_FRAME *f )
  154. {
  155. int xOffset, yOffset;
  156. if ( f->flags & kQFrameCorner )
  157. xOffset = yOffset = 0;
  158. else
  159. {
  160. xOffset = picanm[f->id].xcenter + tilesizx[f->id] / 2 - origin.x;
  161. yOffset = picanm[f->id].ycenter + tilesizy[f->id] / 2 - origin.y;
  162. }
  163. if (f->x < xOffset - tilesizx[f->id] + 1)
  164. f->x = xOffset - tilesizx[f->id] + 1;
  165. if (f->x > 319 + xOffset)
  166. f->x = 319 + xOffset;
  167. if (f->y < yOffset - tilesizy[f->id] + 1)
  168. f->y = yOffset - tilesizy[f->id] + 1;
  169. if (f->y > 199 + yOffset)
  170. f->y = 199 + yOffset;
  171. }
  172. void EditQAV::SetOrigin( int x, int y )
  173. {
  174. if (keystatus[KEY_LCTRL] || keystatus[KEY_RCTRL])
  175. {
  176. x = ClipRange(x, 0, 319);
  177. y = ClipRange(y, 0, 199);
  178. int dx = x - origin.x;
  179. int dy = y - origin.y;
  180. for (int i = 0; i < nFrames; i++)
  181. {
  182. for (int j = 0; j < kMaxLayers; j++)
  183. {
  184. frame[i].layer[j].x -= dx;
  185. frame[i].layer[j].y -= dy;
  186. }
  187. }
  188. origin.x = x;
  189. origin.y = y;
  190. }
  191. else
  192. {
  193. origin.x = ClipRange(x, 0, 319);
  194. origin.y = ClipRange(y, 0, 199);
  195. // ensure that no frame are offscreen
  196. for (int i = 0; i < nFrames; i++)
  197. {
  198. for (int j = 0; j < kMaxLayers; j++)
  199. {
  200. ClipTileFrame(&frame[i].layer[j]);
  201. }
  202. }
  203. }
  204. }
  205. void EditQAV::DrawOrigin( int nColor )
  206. {
  207. Video.SetColor(nColor);
  208. gfxHLine(origin.y << 1, origin.x - 6 << 1, origin.x - 1 << 1);
  209. gfxHLine(origin.y << 1, origin.x + 1 << 1, origin.x + 6 << 1);
  210. gfxVLine(origin.x << 1, origin.y - 5 << 1, origin.y - 1 << 1);
  211. gfxVLine(origin.x << 1, origin.y + 1 << 1, origin.y + 5 << 1);
  212. }
  213. void EditQAV::HighlightFrame( TILE_FRAME *f )
  214. {
  215. int xOffset, yOffset;
  216. dassert(f->id > 0);
  217. if ( f->flags & kQFrameCorner )
  218. xOffset = yOffset = 0;
  219. else
  220. {
  221. xOffset = picanm[f->id].xcenter + tilesizx[f->id] / 2;
  222. yOffset = picanm[f->id].ycenter + tilesizy[f->id] / 2;
  223. }
  224. int x0 = (origin.x + f->x - mulscale16(xOffset, f->zoom) << 1) - 1;
  225. int y0 = (origin.y + f->y - mulscale16(yOffset, f->zoom) << 1) - 1;
  226. int x1 = x0 + (mulscale16(tilesizx[f->id], f->zoom) << 1) + 1;
  227. int y1 = y0 + (mulscale16(tilesizy[f->id], f->zoom) << 1) + 1;
  228. Video.SetColor(gStdColor[8]);
  229. gfxHLine(y0, x0, x1);
  230. gfxHLine(y1, x0, x1);
  231. gfxVLine(x0, y0, y1);
  232. gfxVLine(x1, y0, y1);
  233. }
  234. void SaveQAV( void )
  235. {
  236. char filename[128];
  237. int hFile;
  238. strcpy(filename, gQAVName);
  239. ChangeExtension(filename, ".QAV");
  240. // see if file exists
  241. if ( access(filename, F_OK) == 0 )
  242. {
  243. char bakname[_MAX_PATH];
  244. strcpy(bakname, filename);
  245. ChangeExtension(bakname, ".BAK");
  246. unlink(bakname);
  247. rename(filename, bakname);
  248. }
  249. hFile = open(filename, O_CREAT | O_WRONLY | O_BINARY | O_TRUNC, S_IWUSR);
  250. if ( hFile == -1 )
  251. ThrowError("Error creating QAV file", ES_ERROR);
  252. memcpy(gQAV->signature, kQAVSig, sizeof(gQAV->signature));
  253. gQAV->version = kQAVVersion;
  254. gQAV->duration = gQAV->nFrames * gQAV->ticksPerFrame;
  255. if ( !FileWrite(hFile, gQAV, sizeof(QAV) + (gQAV->nFrames) * sizeof(FRAME)) )
  256. goto WriteError;
  257. close(hFile);
  258. isModified = FALSE;
  259. scrSetMessage("QAV saved.");
  260. return;
  261. WriteError:
  262. close(hFile);
  263. ThrowError("Error writing QAV file", ES_ERROR);
  264. }
  265. BOOL LoadQAV( void )
  266. {
  267. char filename[128];
  268. int hFile;
  269. int nSize;
  270. strcpy(filename, gQAVName);
  271. ChangeExtension(filename, ".QAV");
  272. hFile = open(filename, O_RDONLY | O_BINARY);
  273. if ( hFile == -1 )
  274. return FALSE;
  275. nSize = filelength(hFile);
  276. QAV *pTemp = (QAV *)Resource::Alloc(nSize);
  277. if ( !FileRead(hFile, pTemp, nSize) )
  278. goto ReadError;
  279. close(hFile);
  280. if (memcmp(pTemp->signature, kQAVSig, sizeof(pTemp->signature)) != 0)
  281. {
  282. close(hFile);
  283. ThrowError("QAV file corrupted", ES_ERROR);
  284. }
  285. gQAV->nFrames = 0;
  286. gQAV->ticksPerFrame = 5;
  287. gQAV->duration = 0;
  288. gQAV->origin.x = 160;
  289. gQAV->origin.y = 100;
  290. memset(&gQAV->frame[0], 0, sizeof(FRAME) * kMaxFrames);
  291. switch ( pTemp->version >> 8 )
  292. {
  293. case 1:
  294. {
  295. QAV1 *pQAV1 = (QAV1 *)pTemp;
  296. gQAV->nFrames = pQAV1->duration / 5;
  297. gQAV->ticksPerFrame = 5;
  298. gQAV->duration = pQAV1->duration;
  299. gQAV->origin = pQAV1->origin;
  300. FRAME1 *pFrame1 = &pQAV1->frame[0];
  301. for (int i = 0; i < pQAV1->frames; i++, pFrame1++)
  302. {
  303. if ( pFrame1->type != 0 )
  304. continue;
  305. int j = pFrame1->timeStart / 5;
  306. FRAME *pFrame = &gQAV->frame[j];
  307. int nLayer = kMaxLayers - 1;
  308. // find highest used layer
  309. while ( nLayer >= 0 && pFrame->layer[nLayer].id == 0 )
  310. nLayer--;
  311. // use next layer up
  312. nLayer++;
  313. if ( nLayer == kMaxLayers )
  314. {
  315. dprintf("Out of layers at time index %d\n", pFrame1->timeStart);
  316. nLayer = 0;
  317. }
  318. for ( ; j < pFrame1->timeStop / 5; j++, pFrame++)
  319. {
  320. pFrame->layer[nLayer].id = pFrame1->id;
  321. pFrame->layer[nLayer].x = pFrame1->x;
  322. pFrame->layer[nLayer].y = pFrame1->y;
  323. pFrame->layer[nLayer].zoom = 0x10000;
  324. pFrame->layer[nLayer].flags = pFrame1->flags;
  325. pFrame->layer[nLayer].shade = (schar)pFrame1->shade;
  326. pFrame->layer[nLayer].pal = (uchar)pFrame1->pal;
  327. pFrame->layer[nLayer].angle = 0;
  328. }
  329. }
  330. break;
  331. }
  332. case 2:
  333. memcpy(gQAV, pTemp, nSize);
  334. break;
  335. }
  336. isModified = FALSE;
  337. return TRUE;
  338. ReadError:
  339. close(hFile);
  340. ThrowError("Error reading QAV file", ES_ERROR);
  341. return FALSE;
  342. }
  343. BOOL SaveAs( void )
  344. {
  345. if ( GetStringBox("Save As", gQAVName) )
  346. {
  347. // load it if it seems valid
  348. if (strlen(gQAVName) > 0)
  349. {
  350. SaveQAV();
  351. return TRUE;
  352. }
  353. }
  354. return FALSE;
  355. }
  356. BOOL LoadAs( void )
  357. {
  358. if ( GetStringBox("Load QAV", gQAVName) )
  359. {
  360. // load it if it seems valid
  361. if (strlen(gQAVName) > 0)
  362. {
  363. LoadQAV();
  364. return TRUE;
  365. }
  366. }
  367. return FALSE;
  368. }
  369. /*******************************************************************************
  370. ** ChangeAcknowledge()
  371. **
  372. ** Returns TRUE if the YES/NO selected, or FALSE if aborted or escape pressed.
  373. *******************************************************************************/
  374. BOOL ChangeAcknowledge(void)
  375. {
  376. // create the dialog
  377. Window dialog(59, 80, 202, 46, "Save Changes?");
  378. TextButton *pbYes = new TextButton( 4, 4, 60, 20, "&Yes", mrYes );
  379. TextButton *pbNo = new TextButton( 68, 4, 60, 20, "&No", mrNo );
  380. TextButton *pbCancel = new TextButton( 132, 4, 60, 20, "&Cancel", mrCancel );
  381. dialog.Insert(pbYes);
  382. dialog.Insert(pbNo);
  383. dialog.Insert(pbCancel);
  384. ShowModal(&dialog);
  385. switch ( dialog.endState )
  386. {
  387. case mrCancel:
  388. return FALSE;
  389. case mrOk:
  390. case mrYes:
  391. return SaveAs();
  392. }
  393. return TRUE;
  394. }
  395. void PlayIt( BOOL looping )
  396. {
  397. ulong timeBase = gGameClock;
  398. ulong t = 0;
  399. int timeFactor;
  400. gQAV->duration = gQAV->nFrames * gQAV->ticksPerFrame;
  401. while (1)
  402. {
  403. BYTE key = keyGet();
  404. BYTE shift = keystatus[KEY_LSHIFT] | keystatus[KEY_RSHIFT];
  405. BYTE ctrl = keystatus[KEY_LCTRL] | keystatus[KEY_RCTRL];
  406. switch (key)
  407. {
  408. case KEY_ESC:
  409. keystatus[KEY_ESC] = 0;
  410. return;
  411. case KEY_PLUS:
  412. gQAV->ticksPerFrame++;
  413. gQAV->duration = gQAV->nFrames * gQAV->ticksPerFrame;
  414. isModified = TRUE;
  415. break;
  416. case KEY_MINUS:
  417. gQAV->ticksPerFrame = ClipLow(gQAV->ticksPerFrame - 1, 1);
  418. gQAV->duration = gQAV->nFrames * gQAV->ticksPerFrame;
  419. isModified = TRUE;
  420. break;
  421. }
  422. if ((t >> 16) >= gQAV->duration)
  423. {
  424. if (!looping)
  425. break;
  426. t -= (gQAV->duration << 16);
  427. continue;
  428. }
  429. clearview(0);
  430. gQAV->Draw(t >> 16, 0, kQFrameScale);
  431. sprintf(buffer, "%2d:%03d TPF=%2d",
  432. (t >> 16) / kTimerRate, (t >> 16) % kTimerRate, gQAV->ticksPerFrame);
  433. gfxDrawText(512, 8, gStdColor[15], buffer);
  434. if (vidoption != 1)
  435. WaitVSync();
  436. scrNextPage();
  437. gFrameTicks = gGameClock - gFrameClock;
  438. gFrameClock += gFrameTicks;
  439. timeFactor = 16;
  440. if ( ctrl )
  441. timeFactor = 15;
  442. if ( shift )
  443. timeFactor = 14;
  444. t += gFrameTicks << timeFactor;
  445. }
  446. }
  447. void DrawEditFrame( FRAME *f )
  448. {
  449. // show the trigger info
  450. TRIGGER_FRAME *tf = &f->trigger;
  451. if ( tf->id > 0 )
  452. {
  453. sprintf( buffer, "Trigger: %6i", tf->id );
  454. gfxDrawText(0, 16, gStdColor[15], buffer);
  455. }
  456. // show the sound info
  457. SOUND_FRAME *sf = &f->sound;
  458. if ( sf->id > 0 )
  459. {
  460. sprintf(buffer, "Snd: %6d Vol: %4d Pri: %4d", sf->id, sf->volume, sf->priority );
  461. gfxDrawText(400, 16, gStdColor[15], buffer);
  462. }
  463. }
  464. void EditLoop( void )
  465. {
  466. int nbuttons;
  467. static int obuttons = 0;
  468. char buffer[256];
  469. int nFrame = 0;
  470. int nLayer = 0;
  471. while (1)
  472. {
  473. FRAME *pFrame = &gQAV->frame[nFrame];
  474. TILE_FRAME *pTFrame = &pFrame->layer[nLayer];
  475. gFrameTicks = gGameClock - gFrameClock;
  476. gFrameClock += gFrameTicks;
  477. UpdateBlinkClock(gFrameTicks);
  478. gQAV->duration = gQAV->nFrames * gQAV->ticksPerFrame;
  479. clearview(0);
  480. if ( nFrame < gQAV->nFrames )
  481. gQAV->Draw(nFrame * gQAV->ticksPerFrame, 0, kQFrameScale);
  482. DrawEditFrame(pFrame);
  483. sprintf(buffer,"%2d/%2d Layer=%d TPF=%2d",
  484. nFrame, gQAV->nFrames, nLayer, gQAV->ticksPerFrame);
  485. gfxDrawText(464, 8, gStdColor[15], buffer);
  486. if (keystatus[KEY_O])
  487. {
  488. gQAV->DrawOrigin(gStdColor[15]);
  489. sprintf(buffer,"%3i,%3i", gQAV->origin.x, gQAV->origin.y);
  490. gfxDrawText(0, 8, gStdColor[15], buffer);
  491. }
  492. else
  493. {
  494. gQAV->DrawOrigin(gStdColor[8]);
  495. if ( pTFrame->id > 0 )
  496. {
  497. if ( IsBlinkOn() )
  498. gQAV->HighlightFrame(pTFrame);
  499. sprintf(buffer,"Tile=%4d %+4d,%+4d Sh=%+4d Pal=%2d Zoom=%8X Ang=%4d",
  500. pTFrame->id,
  501. pTFrame->x,
  502. pTFrame->y,
  503. pTFrame->shade,
  504. pTFrame->pal,
  505. pTFrame->zoom,
  506. pTFrame->angle
  507. );
  508. gfxDrawText(0, 8, gStdColor[15], buffer);
  509. }
  510. }
  511. scrDisplayMessage(gStdColor[kColorWhite]);
  512. if (vidoption != 1)
  513. WaitVSync();
  514. scrNextPage();
  515. BYTE key = keyGet();
  516. BYTE shift = keystatus[KEY_LSHIFT] | keystatus[KEY_RSHIFT];
  517. BYTE ctrl = keystatus[KEY_LCTRL] | keystatus[KEY_RCTRL];
  518. BYTE alt = keystatus[KEY_LALT] | keystatus[KEY_RALT];
  519. BYTE pad5 = keystatus[KEY_PAD5];
  520. switch (key)
  521. {
  522. case KEY_ESC:
  523. keystatus[KEY_ESC] = 0;
  524. if (!isModified || ChangeAcknowledge())
  525. {
  526. free(gQAV);
  527. gQAV = NULL;
  528. return;
  529. }
  530. break;
  531. case KEY_SPACE:
  532. PlayIt(FALSE);
  533. break;
  534. case KEY_ENTER:
  535. PlayIt(TRUE);
  536. break;
  537. case KEY_F2:
  538. if (keystatus[KEY_LCTRL] || keystatus[KEY_RCTRL] || strlen(gQAVName) == 0)
  539. SaveAs();
  540. else
  541. SaveQAV();
  542. break;
  543. case KEY_F3:
  544. if (!isModified || ChangeAcknowledge())
  545. {
  546. LoadAs();
  547. nFrame = 0;
  548. nLayer = 0;
  549. }
  550. break;
  551. case KEY_2:
  552. SetBlinkOn();
  553. nFrame = ClipHigh(nFrame + 1, gQAV->nFrames);
  554. break;
  555. case KEY_1:
  556. SetBlinkOn();
  557. nFrame = ClipLow(nFrame - 1, 0);
  558. break;
  559. case KEY_HOME:
  560. SetBlinkOn();
  561. nFrame = 0;
  562. break;
  563. case KEY_END:
  564. SetBlinkOn();
  565. nFrame = gQAV->nFrames;
  566. break;
  567. case KEY_PLUS:
  568. gQAV->ticksPerFrame++;
  569. isModified = TRUE;
  570. break;
  571. case KEY_MINUS:
  572. gQAV->ticksPerFrame = ClipLow(gQAV->ticksPerFrame - 1, 1);
  573. isModified = TRUE;
  574. break;
  575. case KEY_INSERT:
  576. {
  577. if ( ctrl )
  578. {
  579. // insert a layer
  580. for (int i = 0; i < gQAV->nFrames; i++)
  581. {
  582. for (int j = kMaxLayers - 1; j > nLayer; j--)
  583. {
  584. gQAV->frame[i].layer[j] = gQAV->frame[i].layer[j - 1];
  585. }
  586. memset(&gQAV->frame[i].layer[j], 0, sizeof(TILE_FRAME));
  587. }
  588. isModified = TRUE;
  589. break;
  590. }
  591. if ( alt )
  592. {
  593. // insert a frame
  594. memmove(pFrame + 1, pFrame, (gQAV->nFrames - nFrame) * sizeof(FRAME));
  595. memset(pFrame, 0, sizeof(FRAME));
  596. gQAV->nFrames++;
  597. isModified = TRUE;
  598. break;
  599. }
  600. // just duplicate a tile
  601. if ( pTFrame->id <= 0 && nFrame > 0 )
  602. {
  603. *pTFrame = gQAV->frame[nFrame - 1].layer[nLayer];
  604. isModified = TRUE;
  605. if ( nFrame == gQAV->nFrames )
  606. gQAV->nFrames++;
  607. break;
  608. }
  609. break;
  610. }
  611. case KEY_DELETE:
  612. if ( ctrl )
  613. {
  614. // delete a layer
  615. for (int i = 0; i < gQAV->nFrames; i++)
  616. {
  617. for (int j = nLayer; j < kMaxLayers - 1; j++)
  618. {
  619. gQAV->frame[i].layer[j] = gQAV->frame[i].layer[j + 1];
  620. }
  621. memset(&gQAV->frame[i].layer[j], 0, sizeof(TILE_FRAME));
  622. }
  623. isModified = TRUE;
  624. break;
  625. }
  626. if ( alt )
  627. {
  628. // delete a frame
  629. if ( nFrame < gQAV->nFrames )
  630. {
  631. gQAV->nFrames--;
  632. memmove(pFrame, pFrame + 1, (gQAV->nFrames - nFrame) * sizeof(FRAME));
  633. memset(&gQAV->frame[gQAV->nFrames], 0, sizeof(FRAME));
  634. isModified = TRUE;
  635. }
  636. break;
  637. }
  638. // just delete a tile
  639. if ( pTFrame->id > 0 )
  640. {
  641. memset(pTFrame, 0, sizeof(TILE_FRAME));
  642. isModified = TRUE;
  643. break;
  644. }
  645. break;
  646. case KEY_PAGEUP:
  647. SetBlinkOn();
  648. if ( nLayer < kMaxLayers - 1 )
  649. {
  650. if ( shift )
  651. {
  652. if ( ctrl )
  653. {
  654. // raise entire layer
  655. for (int i = 0; i < gQAV->nFrames; i++)
  656. {
  657. TILE_FRAME temp = gQAV->frame[i].layer[nLayer];
  658. gQAV->frame[i].layer[nLayer] = gQAV->frame[i].layer[nLayer + 1];
  659. gQAV->frame[i].layer[nLayer + 1] = temp;
  660. }
  661. nLayer++;
  662. isModified = TRUE;
  663. break;
  664. }
  665. // raise tile
  666. TILE_FRAME temp = *pTFrame;
  667. *pTFrame = pFrame->layer[nLayer + 1];
  668. pFrame->layer[nLayer + 1] = temp;
  669. nLayer++;
  670. isModified = TRUE;
  671. break;
  672. }
  673. nLayer++;
  674. }
  675. break;
  676. case KEY_PAGEDN:
  677. SetBlinkOn();
  678. if ( nLayer > 0 )
  679. {
  680. if ( shift )
  681. {
  682. if ( ctrl )
  683. {
  684. // lower entire layer
  685. for (int i = 0; i < gQAV->nFrames; i++)
  686. {
  687. TILE_FRAME temp = gQAV->frame[i].layer[nLayer];
  688. gQAV->frame[i].layer[nLayer] = gQAV->frame[i].layer[nLayer - 1];
  689. gQAV->frame[i].layer[nLayer - 1] = temp;
  690. }
  691. nLayer--;
  692. isModified = TRUE;
  693. break;
  694. }
  695. // lower tile
  696. TILE_FRAME temp = *pTFrame;
  697. *pTFrame = pFrame->layer[nLayer - 1];
  698. pFrame->layer[nLayer - 1] = temp;
  699. nLayer--;
  700. isModified = TRUE;
  701. break;
  702. }
  703. nLayer--;
  704. }
  705. break;
  706. case KEY_F:
  707. pFrame->trigger.id = GetNumberBox("Trigger Id", pFrame->trigger.id, pFrame->trigger.id);
  708. if ( pFrame->trigger.id == 0 )
  709. break;
  710. if ( nFrame == gQAV->nFrames )
  711. gQAV->nFrames++;
  712. isModified = TRUE;
  713. break;
  714. case KEY_P:
  715. if ( pTFrame->id > 0 )
  716. {
  717. // set the palette for the highlighted tile frame
  718. if ( alt )
  719. pTFrame->pal = (uchar)GetNumberBox("Palookup", pTFrame->pal, pTFrame->pal );
  720. else
  721. pTFrame->pal = (uchar)IncRotate(pTFrame->pal, kMaxPLU);
  722. isModified = TRUE;
  723. }
  724. break;
  725. case KEY_R:
  726. if ( pTFrame->id > 0 )
  727. {
  728. pTFrame->flags ^= kQFrameCorner;
  729. isModified = TRUE;
  730. }
  731. break;
  732. case KEY_T:
  733. if ( pTFrame->id > 0 )
  734. {
  735. // set translucency flags for the highlighted tile frame
  736. int flags = pTFrame->flags;
  737. int level = 0;
  738. if ( flags & kQFrameTranslucent )
  739. {
  740. level = 1;
  741. if ( flags & kQFrameTranslucentR )
  742. level = 2;
  743. }
  744. level = IncRotate(level, 3);
  745. switch ( level )
  746. {
  747. case 0:
  748. flags &= ~kQFrameTranslucent & ~kQFrameTranslucentR;
  749. break;
  750. case 1:
  751. flags &= ~kQFrameTranslucentR;
  752. flags |= kQFrameTranslucent;
  753. break;
  754. case 2:
  755. flags |= kQFrameTranslucent | kQFrameTranslucentR;
  756. break;
  757. }
  758. pTFrame->flags = flags;
  759. isModified = TRUE;
  760. }
  761. break;
  762. case KEY_V:
  763. {
  764. int nTile = pTFrame->id;
  765. if ( nTile == 0 )
  766. {
  767. if ( nFrame > 0 )
  768. {
  769. *pTFrame = gQAV->frame[nFrame - 1].layer[nLayer];
  770. nTile = pTFrame->id;
  771. pTFrame->id = 0;
  772. }
  773. else
  774. pTFrame->zoom = 0x10000;
  775. }
  776. pTFrame->id = tilePick(nTile, pTFrame->id, SS_ALL);
  777. if ( pTFrame->id == 0 )
  778. break;
  779. if ( nFrame == gQAV->nFrames )
  780. gQAV->nFrames++;
  781. isModified = TRUE;
  782. break;
  783. }
  784. case KEY_X:
  785. if ( pTFrame->id > 0 )
  786. {
  787. pTFrame->flags ^= kQFrameXFlip;
  788. isModified = TRUE;
  789. }
  790. break;
  791. case KEY_Y:
  792. if ( pTFrame->id > 0 )
  793. {
  794. pTFrame->flags ^= kQFrameYFlip;
  795. isModified = TRUE;
  796. }
  797. break;
  798. case KEY_COMMA:
  799. if ( pTFrame->id > 0 )
  800. {
  801. int step = shift ? 4 : 128;
  802. pTFrame->angle = (short)(DecNext(pTFrame->angle, step) & kAngleMask);
  803. isModified = TRUE;
  804. }
  805. break;
  806. case KEY_PERIOD:
  807. if ( pTFrame->id > 0 )
  808. {
  809. int step = shift ? 4 : 128;
  810. pTFrame->angle = (short)(IncNext(pTFrame->angle, step) & kAngleMask);
  811. isModified = TRUE;
  812. }
  813. break;
  814. case KEY_PADSLASH:
  815. if ( pTFrame->id > 0 )
  816. {
  817. int step = shift ? 0x100 : 0x1000;
  818. pTFrame->zoom = pTFrame->zoom + step;
  819. isModified = TRUE;
  820. }
  821. break;
  822. case KEY_PADSTAR:
  823. if ( pTFrame->id > 0 )
  824. {
  825. int step = shift ? 0x100 : 0x1000;
  826. pTFrame->zoom = ClipLow(pTFrame->zoom - step, step);
  827. isModified = TRUE;
  828. }
  829. break;
  830. case KEY_PADPLUS:
  831. if ( pTFrame->id > 0 )
  832. {
  833. if ( ctrl )
  834. pTFrame->shade = -128;
  835. else
  836. pTFrame->shade = (schar)ClipLow( pTFrame->shade - 1, -128 );
  837. isModified = TRUE;
  838. }
  839. break;
  840. case KEY_PADMINUS:
  841. if ( pTFrame->id > 0 )
  842. {
  843. if ( ctrl )
  844. pTFrame->shade = 127;
  845. else
  846. pTFrame->shade = (schar)ClipHigh( pTFrame->shade + 1, 127 );
  847. isModified = TRUE;
  848. }
  849. break;
  850. case KEY_PAD0:
  851. if ( pTFrame->id > 0 )
  852. {
  853. pTFrame->shade = 0;
  854. isModified = TRUE;
  855. }
  856. break;
  857. case KEY_UP:
  858. SetBlinkOff();
  859. if ( keystatus[KEY_O] )
  860. {
  861. gQAV->SetOrigin(gQAV->origin.x, gQAV->origin.y - 1);
  862. isModified = TRUE;
  863. break;
  864. }
  865. if ( pTFrame->id > 0 )
  866. {
  867. pTFrame->y--;
  868. isModified = TRUE;
  869. }
  870. break;
  871. case KEY_DOWN:
  872. SetBlinkOff();
  873. if ( keystatus[KEY_O] )
  874. {
  875. gQAV->SetOrigin(gQAV->origin.x, gQAV->origin.y + 1);
  876. isModified = TRUE;
  877. break;
  878. }
  879. if ( pTFrame->id > 0 )
  880. {
  881. pTFrame->y++;
  882. isModified = TRUE;
  883. }
  884. break;
  885. case KEY_LEFT:
  886. SetBlinkOff();
  887. if ( keystatus[KEY_O] )
  888. {
  889. gQAV->SetOrigin(gQAV->origin.x - 1, gQAV->origin.y);
  890. isModified = TRUE;
  891. break;
  892. }
  893. if ( pTFrame->id > 0 )
  894. {
  895. pTFrame->x--;
  896. isModified = TRUE;
  897. }
  898. break;
  899. case KEY_RIGHT:
  900. SetBlinkOff();
  901. if ( keystatus[KEY_O] )
  902. {
  903. gQAV->SetOrigin(gQAV->origin.x + 1, gQAV->origin.y);
  904. isModified = TRUE;
  905. break;
  906. }
  907. if ( pTFrame->id > 0 )
  908. {
  909. pTFrame->x++;
  910. isModified = TRUE;
  911. }
  912. break;
  913. }
  914. Mouse::Read(gFrameTicks);
  915. // which buttons just got pressed
  916. nbuttons = (short)(~obuttons & Mouse::buttons);
  917. obuttons = Mouse::buttons;
  918. if ( Mouse::buttons & 1 )
  919. {
  920. if ( keystatus[KEY_O] )
  921. {
  922. gQAV->SetOrigin(gQAV->origin.x + Mouse::dX2, gQAV->origin.y + Mouse::dY2);
  923. isModified = TRUE;
  924. }
  925. else
  926. {
  927. SetBlinkOff();
  928. if ( pTFrame->id > 0 )
  929. {
  930. pTFrame->x += Mouse::dX2;
  931. pTFrame->y += Mouse::dY2;
  932. isModified = TRUE;
  933. }
  934. }
  935. }
  936. // make sure x and y don't cause the tile to go off screen
  937. if ( pTFrame->id > 0 )
  938. gQAV->ClipTileFrame(pTFrame);
  939. }
  940. }
  941. void InsertFilename( char *fname )
  942. {
  943. FNODE *n = (FNODE *)malloc(sizeof(FNODE) + strlen(fname));
  944. strcpy(n->name, fname);
  945. // insert the node at the tail, so it stays in order
  946. n->next = tail->next;
  947. tail->next = n;
  948. tail = n;
  949. }
  950. void ConvertWildcards(char *s)
  951. {
  952. char filespec[_MAX_PATH];
  953. char buffer[_MAX_PATH2];
  954. char path[_MAX_PATH];
  955. strcpy(filespec, s);
  956. AddExtension(filespec, ".SEQ");
  957. char *drive, *dir;
  958. // separate the path from the filespec
  959. _splitpath2(s, buffer, &drive, &dir, NULL, NULL);
  960. _makepath(path, drive, dir, NULL, NULL);
  961. struct find_t fileinfo;
  962. unsigned r = _dos_findfirst(s, _A_NORMAL, &fileinfo);
  963. if (r != 0)
  964. printf("%s not found\n", s);
  965. while ( r == 0 )
  966. {
  967. strcpy(filespec, path);
  968. strcat(filespec, fileinfo.name);
  969. InsertFilename(filespec);
  970. r = _dos_findnext( &fileinfo );
  971. }
  972. _dos_findclose(&fileinfo);
  973. // process the file list
  974. for (FNODE *n = head.next; n != &head; n = n->next)
  975. {
  976. strcpy(gQAVName, n->name);
  977. printf("Converting: %s\n", n->name);
  978. LoadQAV();
  979. SaveQAV();
  980. }
  981. }
  982. /***********************************************************************
  983. * Process command line arguments
  984. **********************************************************************/
  985. void ParseOptions( void )
  986. {
  987. enum {
  988. kSwitchHelp,
  989. kSwitchConvert,
  990. };
  991. static SWITCH switches[] = {
  992. { "?", kSwitchHelp, FALSE },
  993. { "C", kSwitchConvert, TRUE },
  994. { NULL, 0, FALSE },
  995. };
  996. int r;
  997. while ( (r = GetOptions(switches)) != GO_EOF )
  998. {
  999. switch (r)
  1000. {
  1001. case GO_INVALID:
  1002. QuitMessage("Invalid argument: %s", OptArgument);
  1003. case GO_FULL:
  1004. strcpy(gQAVName, OptArgument);
  1005. break;
  1006. case kSwitchHelp:
  1007. ShowUsage();
  1008. break;
  1009. case kSwitchConvert:
  1010. ConvertWildcards(OptArgument);
  1011. exit(0);
  1012. }
  1013. }
  1014. }
  1015. void main( void )
  1016. {
  1017. ShowBanner();
  1018. gOldDisplayMode = getvmode();
  1019. if ( _grow_handles(kRequiredFiles) < kRequiredFiles )
  1020. ThrowError("Not enough file handles available", ES_ERROR);
  1021. gGamma = BloodINI.GetKeyInt("View", "Gamma", 0);
  1022. Resource::heap = new QHeap(dpmiDetermineMaxRealAlloc());
  1023. gQAV = (EditQAV *)Resource::Alloc(sizeof(EditQAV) + kMaxFrames * sizeof(FRAME));
  1024. dassert(gQAV != NULL);
  1025. ParseOptions();
  1026. gSysRes.Init("BLOOD.RFF", "*.*");
  1027. gGuiRes.Init("GUI.RFF", NULL);
  1028. if ( !initmouse() )
  1029. QuitMessage("Mouse not detected");
  1030. // install our error handler
  1031. prevErrorHandler = errSetHandler(EditorErrorHandler);
  1032. InitEngine(1, 640, 400);
  1033. Mouse::SetRange(xdim, ydim);
  1034. if (tileInit() == 0)
  1035. ThrowError("ART files not found", ES_ERROR);
  1036. scrInit();
  1037. keyInstall();
  1038. scrCreateStdColors();
  1039. timerRegisterClient(ClockStrobe, kTimerRate);
  1040. timerInstall();
  1041. scrSetGameMode();
  1042. scrSetGamma(gGamma);
  1043. scrSetDac(0);
  1044. isModified = FALSE;
  1045. if ( strlen(gQAVName) > 0 )
  1046. LoadQAV();
  1047. else
  1048. {
  1049. gQAV->nFrames = 0;
  1050. gQAV->ticksPerFrame = 5;
  1051. gQAV->duration = 0;
  1052. gQAV->origin.x = 160;
  1053. gQAV->origin.y = 100;
  1054. memset(&gQAV->frame[0], 0, sizeof(FRAME) * kMaxFrames);
  1055. }
  1056. EditLoop();
  1057. setvmode(gOldDisplayMode);
  1058. dprintf("Removing timer\n");
  1059. timerRemove();
  1060. dprintf("uninitengine()\n");
  1061. uninitengine();
  1062. dprintf("All subsystems shut down. Processing exit functions\n");
  1063. errSetHandler(prevErrorHandler);
  1064. }