Exemple #1
0
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 );
			}

		}

	}

}
Exemple #3
0
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 );
}
Exemple #4
0
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 );
}
Exemple #5
0
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 );
}
Exemple #6
0
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 );
}