void UpdateSmokeEffectGraphics( ) { UINT32 uiCnt; SMOKEEFFECT *pSmoke; INT8 bLevel; //loop through and save the number of smoke effects for( uiCnt=0; uiCnt < guiNumSmokeEffects; uiCnt++) { pSmoke = &gSmokeEffectData[ uiCnt ]; //if the smoke is active if( gSmokeEffectData[ uiCnt ].fAllocated ) { if ( gSmokeEffectData[uiCnt].bFlags & SMOKE_EFFECT_ON_ROOF ) { bLevel = 1; } else { bLevel = 0; } SpreadEffect( pSmoke->sGridNo, pSmoke->ubRadius, pSmoke->usItem, pSmoke->ubOwner, ERASE_SPREAD_EFFECT, bLevel, uiCnt ); SpreadEffect( pSmoke->sGridNo, pSmoke->ubRadius, pSmoke->usItem, pSmoke->ubOwner, TRUE, bLevel, uiCnt ); } } }
void UpdateAniTiles( ) { ANITILE *pAniNode = NULL; ANITILE *pNode = NULL; UINT32 uiClock = GetJA2Clock( ); UINT16 usMaxFrames, usMinFrames; UINT8 ubTempDir; // LOOP THROUGH EACH NODE pAniNode = pAniTileHead; while( pAniNode != NULL ) { pNode = pAniNode; pAniNode = pAniNode->pNext; if ( (uiClock - pNode->uiTimeLastUpdate ) > (UINT32)pNode->sDelay && !( pNode->uiFlags & ANITILE_PAUSED ) ) { pNode->uiTimeLastUpdate = GetJA2Clock( ); if ( pNode->uiFlags & ( ANITILE_OPTIMIZEFORSLOWMOVING ) ) { pNode->pLevelNode->uiFlags |= (LEVELNODE_DYNAMIC ); pNode->pLevelNode->uiFlags &= (~LEVELNODE_LASTDYNAMIC); } else if ( pNode->uiFlags & ( ANITILE_OPTIMIZEFORSMOKEEFFECT ) ) { // pNode->pLevelNode->uiFlags |= LEVELNODE_DYNAMICZ; ResetSpecificLayerOptimizing( TILES_DYNAMIC_STRUCTURES ); pNode->pLevelNode->uiFlags &= (~LEVELNODE_LASTDYNAMIC); pNode->pLevelNode->uiFlags |= (LEVELNODE_DYNAMIC ); } if ( pNode->uiFlags & ANITILE_FORWARD ) { usMaxFrames = pNode->usNumFrames; if ( pNode->uiFlags & ANITILE_USE_DIRECTION_FOR_START_FRAME ) { ubTempDir = gOneCDirection[ pNode->uiUserData3 ]; usMaxFrames = (UINT16)usMaxFrames + ( pNode->usNumFrames * ubTempDir ); } if ( pNode->uiFlags & ANITILE_USE_4DIRECTION_FOR_START_FRAME ) { ubTempDir = gb4DirectionsFrom8[ pNode->uiUserData3 ]; usMaxFrames = (UINT16)usMaxFrames + ( pNode->usNumFrames * ubTempDir ); } if ( ( pNode->sCurrentFrame + 1 ) < usMaxFrames ) { pNode->sCurrentFrame++; pNode->pLevelNode->sCurrentFrame = pNode->sCurrentFrame; if ( pNode->uiFlags & ANITILE_EXPLOSION ) { // Talk to the explosion data... UpdateExplosionFrame( pNode->uiUserData3, pNode->sCurrentFrame ); } // CHECK IF WE SHOULD BE DISPLAYING TRANSLUCENTLY! if ( pNode->sCurrentFrame == pNode->ubKeyFrame1 ) { switch( pNode->uiKeyFrame1Code ) { case ANI_KEYFRAME_BEGIN_TRANSLUCENCY: pNode->pLevelNode->uiFlags |= LEVELNODE_REVEAL; break; case ANI_KEYFRAME_CHAIN_WATER_EXPLOSION: IgniteExplosion( pNode->ubUserData2, pNode->pLevelNode->sRelativeX, pNode->pLevelNode->sRelativeY, 0, pNode->sGridNo, (UINT16)( pNode->uiUserData ), 0 ); break; case ANI_KEYFRAME_DO_SOUND: PlayJA2Sample( pNode->uiUserData, RATE_11025, SoundVolume( MIDVOLUME, (INT16)pNode->uiUserData3 ), 1, SoundDir( (INT16)pNode->uiUserData3 ) ); break; } } // CHECK IF WE SHOULD BE DISPLAYING TRANSLUCENTLY! if ( pNode->sCurrentFrame == pNode->ubKeyFrame2 ) { UINT8 ubExpType; switch( pNode->uiKeyFrame2Code ) { case ANI_KEYFRAME_BEGIN_DAMAGE: ubExpType = Explosive[ Item[ (UINT16)pNode->uiUserData ].ubClassIndex ].ubType; if ( ubExpType == EXPLOSV_TEARGAS || ubExpType == EXPLOSV_MUSTGAS || ubExpType == EXPLOSV_SMOKE ) { // Do sound.... // PlayJA2Sample( AIR_ESCAPING_1, RATE_11025, SoundVolume( HIGHVOLUME, pNode->sGridNo ), 1, SoundDir( pNode->sGridNo ) ); NewSmokeEffect( pNode->sGridNo, (UINT16)pNode->uiUserData, gExplosionData[ pNode->uiUserData3 ].Params.bLevel, (UINT8)pNode->ubUserData2 ); } else { SpreadEffect( pNode->sGridNo, Explosive[ Item[ (UINT16)pNode->uiUserData ].ubClassIndex ].ubRadius, (UINT16)pNode->uiUserData, (UINT8)pNode->ubUserData2, FALSE, gExplosionData[ pNode->uiUserData3 ].Params.bLevel, -1 ); } // Forfait any other animations this frame.... return; } } } else { // We are done! if ( pNode->uiFlags & ANITILE_LOOPING ) { pNode->sCurrentFrame = pNode->sStartFrame; if ( ( pNode->uiFlags & ANITILE_USE_DIRECTION_FOR_START_FRAME ) ) { // Our start frame is actually a direction indicator ubTempDir = gOneCDirection[ pNode->uiUserData3 ]; pNode->sCurrentFrame = (UINT16)( pNode->usNumFrames * ubTempDir ); } if ( ( pNode->uiFlags & ANITILE_USE_4DIRECTION_FOR_START_FRAME ) ) { // Our start frame is actually a direction indicator ubTempDir = gb4DirectionsFrom8[ pNode->uiUserData3 ]; pNode->sCurrentFrame = (UINT16)( pNode->usNumFrames * ubTempDir ); } } else if ( pNode->uiFlags & ANITILE_REVERSE_LOOPING ) { // Turn off backwards flag pNode->uiFlags &= (~ANITILE_FORWARD ); // Turn onn forwards flag pNode->uiFlags |= ANITILE_BACKWARD; } else { // Delete from world! DeleteAniTile( pNode ); // Turn back on redunency checks! gTacticalStatus.uiFlags &= (~NOHIDE_REDUNDENCY); return; } } } if ( pNode->uiFlags & ANITILE_BACKWARD ) { if ( pNode->uiFlags & ANITILE_ERASEITEMFROMSAVEBUFFFER ) { // ATE: Check if bounding box is on the screen... if ( pNode->bFrameCountAfterStart == 0 ) { pNode->bFrameCountAfterStart = 1; pNode->pLevelNode->uiFlags |= (LEVELNODE_DYNAMIC ); // Dangerous here, since we may not even be on the screen... SetRenderFlags( RENDER_FLAG_FULL ); continue; } } usMinFrames = 0; if ( pNode->uiFlags & ANITILE_USE_DIRECTION_FOR_START_FRAME ) { ubTempDir = gOneCDirection[ pNode->uiUserData3 ]; usMinFrames = ( pNode->usNumFrames * ubTempDir ); } if ( pNode->uiFlags & ANITILE_USE_4DIRECTION_FOR_START_FRAME ) { ubTempDir = gb4DirectionsFrom8[ pNode->uiUserData3 ]; usMinFrames = ( pNode->usNumFrames * ubTempDir ); } if ( ( pNode->sCurrentFrame - 1 ) >= usMinFrames ) { pNode->sCurrentFrame--; pNode->pLevelNode->sCurrentFrame = pNode->sCurrentFrame; if ( pNode->uiFlags & ANITILE_EXPLOSION ) { // Talk to the explosion data... UpdateExplosionFrame( pNode->uiUserData3, pNode->sCurrentFrame ); } } else { // We are done! if ( pNode->uiFlags & ANITILE_PAUSE_AFTER_LOOP ) { // Turn off backwards flag pNode->uiFlags &= (~ANITILE_BACKWARD ); // Pause pNode->uiFlags |= ANITILE_PAUSED; } else if ( pNode->uiFlags & ANITILE_LOOPING ) { pNode->sCurrentFrame = pNode->sStartFrame; if ( ( pNode->uiFlags & ANITILE_USE_DIRECTION_FOR_START_FRAME ) ) { // Our start frame is actually a direction indicator ubTempDir = gOneCDirection[ pNode->uiUserData3 ]; pNode->sCurrentFrame = (UINT16)( pNode->usNumFrames * ubTempDir ); } if ( ( pNode->uiFlags & ANITILE_USE_4DIRECTION_FOR_START_FRAME ) ) { // Our start frame is actually a direction indicator ubTempDir = gb4DirectionsFrom8[ pNode->uiUserData3 ]; pNode->sCurrentFrame = (UINT16)( pNode->usNumFrames * ubTempDir ); } } else if ( pNode->uiFlags & ANITILE_REVERSE_LOOPING ) { // Turn off backwards flag pNode->uiFlags &= (~ANITILE_BACKWARD ); // Turn onn forwards flag pNode->uiFlags |= ANITILE_FORWARD; } else { // Delete from world! DeleteAniTile( pNode ); return; } if ( pNode->uiFlags & ANITILE_ERASEITEMFROMSAVEBUFFFER ) { // ATE: Check if bounding box is on the screen... pNode->bFrameCountAfterStart = 0; //pNode->pLevelNode->uiFlags |= LEVELNODE_UPDATESAVEBUFFERONCE; // Dangerous here, since we may not even be on the screen... SetRenderFlags( RENDER_FLAG_FULL ); } } } } else { if ( pNode->uiFlags & ( ANITILE_OPTIMIZEFORSLOWMOVING ) ) { // ONLY TURN OFF IF PAUSED... if ( ( pNode->uiFlags & ANITILE_ERASEITEMFROMSAVEBUFFFER ) ) { if ( pNode->uiFlags & ANITILE_PAUSED ) { if ( pNode->pLevelNode->uiFlags & LEVELNODE_DYNAMIC ) { pNode->pLevelNode->uiFlags &= (~LEVELNODE_DYNAMIC ); pNode->pLevelNode->uiFlags |= (LEVELNODE_LASTDYNAMIC); SetRenderFlags( RENDER_FLAG_FULL ); } } } else { pNode->pLevelNode->uiFlags &= (~LEVELNODE_DYNAMIC ); pNode->pLevelNode->uiFlags |= (LEVELNODE_LASTDYNAMIC); } } else if ( pNode->uiFlags & ( ANITILE_OPTIMIZEFORSMOKEEFFECT ) ) { pNode->pLevelNode->uiFlags |= (LEVELNODE_LASTDYNAMIC); pNode->pLevelNode->uiFlags &= (~LEVELNODE_DYNAMIC ); } } } }
BOOLEAN LoadSmokeEffectsFromMapTempFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ ) { UINT32 uiNumBytesRead; UINT32 uiCount; UINT32 uiCnt=0; HWFILE hFile; UINT32 uiNumBytesWritten=0; CHAR8 zMapName[ 128 ]; INT8 bLevel; GetMapTempFileName( SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS, zMapName, sMapX, sMapY, bMapZ ); //Open the file for reading, Create it if it doesnt exist hFile = FileOpen( zMapName, FILE_ACCESS_READ | FILE_OPEN_EXISTING, FALSE ); if( hFile == 0 ) { //Error opening map modification file return( FALSE ); } //Clear out the old list ResetSmokeEffects(); //Load the Number of Smoke Effects FileRead( hFile, &guiNumSmokeEffects, sizeof( UINT32 ), &uiNumBytesRead ); if( uiNumBytesRead != sizeof( UINT32 ) ) { FileClose( hFile ); return( FALSE ); } //loop through and load the list for( uiCnt=0; uiCnt<guiNumSmokeEffects; uiCnt++) { //Load the Smoke effect Data FileRead( hFile, &gSmokeEffectData[ uiCnt ], sizeof( SMOKEEFFECT ), &uiNumBytesRead ); if( uiNumBytesRead != sizeof( SMOKEEFFECT ) ) { FileClose( hFile ); return( FALSE ); } } //loop through and apply the smoke effects to the map for(uiCount=0; uiCount < guiNumSmokeEffects; uiCount++) { //if this slot is allocated if( gSmokeEffectData[uiCount].fAllocated ) { if ( gSmokeEffectData[uiCount].bFlags & SMOKE_EFFECT_ON_ROOF ) { bLevel = 1; } else { bLevel = 0; } SpreadEffect( gSmokeEffectData[uiCount].sGridNo, gSmokeEffectData[uiCount].ubRadius, gSmokeEffectData[uiCount].usItem, gSmokeEffectData[uiCount].ubOwner, TRUE, bLevel, uiCount ); } } FileClose( hFile ); return( TRUE ); }
BOOLEAN LoadSmokeEffectsFromLoadGameFile( HWFILE hFile ) { UINT32 uiNumBytesRead; UINT32 uiCount; UINT32 uiCnt=0; INT8 bLevel; //no longer need to load smoke effects. They are now in temp files if( guiSaveGameVersion < 75 ) { //Clear out the old list memset( gSmokeEffectData, 0, sizeof( SMOKEEFFECT ) * NUM_SMOKE_EFFECT_SLOTS ); //Load the Number of Smoke Effects FileRead( hFile, &guiNumSmokeEffects, sizeof( UINT32 ), &uiNumBytesRead ); if( uiNumBytesRead != sizeof( UINT32 ) ) { return( FALSE ); } //This is a TEMP hack to allow us to use the saves if( guiSaveGameVersion < 37 && guiNumSmokeEffects == 0 ) { //Load the Smoke effect Data FileRead( hFile, gSmokeEffectData, sizeof( SMOKEEFFECT ), &uiNumBytesRead ); if( uiNumBytesRead != sizeof( SMOKEEFFECT ) ) { return( FALSE ); } } //loop through and load the list for( uiCnt=0; uiCnt<guiNumSmokeEffects; uiCnt++) { //Load the Smoke effect Data FileRead( hFile, &gSmokeEffectData[ uiCnt ], sizeof( SMOKEEFFECT ), &uiNumBytesRead ); if( uiNumBytesRead != sizeof( SMOKEEFFECT ) ) { return( FALSE ); } //This is a TEMP hack to allow us to use the saves if( guiSaveGameVersion < 37 ) break; } //loop through and apply the smoke effects to the map for(uiCount=0; uiCount < guiNumSmokeEffects; uiCount++) { //if this slot is allocated if( gSmokeEffectData[uiCount].fAllocated ) { if ( gSmokeEffectData[uiCount].bFlags & SMOKE_EFFECT_ON_ROOF ) { bLevel = 1; } else { bLevel = 0; } SpreadEffect( gSmokeEffectData[uiCount].sGridNo, gSmokeEffectData[uiCount].ubRadius, gSmokeEffectData[uiCount].usItem, gSmokeEffectData[uiCount].ubOwner, TRUE, bLevel, uiCount ); } } } return( TRUE ); }
void DecaySmokeEffects( UINT32 uiTime ) { SMOKEEFFECT *pSmoke; UINT32 cnt, cnt2; BOOLEAN fUpdate = FALSE; BOOLEAN fSpreadEffect; INT8 bLevel; UINT16 usNumUpdates = 1; for ( cnt = 0; cnt < guiNumMercSlots; cnt++ ) { if ( MercSlots[ cnt ] ) { // reset 'hit by gas' flags MercSlots[ cnt ]->fHitByGasFlags = 0; } } // ATE: 1 ) make first pass and delete/mark any smoke effect for update // all the deleting has to be done first/// // age all active tear gas clouds, deactivate those that are just dispersing for ( cnt = 0; cnt < guiNumSmokeEffects; cnt++ ) { fSpreadEffect = TRUE; pSmoke = &gSmokeEffectData[ cnt ]; if ( pSmoke->fAllocated ) { if ( pSmoke->bFlags & SMOKE_EFFECT_ON_ROOF ) { bLevel = 1; } else { bLevel = 0; } // Do things differently for combat /vs realtime // always try to update during combat if (gTacticalStatus.uiFlags & INCOMBAT ) { fUpdate = TRUE; } else { // ATE: Do this every so ofte, to acheive the effect we want... if ( ( uiTime - pSmoke->uiTimeOfLastUpdate ) > 10 ) { fUpdate = TRUE; usNumUpdates = ( UINT16 ) ( ( uiTime - pSmoke->uiTimeOfLastUpdate ) / 10 ); } } if ( fUpdate ) { pSmoke->uiTimeOfLastUpdate = uiTime; for ( cnt2 = 0; cnt2 < usNumUpdates; cnt2++ ) { pSmoke->bAge++; if ( pSmoke->bAge == 1 ) { // ATE: At least mark for update! pSmoke->bFlags |= SMOKE_EFFECT_MARK_FOR_UPDATE; fSpreadEffect = FALSE; } else { fSpreadEffect = TRUE; } if ( fSpreadEffect ) { // if this cloud remains effective (duration not reached) if ( pSmoke->bAge <= pSmoke->ubDuration) { // ATE: Only mark now and increse radius - actual drawing is done // in another pass cause it could // just get erased... pSmoke->bFlags |= SMOKE_EFFECT_MARK_FOR_UPDATE; // calculate the new cloud radius // cloud expands by 1 every turn outdoors, and every other turn indoors // ATE: If radius is < maximun, increase radius, otherwise keep at max if ( pSmoke->ubRadius < Explosive[ Item[ pSmoke->usItem ].ubClassIndex ].ubRadius ) { pSmoke->ubRadius++; } } else { // deactivate tear gas cloud (use last known radius) SpreadEffect( pSmoke->sGridNo, pSmoke->ubRadius, pSmoke->usItem, pSmoke->ubOwner, ERASE_SPREAD_EFFECT, bLevel, cnt ); pSmoke->fAllocated = FALSE; break; } } } } else { // damage anyone standing in cloud SpreadEffect( pSmoke->sGridNo, pSmoke->ubRadius, pSmoke->usItem, pSmoke->ubOwner, REDO_SPREAD_EFFECT, 0, cnt ); } } } for ( cnt = 0; cnt < guiNumSmokeEffects; cnt++ ) { pSmoke = &gSmokeEffectData[ cnt ]; if ( pSmoke->fAllocated ) { if ( pSmoke->bFlags & SMOKE_EFFECT_ON_ROOF ) { bLevel = 1; } else { bLevel = 0; } // if this cloud remains effective (duration not reached) if ( pSmoke->bFlags & SMOKE_EFFECT_MARK_FOR_UPDATE ) { SpreadEffect( pSmoke->sGridNo, pSmoke->ubRadius, pSmoke->usItem, pSmoke->ubOwner, TRUE, bLevel, cnt ); pSmoke->bFlags &= (~SMOKE_EFFECT_MARK_FOR_UPDATE); } } } AllTeamsLookForAll( TRUE ); }
INT32 NewSmokeEffect( INT16 sGridNo, UINT16 usItem, INT8 bLevel, UINT8 ubOwner ) { SMOKEEFFECT *pSmoke; INT32 iSmokeIndex; INT8 bSmokeEffectType=0; UINT8 ubDuration=0; UINT8 ubStartRadius=0; if( ( iSmokeIndex = GetFreeSmokeEffect() )==(-1) ) return(-1); memset( &gSmokeEffectData[ iSmokeIndex ], 0, sizeof( SMOKEEFFECT ) ); pSmoke = &gSmokeEffectData[ iSmokeIndex ]; // Set some values... pSmoke->sGridNo = sGridNo; pSmoke->usItem = usItem; pSmoke->uiTimeOfLastUpdate = GetWorldTotalSeconds( ); // Are we indoors? if ( GetTerrainType( sGridNo ) == FLAT_FLOOR ) { pSmoke->bFlags |= SMOKE_EFFECT_INDOORS; } switch( usItem ) { case MUSTARD_GRENADE: bSmokeEffectType = MUSTARDGAS_SMOKE_EFFECT; ubDuration = 5; ubStartRadius = 1; break; case TEARGAS_GRENADE: case GL_TEARGAS_GRENADE: bSmokeEffectType = TEARGAS_SMOKE_EFFECT; ubDuration = 5; ubStartRadius = 1; break; case BIG_TEAR_GAS: bSmokeEffectType = TEARGAS_SMOKE_EFFECT; ubDuration = 5; ubStartRadius = 1; break; case SMOKE_GRENADE: case GL_SMOKE_GRENADE: bSmokeEffectType = NORMAL_SMOKE_EFFECT; ubDuration = 5; ubStartRadius = 1; break; case SMALL_CREATURE_GAS: bSmokeEffectType = CREATURE_SMOKE_EFFECT; ubDuration = 3; ubStartRadius = 1; break; case LARGE_CREATURE_GAS: bSmokeEffectType = CREATURE_SMOKE_EFFECT; ubDuration = 3; ubStartRadius = Explosive[ Item[ LARGE_CREATURE_GAS ].ubClassIndex ].ubRadius; break; case VERY_SMALL_CREATURE_GAS: bSmokeEffectType = CREATURE_SMOKE_EFFECT; ubDuration = 2; ubStartRadius = 0; break; } pSmoke->ubDuration = ubDuration; pSmoke->ubRadius = ubStartRadius; pSmoke->bAge = 0; pSmoke->fAllocated = TRUE; pSmoke->bType = bSmokeEffectType; pSmoke->ubOwner = ubOwner; if ( pSmoke->bFlags & SMOKE_EFFECT_INDOORS ) { // Duration is increased by 2 turns...indoors pSmoke->ubDuration += 3; } if ( bLevel ) { pSmoke->bFlags |= SMOKE_EFFECT_ON_ROOF; } // ATE: FALSE into subsequent-- it's the first one! SpreadEffect( pSmoke->sGridNo, pSmoke->ubRadius, pSmoke->usItem, pSmoke->ubOwner, FALSE, bLevel, iSmokeIndex ); return( iSmokeIndex ); }