VIEW.CPP 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576
  1. #include <string.h>
  2. #include "engine.h"
  3. #include "multi.h"
  4. #include "typedefs.h"
  5. #include "misc.h"
  6. #include "gameutil.h"
  7. #include "trig.h"
  8. #include "view.h"
  9. #include "globals.h"
  10. #include "textio.h"
  11. #include "names.h"
  12. #include "db.h"
  13. #include "debug4g.h"
  14. #include "resource.h"
  15. #include "error.h"
  16. #include "player.h"
  17. #include "screen.h"
  18. #include "options.h"
  19. #include "tile.h"
  20. #include "levels.h"
  21. #include "actor.h"
  22. #include "sectorfx.h"
  23. #include "mirrors.h"
  24. #include "fire.h"
  25. #include "weapon.h"
  26. #include "map2d.h"
  27. #include "gfx.h"
  28. #include <memcheck.h>
  29. #define kStatBarHeight 25
  30. /***********************************************************************
  31. * Variables
  32. **********************************************************************/
  33. int gViewIndex = 0;
  34. int gViewSize = 1;
  35. int gViewMode = kView3D;
  36. VIEWPOS gViewPos = kViewPosCenter;
  37. int gZoom = 1024;
  38. int gViewX0, gViewY0, gViewX1, gViewY1;
  39. int gViewXCenter, gViewYCenter;
  40. static long messageTime = 0;
  41. static char message[256];
  42. static int pcBackground = 0;
  43. int gShowFrameRate = FALSE;
  44. int gShowFrags = FALSE;
  45. long gScreenTilt = 0;
  46. int deliriumTilt = 0;
  47. int deliriumTurn = 0;
  48. int deliriumPitch = 0;
  49. struct PLOCATION
  50. {
  51. int x, y, z;
  52. int bobHeight, bobWidth;
  53. int swayHeight, swayWidth;
  54. int horiz;
  55. short ang;
  56. } gPrevPlayerLoc[kMaxPlayers];
  57. struct LOCATION
  58. {
  59. int x, y, z;
  60. short ang;
  61. } gPrevSpriteLoc[kMaxSprites];
  62. int gInterpolate;
  63. int gViewPosAngle[] =
  64. {
  65. 0, // kViewPosCenter
  66. kAngle180, // kViewPosBack
  67. kAngle180 - kAngle45, // kViewPosLeftBack
  68. kAngle90, // kViewPosLeft
  69. kAngle45, // kViewPosLeftFront
  70. 0, // kViewPosFront
  71. -kAngle45, // kViewPosRightFront
  72. -kAngle90, // kViewPosRight
  73. -kAngle90 - kAngle45, // kViewPosRightBack
  74. };
  75. void viewDrawChar( QFONT *pFont, BYTE c, int x, int y, BYTE *pPalookup )
  76. {
  77. dassert(pFont != NULL);
  78. y += pFont->baseline;
  79. CHARINFO *pInfo = &pFont->info[c];
  80. int sizeX = pInfo->cols;
  81. int sizeY = pInfo->rows;
  82. int nSize = sizeX * sizeY;
  83. if ( nSize == 0 )
  84. return;
  85. Rect dest(x, y + pInfo->voffset, x + sizeX, y + sizeY + pInfo->voffset);
  86. Rect screen(0, 0, xdim, ydim);
  87. dest &= screen;
  88. if ( !dest )
  89. return;
  90. BYTE *pSource = &pFont->data[pInfo->offset];
  91. for (int i = 0; i < 4; i++)
  92. {
  93. palookupoffse[i] = pPalookup;
  94. vince[i] = 0x00010000;
  95. }
  96. BYTE *bufplc = pSource;
  97. BYTE *p = frameplace + ylookup[dest.y0] + dest.x0;
  98. x = dest.x0;
  99. // dword align to video memory
  100. while (x < dest.x1 && (x & 3) )
  101. {
  102. mvlineasm1(0x00010000, pPalookup, sizeY - 1, 0, bufplc, p);
  103. bufplc += sizeY;
  104. p++;
  105. x++;
  106. }
  107. while ( x + 3 < dest.x1 )
  108. {
  109. for (i = 0; i < 4; i++)
  110. {
  111. bufplce[i] = bufplc;
  112. bufplc += sizeY;
  113. vplce[i] = 0;
  114. }
  115. mvlineasm4(sizeY, p);
  116. p += 4;
  117. x += 4;
  118. }
  119. while ( x < dest.x1 )
  120. {
  121. mvlineasm1(0x00010000, pPalookup, sizeY - 1, 0, bufplc, p);
  122. bufplc += sizeY;
  123. p++;
  124. x++;
  125. }
  126. }
  127. void viewDrawText( FONT_ID nFontId, char *string, int x, int y, int shade, int nPLU, int nAlign )
  128. {
  129. char *s;
  130. dassert(string != NULL);
  131. RESHANDLE hFont = gSysRes.Lookup(nFontId, ".QFN");
  132. dassert(hFont != NULL);
  133. QFONT *pFont = (QFONT *)gSysRes.Lock(hFont);
  134. BYTE *pPalookup = palookup[nPLU] + (getpalookup(0, shade) << 8);
  135. setupmvlineasm(16);
  136. if ( nAlign != TA_LEFT )
  137. {
  138. int nWidth = -pFont->charSpace;
  139. for ( s = string; *s; s++ )
  140. nWidth += pFont->info[*s].hspace + pFont->charSpace;
  141. if ( nAlign == TA_CENTER )
  142. nWidth >>= 1;
  143. x -= nWidth;
  144. }
  145. for ( s = string; *s; s++ )
  146. {
  147. viewDrawChar(pFont, *s, x, y, pPalookup);
  148. x += pFont->info[*s].hspace + pFont->charSpace;
  149. }
  150. gSysRes.Unlock(hFont);
  151. }
  152. static void TileSprite( int nTile, int shade, int nPLU, int x0, int y0, int x1, int y1)
  153. {
  154. long x, y, i;
  155. Rect clip(x0, y0, x1, y1);
  156. Rect screen(0, 0, xdim, ydim);
  157. clip &= screen;
  158. if ( !clip)
  159. return;
  160. dassert(nTile >= 0 && nTile < kMaxTiles);
  161. int sizeX = tilesizx[nTile];
  162. int sizeY = tilesizy[nTile];
  163. int nSize = sizeX * sizeY;
  164. if ( nSize == 0 )
  165. return;
  166. BYTE *palookupoffs = palookup[nPLU] + (getpalookup(0, shade) << 8);
  167. BYTE *pTile = tileLoadTile(nTile);
  168. BYTE *wrap = pTile + nSize;
  169. setupvlineasm(16);
  170. for (i = 0; i < 4; i++)
  171. {
  172. palookupoffse[i] = palookupoffs;
  173. vince[i] = 0x00010000;
  174. }
  175. int yNext;
  176. for (y = clip.y0; y < clip.y1; y = yNext)
  177. {
  178. yNext = ClipHigh(IncBy(y, sizeY), clip.y1);
  179. x = clip.x0;
  180. BYTE *bufplc = pTile + (x % sizeX) * sizeY + (y % sizeY);
  181. BYTE *p = frameplace + ylookup[y] + x;
  182. // dword align to video memory
  183. while (x < clip.x1 && (x & 3) )
  184. {
  185. vlineasm1(0x00010000, palookupoffs, yNext - y - 1, 0, bufplc, p);
  186. bufplc += sizeY;
  187. if (bufplc >= wrap) bufplc -= nSize;
  188. p++;
  189. x++;
  190. }
  191. while ( x + 3 < clip.x1 )
  192. {
  193. for (i = 0; i < 4; i++)
  194. {
  195. bufplce[i] = bufplc;
  196. bufplc += sizeY;
  197. if (bufplc >= wrap) bufplc -= nSize;
  198. vplce[i] = 0;
  199. }
  200. vlineasm4(yNext - y, p);
  201. p += 4;
  202. x += 4;
  203. }
  204. while ( x < clip.x1 )
  205. {
  206. vlineasm1(0x00010000, palookupoffs, yNext - y - 1, 0, bufplc, p);
  207. bufplc += sizeY;
  208. if (bufplc >= wrap) bufplc -= nSize;
  209. p++;
  210. x++;
  211. }
  212. }
  213. }
  214. static void ClipSprite( int x, int y, int nTile, int shade, int nPLU, int x0, int y0, int x1, int y1 )
  215. {
  216. Rect clip(x0, y0, x1, y1);
  217. Rect screen(0, 0, xdim, ydim);
  218. clip &= screen;
  219. if ( !clip)
  220. return;
  221. dassert(nTile >= 0 && nTile < kMaxTiles);
  222. int sizeX = tilesizx[nTile];
  223. int sizeY = tilesizy[nTile];
  224. int nSize = sizeX * sizeY;
  225. if ( nSize == 0 )
  226. return;
  227. Rect dest(x, y, x + sizeX, y + sizeY);
  228. dest &= clip;
  229. if ( !dest )
  230. return;
  231. Rect source(dest);
  232. source.offset(-x, -y);
  233. BYTE *palookupoffs = palookup[nPLU] + (getpalookup(0, shade) << 8);
  234. BYTE *pTile = tileLoadTile(nTile);
  235. setupvlineasm(16);
  236. for (int i = 0; i < 4; i++)
  237. {
  238. palookupoffse[i] = palookupoffs;
  239. vince[i] = 0x00010000;
  240. }
  241. BYTE *bufplc = pTile + (source.x0 % sizeX) * sizeY + (source.y0 % sizeY);
  242. BYTE *p = frameplace + ylookup[dest.y0] + dest.x0;
  243. x = dest.x0;
  244. // dword align to video memory
  245. while (x < dest.x1 && (x & 3) )
  246. {
  247. vlineasm1(0x00010000, palookupoffs, source.rows() - 1, 0, bufplc, p);
  248. bufplc += sizeY;
  249. p++;
  250. x++;
  251. }
  252. while ( x + 3 < dest.x1 )
  253. {
  254. for (i = 0; i < 4; i++)
  255. {
  256. bufplce[i] = bufplc;
  257. bufplc += sizeY;
  258. vplce[i] = 0;
  259. }
  260. vlineasm4(source.rows(), p);
  261. p += 4;
  262. x += 4;
  263. }
  264. while ( x < dest.x1 )
  265. {
  266. vlineasm1(0x00010000, palookupoffs, source.rows() - 1, 0, bufplc, p);
  267. bufplc += sizeY;
  268. p++;
  269. x++;
  270. }
  271. }
  272. void InitStatusBar( void )
  273. {
  274. tileLoadTile(kPicStatBar);
  275. }
  276. static void DrawStatSprite( int nTile, int x, int y, int nShade = 0, int nPLU = kPLUNormal )
  277. {
  278. rotatesprite(x << 16, y << 16, 0x10000, 0, (short)nTile, (schar)nShade, (char)nPLU,
  279. kRotateStatus | kRotateNoMask, 0, 0, xdim-1, ydim-1);
  280. }
  281. static void DrawStatMaskedSprite( int nTile, int x, int y, int nShade = 0, int nPLU = kPLUNormal )
  282. {
  283. rotatesprite(x << 16, y << 16, 0x10000, 0, (short)nTile, (schar)nShade, (char)nPLU,
  284. kRotateStatus, 0, 0, xdim-1, ydim-1);
  285. }
  286. static void DrawStatNumber( char *sFormat, int n, int nTile, int x, int y, int xSpace )
  287. {
  288. char buffer[80];
  289. sprintf(buffer, sFormat, n);
  290. for (int i = 0; i < strlen(buffer); i++)
  291. {
  292. if ( buffer[i] != ' ' )
  293. DrawStatSprite(nTile + buffer[i] - '0', x + i * xSpace, y);
  294. }
  295. }
  296. static void TileHGauge( int nTile, int x, int y, int n, int total )
  297. {
  298. int nGauge = n * tilesizx[nTile] / total;
  299. ClipSprite(x, y, nTile, 0, 0, 0, 0, x + nGauge, ydim);
  300. }
  301. static void UpdateStatusBar(void)
  302. {
  303. SPRITE *pSprite = gView->sprite;
  304. XSPRITE *pXSprite = gView->xsprite;
  305. int i;
  306. if (gViewMode == kView2D || gViewSize > 0) // status bar present?
  307. {
  308. DrawStatMaskedSprite(2200, 160, 178); // status bar
  309. DrawStatMaskedSprite(2234, 296, 179); // heart
  310. int nHealthTile = 2231; // green
  311. if ( pXSprite->health < (80 << 4) )
  312. nHealthTile = 2232; // yellow
  313. if ( pXSprite->health < (40 << 4) )
  314. nHealthTile = 2227; // red
  315. // show health amount
  316. DrawStatNumber("%3d", pXSprite->health >> 4, 2250, 157, 182, 5);
  317. TileHGauge(nHealthTile, 174, 180, pXSprite->health, 100 << 4); // health meter
  318. TileHGauge(2226, 221, 192, gView->bloodlust, 100 << 4); // lust
  319. // draw keys
  320. for (i = 0; i < 6; i++)
  321. {
  322. if ( gView->hasKey[i+1] )
  323. DrawStatSprite(2220 + i, 156 + i * 10, 193);
  324. else
  325. DrawStatSprite(2220 + i, 156 + i * 10, 193, 40, kPLUGrayish);
  326. }
  327. if ( gView->weapon != 0 )
  328. {
  329. DrawStatMaskedSprite(2229, 38 + gView->weapon * 13, 185); // highlight
  330. // show ammo count
  331. if ( gView->weaponAmmo != kAmmoNone )
  332. DrawStatNumber("%3d", gView->ammoCount[gView->weaponAmmo], 2190, 13, 180, 9);
  333. }
  334. // display level name
  335. if ( gViewMode == kView2D )
  336. gfxDrawText(0, 160, gStdColor[kColorWhite], gLevelDescription);
  337. }
  338. if (gCacheMiss)
  339. {
  340. DrawStatSprite(kPicDisk, xdim - 15, ydim - 15);
  341. gCacheMiss = ClipLow(gCacheMiss - kFrameTicks, 0);
  342. }
  343. }
  344. void viewInit(void)
  345. {
  346. gViewXCenter = xdim / 2;
  347. gViewYCenter = ydim / 2;
  348. gViewSize = BloodINI.GetKeyInt("View", "Size", 1);
  349. tioPrint("Initializing status bar");
  350. InitStatusBar();
  351. }
  352. void viewResizeView(int size)
  353. {
  354. //int x0, y0, x1, y1;
  355. gViewSize = ClipRange(size, 0, 8);
  356. // full screen mode
  357. if (gViewSize == 0)
  358. {
  359. gViewX0 = 0;
  360. gViewY0 = 0;
  361. gViewX1 = xdim - 1;
  362. gViewY1 = ydim - 1;
  363. setview(gViewX0, gViewY0, gViewX1, gViewY1);
  364. return;
  365. }
  366. gViewX0 = 0;
  367. gViewY0 = 0;
  368. gViewX1 = xdim - 1;
  369. gViewY1 = ydim - kStatBarHeight;
  370. gViewX0 += (gViewSize - 1) * xdim / 16;
  371. gViewX1 -= (gViewSize - 1) * xdim / 16;
  372. gViewY0 += (gViewSize - 1) * ydim / 16;
  373. gViewY1 -= (gViewSize - 1) * ydim / 16;
  374. setview(gViewX0, gViewY0, gViewX1, gViewY1);
  375. pcBackground = numpages;
  376. }
  377. #define kBackTile 230
  378. void viewDrawInterface( void )
  379. {
  380. int x0, y0, x1, y1;
  381. if (gViewMode == kView3D && gViewSize > 1)
  382. {
  383. if ( pcBackground )
  384. {
  385. x0 = gViewX0;
  386. y0 = gViewY0;
  387. x1 = gViewX1;
  388. y1 = gViewY1;
  389. TileSprite(kBackTile, 20, kPLUNormal, 0, 0, xdim, y0-3); // top
  390. TileSprite(kBackTile, 20, kPLUNormal, 0, y1+4, xdim, ydim); // bottom
  391. TileSprite(kBackTile, 20, kPLUNormal, 0, y0-3, x0-3, y1+4); // left
  392. TileSprite(kBackTile, 20, kPLUNormal, x1+4, y0-3, xdim, y1+4); // right
  393. TileSprite(kBackTile, 40, kPLUNormal, x0-3, y0-3, x0, y1+1); // left
  394. TileSprite(kBackTile, 40, kPLUNormal, x0, y0-3, x1+4, y0); // top
  395. TileSprite(kBackTile, 0, kPLUNormal, x1+1, y0, x1+4, y1+4); // right
  396. TileSprite(kBackTile, 0, kPLUNormal, x0-3, y1+1, x1+1, y1+4); // bottom
  397. pcBackground--;
  398. }
  399. }
  400. UpdateStatusBar();
  401. powerupDraw( gView );
  402. }
  403. #if 0
  404. short viewInsertTSprite( short nSector, short nStatus )
  405. {
  406. short nTSprite = -1;
  407. nTSprite = (short)spritesortcnt;
  408. SPRITE *pTSprite = &tsprite[nTSprite];
  409. memset(pTSprite, 0, sizeof(SPRITE));
  410. pTSprite->type = kNothing;
  411. pTSprite->sectnum = nSector;
  412. pTSprite->statnum = nStatus;
  413. pTSprite->cstat = kSpriteOriginAlign;
  414. pTSprite->xrepeat = 64;
  415. pTSprite->yrepeat = 64;
  416. pTSprite->owner = -1;
  417. pTSprite->extra = -1;
  418. spritesortcnt++;
  419. return nTSprite;
  420. }
  421. #endif
  422. static SPRITE *viewInsertTSprite( short nSector, short nStatus, SPRITE *pSource = NULL );
  423. static SPRITE *viewInsertTSprite( short nSector, short nStatus, SPRITE *pSource )
  424. {
  425. short nTSprite = -1;
  426. nTSprite = (short)spritesortcnt;
  427. SPRITE *pTSprite = &tsprite[nTSprite];
  428. memset(pTSprite, 0, sizeof(SPRITE));
  429. pTSprite->type = (short)-spritesortcnt; // negated temporary tsprite index - cleared after display
  430. pTSprite->sectnum = nSector;
  431. pTSprite->statnum = nStatus;
  432. pTSprite->cstat = kSpriteOriginAlign;
  433. pTSprite->xrepeat = 64;
  434. pTSprite->yrepeat = 64;
  435. pTSprite->owner = -1;
  436. pTSprite->extra = -1;
  437. spritesortcnt++;
  438. if ( pSource != NULL )
  439. {
  440. pTSprite->x = pSource->x;
  441. pTSprite->y = pSource->y;
  442. pTSprite->z = pSource->z;
  443. pTSprite->owner = pSource->owner;
  444. pTSprite->ang = pSource->ang;
  445. }
  446. return &tsprite[nTSprite];
  447. }
  448. enum VIEW_EFFECT {
  449. kViewEffectShadow = 0,
  450. kViewEffectFlareHalo,
  451. kViewEffectCeilGlow,
  452. kViewEffectFloorGlow,
  453. kViewEffectTorchHigh,
  454. kViewEffectTorchLow,
  455. kViewEffectSmokeHigh,
  456. kViewEffectSmokeLow,
  457. kViewEffectFlame,
  458. kViewEffectSpear,
  459. kViewEffectBloodSpray,
  460. kViewEffectPhase,
  461. kViewEffectMax,
  462. };
  463. int effectDetail[ kViewEffectMax ] =
  464. {
  465. kDetailLevelMax, // kViewEffectShadow
  466. kDetailLevelMax, // kViewEffectFlareHalo
  467. kDetailLevelMax, // kViewEffectCeilGlow,
  468. kDetailLevelMax, // kViewEffectFloorGlow,
  469. kDetailLevelMin, // kViewEffectTorchHigh
  470. kDetailLevelMin, // kViewEffectTorchLow
  471. kDetailLevelMin, // kViewEffectSmokeHigh
  472. kDetailLevelMin, // kViewEffectSmokeLow
  473. kDetailLevelMin, // kViewEffectFlame
  474. kDetailLevelMin, // kViewEffectSpear
  475. kDetailLevel2, // kViewEffectBloodSpray
  476. };
  477. static void viewAddEffect( int nTSprite, VIEW_EFFECT nViewEffect )
  478. {
  479. dassert( nViewEffect >= 0 && nViewEffect < kViewEffectMax );
  480. SPRITE *pTSprite = &tsprite[nTSprite];
  481. if ( gDetail < effectDetail[nViewEffect] ) // skip effects at higher detail levels
  482. return;
  483. // can more tsprites be inserted?
  484. if ( spritesortcnt < kMaxViewSprites )
  485. {
  486. switch (nViewEffect)
  487. {
  488. case kViewEffectPhase:
  489. {
  490. int nAngle = pTSprite->ang;
  491. // remember: things like butcher knive sprites are already +kAngle90 because they are wall sprites
  492. if (pTSprite->cstat & kSpriteWall)
  493. nAngle = (nAngle + kAngle90) & kAngleMask;
  494. else
  495. nAngle = (nAngle + kAngle180) & kAngleMask;
  496. for (int i=0; i<5 && spritesortcnt < kMaxViewSprites; i++)
  497. {
  498. short nSector;
  499. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF );
  500. pTEffect->ang = pTSprite->ang;
  501. pTEffect->x = pTSprite->x + mulscale30( (i+1) << 7, Cos(nAngle));
  502. pTEffect->y = pTSprite->y + mulscale30( (i+1) << 7, Sin(nAngle));
  503. pTEffect->z = pTSprite->z;
  504. FindSector(pTEffect->x, pTEffect->y, pTEffect->z, &nSector);
  505. pTEffect->sectnum = nSector;
  506. pTEffect->owner = pTSprite->owner;
  507. pTEffect->picnum = pTSprite->picnum;
  508. pTEffect->cstat = (uchar)(pTSprite->cstat & ~kSpriteBlocking);
  509. pTEffect->cstat |= kSpriteTranslucent;
  510. if (i < 2)
  511. pTEffect->cstat |= kSpriteTranslucentR;
  512. pTEffect->shade = (schar)ClipLow(pTSprite->shade - 16, -128);
  513. pTEffect->xrepeat = pTSprite->xrepeat;
  514. pTEffect->yrepeat = pTSprite->yrepeat;
  515. pTEffect->picnum = pTSprite->picnum;
  516. }
  517. break;
  518. }
  519. case kViewEffectFlame:
  520. {
  521. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF, pTSprite);
  522. pTEffect->z = pTSprite->z;
  523. pTEffect->cstat = (uchar)(pTSprite->cstat & ~kSpriteBlocking);
  524. pTEffect->shade = kMaxShade;
  525. pTEffect->xrepeat = pTEffect->yrepeat =
  526. (uchar)(tilesizx[pTSprite->picnum] * pTSprite->xrepeat / 64);
  527. pTEffect->picnum = kAnmFlame3;
  528. pTEffect->statnum = kStatDefault; // show up in front of burning objects
  529. break;
  530. }
  531. case kViewEffectSmokeHigh:
  532. {
  533. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF, pTSprite);
  534. int zTop, zBot;
  535. GetSpriteExtents(pTSprite, &zTop, &zBot);
  536. pTEffect->z = zTop;
  537. if ( IsDudeSprite(pTSprite->owner) )
  538. pTEffect->picnum = kAnmSmoke1;
  539. else
  540. pTEffect->picnum = kAnmSmoke2;
  541. pTEffect->cstat = (short)(pTSprite->cstat | kSpriteTranslucent & ~kSpriteBlocking);
  542. pTEffect->shade = 8;
  543. pTEffect->xrepeat = pTSprite->xrepeat;
  544. pTEffect->yrepeat = pTSprite->yrepeat;
  545. break;
  546. }
  547. case kViewEffectSmokeLow:
  548. {
  549. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF, pTSprite);
  550. int zTop, zBot;
  551. GetSpriteExtents(pTSprite, &zTop, &zBot);
  552. pTEffect->z = zBot;
  553. if ( IsDudeSprite(pTSprite->owner) )
  554. pTEffect->picnum = kAnmSmoke1;
  555. else
  556. pTEffect->picnum = kAnmSmoke2;
  557. pTEffect->cstat = (short)(pTSprite->cstat | kSpriteTranslucent & ~kSpriteBlocking);
  558. pTEffect->shade = 8;
  559. pTEffect->xrepeat = pTSprite->xrepeat;
  560. pTEffect->yrepeat = pTSprite->yrepeat;
  561. break;
  562. }
  563. case kViewEffectTorchHigh:
  564. {
  565. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF, pTSprite);
  566. int zTop, zBot;
  567. GetSpriteExtents(pTSprite, &zTop, &zBot);
  568. pTEffect->z = zTop;
  569. pTEffect->picnum = kAnmFlame2;
  570. pTEffect->cstat = (short)(pTSprite->cstat & ~kSpriteBlocking);
  571. pTEffect->shade = kMaxShade;
  572. pTEffect->xrepeat = pTEffect->yrepeat =
  573. (uchar)(tilesizx[pTSprite->picnum] * pTSprite->xrepeat / 32);
  574. break;
  575. }
  576. case kViewEffectTorchLow:
  577. {
  578. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF, pTSprite);
  579. int zTop, zBot;
  580. GetSpriteExtents(pTSprite, &zTop, &zBot);
  581. pTEffect->z = zBot;
  582. pTEffect->picnum = kAnmFlame2;
  583. pTEffect->cstat = (short)(pTSprite->cstat & ~kSpriteBlocking);
  584. pTEffect->shade = kMaxShade;
  585. pTEffect->xrepeat = pTEffect->yrepeat =
  586. (uchar)(tilesizx[pTSprite->picnum] * pTSprite->xrepeat / 32);
  587. break;
  588. }
  589. case kViewEffectShadow:
  590. {
  591. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF, pTSprite);
  592. // insert a shadow
  593. pTEffect->z = getflorzofslope(pTSprite->sectnum, pTEffect->x, pTEffect->y);
  594. pTEffect->cstat = (uchar)(pTSprite->cstat | kSpriteTranslucent);
  595. pTEffect->shade = kMinShade;
  596. pTEffect->xrepeat = pTSprite->xrepeat;
  597. pTEffect->yrepeat = (uchar)(pTSprite->yrepeat >> 2);
  598. pTEffect->picnum = pTSprite->picnum;
  599. int nTile = pTEffect->picnum;
  600. // position it so it's based on the floor
  601. pTEffect->z -= (tilesizy[nTile] - (tilesizy[nTile] / 2 + picanm[nTile].ycenter)) * (pTEffect->yrepeat << 2);
  602. break;
  603. }
  604. case kViewEffectFlareHalo:
  605. {
  606. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF, pTSprite);
  607. // insert a lens flare halo effect around flare missiles
  608. pTEffect->z = pTSprite->z;
  609. pTEffect->cstat = (uchar)(pTSprite->cstat | kSpriteTranslucent);
  610. pTEffect->shade = kMaxShade;
  611. pTEffect->pal = kPLURed;
  612. pTEffect->xrepeat = pTSprite->xrepeat;
  613. pTEffect->yrepeat = pTSprite->yrepeat;
  614. pTEffect->picnum = kAnmFlareHalo;
  615. break;
  616. }
  617. case kViewEffectCeilGlow:
  618. {
  619. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF, pTSprite);
  620. SECTOR *pSector = &sector[pTSprite->sectnum];
  621. int zDist = (pTSprite->z - pSector->ceilingz) >> 8;
  622. pTEffect->x = pTSprite->x;
  623. pTEffect->y = pTSprite->y;
  624. pTEffect->z = pSector->ceilingz;
  625. pTEffect->cstat = (uchar)(pTSprite->cstat | kSpriteTranslucent | kSpriteFloor | kSpriteOneSided | kSpriteFlipY);
  626. pTEffect->shade = (schar)(-64 + zDist);
  627. pTEffect->pal = kPLURed;
  628. pTEffect->xrepeat = 64;
  629. pTEffect->yrepeat = 64;
  630. pTEffect->picnum = kAnmGlowSpot1;
  631. pTEffect->ang = pTSprite->ang;
  632. pTEffect->owner = pTSprite->owner; //(short)nTSprite;
  633. break;
  634. }
  635. case kViewEffectFloorGlow:
  636. {
  637. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF, pTSprite);
  638. SECTOR *pSector = &sector[pTSprite->sectnum];
  639. int zDist = (pSector->floorz - pTSprite->z) >> 8;
  640. pTEffect->x = pTSprite->x;
  641. pTEffect->y = pTSprite->y;
  642. pTEffect->z = pSector->floorz;
  643. pTEffect->cstat = (uchar)(pTSprite->cstat | kSpriteTranslucent | kSpriteFloor | kSpriteOneSided);
  644. pTEffect->shade = (schar)(-32 + zDist);
  645. pTEffect->pal = kPLURed;
  646. pTEffect->xrepeat = (uchar)zDist;
  647. pTEffect->yrepeat = (uchar)zDist;
  648. pTEffect->picnum = kAnmGlowSpot1;
  649. pTEffect->ang = pTSprite->ang;
  650. pTEffect->owner = pTSprite->owner; //(short)nTSprite;
  651. break;
  652. }
  653. case kViewEffectSpear:
  654. {
  655. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF, pTSprite);
  656. pTEffect->z = pTSprite->z;
  657. pTEffect->cstat = (uchar)((pTSprite->cstat & ~kSpriteRMask) | kSpriteFloor);
  658. pTEffect->shade = pTSprite->shade;
  659. pTEffect->xrepeat = pTSprite->xrepeat;
  660. pTEffect->yrepeat = pTSprite->yrepeat;
  661. pTEffect->picnum = pTSprite->picnum;
  662. pTSprite->ang += kAngle180;
  663. pTSprite->ang &= kAngleMask;
  664. break;
  665. }
  666. case kViewEffectBloodSpray:
  667. {
  668. SPRITE *pTEffect = viewInsertTSprite( pTSprite->sectnum, 0x7FFF, pTSprite);
  669. pTEffect->z = pTSprite->z;
  670. pTEffect->cstat = (uchar)(pTSprite->cstat & ~kSpriteBlocking);
  671. if (gDetail > kDetailLevel2)
  672. pTEffect->cstat |= kSpriteTranslucent | kSpriteTranslucentR;
  673. pTEffect->shade = (schar)ClipLow((int)(pTSprite->shade - 32), -128);
  674. pTEffect->xrepeat = pTSprite->xrepeat;
  675. pTEffect->yrepeat = 64;
  676. pTEffect->picnum = kAnmBloodSpray;
  677. break;
  678. }
  679. }
  680. }
  681. }
  682. void viewProcessSprites( int nViewX, int nViewY, int nViewZ )
  683. {
  684. int nTSprite, nOctant;
  685. short nXSprite;
  686. long dx, dy;
  687. // count down so we don't process shadows
  688. for (nTSprite = spritesortcnt - 1; nTSprite >= 0; nTSprite--)
  689. {
  690. SPRITE *pTSprite = &tsprite[nTSprite];
  691. XSPRITE *pTXSprite = NULL;
  692. nXSprite = pTSprite->extra;
  693. if ( nXSprite > 0 )
  694. pTXSprite = &xsprite[nXSprite];
  695. // KEN'S CODE TO SHADE SPRITES
  696. // Add relative shading code for textures, and possibly sector cstat bit to
  697. // indicate where shading comes from (i.e. shadows==floorshade, sky==ceilingshade)
  698. // ALSO: This code does not affect sprite effects added to the tsprite list
  699. pTSprite->shade = (schar)ClipRange( pTSprite->shade + 6, -128, 127 );
  700. if ( (sector[pTSprite->sectnum].ceilingstat & 1)
  701. && !(sector[pTSprite->sectnum].floorstat & kSectorFloorShade) )
  702. pTSprite->shade = (schar)ClipRange( pTSprite->shade + sector[pTSprite->sectnum].ceilingshade, -128, 127 );
  703. else
  704. pTSprite->shade = (schar)ClipRange( pTSprite->shade + sector[pTSprite->sectnum].floorshade, -128, 127 );
  705. int nTile = pTSprite->picnum;
  706. if (nTile < 0 || nTile >= kMaxTiles)
  707. {
  708. dprintf("tsprite[].cstat = %i\n", pTSprite->cstat);
  709. dprintf("tsprite[].shade = %i\n", pTSprite->shade);
  710. dprintf("tsprite[].pal = %i\n", pTSprite->pal);
  711. dprintf("tsprite[].picnum = %i\n", pTSprite->picnum);
  712. dprintf("tsprite[].ang = %i\n", pTSprite->ang);
  713. dprintf("tsprite[].owner = %i\n", pTSprite->owner);
  714. dprintf("tsprite[].sectnum = %i\n", pTSprite->sectnum);
  715. dprintf("tsprite[].statnum = %i\n", pTSprite->statnum);
  716. dprintf("tsprite[].type = %i\n", pTSprite->type);
  717. dprintf("tsprite[].flags = %i\n", pTSprite->flags);
  718. dprintf("tsprite[].extra = %i\n", pTSprite->extra);
  719. dassert(nTile >= 0 && nTile < kMaxTiles);
  720. }
  721. // only interpolate certain moving things
  722. if ( pTSprite->flags & kAttrMove )
  723. {
  724. long x = gPrevSpriteLoc[pTSprite->owner].x;
  725. long y = gPrevSpriteLoc[pTSprite->owner].y;
  726. long z = gPrevSpriteLoc[pTSprite->owner].z;
  727. short nAngle = gPrevSpriteLoc[pTSprite->owner].ang;
  728. // interpolate sprite position
  729. x += mulscale16(pTSprite->x - gPrevSpriteLoc[pTSprite->owner].x, gInterpolate);
  730. y += mulscale16(pTSprite->y - gPrevSpriteLoc[pTSprite->owner].y, gInterpolate);
  731. z += mulscale16(pTSprite->z - gPrevSpriteLoc[pTSprite->owner].z, gInterpolate);
  732. nAngle += mulscale16(((pTSprite->ang - gPrevSpriteLoc[pTSprite->owner].ang + kAngle180) & kAngleMask) - kAngle180, gInterpolate);
  733. pTSprite->x = x;
  734. pTSprite->y = y;
  735. pTSprite->z = z;
  736. pTSprite->ang = nAngle;
  737. }
  738. int nFrames = picanm[nTile].frames + 1;
  739. switch ( picanm[nTile].view )
  740. {
  741. case kSpriteViewSingle:
  742. if (nXSprite > 0)
  743. {
  744. dassert(nXSprite < kMaxXSprites);
  745. switch ( pTSprite->type )
  746. {
  747. case kSwitchToggle:
  748. case kSwitchMomentary:
  749. if ( xsprite[nXSprite].state )
  750. pTSprite->picnum = (short)(nTile + nFrames);
  751. break;
  752. case kSwitchCombination:
  753. pTSprite->picnum = (short)(nTile + xsprite[nXSprite].data1 * nFrames);
  754. break;
  755. }
  756. }
  757. break;
  758. case kSpriteView5Full:
  759. // Calculate which of the 8 angles of the sprite to draw (0-7)
  760. dx = nViewX - pTSprite->x;
  761. dy = nViewY - pTSprite->y;
  762. RotateVector(&dx, &dy, -pTSprite->ang + kAngle45 / 2);
  763. nOctant = GetOctant(dx, dy);
  764. if (nOctant <= 4)
  765. {
  766. pTSprite->picnum = (short)(nTile + nOctant);
  767. pTSprite->cstat &= ~4; // clear x-flipping bit
  768. }
  769. else
  770. {
  771. pTSprite->picnum = (short)(nTile + 8 - nOctant);
  772. pTSprite->cstat |= 4; // set x-flipping bit
  773. }
  774. break;
  775. case kSpriteView8Full:
  776. // Calculate which of the 8 angles of the sprite to draw (0-7)
  777. dx = nViewX - pTSprite->x;
  778. dy = nViewY - pTSprite->y;
  779. RotateVector(&dx, &dy, -pTSprite->ang + kAngle45 / 2);
  780. nOctant = GetOctant(dx, dy);
  781. pTSprite->picnum = (short)(nTile + nOctant);
  782. break;
  783. case kSpriteView5Half:
  784. break;
  785. }
  786. if ( spritesortcnt < kMaxViewSprites )
  787. {
  788. if (pTSprite->statnum == kStatDude || pTSprite->statnum == kStatThing || pTSprite->statnum == kStatMissile)
  789. {
  790. if ( pTXSprite && actGetBurnTime(pTXSprite) > 0 )
  791. viewAddEffect( nTSprite, kViewEffectSmokeLow );
  792. if ( pTSprite->flags & kAttrSmoke )
  793. viewAddEffect(nTSprite, kViewEffectSmokeHigh);
  794. if (powerupCheck(gView, kItemRoseGlasses - kItemBase) > 0 && pTSprite->statnum == kStatDude)
  795. pTSprite->shade = kMaxShade;
  796. if (pTSprite->type >= kDudePlayer1 && pTSprite->type <= kDudePlayer8)
  797. {
  798. PLAYER *pPlayer = &gPlayer[pTSprite->type - kDudePlayer1];
  799. if ( powerupCheck(pPlayer, kItemLtdInvisibility - kItemBase) > 0
  800. && powerupCheck(gView, kItemRoseGlasses - kItemBase) == 0 )
  801. {
  802. pTSprite->cstat |= kSpriteTranslucent; // kSpriteInvisible;
  803. pTSprite->pal = kPLUGray;
  804. }
  805. // if not invisible, show the temporary player ID
  806. if ( !(pTSprite->cstat & kSpriteTranslucent) )
  807. pTSprite->pal = (uchar )(kPLUPlayer1 + ( pPlayer->teamID & 3 ));
  808. }
  809. switch (pTSprite->type)
  810. {
  811. case kMissileButcherKnife:
  812. viewAddEffect( nTSprite, kViewEffectPhase );
  813. break;
  814. case kMissileSpear:
  815. viewAddEffect( nTSprite, kViewEffectSpear );
  816. break;
  817. case kMissileFlare:
  818. {
  819. viewAddEffect( nTSprite, kViewEffectFlareHalo );
  820. SECTOR *pSector = &sector[pTSprite->sectnum];
  821. int zDist = (pTSprite->z - pSector->ceilingz) >> 8;
  822. if ( !(pSector->ceilingstat & kSectorParallax) && zDist < 64 )
  823. viewAddEffect( nTSprite, kViewEffectCeilGlow );
  824. zDist = (pSector->floorz - pTSprite->z) >> 8;
  825. if ( !(pSector->floorstat & kSectorParallax) && zDist < 64 )
  826. viewAddEffect( nTSprite, kViewEffectFloorGlow );
  827. break;
  828. }
  829. case kThingTNTStick:
  830. if ( gSpriteHit[nXSprite].floorHit == 0 )
  831. {
  832. pTSprite->picnum = 2036;
  833. viewAddEffect(nTSprite, kViewEffectShadow);
  834. }
  835. break;
  836. case kThingTNTBundle:
  837. if ( gSpriteHit[nXSprite].floorHit == 0 )
  838. {
  839. pTSprite->picnum = 2028;
  840. viewAddEffect(nTSprite, kViewEffectShadow);
  841. }
  842. break;
  843. default:
  844. // only add shadow if will be below the view z
  845. if ( getflorzofslope(pTSprite->sectnum, pTSprite->x, pTSprite->y) >= nViewZ)
  846. {
  847. // don't add to kThings already on the ground
  848. if (pTSprite->type >= kThingBase && pTSprite->type < kThingMax)
  849. {
  850. if ( gSpriteHit[nXSprite].floorHit != 0 )
  851. break;
  852. }
  853. viewAddEffect( nTSprite, kViewEffectShadow );
  854. }
  855. break;
  856. }
  857. }
  858. else switch ( pTSprite->type )
  859. {
  860. case kMiscTorch:
  861. if ( pTXSprite )
  862. {
  863. if ( pTXSprite->state > 0 )
  864. {
  865. pTSprite->picnum++;
  866. viewAddEffect( nTSprite, kViewEffectTorchHigh );
  867. } else {
  868. viewAddEffect( nTSprite, kViewEffectSmokeHigh );
  869. }
  870. }
  871. else
  872. {
  873. pTSprite->picnum++;
  874. viewAddEffect( nTSprite, kViewEffectTorchHigh );
  875. }
  876. break;
  877. case kMiscHangingTorch:
  878. if ( pTXSprite )
  879. {
  880. if ( pTXSprite->state > 0 )
  881. {
  882. pTSprite->picnum++;
  883. viewAddEffect( nTSprite, kViewEffectTorchLow );
  884. } else {
  885. viewAddEffect( nTSprite, kViewEffectSmokeLow );
  886. }
  887. }
  888. else
  889. {
  890. pTSprite->picnum++;
  891. viewAddEffect( nTSprite, kViewEffectTorchLow );
  892. }
  893. break;
  894. case kTrapSawBlade:
  895. if ( pTXSprite->state )
  896. {
  897. if ( pTXSprite->data1 ) // has been bloodied
  898. {
  899. pTSprite->picnum = kAnmCircSaw2;
  900. if ( pTXSprite->data2 )
  901. viewAddEffect( nTSprite, kViewEffectBloodSpray );
  902. }
  903. }
  904. else
  905. {
  906. if ( pTXSprite->data1 ) // this blade has been bloodied
  907. pTSprite->picnum = kAnmCircSaw2 + 1;
  908. else
  909. pTSprite->picnum = kAnmCircSaw1 + 1;
  910. }
  911. break;
  912. }
  913. }
  914. }
  915. }
  916. #define kViewDistance (80 << 4)
  917. extern void viewCalcPosition( SPRITE *pSprite, long *px, long *py, long *pz, short *pAngle, short *pSector )
  918. {
  919. int nAngle = (*pAngle + gViewPosAngle[gViewPos]) & kAngleMask;
  920. int dx = mulscale30(kViewDistance, Cos(nAngle));
  921. int dy = mulscale30(kViewDistance, Sin(nAngle));
  922. *pAngle = (short)((nAngle + kAngle180) & kAngleMask);
  923. ushort cstat = pSprite->cstat;
  924. pSprite->cstat &= ~kSpriteBlocking;
  925. ClipMove(px, py, pz, pSector, dx, dy, 4 << 4, 1, 1, 0);
  926. pSprite->cstat = cstat;
  927. }
  928. void viewBackupPlayerLoc( int nPlayer )
  929. {
  930. SPRITE *pSprite = gPlayer[nPlayer].sprite;
  931. PLOCATION *pPLocation = &gPrevPlayerLoc[nPlayer];
  932. pPLocation->x = pSprite->x;
  933. pPLocation->y = pSprite->y;
  934. pPLocation->z = pSprite->z;
  935. pPLocation->ang = pSprite->ang;
  936. pPLocation->horiz = gPlayer[nPlayer].horiz;
  937. pPLocation->bobHeight = gPlayer[nPlayer].bobHeight;
  938. pPLocation->bobWidth = gPlayer[nPlayer].bobWidth;
  939. pPLocation->swayHeight = gPlayer[nPlayer].swayHeight;
  940. pPLocation->swayWidth = gPlayer[nPlayer].swayWidth;
  941. }
  942. void viewBackupSpriteLoc( int nSprite, SPRITE *pSprite )
  943. {
  944. LOCATION *pLocation = &gPrevSpriteLoc[nSprite];
  945. pLocation->x = pSprite->x;
  946. pLocation->y = pSprite->y;
  947. pLocation->z = pSprite->z;
  948. pLocation->ang = pSprite->ang;
  949. }
  950. void viewBackupAllSpriteLoc( void )
  951. {
  952. SPRITE *pSprite = &sprite[0];
  953. LOCATION *pLocation = &gPrevSpriteLoc[0];
  954. for (int i = 0; i < kMaxSprites; i++, pSprite++, pLocation++)
  955. {
  956. if ( pSprite->flags & kAttrMove )
  957. {
  958. pLocation->x = pSprite->x;
  959. pLocation->y = pSprite->y;
  960. pLocation->z = pSprite->z;
  961. pLocation->ang = pSprite->ang;
  962. }
  963. }
  964. }
  965. /***********************************************************************
  966. * viewDrawSprite()
  967. *
  968. * Draws tiles to the screen using a unified set of flags
  969. * similar to those in overwritesprite/rotatesprite
  970. **********************************************************************/
  971. void viewDrawSprite( long sx, long sy,
  972. long nZoom, int nAngle, short nTile, schar nShade, char nPLU, ushort nFlags,
  973. long wx1, long wy1, long wx2, long wy2 )
  974. {
  975. // convert x-flipping
  976. if ( nFlags & kDrawXFlip )
  977. {
  978. nAngle = (nAngle + kAngle180) & kAngleMask;
  979. nFlags ^= kDrawYFlip;
  980. }
  981. // call rotatesprite passing only compatible bits in nFlags
  982. rotatesprite( sx, sy, nZoom, (short)nAngle, nTile, nShade, nPLU,
  983. (char)nFlags, wx1, wy1, wx2, wy2 );
  984. }
  985. #define kMaxViewFlames 9
  986. static struct {
  987. short tile;
  988. uchar flags;
  989. char pal;
  990. long zoom;
  991. short x;
  992. short y;
  993. } burnTable[ kMaxViewFlames ] = {
  994. { kAnmFlame2, (uchar)(kDrawScale), 0, 0x22000, 10, 200 },
  995. { kAnmFlame2, (uchar)(kDrawScale|kDrawXFlip), 0, 0x20000, 40, 200 },
  996. { kAnmFlame2, (uchar)(kDrawScale), 0, 0x19000, 85, 200 },
  997. { kAnmFlame2, (uchar)(kDrawScale), 0, 0x16000, 120, 200 },
  998. { kAnmFlame2, (uchar)(kDrawScale|kDrawXFlip), 0, 0x14000, 160, 200 },
  999. { kAnmFlame2, (uchar)(kDrawScale|kDrawXFlip), 0, 0x17000, 200, 200 },
  1000. { kAnmFlame2, (uchar)(kDrawScale), 0, 0x18000, 235, 200 },
  1001. { kAnmFlame2, (uchar)(kDrawScale), 0, 0x20000, 275, 200 },
  1002. { kAnmFlame2, (uchar)(kDrawScale|kDrawXFlip), 0, 0x23000, 310, 200 },
  1003. };
  1004. /***********************************************************************
  1005. * viewBurnTime()
  1006. **********************************************************************/
  1007. void viewBurnTime( int nTicks )
  1008. {
  1009. if ( nTicks == 0 )
  1010. return;
  1011. for ( int i = 0; i < kMaxViewFlames; i++ )
  1012. {
  1013. // fake a sprite type for animateoffs to derive an index into an animation sequence
  1014. short nTile = burnTable[i].tile;
  1015. nTile += animateoffs( nTile, (ushort)(0x8000 + i));
  1016. long nZoom = burnTable[i].zoom;
  1017. // size diminishes during last 5 seconds
  1018. if ( nTicks < 5 * kTimerRate )
  1019. nZoom = muldiv(nZoom, nTicks, 5 * kTimerRate);
  1020. viewDrawSprite( burnTable[i].x << 16, burnTable[i].y << 16, nZoom, 0, nTile, 0,
  1021. burnTable[i].pal, burnTable[i].flags, windowx1, windowy1, windowx2, windowy2);
  1022. }
  1023. }
  1024. void viewSetMessage( char *s )
  1025. {
  1026. messageTime = gFrameClock;
  1027. strcpy(message, s);
  1028. }
  1029. void viewDisplayMessage( void )
  1030. {
  1031. if (gFrameClock < messageTime + kTimerRate * 2)
  1032. viewDrawText(kFontMessage, message, windowx1 + 1, windowy1 + 1, 0, 0);
  1033. }
  1034. void viewDrawScreen( void )
  1035. {
  1036. static lastDacUpdate = 0;
  1037. BOOL fInterpolateRangeError = FALSE;
  1038. if ( gViewMode == kView3D || gViewMode == kView2DIcon || gOverlayMap )
  1039. {
  1040. DoSectorLighting();
  1041. DoSectorPanning();
  1042. }
  1043. if ((gViewMode == kView3D) || (gOverlayMap))
  1044. {
  1045. int theView = gViewIndex;
  1046. if ( powerupCheck(gMe, kItemCrystalBall - kItemBase) )
  1047. theView = myconnectindex;
  1048. short nSector = gView->sprite->sectnum;
  1049. if (gInterpolate < 0 || gInterpolate > 0x10000)
  1050. {
  1051. fInterpolateRangeError = TRUE;
  1052. gInterpolate = ClipRange(gInterpolate, 0, 0x10000);
  1053. }
  1054. long x = gPrevPlayerLoc[theView].x;
  1055. long y = gPrevPlayerLoc[theView].y;
  1056. long z = gPrevPlayerLoc[theView].z;
  1057. short nAngle = gPrevPlayerLoc[theView].ang;
  1058. int nHoriz = gPrevPlayerLoc[theView].horiz;
  1059. int bobWidth = gPrevPlayerLoc[theView].bobWidth;
  1060. int bobHeight = gPrevPlayerLoc[theView].bobHeight;
  1061. int swayWidth = gPrevPlayerLoc[theView].swayWidth;
  1062. int swayHeight = gPrevPlayerLoc[theView].swayHeight;
  1063. // interpolate player position
  1064. x += mulscale16(gView->sprite->x - gPrevPlayerLoc[theView].x, gInterpolate);
  1065. y += mulscale16(gView->sprite->y - gPrevPlayerLoc[theView].y, gInterpolate);
  1066. z += mulscale16(gView->sprite->z - gPrevPlayerLoc[theView].z, gInterpolate);
  1067. nAngle += mulscale16(((gView->sprite->ang - gPrevPlayerLoc[theView].ang + kAngle180) & kAngleMask) - kAngle180, gInterpolate);
  1068. nHoriz += mulscale16(gView->horiz - gPrevPlayerLoc[theView].horiz, gInterpolate);
  1069. bobWidth += mulscale16(gView->bobWidth - gPrevPlayerLoc[theView].bobWidth, gInterpolate);
  1070. bobHeight += mulscale16(gView->bobHeight - gPrevPlayerLoc[theView].bobHeight, gInterpolate);
  1071. swayWidth += mulscale16(gView->swayWidth - gPrevPlayerLoc[theView].swayWidth, gInterpolate);
  1072. swayHeight += mulscale16(gView->swayHeight - gPrevPlayerLoc[theView].swayHeight, gInterpolate);
  1073. // nAngle = gPrevPlayerLoc[theView].ang;
  1074. if ( gViewPos == kViewPosCenter )
  1075. {
  1076. x -= mulscale30(bobWidth, Sin(nAngle)) >> 4;
  1077. y += mulscale30(bobWidth, Cos(nAngle)) >> 4;
  1078. z += bobHeight + gView->compression - gView->eyeAboveZ + nHoriz * 10;
  1079. }
  1080. else
  1081. {
  1082. viewCalcPosition( gView->sprite, &x, &y, &z, &nAngle, &nSector );
  1083. z -= gView->eyeAboveZ + (16 << 8);
  1084. }
  1085. // should modify the z to handle earthquake type effects
  1086. // something like this might come in handy for the crystal ball
  1087. // need to mod based on number of players, and exclude self
  1088. // int nEyes = (gGameGlock & 0x700) >> 8; // show through new "eyes" every two seconds
  1089. // then render the other view to a tile and draw the tile (after the screen) using a lens effect
  1090. long tiltLock = gScreenTilt;
  1091. BOOL bDelirious = FALSE;
  1092. BOOL bClairvoyant = FALSE;
  1093. bDelirious = ( powerupCheck(gView, kItemShroomDelirium - kItemBase) > 0 );
  1094. if ( tiltLock != 0 || bDelirious )
  1095. {
  1096. if ( waloff[ TILTBUFFER ] == NULL )
  1097. allocatepermanenttile( TILTBUFFER, 320L, 320L );
  1098. dassert( waloff[ TILTBUFFER ] != NULL );
  1099. setviewtotile( TILTBUFFER, 320L, 320L );
  1100. }
  1101. else
  1102. {
  1103. bClairvoyant = ( powerupCheck(gView, kItemCrystalBall - kItemBase) > 0 );
  1104. if ( bClairvoyant && gViewIndex != theView )
  1105. {
  1106. dprintf("CLAIR SETUP\n");
  1107. PLAYER *pViewed = &gPlayer[gViewIndex];
  1108. if ( waloff[ BALLBUFFER ] == NULL )
  1109. allocatepermanenttile( BALLBUFFER, 128L, 128L );
  1110. dassert( waloff[ BALLBUFFER ] != NULL );
  1111. setviewtotile( BALLBUFFER, 128L, 128L );
  1112. long x = gPrevPlayerLoc[gViewIndex].x;
  1113. long y = gPrevPlayerLoc[gViewIndex].y;
  1114. long z = gPrevPlayerLoc[gViewIndex].z;
  1115. short nAngle = gPrevPlayerLoc[gViewIndex].ang;
  1116. int bobWidth = gPrevPlayerLoc[gViewIndex].bobWidth;
  1117. int bobHeight = gPrevPlayerLoc[gViewIndex].bobHeight;
  1118. int swayWidth = gPrevPlayerLoc[gViewIndex].swayWidth;
  1119. int swayHeight = gPrevPlayerLoc[gViewIndex].swayHeight;
  1120. x += mulscale16(pViewed->sprite->x - gPrevPlayerLoc[gViewIndex].x, gInterpolate);
  1121. y += mulscale16(pViewed->sprite->y - gPrevPlayerLoc[gViewIndex].y, gInterpolate);
  1122. z += mulscale16(pViewed->sprite->z - gPrevPlayerLoc[gViewIndex].z, gInterpolate);
  1123. // nAngle += mulscale16(((pViewed->sprite->ang - gPrevPlayerLoc[gViewIndex].ang + kAngle180) & kAngleMask) - kAngle180, gInterpolate);
  1124. // bobWidth += mulscale16(pViewed->bobWidth - gPrevPlayerLoc[gViewIndex].bobWidth, gInterpolate);
  1125. // bobHeight += mulscale16(pViewed->bobHeight - gPrevPlayerLoc[gViewIndex].bobHeight, gInterpolate);
  1126. // swayWidth += mulscale16(pViewed->swayWidth - gPrevPlayerLoc[gViewIndex].swayWidth, gInterpolate);
  1127. // swayHeight += mulscale16(pViewed->swayHeight - gPrevPlayerLoc[gViewIndex].swayHeight, gInterpolate);
  1128. // viewCalcPosition( pViewed->sprite, &x, &y, &z, &nAngle, &nSector );
  1129. // z -= pViewed->eyeAboveZ + (16 << 8);
  1130. DrawMirrors(x, y, z, nAngle, kHorizDefault + pViewed->horiz );
  1131. drawrooms(x, y, z, nAngle, kHorizDefault + pViewed->horiz, nSector);
  1132. viewProcessSprites(x, y, z);
  1133. drawmasks();
  1134. setviewback();
  1135. }
  1136. }
  1137. if ( !bDelirious )
  1138. {
  1139. deliriumTilt = 0;
  1140. deliriumTurn = 0;
  1141. deliriumPitch = 0;
  1142. }
  1143. nAngle = (short)((nAngle + deliriumTurn) & kAngleMask);
  1144. // prevent the player from being drawn (not taken care of automatically if x,y different)
  1145. ushort oldcstat = gView->sprite->cstat;
  1146. if ( gViewPos == kViewPosCenter )
  1147. gView->sprite->cstat |= kSpriteInvisible;
  1148. DrawMirrors(x, y, z, nAngle, kHorizDefault + nHoriz + deliriumPitch);
  1149. drawrooms(x, y, z, nAngle, kHorizDefault + nHoriz + deliriumPitch, nSector);
  1150. viewProcessSprites(x, y, z);
  1151. drawmasks();
  1152. gView->sprite->cstat = oldcstat;
  1153. // process gotpics
  1154. if ( TestBitString(gotpic, kPicFire) )
  1155. {
  1156. FireProcess();
  1157. ClearBitString(gotpic, kPicFire);
  1158. }
  1159. if ( tiltLock != 0 || bDelirious )
  1160. {
  1161. dassert( waloff[ TILTBUFFER ] != NULL );
  1162. setviewback();
  1163. uchar nFlags = kRotateScale | kRotateYFlip | kRotateNoMask;
  1164. if ( bDelirious )
  1165. nFlags |= kRotateTranslucent;
  1166. rotatesprite( 320 << 15, 200 << 15, 0x10000, (short)(tiltLock + kAngle90), TILTBUFFER, 0, 0, nFlags,
  1167. gViewX0, gViewY0, gViewX1, gViewY1);
  1168. }
  1169. else
  1170. {
  1171. if ( bClairvoyant && gViewIndex != theView )
  1172. {
  1173. dprintf("CLAIR DRAW\n");
  1174. rotatesprite(0,0,0x10000,0,BALLBUFFER,0,0,0,gViewX0, gViewY0, gViewX1, gViewY1);
  1175. }
  1176. }
  1177. if ( gViewPos == kViewPosCenter )
  1178. {
  1179. if ( gAimReticle )
  1180. {
  1181. // draw aiming reticle
  1182. dassert(gView->relAim.dx > 0);
  1183. x = 160 + gView->relAim.dy * 160 / gView->relAim.dx;
  1184. y = kHorizDefault + nHoriz + (gView->relAim.dz >> 7);
  1185. rotatesprite(x << 16, y << 16, 0x10000, 0, 2319, 0, 0, kRotateScale,
  1186. gViewX0, gViewY0, gViewX1, gViewY1);
  1187. }
  1188. x = 160 + (swayWidth >> 8);
  1189. y = 200 + gPosture[gView->lifemode].swayV + (swayHeight >> 8) + (gView->compression >> 8);
  1190. int nShade = sector[nSector].floorshade;
  1191. WeaponDraw(gView, nShade, x, y);
  1192. }
  1193. if ( gViewPos == kViewPosCenter && actGetBurnTime(gView->xsprite) > (kTimerRate / 2) )
  1194. viewBurnTime( actGetBurnTime(gView->xsprite)) ;
  1195. if ( powerupCheck(gView, kItemDivingSuit - kItemBase) > 0 )
  1196. {
  1197. uchar nFlags = kRotateScale|kRotateCorner;
  1198. // upper-left
  1199. rotatesprite( 0, 0, 0x10000, 0, kMaskDivingSuit, 0, 0, nFlags,
  1200. gViewX0, gViewY0, gViewX1, gViewY1);
  1201. // upper-right
  1202. rotatesprite( 320 << 16, 0, 0x10000, 1024, kMaskDivingSuit, 0, 0, (uchar)(nFlags|kRotateYFlip),
  1203. gViewX0, gViewY0, gViewX1, gViewY1);
  1204. // lower-left
  1205. rotatesprite( 0, 200 << 16, 0x10000, 0, kMaskDivingSuit, 0, 0, (uchar)(nFlags|kRotateYFlip),
  1206. gViewX0, gViewY0, gViewX1, gViewY1);
  1207. // lower-right
  1208. rotatesprite( 320 << 16, 200 << 16, 0x10000, 1024, kMaskDivingSuit, 0, 0, nFlags,
  1209. gViewX0, gViewY0, gViewX1, gViewY1);
  1210. if ( gDetail >= kDetailLevelMax )
  1211. {
  1212. // upper-left reflection
  1213. rotatesprite( 15 << 16, 3 << 16, 0x10000, 0, kMaskReflect1, 32, 0, (uchar)(nFlags|kRotateTranslucent),
  1214. gViewX0, gViewY0, gViewX1, gViewY1);
  1215. // lower-right reflection
  1216. rotatesprite( 212 << 16, 77 << 16, 0x10000, 0, kMaskReflect2, 32, 0, (uchar)(nFlags|kRotateTranslucent),
  1217. gViewX0, gViewY0, gViewX1, gViewY1);
  1218. }
  1219. }
  1220. if ( powerupCheck(gView, kItemAsbestosArmor - kItemBase) > 0 )
  1221. {
  1222. uchar nFlags = kRotateScale|kRotateCorner;
  1223. // upper-left
  1224. rotatesprite( 0, 0, 0x10000, 0, kMaskFireSuit, 0, 0, nFlags,
  1225. gViewX0, gViewY0, gViewX1, gViewY1);
  1226. // upper-right
  1227. rotatesprite( 320 << 16, 0, 0x10000, 1024, kMaskFireSuit, 0, 0, (uchar)(nFlags|kRotateYFlip),
  1228. gViewX0, gViewY0, gViewX1, gViewY1);
  1229. // lower-left
  1230. rotatesprite( 0, 200 << 16, 0x10000, 0, kMaskFireSuit, 0, 0, (uchar)(nFlags|kRotateYFlip),
  1231. gViewX0, gViewY0, gViewX1, gViewY1);
  1232. // lower-right
  1233. rotatesprite( 320 << 16, 200 << 16, 0x10000, 1024, kMaskFireSuit, 0, 0, nFlags,
  1234. gViewX0, gViewY0, gViewX1, gViewY1);
  1235. }
  1236. }
  1237. else
  1238. clearview(0); // Clear screen to specified color
  1239. if ( gViewMode == kView2DIcon )
  1240. drawmapview(gView->sprite->x, gView->sprite->y, gZoom >> 2, gView->sprite->ang);
  1241. if ( gViewMode == kView2D /*|| gViewMode == kView2DIcon */)
  1242. {
  1243. // drawoverheadmap(gView->sprite->x, gView->sprite->y, gZoom, gView->sprite->ang);
  1244. DrawMap(gView->sprite->x, gView->sprite->y, gView->sprite->ang, gZoom);
  1245. }
  1246. viewDrawInterface();
  1247. viewDisplayMessage();
  1248. CalcFrameRate();
  1249. if ( gShowFrameRate )
  1250. {
  1251. char buffer[16];
  1252. sprintf(buffer, "%3i", gFrameRate);
  1253. printext256(gViewX1 - 12, gViewY0, 31, -1, buffer, 1);
  1254. }
  1255. if ( gShowFrags )
  1256. {
  1257. for ( int i = 0; i < numplayers; i++)
  1258. {
  1259. char buffer[16];
  1260. sprintf(buffer, "%i:%i", i, gPlayer[i].fragCount);
  1261. printext256(gViewX0 + 12, gViewY0+(i*8), 31, -1, buffer, 1);
  1262. }
  1263. }
  1264. if ( gPaused )
  1265. viewDrawText(kFontMenu, "PAUSED", gViewX1 / 2, gViewY1 / 2, 0, 0, TA_CENTER);
  1266. if ( fInterpolateRangeError )
  1267. gfxDrawText(windowx2 - 16, windowy1, gStdColor[kColorWhite], "I");
  1268. if ( gView->xsprite->moveState == kMoveFall )
  1269. gfxDrawText(windowx2 - 24, windowy1, gStdColor[kColorWhite], "F");
  1270. scrSetDac(gGameClock - lastDacUpdate);
  1271. lastDacUpdate = gGameClock;
  1272. scrNextPage();
  1273. }
  1274. void Detail( int nType, BOOL bDetail )
  1275. {
  1276. switch ( nType )
  1277. {
  1278. case kDetailSprites:
  1279. {
  1280. int nSprite, nNext;
  1281. for (nSprite = headspritestat[kStatProximity]; nSprite >= 0; nSprite = nNext)
  1282. {
  1283. nNext = nextspritestat[nSprite];
  1284. if (bDetail)
  1285. sprite[nSprite].cstat &= ~kSpriteInvisible;
  1286. else
  1287. sprite[nSprite].cstat |= kSpriteInvisible;
  1288. }
  1289. break;
  1290. }
  1291. default:
  1292. break;
  1293. }
  1294. }
  1295. void viewSetDetail( int nDetail )
  1296. {
  1297. dassert( nDetail >= kDetailLevelMin && nDetail <= kDetailLevelMax );
  1298. switch ( nDetail )
  1299. {
  1300. // no kStatDetail sprites, no fake gibs, no shadows, no smoke trail effects, no glow or lens flares
  1301. case kDetailLevelMin:
  1302. Detail( kDetailSprites, FALSE );
  1303. break;
  1304. case kDetailLevel2:
  1305. Detail( kDetailSprites, FALSE );
  1306. break;
  1307. case kDetailLevel3:
  1308. Detail( kDetailSprites, FALSE );
  1309. break;
  1310. case kDetailLevel4:
  1311. Detail( kDetailSprites, FALSE );
  1312. break;
  1313. case kDetailLevelMax:
  1314. Detail( kDetailSprites, TRUE );
  1315. break;
  1316. }
  1317. gDetail = nDetail;
  1318. }