Tile Animation.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. #ifdef PRECOMPILEDHEADERS
  2. #include "TileEngine All.h"
  3. #else
  4. #include "worlddef.h"
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include "wcheck.h"
  8. #include "stdlib.h"
  9. #include "time.h"
  10. #include "video.h"
  11. #include "debug.h"
  12. #include "smooth.h"
  13. #include "worldman.h"
  14. #include "lighting.h"
  15. #include "renderworld.h"
  16. #include "overhead.h"
  17. #include "ai.h"
  18. #include "Sound Control.h"
  19. #include "animation control.h"
  20. #include "isometric utils.h"
  21. #include "Font Control.h"
  22. #include "message.h"
  23. #include "tile animation.h"
  24. #include "tile cache.h"
  25. #include "explosion control.h"
  26. #include "weapons.h"
  27. #include "Keys.h"
  28. #include "bullets.h"
  29. #endif
  30. ANITILE *pAniTileHead = NULL;
  31. ANITILE *CreateAnimationTile( ANITILE_PARAMS *pAniParams )
  32. {
  33. ANITILE *pAniNode;
  34. ANITILE *pNewAniNode;
  35. LEVELNODE *pNode;
  36. INT32 iCachedTile=-1;
  37. INT16 sGridNo;
  38. UINT8 ubLevel;
  39. INT16 usTileType;
  40. INT16 usTileIndex;
  41. INT16 sDelay;
  42. INT16 sStartFrame=-1;
  43. UINT32 uiFlags;
  44. LEVELNODE *pGivenNode;
  45. INT16 sX, sY, sZ;
  46. UINT8 ubTempDir;
  47. // Get some parameters from structure sent in...
  48. sGridNo = pAniParams->sGridNo;
  49. ubLevel = pAniParams->ubLevelID;
  50. usTileType = pAniParams->usTileType;
  51. usTileIndex = pAniParams->usTileIndex;
  52. sDelay = pAniParams->sDelay;
  53. sStartFrame = pAniParams->sStartFrame;
  54. uiFlags = pAniParams->uiFlags;
  55. pGivenNode = pAniParams->pGivenLevelNode;
  56. sX = pAniParams->sX;
  57. sY = pAniParams->sY;
  58. sZ = pAniParams->sZ;
  59. pAniNode = pAniTileHead;
  60. // Allocate head
  61. pNewAniNode = MemAlloc( sizeof( ANITILE ) );
  62. if ( (uiFlags & ANITILE_EXISTINGTILE ) )
  63. {
  64. pNewAniNode->pLevelNode = pGivenNode;
  65. pNewAniNode->pLevelNode->pAniTile = pNewAniNode;
  66. }
  67. else
  68. {
  69. if ( ( uiFlags & ANITILE_CACHEDTILE ) )
  70. {
  71. iCachedTile = GetCachedTile( pAniParams->zCachedFile );
  72. if ( iCachedTile == -1 )
  73. {
  74. return( NULL );
  75. }
  76. usTileIndex = iCachedTile + TILE_CACHE_START_INDEX;
  77. }
  78. // ALLOCATE NEW TILE
  79. switch( ubLevel )
  80. {
  81. case ANI_STRUCT_LEVEL:
  82. pNode = ForceStructToTail( sGridNo, usTileIndex );
  83. break;
  84. case ANI_SHADOW_LEVEL:
  85. AddShadowToHead( sGridNo, usTileIndex );
  86. pNode = gpWorldLevelData[ sGridNo ].pShadowHead;
  87. break;
  88. case ANI_OBJECT_LEVEL:
  89. AddObjectToHead( sGridNo, usTileIndex );
  90. pNode = gpWorldLevelData[ sGridNo ].pObjectHead;
  91. break;
  92. case ANI_ROOF_LEVEL:
  93. AddRoofToHead( sGridNo, usTileIndex );
  94. pNode = gpWorldLevelData[ sGridNo ].pRoofHead;
  95. break;
  96. case ANI_ONROOF_LEVEL:
  97. AddOnRoofToHead( sGridNo, usTileIndex );
  98. pNode = gpWorldLevelData[ sGridNo ].pOnRoofHead;
  99. break;
  100. case ANI_TOPMOST_LEVEL:
  101. AddTopmostToHead( sGridNo, usTileIndex );
  102. pNode = gpWorldLevelData[ sGridNo ].pTopmostHead;
  103. break;
  104. default:
  105. return( NULL );
  106. }
  107. // SET NEW TILE VALUES
  108. pNode->ubShadeLevel=DEFAULT_SHADE_LEVEL;
  109. pNode->ubNaturalShadeLevel=DEFAULT_SHADE_LEVEL;
  110. pNewAniNode->pLevelNode = pNode;
  111. if ( ( uiFlags & ANITILE_CACHEDTILE ) )
  112. {
  113. pNewAniNode->pLevelNode->uiFlags |= ( LEVELNODE_CACHEDANITILE );
  114. pNewAniNode->sCachedTileID = (INT16)iCachedTile;
  115. pNewAniNode->usCachedTileSubIndex = usTileType;
  116. pNewAniNode->pLevelNode->pAniTile = pNewAniNode;
  117. pNewAniNode->sRelativeX = sX;
  118. pNewAniNode->sRelativeY = sY;
  119. pNewAniNode->pLevelNode->sRelativeZ = sZ;
  120. }
  121. // Can't set relative X,Y,Z IF FLAGS ANITILE_CACHEDTILE set!
  122. else if ( (uiFlags & ANITILE_USEABSOLUTEPOS ) )
  123. {
  124. pNewAniNode->pLevelNode->sRelativeX = sX;
  125. pNewAniNode->pLevelNode->sRelativeY = sY;
  126. pNewAniNode->pLevelNode->sRelativeZ = sZ;
  127. pNewAniNode->pLevelNode->uiFlags |= ( LEVELNODE_USEABSOLUTEPOS );
  128. }
  129. }
  130. switch( ubLevel )
  131. {
  132. case ANI_STRUCT_LEVEL:
  133. ResetSpecificLayerOptimizing( TILES_DYNAMIC_STRUCTURES );
  134. break;
  135. case ANI_SHADOW_LEVEL:
  136. ResetSpecificLayerOptimizing( TILES_DYNAMIC_SHADOWS );
  137. break;
  138. case ANI_OBJECT_LEVEL:
  139. ResetSpecificLayerOptimizing( TILES_DYNAMIC_OBJECTS );
  140. break;
  141. case ANI_ROOF_LEVEL:
  142. ResetSpecificLayerOptimizing( TILES_DYNAMIC_ROOF );
  143. break;
  144. case ANI_ONROOF_LEVEL:
  145. ResetSpecificLayerOptimizing( TILES_DYNAMIC_ONROOF );
  146. break;
  147. case ANI_TOPMOST_LEVEL:
  148. ResetSpecificLayerOptimizing( TILES_DYNAMIC_TOPMOST );
  149. break;
  150. }
  151. // SET FLAGS FOR LEVELNODE
  152. pNewAniNode->pLevelNode->uiFlags |= ( LEVELNODE_ANIMATION | LEVELNODE_USEZ | LEVELNODE_DYNAMIC );
  153. if ( ( uiFlags & ANITILE_NOZBLITTER ) )
  154. {
  155. pNewAniNode->pLevelNode->uiFlags |= LEVELNODE_NOZBLITTER;
  156. }
  157. if ( ( uiFlags & ANITILE_ALWAYS_TRANSLUCENT ) )
  158. {
  159. pNewAniNode->pLevelNode->uiFlags |= LEVELNODE_REVEAL;
  160. }
  161. if ( ( uiFlags & ANITILE_USEBEST_TRANSLUCENT ) )
  162. {
  163. pNewAniNode->pLevelNode->uiFlags |= LEVELNODE_USEBESTTRANSTYPE;
  164. }
  165. if ( ( uiFlags & ANITILE_ANIMATE_Z ) )
  166. {
  167. pNewAniNode->pLevelNode->uiFlags |= LEVELNODE_DYNAMICZ;
  168. }
  169. if ( ( uiFlags & ANITILE_PAUSED ) )
  170. {
  171. pNewAniNode->pLevelNode->uiFlags |= ( LEVELNODE_LASTDYNAMIC | LEVELNODE_UPDATESAVEBUFFERONCE );
  172. pNewAniNode->pLevelNode->uiFlags &= (~LEVELNODE_DYNAMIC );
  173. }
  174. if ( ( uiFlags & ANITILE_OPTIMIZEFORSMOKEEFFECT ) )
  175. {
  176. pNewAniNode->pLevelNode->uiFlags |= LEVELNODE_NOWRITEZ;
  177. }
  178. // SET ANITILE VALUES
  179. pNewAniNode->ubLevelID = ubLevel;
  180. pNewAniNode->usTileIndex = usTileIndex;
  181. if ( ( uiFlags & ANITILE_CACHEDTILE ) )
  182. {
  183. pNewAniNode->usNumFrames = gpTileCache[ iCachedTile ].ubNumFrames;
  184. }
  185. else
  186. {
  187. Assert( gTileDatabase[ usTileIndex ].pAnimData != NULL );
  188. pNewAniNode->usNumFrames = gTileDatabase[ usTileIndex ].pAnimData->ubNumFrames;
  189. }
  190. if ( ( uiFlags & ANITILE_USE_DIRECTION_FOR_START_FRAME ) )
  191. {
  192. // Our start frame is actually a direction indicator
  193. ubTempDir = gOneCDirection[ pAniParams->uiUserData3 ];
  194. sStartFrame = (UINT16)sStartFrame + ( pNewAniNode->usNumFrames * ubTempDir );
  195. }
  196. if ( ( uiFlags & ANITILE_USE_4DIRECTION_FOR_START_FRAME ) )
  197. {
  198. // Our start frame is actually a direction indicator
  199. ubTempDir = gb4DirectionsFrom8[ pAniParams->uiUserData3 ];
  200. sStartFrame = (UINT16)sStartFrame + ( pNewAniNode->usNumFrames * ubTempDir );
  201. }
  202. pNewAniNode->usTileType = usTileType;
  203. pNewAniNode->pNext = pAniNode;
  204. pNewAniNode->uiFlags = uiFlags;
  205. pNewAniNode->sDelay = sDelay;
  206. pNewAniNode->sCurrentFrame = sStartFrame;
  207. pNewAniNode->uiTimeLastUpdate = GetJA2Clock( );
  208. pNewAniNode->sGridNo = sGridNo;
  209. pNewAniNode->sStartFrame = sStartFrame;
  210. pNewAniNode->ubKeyFrame1 = pAniParams->ubKeyFrame1;
  211. pNewAniNode->uiKeyFrame1Code = pAniParams->uiKeyFrame1Code;
  212. pNewAniNode->ubKeyFrame2 = pAniParams->ubKeyFrame2;
  213. pNewAniNode->uiKeyFrame2Code = pAniParams->uiKeyFrame2Code;
  214. pNewAniNode->uiUserData = pAniParams->uiUserData;
  215. pNewAniNode->ubUserData2 = pAniParams->ubUserData2;
  216. pNewAniNode->uiUserData3 = pAniParams->uiUserData3;
  217. //Set head
  218. pAniTileHead = pNewAniNode;
  219. // Set some special stuff
  220. return( pNewAniNode );
  221. }
  222. // Loop throug all ani tiles and remove...
  223. void DeleteAniTiles( )
  224. {
  225. ANITILE *pAniNode = NULL;
  226. ANITILE *pNode = NULL;
  227. // LOOP THROUGH EACH NODE
  228. // And call delete function...
  229. pAniNode = pAniTileHead;
  230. while( pAniNode != NULL )
  231. {
  232. pNode = pAniNode;
  233. pAniNode = pAniNode->pNext;
  234. DeleteAniTile( pNode );
  235. }
  236. }
  237. void DeleteAniTile( ANITILE *pAniTile )
  238. {
  239. ANITILE *pAniNode = NULL;
  240. ANITILE *pOldAniNode = NULL;
  241. TILE_ELEMENT *TileElem;
  242. pAniNode = pAniTileHead;
  243. while( pAniNode!= NULL )
  244. {
  245. if ( pAniNode == pAniTile )
  246. {
  247. // OK, set links
  248. // Check for head or tail
  249. if ( pOldAniNode == NULL )
  250. {
  251. // It's the head
  252. pAniTileHead = pAniTile->pNext;
  253. }
  254. else
  255. {
  256. pOldAniNode->pNext = pAniNode->pNext;
  257. }
  258. if ( !(pAniNode->uiFlags & ANITILE_EXISTINGTILE ) )
  259. {
  260. // Delete memory assosiated with item
  261. switch( pAniNode->ubLevelID )
  262. {
  263. case ANI_STRUCT_LEVEL:
  264. RemoveStructFromLevelNode( pAniNode->sGridNo, pAniNode->pLevelNode );
  265. break;
  266. case ANI_SHADOW_LEVEL:
  267. RemoveShadowFromLevelNode( pAniNode->sGridNo, pAniNode->pLevelNode );
  268. break;
  269. case ANI_OBJECT_LEVEL:
  270. RemoveObject( pAniNode->sGridNo, pAniNode->usTileIndex );
  271. break;
  272. case ANI_ROOF_LEVEL:
  273. RemoveRoof( pAniNode->sGridNo, pAniNode->usTileIndex );
  274. break;
  275. case ANI_ONROOF_LEVEL:
  276. RemoveOnRoof( pAniNode->sGridNo, pAniNode->usTileIndex );
  277. break;
  278. case ANI_TOPMOST_LEVEL:
  279. RemoveTopmostFromLevelNode( pAniNode->sGridNo, pAniNode->pLevelNode );
  280. break;
  281. }
  282. if ( ( pAniNode->uiFlags & ANITILE_CACHEDTILE ) )
  283. {
  284. RemoveCachedTile( pAniNode->sCachedTileID );
  285. }
  286. if ( pAniNode->uiFlags & ANITILE_EXPLOSION )
  287. {
  288. // Talk to the explosion data...
  289. RemoveExplosionData( pAniNode->uiUserData3 );
  290. if ( !gfExplosionQueueActive )
  291. {
  292. // turn on sighting again
  293. // the explosion queue handles all this at the end of the queue
  294. gTacticalStatus.uiFlags &= (~DISALLOW_SIGHT);
  295. }
  296. // Freeup attacker from explosion
  297. DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Reducing attacker busy count..., EXPLOSION effect gone off") );
  298. ReduceAttackBusyCount( (UINT8)pAniNode->ubUserData2, FALSE );
  299. }
  300. if ( pAniNode->uiFlags & ANITILE_RELEASE_ATTACKER_WHEN_DONE )
  301. {
  302. // First delete the bullet!
  303. RemoveBullet( pAniNode->uiUserData3 );
  304. DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - miss finished animation") );
  305. FreeUpAttacker( (UINT8) pAniNode->ubAttackerMissed );
  306. }
  307. }
  308. else
  309. {
  310. TileElem = &( gTileDatabase[ pAniNode->usTileIndex ] );
  311. // OK, update existing tile usIndex....
  312. Assert( TileElem->pAnimData != NULL );
  313. pAniNode->pLevelNode->usIndex = TileElem->pAnimData->pusFrames[ pAniNode->pLevelNode->sCurrentFrame ];
  314. // OK, set our frame data back to zero....
  315. pAniNode->pLevelNode->sCurrentFrame = 0;
  316. // Set some flags to write to Z / update save buffer
  317. // pAniNode->pLevelNode->uiFlags |=( LEVELNODE_LASTDYNAMIC | LEVELNODE_UPDATESAVEBUFFERONCE );
  318. pAniNode->pLevelNode->uiFlags &= ~( LEVELNODE_DYNAMIC | LEVELNODE_USEZ | LEVELNODE_ANIMATION );
  319. if (pAniNode->uiFlags & ANITILE_DOOR)
  320. {
  321. // unset door busy!
  322. DOOR_STATUS * pDoorStatus;
  323. pDoorStatus = GetDoorStatus( pAniNode->sGridNo );
  324. if (pDoorStatus)
  325. {
  326. pDoorStatus->ubFlags &= ~(DOOR_BUSY);
  327. }
  328. if ( GridNoOnScreen( pAniNode->sGridNo ) )
  329. {
  330. SetRenderFlags(RENDER_FLAG_FULL);
  331. }
  332. }
  333. }
  334. MemFree( pAniNode );
  335. return;
  336. }
  337. pOldAniNode = pAniNode;
  338. pAniNode = pAniNode->pNext;
  339. }
  340. }
  341. void UpdateAniTiles( )
  342. {
  343. ANITILE *pAniNode = NULL;
  344. ANITILE *pNode = NULL;
  345. UINT32 uiClock = GetJA2Clock( );
  346. UINT16 usMaxFrames, usMinFrames;
  347. UINT8 ubTempDir;
  348. // LOOP THROUGH EACH NODE
  349. pAniNode = pAniTileHead;
  350. while( pAniNode != NULL )
  351. {
  352. pNode = pAniNode;
  353. pAniNode = pAniNode->pNext;
  354. if ( (uiClock - pNode->uiTimeLastUpdate ) > (UINT32)pNode->sDelay && !( pNode->uiFlags & ANITILE_PAUSED ) )
  355. {
  356. pNode->uiTimeLastUpdate = GetJA2Clock( );
  357. if ( pNode->uiFlags & ( ANITILE_OPTIMIZEFORSLOWMOVING ) )
  358. {
  359. pNode->pLevelNode->uiFlags |= (LEVELNODE_DYNAMIC );
  360. pNode->pLevelNode->uiFlags &= (~LEVELNODE_LASTDYNAMIC);
  361. }
  362. else if ( pNode->uiFlags & ( ANITILE_OPTIMIZEFORSMOKEEFFECT ) )
  363. {
  364. // pNode->pLevelNode->uiFlags |= LEVELNODE_DYNAMICZ;
  365. ResetSpecificLayerOptimizing( TILES_DYNAMIC_STRUCTURES );
  366. pNode->pLevelNode->uiFlags &= (~LEVELNODE_LASTDYNAMIC);
  367. pNode->pLevelNode->uiFlags |= (LEVELNODE_DYNAMIC );
  368. }
  369. if ( pNode->uiFlags & ANITILE_FORWARD )
  370. {
  371. usMaxFrames = pNode->usNumFrames;
  372. if ( pNode->uiFlags & ANITILE_USE_DIRECTION_FOR_START_FRAME )
  373. {
  374. ubTempDir = gOneCDirection[ pNode->uiUserData3 ];
  375. usMaxFrames = (UINT16)usMaxFrames + ( pNode->usNumFrames * ubTempDir );
  376. }
  377. if ( pNode->uiFlags & ANITILE_USE_4DIRECTION_FOR_START_FRAME )
  378. {
  379. ubTempDir = gb4DirectionsFrom8[ pNode->uiUserData3 ];
  380. usMaxFrames = (UINT16)usMaxFrames + ( pNode->usNumFrames * ubTempDir );
  381. }
  382. if ( ( pNode->sCurrentFrame + 1 ) < usMaxFrames )
  383. {
  384. pNode->sCurrentFrame++;
  385. pNode->pLevelNode->sCurrentFrame = pNode->sCurrentFrame;
  386. if ( pNode->uiFlags & ANITILE_EXPLOSION )
  387. {
  388. // Talk to the explosion data...
  389. UpdateExplosionFrame( pNode->uiUserData3, pNode->sCurrentFrame );
  390. }
  391. // CHECK IF WE SHOULD BE DISPLAYING TRANSLUCENTLY!
  392. if ( pNode->sCurrentFrame == pNode->ubKeyFrame1 )
  393. {
  394. switch( pNode->uiKeyFrame1Code )
  395. {
  396. case ANI_KEYFRAME_BEGIN_TRANSLUCENCY:
  397. pNode->pLevelNode->uiFlags |= LEVELNODE_REVEAL;
  398. break;
  399. case ANI_KEYFRAME_CHAIN_WATER_EXPLOSION:
  400. IgniteExplosion( pNode->ubUserData2, pNode->pLevelNode->sRelativeX, pNode->pLevelNode->sRelativeY, 0, pNode->sGridNo, (UINT16)( pNode->uiUserData ), 0 );
  401. break;
  402. case ANI_KEYFRAME_DO_SOUND:
  403. PlayJA2Sample( pNode->uiUserData, RATE_11025, SoundVolume( MIDVOLUME, (INT16)pNode->uiUserData3 ), 1, SoundDir( (INT16)pNode->uiUserData3 ) );
  404. break;
  405. }
  406. }
  407. // CHECK IF WE SHOULD BE DISPLAYING TRANSLUCENTLY!
  408. if ( pNode->sCurrentFrame == pNode->ubKeyFrame2 )
  409. {
  410. UINT8 ubExpType;
  411. switch( pNode->uiKeyFrame2Code )
  412. {
  413. case ANI_KEYFRAME_BEGIN_DAMAGE:
  414. ubExpType = Explosive[ Item[ (UINT16)pNode->uiUserData ].ubClassIndex ].ubType;
  415. if ( ubExpType == EXPLOSV_TEARGAS || ubExpType == EXPLOSV_MUSTGAS ||
  416. ubExpType == EXPLOSV_SMOKE )
  417. {
  418. // Do sound....
  419. // PlayJA2Sample( AIR_ESCAPING_1, RATE_11025, SoundVolume( HIGHVOLUME, pNode->sGridNo ), 1, SoundDir( pNode->sGridNo ) );
  420. NewSmokeEffect( pNode->sGridNo, (UINT16)pNode->uiUserData, gExplosionData[ pNode->uiUserData3 ].Params.bLevel, (UINT8)pNode->ubUserData2 );
  421. }
  422. else
  423. {
  424. SpreadEffect( pNode->sGridNo, Explosive[ Item[ (UINT16)pNode->uiUserData ].ubClassIndex ].ubRadius, (UINT16)pNode->uiUserData, (UINT8)pNode->ubUserData2, FALSE, gExplosionData[ pNode->uiUserData3 ].Params.bLevel, -1 );
  425. }
  426. // Forfait any other animations this frame....
  427. return;
  428. }
  429. }
  430. }
  431. else
  432. {
  433. // We are done!
  434. if ( pNode->uiFlags & ANITILE_LOOPING )
  435. {
  436. pNode->sCurrentFrame = pNode->sStartFrame;
  437. if ( ( pNode->uiFlags & ANITILE_USE_DIRECTION_FOR_START_FRAME ) )
  438. {
  439. // Our start frame is actually a direction indicator
  440. ubTempDir = gOneCDirection[ pNode->uiUserData3 ];
  441. pNode->sCurrentFrame = (UINT16)( pNode->usNumFrames * ubTempDir );
  442. }
  443. if ( ( pNode->uiFlags & ANITILE_USE_4DIRECTION_FOR_START_FRAME ) )
  444. {
  445. // Our start frame is actually a direction indicator
  446. ubTempDir = gb4DirectionsFrom8[ pNode->uiUserData3 ];
  447. pNode->sCurrentFrame = (UINT16)( pNode->usNumFrames * ubTempDir );
  448. }
  449. }
  450. else if ( pNode->uiFlags & ANITILE_REVERSE_LOOPING )
  451. {
  452. // Turn off backwards flag
  453. pNode->uiFlags &= (~ANITILE_FORWARD );
  454. // Turn onn forwards flag
  455. pNode->uiFlags |= ANITILE_BACKWARD;
  456. }
  457. else
  458. {
  459. // Delete from world!
  460. DeleteAniTile( pNode );
  461. // Turn back on redunency checks!
  462. gTacticalStatus.uiFlags &= (~NOHIDE_REDUNDENCY);
  463. return;
  464. }
  465. }
  466. }
  467. if ( pNode->uiFlags & ANITILE_BACKWARD )
  468. {
  469. if ( pNode->uiFlags & ANITILE_ERASEITEMFROMSAVEBUFFFER )
  470. {
  471. // ATE: Check if bounding box is on the screen...
  472. if ( pNode->bFrameCountAfterStart == 0 )
  473. {
  474. pNode->bFrameCountAfterStart = 1;
  475. pNode->pLevelNode->uiFlags |= (LEVELNODE_DYNAMIC );
  476. // Dangerous here, since we may not even be on the screen...
  477. SetRenderFlags( RENDER_FLAG_FULL );
  478. continue;
  479. }
  480. }
  481. usMinFrames = 0;
  482. if ( pNode->uiFlags & ANITILE_USE_DIRECTION_FOR_START_FRAME )
  483. {
  484. ubTempDir = gOneCDirection[ pNode->uiUserData3 ];
  485. usMinFrames = ( pNode->usNumFrames * ubTempDir );
  486. }
  487. if ( pNode->uiFlags & ANITILE_USE_4DIRECTION_FOR_START_FRAME )
  488. {
  489. ubTempDir = gb4DirectionsFrom8[ pNode->uiUserData3 ];
  490. usMinFrames = ( pNode->usNumFrames * ubTempDir );
  491. }
  492. if ( ( pNode->sCurrentFrame - 1 ) >= usMinFrames )
  493. {
  494. pNode->sCurrentFrame--;
  495. pNode->pLevelNode->sCurrentFrame = pNode->sCurrentFrame;
  496. if ( pNode->uiFlags & ANITILE_EXPLOSION )
  497. {
  498. // Talk to the explosion data...
  499. UpdateExplosionFrame( pNode->uiUserData3, pNode->sCurrentFrame );
  500. }
  501. }
  502. else
  503. {
  504. // We are done!
  505. if ( pNode->uiFlags & ANITILE_PAUSE_AFTER_LOOP )
  506. {
  507. // Turn off backwards flag
  508. pNode->uiFlags &= (~ANITILE_BACKWARD );
  509. // Pause
  510. pNode->uiFlags |= ANITILE_PAUSED;
  511. }
  512. else if ( pNode->uiFlags & ANITILE_LOOPING )
  513. {
  514. pNode->sCurrentFrame = pNode->sStartFrame;
  515. if ( ( pNode->uiFlags & ANITILE_USE_DIRECTION_FOR_START_FRAME ) )
  516. {
  517. // Our start frame is actually a direction indicator
  518. ubTempDir = gOneCDirection[ pNode->uiUserData3 ];
  519. pNode->sCurrentFrame = (UINT16)( pNode->usNumFrames * ubTempDir );
  520. }
  521. if ( ( pNode->uiFlags & ANITILE_USE_4DIRECTION_FOR_START_FRAME ) )
  522. {
  523. // Our start frame is actually a direction indicator
  524. ubTempDir = gb4DirectionsFrom8[ pNode->uiUserData3 ];
  525. pNode->sCurrentFrame = (UINT16)( pNode->usNumFrames * ubTempDir );
  526. }
  527. }
  528. else if ( pNode->uiFlags & ANITILE_REVERSE_LOOPING )
  529. {
  530. // Turn off backwards flag
  531. pNode->uiFlags &= (~ANITILE_BACKWARD );
  532. // Turn onn forwards flag
  533. pNode->uiFlags |= ANITILE_FORWARD;
  534. }
  535. else
  536. {
  537. // Delete from world!
  538. DeleteAniTile( pNode );
  539. return;
  540. }
  541. if ( pNode->uiFlags & ANITILE_ERASEITEMFROMSAVEBUFFFER )
  542. {
  543. // ATE: Check if bounding box is on the screen...
  544. pNode->bFrameCountAfterStart = 0;
  545. //pNode->pLevelNode->uiFlags |= LEVELNODE_UPDATESAVEBUFFERONCE;
  546. // Dangerous here, since we may not even be on the screen...
  547. SetRenderFlags( RENDER_FLAG_FULL );
  548. }
  549. }
  550. }
  551. }
  552. else
  553. {
  554. if ( pNode->uiFlags & ( ANITILE_OPTIMIZEFORSLOWMOVING ) )
  555. {
  556. // ONLY TURN OFF IF PAUSED...
  557. if ( ( pNode->uiFlags & ANITILE_ERASEITEMFROMSAVEBUFFFER ) )
  558. {
  559. if ( pNode->uiFlags & ANITILE_PAUSED )
  560. {
  561. if ( pNode->pLevelNode->uiFlags & LEVELNODE_DYNAMIC )
  562. {
  563. pNode->pLevelNode->uiFlags &= (~LEVELNODE_DYNAMIC );
  564. pNode->pLevelNode->uiFlags |= (LEVELNODE_LASTDYNAMIC);
  565. SetRenderFlags( RENDER_FLAG_FULL );
  566. }
  567. }
  568. }
  569. else
  570. {
  571. pNode->pLevelNode->uiFlags &= (~LEVELNODE_DYNAMIC );
  572. pNode->pLevelNode->uiFlags |= (LEVELNODE_LASTDYNAMIC);
  573. }
  574. }
  575. else if ( pNode->uiFlags & ( ANITILE_OPTIMIZEFORSMOKEEFFECT ) )
  576. {
  577. pNode->pLevelNode->uiFlags |= (LEVELNODE_LASTDYNAMIC);
  578. pNode->pLevelNode->uiFlags &= (~LEVELNODE_DYNAMIC );
  579. }
  580. }
  581. }
  582. }
  583. void SetAniTileFrame( ANITILE *pAniTile, INT16 sFrame )
  584. {
  585. UINT8 ubTempDir;
  586. INT16 sStartFrame = 0;
  587. if ( (pAniTile->uiFlags & ANITILE_USE_DIRECTION_FOR_START_FRAME ) )
  588. {
  589. // Our start frame is actually a direction indicator
  590. ubTempDir = gOneCDirection[ pAniTile->uiUserData3 ];
  591. sStartFrame = (UINT16)sFrame + ( pAniTile->usNumFrames * ubTempDir );
  592. }
  593. if ( (pAniTile->uiFlags & ANITILE_USE_4DIRECTION_FOR_START_FRAME ) )
  594. {
  595. // Our start frame is actually a direction indicator
  596. ubTempDir = gb4DirectionsFrom8[ pAniTile->uiUserData3 ];
  597. sStartFrame = (UINT16)sFrame + ( pAniTile->usNumFrames * ubTempDir );
  598. }
  599. pAniTile->sCurrentFrame = sStartFrame;
  600. }
  601. ANITILE *GetCachedAniTileOfType( INT16 sGridNo, UINT8 ubLevelID, UINT32 uiFlags )
  602. {
  603. LEVELNODE *pNode = NULL;
  604. switch( ubLevelID )
  605. {
  606. case ANI_STRUCT_LEVEL:
  607. pNode = gpWorldLevelData[ sGridNo ].pStructHead;
  608. break;
  609. case ANI_SHADOW_LEVEL:
  610. pNode = gpWorldLevelData[ sGridNo ].pShadowHead;
  611. break;
  612. case ANI_OBJECT_LEVEL:
  613. pNode = gpWorldLevelData[ sGridNo ].pObjectHead;
  614. break;
  615. case ANI_ROOF_LEVEL:
  616. pNode = gpWorldLevelData[ sGridNo ].pRoofHead;
  617. break;
  618. case ANI_ONROOF_LEVEL:
  619. pNode = gpWorldLevelData[ sGridNo ].pOnRoofHead;
  620. break;
  621. case ANI_TOPMOST_LEVEL:
  622. pNode = gpWorldLevelData[ sGridNo ].pTopmostHead;
  623. break;
  624. default:
  625. return( NULL );
  626. }
  627. while( pNode != NULL )
  628. {
  629. if ( pNode->uiFlags & LEVELNODE_CACHEDANITILE )
  630. {
  631. if ( pNode->pAniTile->uiFlags & uiFlags )
  632. {
  633. return( pNode->pAniTile );
  634. }
  635. }
  636. pNode = pNode->pNext;
  637. }
  638. return( NULL );
  639. }
  640. void HideAniTile( ANITILE *pAniTile, BOOLEAN fHide )
  641. {
  642. if ( fHide )
  643. {
  644. pAniTile->pLevelNode->uiFlags |= LEVELNODE_HIDDEN;
  645. }
  646. else
  647. {
  648. pAniTile->pLevelNode->uiFlags &= (~LEVELNODE_HIDDEN );
  649. }
  650. }
  651. void PauseAniTile( ANITILE *pAniTile, BOOLEAN fPause )
  652. {
  653. if ( fPause )
  654. {
  655. pAniTile->uiFlags |= ANITILE_PAUSED;
  656. }
  657. else
  658. {
  659. pAniTile->uiFlags &= (~ANITILE_PAUSED );
  660. }
  661. }
  662. void PauseAllAniTilesOfType( UINT32 uiType, BOOLEAN fPause )
  663. {
  664. ANITILE *pAniNode = NULL;
  665. ANITILE *pNode = NULL;
  666. // LOOP THROUGH EACH NODE
  667. pAniNode = pAniTileHead;
  668. while( pAniNode != NULL )
  669. {
  670. pNode = pAniNode;
  671. pAniNode = pAniNode->pNext;
  672. if ( pNode->uiFlags & uiType )
  673. {
  674. PauseAniTile( pNode, fPause );
  675. }
  676. }
  677. }