Files
source/TileEngine/SmokeEffects.cpp
T
Overhaul 7a27e7105d New attack busy system
Added missing #includes

Added LUA scripting and console

Changed the way tracers are visualized, so they work more like real tracers instead of a light fountain

Fixed signedness of many grid variables used in GetMouseMapPos calls

Fixed enemy weapon choosing:  Sometimes a mortar is chosen but later rejected, but the grenade class was not reset.  Caused assertion failure

Added checks so enemies don't try to chuck RPG grenades with their hands

Now possible to shoot a someone in the head if he's in water

Fixed InitSightArrays to also clear soldier interrupt duel points.  This was causing an assertion failure elsewhere in the code because the interrupt list still had soldiers on it sometimes when this function was called.

Soldiers are much less willing to forfeit their turn over an attempt to use more APs than they have

Removed early setting of muzzle flash.  This would allow enemies to get an interrupt before you even fired.

Fixed item dropping by AI.  If AI tried to drop something while standing it would cause deadlock

Change to greatly speed up closing the sector inventory window in an unloaded sector

Added conditional compile flag to always give robot weapon ready advantage, even for 360 degree sighting


Check builddefines.h for the conditional flags.  Of greatest interest might be LUA_CONSOLE.  This will cause the game to bring up a command console when run.  However this console is severely lacking in many areas.  If anybody knows of an open-source terminal/console that could be used instead, it would be appreciated.  The existing console does bad things when you try to close it, and since it counts as a separate app, it pauses the game while it has focus.

