ARTEDIT.CPP 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291
  1. /*******************************************************************************
  2. FILE: ARTEDIT.CPP
  3. DESCRIPTION: Allows rearrangement of art tiles
  4. AUTHOR: Peter M. Freese
  5. CREATED: 06-19-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 <ctype.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 "screen.h"
  28. #include "textio.h"
  29. #include "inifile.h"
  30. #include "options.h"
  31. #include "timer.h"
  32. #include "getopt.h"
  33. #include "mouse.h"
  34. #include "db.h"
  35. #include "trig.h"
  36. #include <memcheck.h>
  37. #define kAttrTitle (kColorGreen * 16 + kColorYellow)
  38. #define kMaxUndo 100
  39. struct UNDO
  40. {
  41. int start, length, shift, cursor;
  42. };
  43. struct NAMED_TYPE
  44. {
  45. short id;
  46. char *name;
  47. };
  48. int pickSize[] = { 20, 32, 40, 64, 80, 128, 160 };
  49. BOOL tilesModified = FALSE;
  50. BOOL tilesMoved = FALSE;
  51. POINT origin;
  52. int nOctant = 0;
  53. char buffer[256];
  54. EHF prevErrorHandler;
  55. UNDO undo[kMaxUndo];
  56. int undoCount = 0, undoCountMax = 0;
  57. int nCursor;
  58. BOOL bForceVersion = FALSE;
  59. int nVersion;
  60. int nSelect1 = -1, nSelect2 = -1;
  61. int nSelectBegin = 0, nSelectEnd = -1;
  62. PICANM oldpicanm[kMaxTiles];
  63. static BYTE *inverseCLU = NULL;
  64. #define kMaxNameLength 17 // this is ken's lame-o size that can't be changed...
  65. static char oldNames[ kMaxTiles ][ kMaxNameLength ];
  66. static char tileNames[ kMaxTiles ][ kMaxNameLength ];
  67. BOOL namesModified = FALSE;
  68. char *viewNames[] =
  69. {
  70. "SINGLE",
  71. "5 FULL",
  72. "8 FULL",
  73. "5 HALF",
  74. "3 FLAT",
  75. "4 FLAT",
  76. };
  77. char *animNames[] =
  78. {
  79. "NoAnm",
  80. "Oscil",
  81. "AnmFw",
  82. "AnmBk",
  83. };
  84. char *surfNames[256];
  85. NAMED_TYPE surfNTNames[] =
  86. {
  87. kSurfNone, "NONE",
  88. kSurfStone, "STONE",
  89. kSurfMetal, "METAL",
  90. kSurfWood, "WOOD",
  91. kSurfFlesh, "FLESH",
  92. kSurfWater, "WATER",
  93. kSurfDirt, "DIRT",
  94. kSurfClay, "CLAY",
  95. kSurfSnow, "SNOW",
  96. kSurfIce, "ICE",
  97. kSurfLeaves, "LEAVES",
  98. kSurfCloth, "CLOTH",
  99. kSurfPlant, "PLANT",
  100. kSurfGoo, "GOO",
  101. kSurfLava, "LAVA",
  102. };
  103. /***********************************************************************
  104. * LoadTileNames
  105. *
  106. **********************************************************************/
  107. int LoadTileNames( void )
  108. {
  109. char buffer[160], ch;
  110. int fil, i, num, buffercnt;
  111. if ((fil = open("names.h", O_TEXT | O_RDWR, S_IREAD)) == -1)
  112. return(-1);
  113. i = read(fil,&ch,1);
  114. while ( ch != '#' && i > 0)
  115. {
  116. i = read(fil,&ch,1);
  117. }
  118. while ( ch == '#' )
  119. {
  120. // find first space
  121. while ( !isspace(ch) )
  122. read(fil,&ch,1);
  123. // find non-space
  124. while ( isspace(ch) )
  125. read(fil,&ch,1);
  126. // get name
  127. buffercnt = 0;
  128. while ( !isspace(ch) )
  129. {
  130. buffer[buffercnt++] = ch;
  131. read(fil,&ch,1);
  132. }
  133. // find non-space
  134. while ( isspace(ch) )
  135. read(fil,&ch,1);
  136. // get number
  137. num = 0;
  138. while ( isdigit(ch) )
  139. {
  140. num = num*10+(ch-48);
  141. read(fil,&ch,1);
  142. }
  143. // find end of line
  144. while ( ch != '\n' )
  145. read(fil,&ch,1);
  146. memcpy(tileNames[num], buffer, buffercnt);
  147. tileNames[num][buffercnt] = 0;
  148. read(fil,&ch,1);
  149. }
  150. close(fil);
  151. memcpy(oldNames, tileNames, sizeof(oldNames));
  152. namesModified = FALSE;
  153. return(0);
  154. }
  155. /***********************************************************************
  156. * SaveTileNames
  157. *
  158. **********************************************************************/
  159. void SaveTileNames( void )
  160. {
  161. char buffer[160];
  162. int hFile;
  163. int len;
  164. if (namesModified == FALSE)
  165. return;
  166. if ((hFile = open("names.h",O_TEXT | O_TRUNC | O_CREAT | O_WRONLY, S_IWRITE)) == -1)
  167. return;
  168. strcpy(buffer,"//Be careful when changing this file - it is parsed by Editart and Build.\n");
  169. write(hFile, buffer, strlen(buffer));
  170. for (int i = 0; i < kMaxTiles; i++)
  171. {
  172. if (tileNames[i][0] != 0)
  173. {
  174. len = sprintf(buffer, "#define %s %d\n", tileNames[i], i);
  175. write(hFile, buffer, len);
  176. }
  177. }
  178. close(hFile);
  179. namesModified = FALSE;
  180. return;
  181. }
  182. /***********************************************************************
  183. * FillNameArray
  184. *
  185. **********************************************************************/
  186. void FillNameArray( char **names, NAMED_TYPE *ntNames, int length )
  187. {
  188. for (int i = 0; i < length; i++)
  189. {
  190. names[ntNames->id] = ntNames->name;
  191. ntNames++;
  192. }
  193. }
  194. void faketimerhandler( void )
  195. { }
  196. /***********************************************************************
  197. * EditorErrorHandler()
  198. *
  199. * Terminate from error condition, displaying a message in text mode.
  200. *
  201. **********************************************************************/
  202. ErrorResult EditorErrorHandler( const Error& error )
  203. {
  204. uninitengine();
  205. keyRemove();
  206. setvmode(gOldDisplayMode);
  207. // chain to the default error handler
  208. return prevErrorHandler(error);
  209. };
  210. void SetOrigin( int x, int y )
  211. {
  212. origin.x = ClipRange(x, 0, xdim - 1);
  213. origin.y = ClipRange(y, 0, ydim - 1);
  214. }
  215. void DrawOrigin( int nColor )
  216. {
  217. Video.SetColor(nColor);
  218. gfxHLine(origin.y, origin.x - 6, origin.x - 1);
  219. gfxHLine(origin.y, origin.x + 1, origin.x + 6);
  220. gfxVLine(origin.x, origin.y - 5, origin.y - 1);
  221. gfxVLine(origin.x, origin.y + 1, origin.y + 5);
  222. }
  223. void AddUndo( int start, int length, int shift, int cursor)
  224. {
  225. if (undoCount == kMaxUndo)
  226. {
  227. undoCount--;
  228. memmove(&undo[0], &undo[1], undoCount * sizeof(UNDO));
  229. }
  230. undo[undoCount].start = start;
  231. undo[undoCount].length = length;
  232. undo[undoCount].shift = shift;
  233. undo[undoCount].cursor = cursor;
  234. undoCountMax = ++undoCount;
  235. }
  236. void Undo( void )
  237. {
  238. if (undoCount > 0)
  239. {
  240. undoCount--;
  241. tileRotateTiles(undo[undoCount].start, undo[undoCount].length, -undo[undoCount].shift);
  242. scrSetMessage("Move undone");
  243. nCursor = undo[undoCount].cursor;
  244. }
  245. else
  246. scrSetMessage("Nothing to undo.");
  247. }
  248. void Redo( void )
  249. {
  250. if (undoCount < undoCountMax)
  251. {
  252. tileRotateTiles(undo[undoCount].start, undo[undoCount].length, undo[undoCount].shift);
  253. scrSetMessage("Move redone");
  254. nCursor = undo[undoCount].cursor;
  255. undoCount++;
  256. }
  257. else
  258. scrSetMessage("Nothing to redo.");
  259. }
  260. void MoveTiles( int dest, int source, int count )
  261. {
  262. int start, length, shift;
  263. if (source < dest)
  264. {
  265. start = source;
  266. length = dest - source;
  267. shift = count;
  268. }
  269. else
  270. {
  271. start = dest;
  272. length = source - dest + count;
  273. shift = source - dest;
  274. }
  275. tileRotateTiles(start, length, shift);
  276. AddUndo(start, length, shift, nCursor);
  277. scrSetMessage("Tiles moved");
  278. tilesMoved = tilesModified = TRUE;
  279. }
  280. BOOL AcknowledgeTileChange(void)
  281. {
  282. // create the dialog
  283. Window dialog(0, 0, 202, 46, "Save Art Changes?");
  284. TextButton *pbYes = new TextButton( 4, 4, 60, 20, "&Yes", mrYes );
  285. TextButton *pbNo = new TextButton( 68, 4, 60, 20, "&No", mrNo );
  286. TextButton *pbCancel = new TextButton( 132, 4, 60, 20, "&Cancel", mrCancel );
  287. dialog.Insert(pbYes);
  288. dialog.Insert(pbNo);
  289. dialog.Insert(pbCancel);
  290. ShowModal(&dialog);
  291. switch ( dialog.endState )
  292. {
  293. case mrCancel:
  294. return FALSE;
  295. case mrOk:
  296. case mrYes:
  297. if ( tilesMoved )
  298. tileSaveArt();
  299. else
  300. tileSaveArtInfo();
  301. if ( namesModified )
  302. SaveTileNames();
  303. break;
  304. }
  305. return TRUE;
  306. }
  307. MODAL_RESULT KeepTileChanges(void)
  308. {
  309. // create the dialog
  310. Window dialog(0, 0, 202, 46, "Keep tile changes?");
  311. TextButton *pbYes = new TextButton( 4, 4, 60, 20, "&Yes", mrYes );
  312. TextButton *pbNo = new TextButton( 68, 4, 60, 20, "&No", mrNo );
  313. TextButton *pbCancel = new TextButton( 132, 4, 60, 20, "&Cancel", mrCancel );
  314. dialog.Insert(pbYes);
  315. dialog.Insert(pbNo);
  316. dialog.Insert(pbCancel);
  317. ShowModal(&dialog);
  318. return dialog.endState;
  319. }
  320. BOOL EditSelectedTiles(void)
  321. {
  322. // create the dialog
  323. Window dialog(0, 0, 202, 46, "Edit all selected?");
  324. TextButton *pbYes = new TextButton( 4, 4, 60, 20, "&Yes", mrYes );
  325. TextButton *pbNo = new TextButton( 68, 4, 60, 20, "&No", mrNo );
  326. TextButton *pbCancel = new TextButton( 132, 4, 60, 20, "&Cancel", mrCancel );
  327. dialog.Insert(pbYes);
  328. dialog.Insert(pbNo);
  329. dialog.Insert(pbCancel);
  330. ShowModal(&dialog);
  331. return dialog.endState;
  332. }
  333. int DrawTile( int nTile )
  334. {
  335. char nShade = 0;
  336. char nFlags = kRotateNormal;
  337. short nAngle = 0;
  338. switch ( picanm[nTile].view )
  339. {
  340. case kSpriteViewSingle:
  341. break;
  342. case kSpriteView5Full:
  343. if (nOctant <= 4)
  344. nTile += nOctant;
  345. else
  346. {
  347. nTile += 8 - nOctant;
  348. nAngle = kAngle180;
  349. nFlags |= kRotateYFlip;
  350. }
  351. break;
  352. case kSpriteView8Full:
  353. nTile += nOctant;
  354. break;
  355. case kSpriteView5Half:
  356. break;
  357. }
  358. rotatesprite(origin.x << 16, origin.y << 16, 0x10000, 0, (short)nTile, nShade, kPLUNormal,
  359. nFlags, 0, 0, xdim - 1, ydim - 1);
  360. return nTile;
  361. }
  362. int EditTileLoop( int nTile )
  363. {
  364. BYTE key, shift, ctrl;
  365. int nbuttons;
  366. static int obuttons = 0;
  367. char buffer[256];
  368. int nTileView = 0;
  369. BOOL playing = FALSE;
  370. BOOL localModified = FALSE;
  371. int xcenter, ycenter;
  372. BOOL localNamesModified = FALSE;
  373. memcpy(oldpicanm, picanm, sizeof(oldpicanm));
  374. memcpy(oldNames, tileNames, sizeof(oldNames));
  375. while (1)
  376. {
  377. gFrameTicks = gGameClock - gFrameClock;
  378. gFrameClock += gFrameTicks;
  379. UpdateBlinkClock(gFrameTicks);
  380. clearview(0);
  381. // turn off animation playing if the tile doesn't support it
  382. if (picanm[nTile].type == 0)
  383. playing = FALSE;
  384. if (playing)
  385. {
  386. rotatesprite(origin.x << 16, origin.y << 16, 0x10000, 0,
  387. (short)(nTile + animateoffs((short)nTile, 0)), 0, kPLUNormal,
  388. kRotateNormal, 0, 0, xdim - 1, ydim - 1);
  389. nTileView = nTile;
  390. }
  391. else
  392. nTileView = DrawTile(nTile);
  393. if (tileNames[nTile][0] != '\0')
  394. {
  395. sprintf(buffer, "Name: %s", tileNames[nTile]);
  396. printext256(0, 0, gStdColor[7], -1, buffer, 0);
  397. }
  398. sprintf(buffer, "Tile: %4i Surf: %s", nTile, surfNames[surfType[nTile]]);
  399. printext256(0, ydim - 20, gStdColor[7], -1, buffer, 0);
  400. sprintf(buffer, "%s:%2i [%2i] VIEW: %s", animNames[picanm[nTile].type],
  401. picanm[nTile].frames, picanm[nTile].speed, viewNames[picanm[nTile].view]);
  402. printext256(0, ydim - 10, gStdColor[15], -1, buffer, 0);
  403. DrawOrigin(gStdColor[keystatus[KEY_O] ? 15 : 8]);
  404. sprintf(buffer,"ANG: %3i", nOctant * 45);
  405. printext256(xdim - 80, ydim - 20, gStdColor[7], -1, buffer, 0);
  406. scrDisplayMessage(gStdColor[kColorWhite]);
  407. WaitVSync();
  408. scrNextPage();
  409. xcenter = picanm[nTileView].xcenter;
  410. ycenter = picanm[nTileView].ycenter;
  411. key = keyGet();
  412. shift = keystatus[KEY_LSHIFT] | keystatus[KEY_RSHIFT];
  413. ctrl = keystatus[KEY_LCTRL] | keystatus[KEY_RCTRL];
  414. switch (key)
  415. {
  416. case KEY_ESC:
  417. if ( !localModified && !localNamesModified )
  418. return nTile;
  419. switch ( KeepTileChanges() )
  420. {
  421. case mrOk:
  422. case mrYes:
  423. if (localModified)
  424. tilesModified = TRUE;
  425. if (localNamesModified)
  426. namesModified = TRUE;
  427. return nTile;
  428. case mrNo:
  429. if (localModified)
  430. memcpy(picanm, oldpicanm, sizeof(oldpicanm));
  431. if (localNamesModified)
  432. memcpy(tileNames, oldNames, sizeof(tileNames));
  433. return nTile;
  434. }
  435. break;
  436. case KEY_SPACE:
  437. playing = !playing;
  438. break;
  439. case KEY_COMMA: // "<"
  440. nOctant = DecRotate(nOctant, 8);
  441. break;
  442. case KEY_PERIOD: // ">"
  443. nOctant = IncRotate(nOctant, 8);
  444. break;
  445. case KEY_SLASH:
  446. nOctant = 0;
  447. break;
  448. case KEY_A:
  449. picanm[nTile].type++;
  450. tileMarkDirty(nTileView);
  451. localModified = TRUE;
  452. break;
  453. case KEY_G:
  454. nTile = GetNumberBox("Goto tile", 0, nTile);
  455. break;
  456. case KEY_N:
  457. {
  458. char buffer[80];
  459. strcpy(buffer, tileNames[nTile]);
  460. if (GetStringBox( " Tile Name (max. 16 letters) ", buffer) != 0) // check for cancelled dialog box
  461. {
  462. strncpy(tileNames[nTile], buffer, 16);
  463. tileNames[nTile][16] = '\0';
  464. localNamesModified = TRUE;
  465. }
  466. break;
  467. }
  468. case KEY_P:
  469. {
  470. int c = 0;
  471. for ( int i = 0; i < 16; i++)
  472. {
  473. for (int j = 0; j < 16; j++)
  474. {
  475. Video.SetColor(c++);
  476. gfxFillBox(i * 8, j * 8, i * 8 + 8, j * 8 + 8);
  477. }
  478. }
  479. scrNextPage();
  480. while ( keyGet() == 0 );
  481. break;
  482. }
  483. case KEY_W:
  484. picanm[nTile].view = IncRotate(picanm[nTile].view, LENGTH(viewNames));
  485. tileMarkDirty(nTile);
  486. localModified = TRUE;
  487. break;
  488. case KEY_PADPLUS:
  489. if (shift)
  490. {
  491. if (picanm[nTile].speed > 0)
  492. {
  493. picanm[nTile].speed--;
  494. tileMarkDirty(nTileView);
  495. localModified = TRUE;
  496. }
  497. }
  498. else
  499. {
  500. if (picanm[nTile].frames < 63)
  501. {
  502. picanm[nTile].frames++;
  503. if (picanm[nTile].type == 0)
  504. picanm[nTile].type = 2; // forward
  505. tileMarkDirty(nTileView);
  506. localModified = TRUE;
  507. }
  508. }
  509. break;
  510. case KEY_PADMINUS:
  511. if (shift)
  512. {
  513. if (picanm[nTile].speed < 15)
  514. {
  515. picanm[nTile].speed++;
  516. tileMarkDirty(nTileView);
  517. localModified = TRUE;
  518. }
  519. }
  520. else
  521. {
  522. if (picanm[nTile].frames > 0)
  523. {
  524. picanm[nTile].frames--;
  525. if (picanm[nTile].frames == 0)
  526. picanm[nTile].type = 0;
  527. tileMarkDirty(nTileView);
  528. localModified = TRUE;
  529. }
  530. }
  531. break;
  532. case KEY_PAD0:
  533. break;
  534. case KEY_PAGEUP:
  535. while (nTile > 0)
  536. {
  537. nTile--;
  538. if (tilesizx[nTile] > 0 && tilesizy[nTile] > 0)
  539. break;
  540. }
  541. break;
  542. case KEY_PAGEDN:
  543. while (nTile < kMaxTiles - 1)
  544. {
  545. nTile++;
  546. if (tilesizx[nTile] > 0 && tilesizy[nTile] > 0)
  547. break;
  548. }
  549. break;
  550. case KEY_UP:
  551. case KEY_PADUP:
  552. if ( keystatus[KEY_O] )
  553. {
  554. SetOrigin(origin.x, origin.y - 1);
  555. }
  556. else if (ctrl)
  557. {
  558. picanm[nTileView].ycenter = -tilesizy[nTileView] / 2;
  559. tileMarkDirty(nTileView);
  560. localModified = TRUE;
  561. }
  562. else
  563. {
  564. picanm[nTileView].ycenter++;
  565. tileMarkDirty(nTileView);
  566. localModified = TRUE;
  567. }
  568. break;
  569. case KEY_DOWN:
  570. case KEY_PADDOWN:
  571. if ( keystatus[KEY_O] )
  572. {
  573. SetOrigin(origin.x, origin.y + 1);
  574. }
  575. else if (ctrl)
  576. {
  577. picanm[nTileView].ycenter = tilesizy[nTileView] - tilesizy[nTileView] / 2;
  578. tileMarkDirty(nTileView);
  579. localModified = TRUE;
  580. }
  581. else
  582. {
  583. picanm[nTileView].ycenter--;
  584. tileMarkDirty(nTileView);
  585. localModified = TRUE;
  586. }
  587. break;
  588. case KEY_PAD5:
  589. if (ctrl)
  590. {
  591. picanm[nTileView].xcenter = 0;
  592. picanm[nTileView].ycenter = 0;
  593. tileMarkDirty(nTileView);
  594. localModified = TRUE;
  595. }
  596. break;
  597. case KEY_LEFT:
  598. case KEY_PADLEFT:
  599. if ( keystatus[KEY_O] )
  600. {
  601. SetOrigin(origin.x - 1, origin.y);
  602. }
  603. else if (ctrl)
  604. {
  605. picanm[nTileView].xcenter = -tilesizx[nTileView] / 2;
  606. tileMarkDirty(nTileView);
  607. localModified = TRUE;
  608. }
  609. else
  610. {
  611. picanm[nTileView].xcenter++;
  612. tileMarkDirty(nTileView);
  613. localModified = TRUE;
  614. }
  615. break;
  616. case KEY_RIGHT:
  617. case KEY_PADRIGHT:
  618. if ( keystatus[KEY_O] )
  619. {
  620. SetOrigin(origin.x + 1, origin.y);
  621. }
  622. else if (ctrl)
  623. {
  624. picanm[nTileView].xcenter = tilesizx[nTileView] - tilesizx[nTileView] / 2;
  625. tileMarkDirty(nTileView);
  626. localModified = TRUE;
  627. }
  628. else
  629. {
  630. picanm[nTileView].xcenter--;
  631. tileMarkDirty(nTileView);
  632. localModified = TRUE;
  633. }
  634. break;
  635. }
  636. Mouse::Read(gFrameTicks);
  637. // which buttons just got pressed
  638. nbuttons = (short)(~obuttons & Mouse::buttons);
  639. obuttons = Mouse::buttons;
  640. if ( Mouse::buttons & 1 )
  641. {
  642. if ( keystatus[KEY_O] )
  643. SetOrigin(origin.x + Mouse::dX2, origin.y + Mouse::dY2);
  644. }
  645. if ( nTileView >= nSelectBegin && nTileView <= nSelectEnd )
  646. {
  647. for (int i = nSelectBegin; i <= nSelectEnd; i++)
  648. {
  649. if ( i != nTileView )
  650. {
  651. picanm[i].xcenter += picanm[nTileView].xcenter - xcenter;
  652. picanm[i].ycenter += picanm[nTileView].ycenter - ycenter;
  653. tileMarkDirty(i);
  654. }
  655. }
  656. }
  657. }
  658. }
  659. void DrawTileScreen( long nStart, long nCursor, int size, int nMax )
  660. {
  661. int n, i, j, k, nTile, uSize, vSize;
  662. long duv;
  663. int x, y;
  664. long u;
  665. uchar *pTile, *pScreen;
  666. int height, width;
  667. int nCols = xdim / size;
  668. int nRows = ydim / size;
  669. char buffer[256];
  670. setupvlineasm(16);
  671. Video.SetColor(gStdColor[0]);
  672. clearview(0);
  673. n = 0;
  674. y = 0;
  675. for ( i = 0; i < nRows; i++, y += size )
  676. {
  677. x = 0;
  678. for ( j = 0; j < nCols; j++, n++, x += size )
  679. {
  680. if (nStart + n >= nMax)
  681. break;
  682. nTile = tileIndex[nStart + n];
  683. if ( tilesizx[nTile] > 0 && tilesizy[nTile] > 0 )
  684. {
  685. palookupoffse[0] = palookupoffse[1] = palookupoffse[2] = palookupoffse[3] = palookup[kPLUNormal];
  686. if ( nTile >= nSelectBegin && nTile <= nSelectEnd )
  687. palookupoffse[0] = palookupoffse[1] = palookupoffse[2] = palookupoffse[3] = inverseCLU;
  688. pTile = tileLoadTile(nTile);
  689. uSize = tilesizx[nTile];
  690. vSize = tilesizy[nTile];
  691. pScreen = frameplace + ylookup[y] + x;
  692. // draw actual size
  693. if ( uSize <= size && vSize <= size )
  694. {
  695. vince[0] = vince[1] = vince[2] = vince[3] = 0x00010000;
  696. bufplce[3] = pTile - vSize;
  697. for (u = 0; u + 3 < uSize; u += 4)
  698. {
  699. bufplce[0] = bufplce[3] + vSize;
  700. bufplce[1] = bufplce[0] + vSize;
  701. bufplce[2] = bufplce[1] + vSize;
  702. bufplce[3] = bufplce[2] + vSize;
  703. vplce[0] = vplce[1] = vplce[2] = vplce[3] = 0;
  704. vlineasm4(vSize, pScreen);
  705. pTile += 4 * vSize;
  706. pScreen += 4;
  707. }
  708. for (; u < uSize; u++)
  709. {
  710. vlineasm1(0x00010000, palookupoffse[0], vSize - 1, 0, pTile, pScreen);
  711. pTile += vSize;
  712. pScreen++;
  713. }
  714. }
  715. else
  716. {
  717. if (uSize > vSize) // wider
  718. {
  719. duv = (uSize << 16) / size;
  720. height = size * vSize / uSize;
  721. width = size;
  722. }
  723. else // taller
  724. {
  725. duv = (vSize << 16) / size;
  726. height = size;
  727. width = size * uSize / vSize;
  728. }
  729. // don't draw any that are too small to see
  730. if (height == 0)
  731. continue;
  732. vince[0] = vince[1] = vince[2] = vince[3] = duv;
  733. u = 0;
  734. for (k = 0; k + 3 < width; k += 4)
  735. {
  736. bufplce[0] = waloff[nTile] + vSize * (u >> 16);
  737. u += duv;
  738. bufplce[1] = waloff[nTile] + vSize * (u >> 16);
  739. u += duv;
  740. bufplce[2] = waloff[nTile] + vSize * (u >> 16);
  741. u += duv;
  742. bufplce[3] = waloff[nTile] + vSize * (u >> 16);
  743. u += duv;
  744. vplce[0] = vplce[1] = vplce[2] = vplce[3] = 0;
  745. vlineasm4(height, pScreen);
  746. pTile += 4 * vSize;
  747. pScreen += 4;
  748. }
  749. for (; k < width; k++)
  750. {
  751. pTile = waloff[nTile] + vSize * (u >> 16);
  752. vlineasm1(duv, palookupoffse[0], height - 1, 0, pTile, pScreen);
  753. pScreen++;
  754. u += duv;
  755. }
  756. }
  757. // overlay the surface type
  758. if ( !keystatus[KEY_CAPSLOCK] )
  759. {
  760. sprintf(buffer, "%s", surfNames[surfType[nTile]]);
  761. Video.FillBox(0, x, y + size - 7, x + strlen(buffer) * 4 + 1, y + size);
  762. printext256(x + 1, y + size - 7, gStdColor[surfType[nTile] == kSurfNone ? 4 : 11], -1, buffer, 1);
  763. }
  764. }
  765. // overlay the tile number
  766. if ( !keystatus[KEY_CAPSLOCK] )
  767. {
  768. sprintf(buffer, "%d", nTile);
  769. Video.FillBox(0, x, y, x + strlen(buffer) * 4 + 1, y + 7);
  770. printext256(x + 1, y, gStdColor[14], -1, buffer, 1);
  771. }
  772. }
  773. }
  774. if ( IsBlinkOn() )
  775. {
  776. k = nCursor - nStart; //draw open white box
  777. x = (k % nCols) * size;
  778. y = (k / nCols) * size;
  779. Video.SetColor(gStdColor[15]);
  780. Video.HLine(0, y, x, x + size - 1);
  781. Video.HLine(0, y + size - 1, x, x + size - 1);
  782. Video.VLine(0, x, y, y + size - 1);
  783. Video.VLine(0, x + size - 1, y, y + size - 1);
  784. }
  785. }
  786. void MainEditLoop( void )
  787. {
  788. static int nZoom = 3;
  789. int nStart;
  790. BYTE key, shift, alt;
  791. int size = pickSize[nZoom];
  792. int nCols = xdim / size;
  793. int nRows = ydim / size;
  794. BOOL selecting = FALSE;
  795. for (int i = 0; i < kMaxTiles; i++)
  796. tileIndex[i] = (short)i;
  797. nCursor = 0;
  798. nStart = ClipLow((nCursor - nRows * nCols + nCols) / nCols * nCols, 0);
  799. while (1)
  800. {
  801. DrawTileScreen(nStart, nCursor, pickSize[nZoom], kMaxTiles );
  802. scrDisplayMessage(gStdColor[15]);
  803. scrNextPage();
  804. if (vidoption != 1)
  805. WaitVSync();
  806. gFrameTicks = gGameClock - gFrameClock;
  807. gFrameClock += gFrameTicks;
  808. UpdateBlinkClock(gFrameTicks);
  809. key = keyGet();
  810. shift = keystatus[KEY_LSHIFT] | keystatus[KEY_RSHIFT];
  811. alt = keystatus[KEY_LALT] | keystatus[KEY_RALT];
  812. switch (key)
  813. {
  814. case KEY_LSHIFT:
  815. case KEY_RSHIFT:
  816. nSelect1 = nCursor;
  817. selecting = TRUE;
  818. break;
  819. case KEY_PADSTAR:
  820. if (nZoom > 0)
  821. {
  822. nZoom--;
  823. size = pickSize[nZoom];
  824. nCols = xdim / size;
  825. nRows = ydim / size;
  826. nStart = ClipLow((nCursor - nRows * nCols + nCols) / nCols * nCols, 0);
  827. }
  828. break;
  829. case KEY_PADSLASH:
  830. if (nZoom + 1 < LENGTH(pickSize))
  831. {
  832. nZoom++;
  833. size = pickSize[nZoom];
  834. nCols = xdim / size;
  835. nRows = ydim / size;
  836. nStart = ClipLow((nCursor - nRows * nCols + nCols) / nCols * nCols, 0);
  837. }
  838. break;
  839. case KEY_BACKSPACE:
  840. if (alt)
  841. Undo();
  842. break;
  843. case KEY_ENTER:
  844. if (alt)
  845. Redo();
  846. else
  847. {
  848. if ( nSelectEnd >= nSelectBegin )
  849. {
  850. switch ( EditSelectedTiles() )
  851. {
  852. case mrOk:
  853. case mrYes:
  854. nCursor = EditTileLoop(nCursor);
  855. break;
  856. case mrNo:
  857. nSelectEnd = nSelectBegin - 1;
  858. nCursor = EditTileLoop(nCursor);
  859. break;
  860. }
  861. }
  862. else
  863. nCursor = EditTileLoop(nCursor);
  864. }
  865. break;
  866. case KEY_S:
  867. {
  868. surfType[nCursor] = (BYTE)IncRotate(surfType[nCursor], kSurfMax);
  869. tilesModified = TRUE;
  870. if ( nCursor >= nSelectBegin && nCursor <= nSelectEnd )
  871. {
  872. for (int i = nSelectBegin; i <= nSelectEnd; i++)
  873. {
  874. surfType[i] = surfType[nCursor];
  875. }
  876. }
  877. break;
  878. }
  879. case KEY_LEFT:
  880. if (nCursor - 1 >= 0)
  881. nCursor--;
  882. SetBlinkOn();
  883. break;
  884. case KEY_RIGHT:
  885. if (nCursor + 1 < kMaxTiles)
  886. nCursor++;
  887. SetBlinkOn();
  888. break;
  889. case KEY_UP:
  890. if (nCursor - nCols >= 0)
  891. {
  892. nCursor -= nCols;
  893. }
  894. SetBlinkOn();
  895. break;
  896. case KEY_DOWN:
  897. if (nCursor + nCols < kMaxTiles)
  898. {
  899. nCursor += nCols;
  900. }
  901. SetBlinkOn();
  902. break;
  903. case KEY_PAGEUP:
  904. if (nCursor - nRows * nCols >= 0)
  905. {
  906. nCursor -= nRows * nCols;
  907. nStart -= nRows * nCols;
  908. if (nStart < 0) nStart = 0;
  909. }
  910. SetBlinkOn();
  911. break;
  912. case KEY_PAGEDN:
  913. if (nCursor + nRows * nCols < kMaxTiles)
  914. {
  915. nCursor += nRows * nCols;
  916. nStart += nRows * nCols;
  917. }
  918. SetBlinkOn();
  919. break;
  920. case KEY_HOME:
  921. nCursor = 0;
  922. SetBlinkOn();
  923. break;
  924. case KEY_END:
  925. nCursor = kMaxTiles - 1;
  926. SetBlinkOn();
  927. break;
  928. case KEY_G:
  929. nCursor = (short)GetNumberBox("Goto tile", 0, tileIndex[nCursor]);
  930. break;
  931. case KEY_ESC:
  932. keystatus[KEY_ESC] = 0;
  933. return;
  934. case KEY_INSERT:
  935. if ( nSelectBegin <= nSelectEnd )
  936. {
  937. MoveTiles(nCursor, nSelectBegin, nSelectEnd - nSelectBegin + 1);
  938. nSelect1 = nSelect2 = nSelectBegin = nSelectEnd = -1;
  939. }
  940. break;
  941. }
  942. if (selecting)
  943. {
  944. nSelect2 = nCursor;
  945. if (nSelect1 < nSelect2)
  946. {
  947. nSelectBegin = nSelect1;
  948. nSelectEnd = nSelect2 - 1;
  949. }
  950. else
  951. {
  952. nSelectBegin = nSelect2;
  953. nSelectEnd = nSelect1 - 1;
  954. }
  955. }
  956. if ( !shift )
  957. selecting = FALSE;
  958. while (nCursor < nStart)
  959. nStart -= nCols;
  960. while (nStart + nRows * nCols <= nCursor)
  961. nStart += nCols;
  962. if (key != 0)
  963. keyFlushStream();
  964. }
  965. }
  966. /***********************************************************************
  967. * ShowUsage
  968. *
  969. * Display command-line parameter usage, then exit.
  970. **********************************************************************/
  971. void ShowUsage(void)
  972. {
  973. printf("Syntax: ARTEDIT [options]\n");
  974. printf("-vN force art version to N\n");
  975. printf("-? This help\n");
  976. exit(0);
  977. }
  978. void QuitMessage(char * fmt, ...)
  979. {
  980. char msg[80];
  981. va_list argptr;
  982. va_start( argptr, fmt );
  983. vsprintf( msg, fmt, argptr );
  984. va_end(argptr);
  985. printf(msg);
  986. exit(1);
  987. }
  988. /***********************************************************************
  989. * Process command line arguments
  990. **********************************************************************/
  991. void ParseOptions( void )
  992. {
  993. enum { kSwitchHelp, kSwitchVersion };
  994. static SWITCH switches[] = {
  995. { "?", kSwitchHelp, FALSE },
  996. { "V", kSwitchVersion, TRUE },
  997. { NULL, 0, FALSE },
  998. };
  999. int r;
  1000. while ( (r = GetOptions(switches)) != GO_EOF )
  1001. {
  1002. switch (r) {
  1003. case GO_INVALID:
  1004. case GO_FULL:
  1005. QuitMessage("Invalid argument: %s", OptArgument);
  1006. break;
  1007. case kSwitchVersion:
  1008. nVersion = strtol(OptArgument, NULL, 0);
  1009. bForceVersion = TRUE;
  1010. break;
  1011. case kSwitchHelp:
  1012. ShowUsage();
  1013. break;
  1014. }
  1015. }
  1016. }
  1017. void main( void )
  1018. {
  1019. char title[256];
  1020. FillNameArray(surfNames, surfNTNames, LENGTH(surfNTNames));
  1021. ParseOptions();
  1022. gOldDisplayMode = getvmode();
  1023. sprintf(title, "Art Editor [%s] -- DO NOT DISTRIBUTE", gBuildDate);
  1024. tioInit();
  1025. tioCenterString(0, 0, tioScreenCols - 1, title, kAttrTitle);
  1026. tioCenterString(tioScreenRows - 1, 0, tioScreenCols - 1,
  1027. "Copyright (c) 1994, 1995 Q Studios Corporation", kAttrTitle);
  1028. tioWindow(1, 0, tioScreenRows - 2, tioScreenCols);
  1029. if ( _grow_handles(kRequiredFiles) < kRequiredFiles )
  1030. ThrowError("Not enough file handles available", ES_ERROR);
  1031. gGamma = BloodINI.GetKeyInt("View", "Gamma", 0);
  1032. tioPrint("Initializing heap and resource system");
  1033. Resource::heap = new QHeap(dpmiDetermineMaxRealAlloc());
  1034. tioPrint("Initializing resource archive");
  1035. gSysRes.Init("BLOOD.RFF", "*.*");
  1036. gGuiRes.Init("GUI.RFF", NULL);
  1037. tioPrint("Loading tiles");
  1038. if (tileInit() == 0)
  1039. ThrowError("ART files not found", ES_ERROR);
  1040. if ( bForceVersion )
  1041. {
  1042. artversion = nVersion;
  1043. tioPrint("Updating art version number");
  1044. tileMarkDirtyAll();
  1045. tileSaveArtInfo();
  1046. exit(0);
  1047. }
  1048. LoadTileNames(); //load constants
  1049. tioPrint("Initializing mouse");
  1050. if ( !initmouse() )
  1051. tioPrint("Mouse not detected");
  1052. // install our error handler
  1053. prevErrorHandler = errSetHandler(EditorErrorHandler);
  1054. InitEngine();
  1055. Mouse::SetRange(xdim, ydim);
  1056. tioPrint("Initializing screen");
  1057. scrInit();
  1058. tioPrint("Installing keyboard handler");
  1059. keyInstall();
  1060. scrCreateStdColors();
  1061. RESHANDLE hInverse = gSysRes.Lookup("INVERSE", ".CLU");
  1062. if ( !hInverse )
  1063. ThrowError("Missing INVERSE.CLU resource", ES_ERROR);
  1064. inverseCLU = (BYTE *)gSysRes.Lock(hInverse);
  1065. tioPrint("Installing timer");
  1066. timerRegisterClient(ClockStrobe, kTimerRate);
  1067. timerInstall();
  1068. tioPrint("Engaging graphics subsystem...");
  1069. scrSetGameMode();
  1070. scrSetGamma(gGamma);
  1071. scrSetDac(0);
  1072. SetOrigin(xdim / 2, ydim / 2);
  1073. do {
  1074. MainEditLoop();
  1075. } while ((tilesModified || namesModified) && !AcknowledgeTileChange());
  1076. setvmode(gOldDisplayMode);
  1077. timerRemove();
  1078. uninitengine();
  1079. errSetHandler(prevErrorHandler);
  1080. }