mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
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
917 lines
21 KiB
C++
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 );
|
|
}
|
|
}
|
|
} |