TILE.CPP 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <i86.h>
  5. #include <io.h>
  6. #include <fcntl.h>
  7. #include "engine.h"
  8. #include "tile.h"
  9. #include "helix.h"
  10. #include "typedefs.h"
  11. #include "debug4g.h"
  12. #include "gameutil.h"
  13. #include "misc.h"
  14. #include "globals.h"
  15. #include "key.h"
  16. #include "gui.h"
  17. #include "screen.h"
  18. #include "error.h"
  19. #include "db.h"
  20. #define kMaxTileFiles 256
  21. static CACHENODE tileNode[kMaxTiles];
  22. static int tileStart[kMaxTileFiles], tileEnd[kMaxTileFiles];
  23. static int hTileFile[kMaxTileFiles];
  24. static BOOL tileFileDirty[kMaxTileFiles];
  25. static int nTileFiles = 0;
  26. static BOOL artLoaded = FALSE;
  27. static int pickSize[] = { 20, 32, 40, 64, 80, 128, 160 };
  28. static int tileHist[kMaxTiles];
  29. short tileIndex[kMaxTiles];
  30. int tileIndexCount;
  31. BYTE surfType[kMaxTiles];
  32. /*******************************************************************************
  33. FUNCTION: tileTerm()
  34. DESCRIPTION: Close all open tile files
  35. *******************************************************************************/
  36. void tileTerm( void )
  37. {
  38. for (int i = 0; i < kMaxTileFiles; i++)
  39. {
  40. if (hTileFile[i] != -1)
  41. {
  42. close(hTileFile[i]);
  43. hTileFile[i] = -1;
  44. }
  45. }
  46. }
  47. static void CalcPicsiz( int nTile, int x, int y )
  48. {
  49. int i;
  50. uchar n = 0;
  51. for (i = 2; i <= x; i <<= 1)
  52. n += 0x01;
  53. for (i = 2; i <= y; i <<= 1)
  54. n += 0x10;
  55. picsiz[nTile] = n;
  56. }
  57. int tileInit( void )
  58. {
  59. char filename[20];
  60. long offset;
  61. int i;
  62. int nTiles;
  63. int nFile, hFile;
  64. // already loaded?
  65. if ( artLoaded )
  66. return nTileFiles;
  67. memset(tilesizx, 0, sizeof(tilesizx));
  68. memset(tilesizy, 0, sizeof(tilesizy));
  69. memset(picanm, 0, sizeof(picanm));
  70. memset(gotpic, 0, sizeof(gotpic));
  71. memset(hTileFile, -1, sizeof(hTileFile));
  72. nFile = 0;
  73. while (1)
  74. {
  75. sprintf(filename, "TILES%03i.ART", nFile);
  76. hFile = open(filename, O_BINARY | O_RDWR);
  77. if ( hFile == -1 )
  78. break;
  79. hTileFile[nFile] = hFile;
  80. read(hFile, &artversion, sizeof(artversion));
  81. read(hFile, &numtiles, sizeof(numtiles));
  82. read(hFile, &tileStart[nFile], sizeof(tileStart[nFile]));
  83. read(hFile, &tileEnd[nFile], sizeof(tileEnd[nFile]));
  84. nTiles = tileEnd[nFile] - tileStart[nFile] + 1;
  85. read(hFile, &tilesizx[tileStart[nFile]], nTiles * sizeof(tilesizx[0]));
  86. read(hFile, &tilesizy[tileStart[nFile]], nTiles * sizeof(tilesizy[0]));
  87. read(hFile, &picanm[tileStart[nFile]], nTiles * sizeof(picanm[0]));
  88. // get current position
  89. offset = lseek(hFile, 0, SEEK_CUR);
  90. for (i = tileStart[nFile]; i <= tileEnd[nFile]; i++)
  91. {
  92. tilefilenum[i] = (char)nFile;
  93. tilefileoffs[i] = offset;
  94. offset += tilesizx[i] * tilesizy[i];
  95. }
  96. nFile++;
  97. }
  98. nTileFiles = nFile;
  99. dprintf("%i tile files opened\n", nTileFiles);
  100. for (i = 0; i < kMaxTiles; i++)
  101. {
  102. // setup the tile size log 2 array for internal engine use
  103. CalcPicsiz(i, tilesizx[i], tilesizy[i]);
  104. waloff[i] = NULL;
  105. tileNode[i].ptr = NULL;
  106. }
  107. hFile = open("SURFACE.DAT", O_BINARY | O_RDWR);
  108. if ( hFile != -1 )
  109. {
  110. read(hFile, surfType, sizeof(surfType));
  111. close(hFile);
  112. }
  113. artLoaded = TRUE;
  114. return nTileFiles;
  115. }
  116. void tileSaveArt( void )
  117. {
  118. int nTiles, hFile, i, j;
  119. char tempName[20], fileName[20], bakName[20];
  120. for (i = 0; i < nTileFiles; i++)
  121. {
  122. if ( tileFileDirty[i] )
  123. {
  124. tmpnam(tempName);
  125. hFile = open(tempName, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IWUSR);
  126. write(hFile, &artversion, sizeof(artversion));
  127. write(hFile, &numtiles, sizeof(numtiles));
  128. write(hFile, &tileStart[i], sizeof(tileStart[i]));
  129. write(hFile, &tileEnd[i], sizeof(tileEnd[i]));
  130. nTiles = tileEnd[i] - tileStart[i] + 1;
  131. write(hFile, &tilesizx[tileStart[i]], nTiles * sizeof(tilesizx[0]));
  132. write(hFile, &tilesizy[tileStart[i]], nTiles * sizeof(tilesizy[0]));
  133. write(hFile, &picanm[tileStart[i]], nTiles * sizeof(picanm[0]));
  134. for (j = tileStart[i]; j <= tileEnd[i]; j++)
  135. write(hFile, tileLoadTile(j), tilesizx[j] * tilesizy[j]);
  136. close(hFile);
  137. sprintf(bakName, "TILES%03i.BAK", i);
  138. remove(bakName);
  139. sprintf(fileName, "TILES%03i.ART", i);
  140. rename(fileName, bakName);
  141. rename(tempName, fileName);
  142. tileFileDirty[i] = FALSE;
  143. }
  144. }
  145. for (i = 0; i < nTileFiles; i++)
  146. {
  147. close(hTileFile[i]);
  148. hTileFile[i] = -1;
  149. }
  150. hFile = open("SURFACE.DAT", O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IWUSR);
  151. write(hFile, surfType, sizeof(surfType));
  152. close(hFile);
  153. artLoaded = FALSE;
  154. tileInit();
  155. }
  156. void tileSaveArtInfo( void )
  157. {
  158. int nTiles;
  159. int hFile;
  160. for (int i = 0; i < nTileFiles; i++)
  161. {
  162. if ( tileFileDirty[i] )
  163. {
  164. hFile = hTileFile[i];
  165. dassert(hFile != -1);
  166. lseek(hFile, 0, SEEK_SET);
  167. write(hFile, &artversion, sizeof(artversion));
  168. write(hFile, &numtiles, sizeof(numtiles));
  169. write(hFile, &tileStart[i], sizeof(tileStart[i]));
  170. write(hFile, &tileEnd[i], sizeof(tileEnd[i]));
  171. nTiles = tileEnd[i] - tileStart[i] + 1;
  172. write(hFile, &tilesizx[tileStart[i]], nTiles * sizeof(tilesizx[0]));
  173. write(hFile, &tilesizy[tileStart[i]], nTiles * sizeof(tilesizy[0]));
  174. write(hFile, &picanm[tileStart[i]], nTiles * sizeof(picanm[0]));
  175. tileFileDirty[i] = FALSE;
  176. }
  177. }
  178. hFile = open("SURFACE.DAT", O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IWUSR);
  179. write(hFile, surfType, sizeof(surfType));
  180. close(hFile);
  181. }
  182. void tileMarkDirty( int nTile )
  183. {
  184. tileFileDirty[tilefilenum[nTile]] = TRUE;
  185. }
  186. void tileMarkDirtyAll( void )
  187. {
  188. for (int i = 0; i < nTileFiles; i++)
  189. tileFileDirty[i] = TRUE;
  190. }
  191. // Remove a tile from the resource cache. This gets called by tileMoveTiles()
  192. void tilePurgeTile( int nTile )
  193. {
  194. CACHENODE *node = &tileNode[nTile];
  195. if (node->ptr != NULL )
  196. Resource::Flush((RESHANDLE)node);
  197. }
  198. void tileRotateTiles( int start, int length, int shift )
  199. {
  200. int i, j, k;
  201. int ttilefileoffs;
  202. short ttilesizx, ttilesizy;
  203. char ttilefilenum;
  204. uchar tpicsiz;
  205. BYTE *twaloff;
  206. PICANM tpicanm;
  207. while (shift < 0)
  208. shift += length;
  209. i = k = start;
  210. for (int n = length; n > 0; n--)
  211. {
  212. // invalidate cache data for this tile
  213. tilePurgeTile(i);
  214. tileMarkDirty(i);
  215. if (i == k)
  216. {
  217. ttilesizx = tilesizx[i];
  218. ttilesizy = tilesizy[i];
  219. ttilefilenum = tilefilenum[i];
  220. ttilefileoffs = tilefileoffs[i];
  221. tpicsiz = picsiz[i];
  222. twaloff = waloff[i];
  223. tpicanm = picanm[i];
  224. }
  225. j = i + shift;
  226. while (j >= start + length)
  227. j -= length;
  228. if (j == k)
  229. {
  230. tilesizx[i] = ttilesizx;
  231. tilesizy[i] = ttilesizy;
  232. tilefilenum[i] = ttilefilenum;
  233. tilefileoffs[i] = ttilefileoffs;
  234. picsiz[i] = tpicsiz;
  235. waloff[i] = twaloff;
  236. picanm[i] = tpicanm;
  237. i = ++k;
  238. continue;
  239. }
  240. tilesizx[i] = tilesizx[j];
  241. tilesizy[i] = tilesizy[j];
  242. tilefilenum[i] = tilefilenum[j];
  243. tilefileoffs[i] = tilefileoffs[j];
  244. picsiz[i] = picsiz[j];
  245. waloff[i] = waloff[j];
  246. picanm[i] = picanm[j];
  247. i = j;
  248. }
  249. }
  250. BYTE *tileLoadTile( int nTile )
  251. {
  252. static nLastTile = 0;
  253. int hFile;
  254. if ( tileNode[nLastTile].lockCount == 0)
  255. waloff[nLastTile] = NULL;
  256. nLastTile = nTile;
  257. dassert(nTile >= 0 && nTile < kMaxTiles);
  258. CACHENODE *node = &tileNode[nTile];
  259. // already in memory?
  260. if (node->ptr != NULL)
  261. {
  262. waloff[nTile] = (BYTE *)node->ptr;
  263. if (node->lockCount == 0)
  264. {
  265. Resource::RemoveMRU(node);
  266. Resource::AddMRU(node);
  267. nLastTile = nTile;
  268. }
  269. else
  270. dprintf("loadtile() called for locked tile %i\n", nTile);
  271. return waloff[nTile];
  272. }
  273. int nSize = tilesizx[nTile] * tilesizy[nTile];
  274. if (nSize <= 0)
  275. return NULL;
  276. gCacheMiss = 30;
  277. dassert(node->lockCount == 0);
  278. node->ptr = Resource::Alloc(nSize);
  279. waloff[nTile] = (BYTE *)node->ptr;
  280. Resource::AddMRU(node);
  281. // load the tile from the art file
  282. hFile = hTileFile[tilefilenum[nTile]];
  283. lseek(hFile, tilefileoffs[nTile], SEEK_SET);
  284. read(hFile, node->ptr, nSize);
  285. return waloff[nTile];
  286. }
  287. BYTE *tileLockTile( int nTile )
  288. {
  289. dassert(nTile >= 0 && nTile < kMaxTiles);
  290. if ( tileLoadTile(nTile) == NULL )
  291. return NULL;
  292. CACHENODE *node = &tileNode[nTile];
  293. if (node->lockCount++ == 0)
  294. Resource::RemoveMRU(node);
  295. return waloff[nTile];
  296. }
  297. void tileUnlockTile( int nTile )
  298. {
  299. dassert(nTile >= 0 && nTile < kMaxTiles);
  300. CACHENODE *node = &tileNode[nTile];
  301. waloff[nTile] = NULL;
  302. if (node->lockCount > 0)
  303. {
  304. if ( --node->lockCount == 0 )
  305. Resource::AddMRU(node);
  306. }
  307. }
  308. BYTE *tileAllocTile( int nTile, int sizeX, int sizeY )
  309. {
  310. int nSize;
  311. void *p;
  312. dassert(nTile >= 0 && nTile < kMaxTiles);
  313. if ( sizeX <= 0 || sizeY <= 0 || nTile >= kMaxTiles )
  314. return NULL;
  315. nSize = sizeX * sizeY;
  316. p = Resource::Alloc( nSize );
  317. dassert( p != NULL );
  318. tileNode[nTile].lockCount++;
  319. tileNode[nTile].ptr = p;
  320. waloff[nTile] = (BYTE *)p;
  321. tilesizx[nTile] = (short)sizeX;
  322. tilesizy[nTile] = (short)sizeY;
  323. //probably should turn this into a union, or just memset 0 over the struct
  324. picanm[nTile].frames = 0;
  325. picanm[nTile].type = 0;
  326. picanm[nTile].xcenter = 0;
  327. picanm[nTile].ycenter = 0;
  328. picanm[nTile].speed = 0;
  329. // setup the tile size log 2 array for internal engine use
  330. CalcPicsiz(nTile, sizeX, sizeY);
  331. return waloff[nTile];
  332. }
  333. void tileFreeTile( int nTile )
  334. {
  335. dassert(nTile >= 0 && nTile < kMaxTiles);
  336. tilePurgeTile(nTile);
  337. waloff[nTile] = NULL;
  338. tilesizx[nTile] = 0;
  339. tilesizy[nTile] = 0;
  340. picsiz[nTile] = 0;
  341. picanm[nTile].frames = 0;
  342. picanm[nTile].type = 0;
  343. picanm[nTile].xcenter = 0;
  344. picanm[nTile].ycenter = 0;
  345. picanm[nTile].speed = 0;
  346. }
  347. /*******************************************************************************
  348. FUNCTION: tilePreloadTile()
  349. DESCRIPTION:
  350. PARAMETERS:
  351. RETURNS:
  352. NOTES:
  353. *******************************************************************************/
  354. void tilePreloadTile( int nTile )
  355. {
  356. int i;
  357. switch (picanm[nTile].view)
  358. {
  359. case kSpriteViewSingle:
  360. if ( picanm[nTile].type != 0 )
  361. {
  362. for (i = picanm[nTile].frames; i >= 0; i--)
  363. {
  364. if (picanm[nTile].type == 3) // special case for backward anims
  365. tileLoadTile(nTile - i);
  366. else
  367. tileLoadTile(nTile + i);
  368. }
  369. }
  370. else
  371. tileLoadTile(nTile);
  372. break;
  373. case kSpriteView5Full:
  374. for (i = 0; i < 5; i++)
  375. tileLoadTile(nTile + i);
  376. }
  377. }
  378. int CompareTileFreqs( const void *ref1, const void *ref2 )
  379. {
  380. return tileHist[*(short *)ref2] - tileHist[*(short *)ref1];
  381. }
  382. /*******************************************************************************
  383. FUNCTION: BuildTileHistogram()
  384. DESCRIPTION: Fills in the tileHist[] array with the usage count for each
  385. tile.
  386. PARAMETERS: type is one of the searchstat types define in engine.h
  387. RETURNS: The index of the most frequently used tile
  388. NOTES:
  389. *******************************************************************************/
  390. short tileBuildHistogram( int type )
  391. {
  392. int i;
  393. memset(tileHist, 0, sizeof(tileHist[0]) * kMaxTiles);
  394. switch ( type )
  395. {
  396. case SS_WALL:
  397. for (i = 0; i < numwalls; i++)
  398. tileHist[wall[i].picnum]++;
  399. break;
  400. case SS_CEILING:
  401. for (i = 0; i < numsectors; i++)
  402. tileHist[sector[i].ceilingpicnum]++;
  403. break;
  404. case SS_FLOOR:
  405. for (i = 0; i < numsectors; i++)
  406. tileHist[sector[i].floorpicnum]++;
  407. break;
  408. case SS_MASKED:
  409. for (i = 0; i < numwalls; i++)
  410. tileHist[wall[i].overpicnum]++;
  411. break;
  412. case SS_SPRITE:
  413. for (i = 0; i < kMaxSprites; i++)
  414. {
  415. if ( sprite[i].statnum == kMaxStatus )
  416. continue;
  417. if ( sprite[i].statnum == kStatMarker)
  418. continue;
  419. if ( sprite[i].cstat & kSpriteInvisible )
  420. continue;
  421. // only add face sprites
  422. if ( (sprite[i].cstat & kSpriteRMask) == kSpriteFace )
  423. tileHist[sprite[i].picnum]++;
  424. }
  425. break;
  426. case SS_FLATSPRITE:
  427. for (i = 0; i < kMaxSprites; i++)
  428. {
  429. if ( sprite[i].statnum == kMaxStatus )
  430. continue;
  431. if ( sprite[i].statnum == kStatMarker)
  432. continue;
  433. if ( sprite[i].cstat & kSpriteInvisible )
  434. continue;
  435. // only add flat sprites
  436. if ( (sprite[i].cstat & kSpriteRMask) != kSpriteFace )
  437. tileHist[sprite[i].picnum]++;
  438. }
  439. break;
  440. }
  441. for (i = 0; i < kMaxTiles; i++)
  442. tileIndex[i] = (short)i;
  443. qsort(tileIndex, kMaxTiles, sizeof(tileIndex[0]), &CompareTileFreqs);
  444. // find out how many used tiles are in the histogram
  445. tileIndexCount = 0;
  446. while (tileHist[tileIndex[tileIndexCount]] > 0 && tileIndexCount < kMaxTiles)
  447. tileIndexCount++;
  448. return tileIndex[0];
  449. }
  450. void tileDrawTileScreen( long nStart, long nCursor, int size, int nMax )
  451. {
  452. int n, i, j, k, nTile, uSize, vSize;
  453. long duv;
  454. int x, y;
  455. long u;
  456. uchar *pTile, *pScreen;
  457. int height, width;
  458. int nCols = xdim / size;
  459. int nRows = ydim / size;
  460. char buffer[8];
  461. setupvlineasm(16);
  462. Video.SetColor(gStdColor[0]);
  463. clearview(0);
  464. n = 0;
  465. y = 0;
  466. for ( i = 0; i < nRows; i++, y += size )
  467. {
  468. x = 0;
  469. for ( j = 0; j < nCols; j++, n++, x += size )
  470. {
  471. if (nStart + n >= nMax)
  472. break;
  473. nTile = tileIndex[nStart + n];
  474. if ( tilesizx[nTile] > 0 && tilesizy[nTile] > 0 )
  475. {
  476. palookupoffse[0] = palookupoffse[1] = palookupoffse[2] = palookupoffse[3] = palookup[kPLUNormal];
  477. pTile = tileLoadTile(nTile);
  478. uSize = tilesizx[nTile];
  479. vSize = tilesizy[nTile];
  480. pScreen = frameplace + ylookup[y] + x;
  481. // draw actual size
  482. if ( uSize <= size && vSize <= size )
  483. {
  484. vince[0] = vince[1] = vince[2] = vince[3] = 0x00010000;
  485. bufplce[3] = pTile - vSize;
  486. for (u = 0; u + 3 < uSize; u += 4)
  487. {
  488. bufplce[0] = bufplce[3] + vSize;
  489. bufplce[1] = bufplce[0] + vSize;
  490. bufplce[2] = bufplce[1] + vSize;
  491. bufplce[3] = bufplce[2] + vSize;
  492. vplce[0] = vplce[1] = vplce[2] = vplce[3] = 0;
  493. vlineasm4(vSize, pScreen);
  494. pTile += 4 * vSize;
  495. pScreen += 4;
  496. }
  497. for (; u < uSize; u++)
  498. {
  499. vlineasm1(0x00010000, palookupoffse[0], vSize - 1, 0, pTile, pScreen);
  500. pTile += vSize;
  501. pScreen++;
  502. }
  503. }
  504. else
  505. {
  506. if (uSize > vSize) // wider
  507. {
  508. duv = (uSize << 16) / size;
  509. height = size * vSize / uSize;
  510. width = size;
  511. }
  512. else // taller
  513. {
  514. duv = (vSize << 16) / size;
  515. height = size;
  516. width = size * uSize / vSize;
  517. }
  518. // don't draw any that are too small to see
  519. if (height == 0)
  520. continue;
  521. vince[0] = vince[1] = vince[2] = vince[3] = duv;
  522. u = 0;
  523. for (k = 0; k + 3 < width; k += 4)
  524. {
  525. bufplce[0] = waloff[nTile] + vSize * (u >> 16);
  526. u += duv;
  527. bufplce[1] = waloff[nTile] + vSize * (u >> 16);
  528. u += duv;
  529. bufplce[2] = waloff[nTile] + vSize * (u >> 16);
  530. u += duv;
  531. bufplce[3] = waloff[nTile] + vSize * (u >> 16);
  532. u += duv;
  533. vplce[0] = vplce[1] = vplce[2] = vplce[3] = 0;
  534. vlineasm4(height, pScreen);
  535. pTile += 4 * vSize;
  536. pScreen += 4;
  537. }
  538. for (; k < width; k++)
  539. {
  540. pTile = waloff[nTile] + vSize * (u >> 16);
  541. vlineasm1(duv, palookupoffse[0], height - 1, 0, pTile, pScreen);
  542. pScreen++;
  543. u += duv;
  544. }
  545. }
  546. // overlay the usage count
  547. if ( nMax < kMaxTiles && !keystatus[KEY_CAPSLOCK] )
  548. {
  549. sprintf(buffer, "%d", tileHist[nTile]);
  550. Video.FillBox(0, x + size - strlen(buffer) * 4 - 2, y, x + size, y + 7);
  551. printext256(x + size - strlen(buffer) * 4 - 1, y, gStdColor[11], -1, buffer, 1);
  552. }
  553. }
  554. // overlay the tile number
  555. if ( !keystatus[KEY_CAPSLOCK] )
  556. {
  557. sprintf(buffer, "%d", nTile);
  558. Video.FillBox(0, x, y, x + strlen(buffer) * 4 + 1, y + 7);
  559. printext256(x + 1, y, gStdColor[14], -1, buffer, 1);
  560. }
  561. }
  562. }
  563. if ( IsBlinkOn() )
  564. {
  565. k = nCursor - nStart; //draw open white box
  566. x = (k % nCols) * size;
  567. y = (k / nCols) * size;
  568. Video.SetColor(gStdColor[15]);
  569. Video.HLine(0, y, x, x + size - 1);
  570. Video.HLine(0, y + size - 1, x, x + size - 1);
  571. Video.VLine(0, x, y, y + size - 1);
  572. Video.VLine(0, x + size - 1, y, y + size - 1);
  573. }
  574. }
  575. /*******************************************************************************
  576. FUNCTION: tilePick()
  577. DESCRIPTION: Allows visual selection of a tile
  578. PARAMETERS: nTile will be the initial highlighted selection
  579. RETURNS:
  580. NOTES:
  581. *******************************************************************************/
  582. short tilePick( int nTile, int nDefault, int type )
  583. {
  584. static int nZoom = 3;
  585. int i, nStart, nCursor;
  586. BYTE key;
  587. int size = pickSize[nZoom];
  588. int nCols = xdim / size;
  589. int nRows = ydim / size;
  590. if ( type != SS_CUSTOM )
  591. tileBuildHistogram(type);
  592. if ( tileIndexCount == 0 )
  593. {
  594. tileIndexCount = kMaxTiles;
  595. for(i = 0; i < kMaxTiles; i++)
  596. tileIndex[i] = (short)i;
  597. }
  598. nCursor = 0;
  599. for (i = 0; i < tileIndexCount; i++)
  600. {
  601. if (tileIndex[i] == nTile)
  602. {
  603. nCursor = i;
  604. break;
  605. }
  606. }
  607. nStart = ClipLow((nCursor - nRows * nCols + nCols) / nCols * nCols, 0);
  608. while (1)
  609. {
  610. tileDrawTileScreen(nStart, nCursor, pickSize[nZoom], tileIndexCount );
  611. if (vidoption != 1)
  612. WaitVSync();
  613. scrNextPage();
  614. gFrameTicks = gGameClock - gFrameClock;
  615. gFrameClock += gFrameTicks;
  616. UpdateBlinkClock(gFrameTicks);
  617. key = keyGet();
  618. switch (key)
  619. {
  620. case KEY_PADSTAR:
  621. if (nZoom > 0)
  622. {
  623. nZoom--;
  624. size = pickSize[nZoom];
  625. nCols = xdim / size;
  626. nRows = ydim / size;
  627. nStart = ClipLow((nCursor - nRows * nCols + nCols) / nCols * nCols, 0);
  628. }
  629. break;
  630. case KEY_PADSLASH:
  631. if (nZoom + 1 < LENGTH(pickSize))
  632. {
  633. nZoom++;
  634. size = pickSize[nZoom];
  635. nCols = xdim / size;
  636. nRows = ydim / size;
  637. nStart = ClipLow((nCursor - nRows * nCols + nCols) / nCols * nCols, 0);
  638. }
  639. break;
  640. case KEY_LEFT:
  641. if (nCursor - 1 >= 0)
  642. nCursor--;
  643. SetBlinkOn();
  644. break;
  645. case KEY_RIGHT:
  646. if (nCursor + 1 < tileIndexCount)
  647. nCursor++;
  648. SetBlinkOn();
  649. break;
  650. case KEY_UP:
  651. if (nCursor - nCols >= 0)
  652. nCursor -= nCols;
  653. SetBlinkOn();
  654. break;
  655. case KEY_DOWN:
  656. if (nCursor + nCols < tileIndexCount)
  657. nCursor += nCols;
  658. SetBlinkOn();
  659. break;
  660. case KEY_PAGEUP:
  661. if (nCursor - nRows * nCols >= 0)
  662. {
  663. nCursor -= nRows * nCols;
  664. nStart -= nRows * nCols;
  665. if (nStart < 0) nStart = 0;
  666. }
  667. SetBlinkOn();
  668. break;
  669. case KEY_PAGEDN:
  670. if (nCursor + nRows * nCols < tileIndexCount)
  671. {
  672. nCursor += nRows * nCols;
  673. nStart += nRows * nCols;
  674. }
  675. SetBlinkOn();
  676. break;
  677. case KEY_HOME:
  678. nCursor = 0;
  679. SetBlinkOn();
  680. break;
  681. case KEY_V:
  682. if ( type != SS_CUSTOM && tileIndexCount < kMaxTiles )
  683. {
  684. nCursor = tileIndex[nCursor];
  685. tileIndexCount = kMaxTiles;
  686. for(i = 0; i < kMaxTiles; i++)
  687. tileIndex[i] = (short)i;
  688. }
  689. break;
  690. case KEY_G:
  691. nTile = (short)GetNumberBox("Goto tile", 0, tileIndex[nCursor]);
  692. if (nTile >= kMaxTiles)
  693. break;
  694. if (nTile != tileIndex[nCursor])
  695. {
  696. // switch to all tile mode if not already there
  697. nCursor = nTile;
  698. tileIndexCount = kMaxTiles;
  699. for(i = 0; i < kMaxTiles; i++)
  700. tileIndex[i] = (short)i;
  701. }
  702. break;
  703. case KEY_ESC:
  704. clearview(0); // clear this page so it isn't 'leftover'
  705. keystatus[KEY_ESC] = 0;
  706. return (short)nDefault;
  707. case KEY_ENTER:
  708. clearview(0); // clear this page so it isn't 'leftover'
  709. nTile = tileIndex[nCursor];
  710. if (tilesizx[nTile] == 0 || tilesizy[nTile] == 0)
  711. return (short)nDefault;
  712. else
  713. return (short)nTile;
  714. }
  715. while (nCursor < nStart)
  716. nStart -= nCols;
  717. while (nStart + nRows * nCols <= nCursor)
  718. nStart += nCols;
  719. // let's see if this fixes the input buffering problem
  720. if (key != 0)
  721. keyFlushStream();
  722. }
  723. }
  724. /*******************************************************************************
  725. FUNCTION: tileGetSurfType()
  726. DESCRIPTION: Helper function to get the surface type for a game object.
  727. PARAMETERS: nHit is the type and index of the hit object.
  728. RETURNS: The surface type of the hit object.
  729. NOTES:
  730. *******************************************************************************/
  731. BYTE tileGetSurfType( int nHit )
  732. {
  733. int nHitType = nHit & kHitTypeMask;
  734. int nHitIndex = nHit & kHitIndexMask;
  735. switch ( nHitType )
  736. {
  737. case kHitFloor:
  738. return surfType[sector[nHitIndex].floorpicnum];
  739. case kHitCeiling:
  740. return surfType[sector[nHitIndex].ceilingpicnum];
  741. case kHitWall:
  742. return surfType[wall[nHitIndex].picnum];
  743. case kHitSprite:
  744. return surfType[sprite[nHitIndex].picnum];
  745. }
  746. return 0;
  747. }