LUA scripting is very limited, basically just proof of concept.  There is one global variable, the Soldiers array.  An array index gives you the soldier in that slot in the currently loaded sector.  The soldier has a few things that can be accessed:  name (short name); fullname (long name); grid (current grid #, can be changed); walkto(grid) (function to walk to another grid); runto(grid) (function to run to another grid)


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@924 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2007-06-09 09:01:04 +00:00

917 lines
21 KiB
C++

#include "builddefines.h"
#ifdef PRECOMPILEDHEADERS
#include "TileEngine All.h"
#else
#include <stdio.h>
#include <string.h>
#include "wcheck.h"
#include "stdlib.h"
#include "debug.h"
#include "soldier control.h"
#include "weapons.h"
#include "handle items.h"
#include "worlddef.h"
#include "worldman.h"
#include "animation control.h"
#include "tile animation.h"
#include "handle items.h"
#include "smokeeffects.h"
#include "message.h"
#include "isometric utils.h"
#include "renderworld.h"
#include "explosion control.h"
#include "Random.h"
#include "Game Clock.h"
#include "opplist.h"
#include "Campaign Types.h"
#include "Tactical Save.h"
#endif
#include "SaveLoadGame.h"
INT8 FromWorldFlagsToSmokeType( UINT16 ubWorldFlags );
UINT16 FromSmokeTypeToWorldFlags( INT8 bType );
#define NUM_SMOKE_EFFECT_SLOTS 25
// GLOBAL FOR SMOKE LISTING
SMOKEEFFECT gSmokeEffectData[ NUM_SMOKE_EFFECT_SLOTS ];
UINT32 guiNumSmokeEffects = 0;
INT32 GetFreeSmokeEffect( void );
void RecountSmokeEffects( void );
INT32 GetFreeSmokeEffect( void )
{
UINT32 uiCount;
for(uiCount=0; uiCount < guiNumSmokeEffects; uiCount++)
{
if(( gSmokeEffectData[uiCount].fAllocated==FALSE ) )
return( (INT32)uiCount );
}
if( guiNumSmokeEffects < NUM_SMOKE_EFFECT_SLOTS )
return( (INT32) guiNumSmokeEffects++ );
return( -1 );
}
void RecountSmokeEffects( void )
{
INT32 uiCount;
for(uiCount=guiNumSmokeEffects-1; (uiCount >=0) ; uiCount--)
{
if( ( gSmokeEffectData[uiCount].fAllocated ) )
{
guiNumSmokeEffects=(UINT32)(uiCount+1);
break;
}
}
}
// Returns NO_SMOKE_EFFECT if none there...
INT8 GetSmokeEffectOnTile( INT16 sGridNo, INT8 bLevel )
{
UINT16 ubExtFlags;
ubExtFlags = gpWorldLevelData[ sGridNo ].ubExtFlags[ bLevel ];
// Look at worldleveldata to find flags..
if ( ubExtFlags & ANY_SMOKE_EFFECT )
{
// Which smoke am i?
return( FromWorldFlagsToSmokeType( ubExtFlags ) );
}
return( NO_SMOKE_EFFECT );
}
INT8 FromWorldFlagsToSmokeType( UINT16 ubWorldFlags )
{
if ( ubWorldFlags & MAPELEMENT_EXT_SMOKE )
{
return( NORMAL_SMOKE_EFFECT );
}
else if ( ubWorldFlags & MAPELEMENT_EXT_TEARGAS )
{
return( TEARGAS_SMOKE_EFFECT );
}
else if ( ubWorldFlags & MAPELEMENT_EXT_MUSTARDGAS )
{
return( MUSTARDGAS_SMOKE_EFFECT );
}
else if ( ubWorldFlags & MAPELEMENT_EXT_CREATUREGAS )
{
return( CREATURE_SMOKE_EFFECT );
}
else if ( ubWorldFlags & MAPELEMENT_EXT_BURNABLEGAS )
{
return( BURNABLEGAS_SMOKE_EFFECT );
}
else
{
return( NO_SMOKE_EFFECT );
}
}
UINT16 FromSmokeTypeToWorldFlags( INT8 bType )
{
switch( bType )
{
case NORMAL_SMOKE_EFFECT:
return( MAPELEMENT_EXT_SMOKE );
break;
case TEARGAS_SMOKE_EFFECT:
return( MAPELEMENT_EXT_TEARGAS );
break;
case MUSTARDGAS_SMOKE_EFFECT:
return( MAPELEMENT_EXT_MUSTARDGAS );
break;
case BURNABLEGAS_SMOKE_EFFECT:
return( MAPELEMENT_EXT_BURNABLEGAS );
break;
case CREATURE_SMOKE_EFFECT:
return( MAPELEMENT_EXT_CREATUREGAS );
break;
default:
return( 0 );
}
}
INT32 NewSmokeEffect( INT16 sGridNo, UINT16 usItem, INT8 bLevel, UINT8 ubOwner )
{
SMOKEEFFECT *pSmoke;
INT32 iSmokeIndex;
INT8 bSmokeEffectType=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( Explosive[Item[usItem].ubClassIndex].ubType )
{
case EXPLOSV_MUSTGAS:
bSmokeEffectType = MUSTARDGAS_SMOKE_EFFECT;
break;
case EXPLOSV_BURNABLEGAS:
bSmokeEffectType = BURNABLEGAS_SMOKE_EFFECT;
break;
case EXPLOSV_TEARGAS:
bSmokeEffectType = TEARGAS_SMOKE_EFFECT;
break;
case EXPLOSV_SMOKE:
bSmokeEffectType = NORMAL_SMOKE_EFFECT;
break;
// case SMALL_CREATURE_GAS:
//bSmokeEffectType = CREATURE_SMOKE_EFFECT;
//ubDuration = 3;
//ubStartRadius = 1;
//break;
case EXPLOSV_CREATUREGAS:
bSmokeEffectType = CREATURE_SMOKE_EFFECT;
break;
// case VERY_SMALL_CREATURE_GAS:
//bSmokeEffectType = CREATURE_SMOKE_EFFECT;
//ubDuration = 2;
//ubStartRadius = 0;
break;
}
pSmoke->ubDuration = (UINT8)Explosive[ Item[ usItem ].ubClassIndex ].ubDuration;
pSmoke->ubRadius = (UINT8)Explosive[ Item[ usItem ].ubClassIndex ].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 );
}
// Add smoke to gridno
// ( Replacement algorithm uses distance away )
void AddSmokeEffectToTile( INT32 iSmokeEffectID, INT8 bType, INT16 sGridNo, INT8 bLevel )
{
ANITILE_PARAMS AniParams;
ANITILE *pAniTile;
SMOKEEFFECT *pSmoke;
BOOLEAN fDissipating = FALSE;
pSmoke = &gSmokeEffectData[ iSmokeEffectID ];
if ( ( pSmoke->ubDuration - pSmoke->bAge ) < 2 )
{
fDissipating = TRUE;
// Remove old one...
RemoveSmokeEffectFromTile( sGridNo, bLevel );
}
// If smoke effect exists already.... stop
if ( gpWorldLevelData[ sGridNo ].ubExtFlags[ bLevel ] & ANY_SMOKE_EFFECT )
{
return;
}
// OK, Create anitile....
memset( &AniParams, 0, sizeof( ANITILE_PARAMS ) );
AniParams.sGridNo = sGridNo;
if ( bLevel == 0 )
{
AniParams.ubLevelID = ANI_STRUCT_LEVEL;
}
else
{
AniParams.ubLevelID = ANI_ONROOF_LEVEL;
}
AniParams.sDelay = (INT16)( 300 + Random( 300 ) );
if ( !( gGameSettings.fOptions[ TOPTION_ANIMATE_SMOKE ] ) )
{
AniParams.sStartFrame = (INT16)0;
}
else
{
AniParams.sStartFrame = (INT16)Random( 5 );
}
// Bare bones flags are...
// AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_OPTIMIZEFORSMOKEEFFECT | ANITILE_SMOKE_EFFECT | ANITILE_LOOPING;
//AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_SMOKE_EFFECT | ANITILE_LOOPING;
if ( !( gGameSettings.fOptions[ TOPTION_ANIMATE_SMOKE ] ) )
{
AniParams.uiFlags = ANITILE_PAUSED | ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_SMOKE_EFFECT | ANITILE_LOOPING;
}
else
{
AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_SMOKE_EFFECT | ANITILE_LOOPING | ANITILE_ALWAYS_TRANSLUCENT;
}
AniParams.sX = CenterX( sGridNo );
AniParams.sY = CenterY( sGridNo );
AniParams.sZ = (INT16)0;
// Use the right graphic based on type..
switch( bType )
{
case NORMAL_SMOKE_EFFECT:
if ( !( gGameSettings.fOptions[ TOPTION_ANIMATE_SMOKE ] ) )
{
strcpy( AniParams.zCachedFile, "TILECACHE\\smkechze.STI" );
}
else
{
if ( fDissipating )
{
strcpy( AniParams.zCachedFile, "TILECACHE\\smalsmke.STI" );
}
else
{
strcpy( AniParams.zCachedFile, "TILECACHE\\SMOKE.STI" );
}
}
break;
case TEARGAS_SMOKE_EFFECT:
if ( !( gGameSettings.fOptions[ TOPTION_ANIMATE_SMOKE ] ) )
{
strcpy( AniParams.zCachedFile, "TILECACHE\\tearchze.STI" );
}
else
{
if ( fDissipating )
{
strcpy( AniParams.zCachedFile, "TILECACHE\\smaltear.STI" );
}
else
{
strcpy( AniParams.zCachedFile, "TILECACHE\\TEARGAS.STI" );
}
}
break;
case MUSTARDGAS_SMOKE_EFFECT:
if ( !( gGameSettings.fOptions[ TOPTION_ANIMATE_SMOKE ] ) )
{
strcpy( AniParams.zCachedFile, "TILECACHE\\mustchze.STI" );
}
else
{
if ( fDissipating )
{
strcpy( AniParams.zCachedFile, "TILECACHE\\smalmust.STI" );
}
else
{
strcpy( AniParams.zCachedFile, "TILECACHE\\MUSTARD2.STI" );
}
}
break;
case BURNABLEGAS_SMOKE_EFFECT:
if ( !( gGameSettings.fOptions[ TOPTION_ANIMATE_SMOKE ] ) )
{
strcpy( AniParams.zCachedFile, "TILECACHE\\FLAMCHZE.STI" );
}
else
{
if ( fDissipating )
{
strcpy( AniParams.zCachedFile, "TILECACHE\\smalflam.STI" );
}
else
{
strcpy( AniParams.zCachedFile, "TILECACHE\\FLAMETH2.STI" );
}
}
break;
case CREATURE_SMOKE_EFFECT:
if ( !( gGameSettings.fOptions[ TOPTION_ANIMATE_SMOKE ] ) )
{
strcpy( AniParams.zCachedFile, "TILECACHE\\spit_gas.STI" );
}
else
{
if ( fDissipating )
{
strcpy( AniParams.zCachedFile, "TILECACHE\\spit_gas.STI" );
}
else
{
strcpy( AniParams.zCachedFile, "TILECACHE\\spit_gas.STI" );
}
}
break;
}
// Create tile...
pAniTile = CreateAnimationTile( &AniParams );
// Set world flags
gpWorldLevelData[ sGridNo ].ubExtFlags[ bLevel ] |= FromSmokeTypeToWorldFlags( bType );
// All done...
// Re-draw..... :(
SetRenderFlags(RENDER_FLAG_FULL);
}
void RemoveSmokeEffectFromTile( INT16 sGridNo, INT8 bLevel )
{
ANITILE *pAniTile;
UINT8 ubLevelID;
// Get ANI tile...
if ( bLevel == 0 )
{
ubLevelID = ANI_STRUCT_LEVEL;
}
else
{
ubLevelID = ANI_ONROOF_LEVEL;
}
pAniTile = GetCachedAniTileOfType( sGridNo, ubLevelID, ANITILE_SMOKE_EFFECT );
if ( pAniTile != NULL )
{
DeleteAniTile( pAniTile );
SetRenderFlags( RENDER_FLAG_FULL );
}
// Unset flags in world....
// ( // check to see if we are the last one....
if ( GetCachedAniTileOfType( sGridNo, ubLevelID, ANITILE_SMOKE_EFFECT ) == NULL )
{
gpWorldLevelData[ sGridNo ].ubExtFlags[ bLevel ] &= ( ~ANY_SMOKE_EFFECT );
}
}
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 );
}
BOOLEAN SaveSmokeEffectsToSaveGameFile( HWFILE hFile )
{
/*
UINT32 uiNumBytesWritten;
UINT32 uiCnt=0;
UINT32 uiNumSmokeEffects=0;
//loop through and count the number of smoke effects
for( uiCnt=0; uiCnt<guiNumSmokeEffects; uiCnt++)
{
if( gSmokeEffectData[ uiCnt ].fAllocated )
uiNumSmokeEffects++;
}
//Save the Number of Smoke Effects
FileWrite( hFile, &uiNumSmokeEffects, sizeof( UINT32 ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( UINT32 ) )
{
return( FALSE );
}
if( uiNumSmokeEffects != 0 )
{
//loop through and save the number of smoke effects
for( uiCnt=0; uiCnt < guiNumSmokeEffects; uiCnt++)
{
//if the smoke is active
if( gSmokeEffectData[ uiCnt ].fAllocated )
{
//Save the Smoke effect Data
FileWrite( hFile, &gSmokeEffectData[ uiCnt ], sizeof( SMOKEEFFECT ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( SMOKEEFFECT ) )
{
return( FALSE );
}
}
}
}
*/
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 );
}
BOOLEAN SaveSmokeEffectsToMapTempFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
{
UINT32 uiNumSmokeEffects=0;
HWFILE hFile;
UINT32 uiNumBytesWritten=0;
CHAR8 zMapName[ 128 ];
UINT32 uiCnt;
//get the name of the map
GetMapTempFileName( SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS, zMapName, sMapX, sMapY, bMapZ );
//delete file the file.
FileDelete( zMapName );
//loop through and count the number of smoke effects
for( uiCnt=0; uiCnt<guiNumSmokeEffects; uiCnt++)
{
if( gSmokeEffectData[ uiCnt ].fAllocated )
uiNumSmokeEffects++;
}
//if there are no smoke effects
if( uiNumSmokeEffects == 0 )
{
//set the fact that there are no smoke effects for this sector
ReSetSectorFlag( sMapX, sMapY, bMapZ, SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS );
return( TRUE );
}
//Open the file for writing
hFile = FileOpen( zMapName, FILE_ACCESS_WRITE | FILE_OPEN_ALWAYS, FALSE );
if( hFile == 0 )
{
//Error opening file
return( FALSE );
}
//Save the Number of Smoke Effects
FileWrite( hFile, &uiNumSmokeEffects, sizeof( UINT32 ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( UINT32 ) )
{
//Close the file
FileClose( hFile );
return( FALSE );
}
//loop through and save the number of smoke effects
for( uiCnt=0; uiCnt < guiNumSmokeEffects; uiCnt++)
{
//if the smoke is active
if( gSmokeEffectData[ uiCnt ].fAllocated )
{
//Save the Smoke effect Data
FileWrite( hFile, &gSmokeEffectData[ uiCnt ], sizeof( SMOKEEFFECT ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( SMOKEEFFECT ) )
{
//Close the file
FileClose( hFile );
return( FALSE );
}
}
}
//Close the file
FileClose( hFile );
SetSectorFlag( sMapX, sMapY, bMapZ, SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS );
return( TRUE );
}
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 );
}
void ResetSmokeEffects()
{
//Clear out the old list
memset( gSmokeEffectData, 0, sizeof( SMOKEEFFECT ) * NUM_SMOKE_EFFECT_SLOTS );
guiNumSmokeEffects = 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 );
}
}
}