Files
source/Tactical/Enemy Soldier Save.cpp
T

1860 lines
55 KiB
C++

#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#include "Enemy Soldier Save.h"
#else
#include "builddefines.h"
#include <stdio.h>
#include <memory.h>
#include "types.h"
#include "strategicmap.h"
#include "overhead.h"
#include "isometric utils.h"
#include "soldier add.h"
#include "soldier create.h"
#include "Soldier Init List.h"
#include "debug.h"
#include "Random.h"
#include "items.h"
#include "cursors.h"
#include "Map Information.h"
#include "soldier profile.h"
#include "Sys Globals.h"
#include "EditorMercs.h"
#include "Animation Data.h"
#include "message.h"
#include "Font Control.h"
#include "Campaign Types.h"
#include "Tactical Save.h"
#include "Game Clock.h"
#include "Queen Command.h"
#include "Scheduling.h"
#endif
#include "GameVersion.h"
//ADB When a savegame is loaded, the enemy and civ stuff needs to be loaded and updated, but this can only happen
//when the temp file is loaded which can happen much later, it cannot load convert and save when updating the savegame
//therefore store a flag to load and convert later
int gEnemyPreservedTempFileVersion[256];
int gCivPreservedTempFileVersion[256];
BOOLEAN AddPlacementToWorld( SOLDIERINITNODE *pNode, GROUP *pGroup = NULL );
BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( UINT8 *pubNumElites, UINT8 *pubNumRegulars, UINT8 *pubNumAdmins, UINT8 *pubNumCreatures );
BOOLEAN gfRestoringEnemySoldiersFromTempFile = FALSE;
BOOLEAN gfRestoringCiviliansFromTempFile = FALSE;
void RemoveCivilianTempFile( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ );
void RemoveEnemySoldierTempFile( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ )
{
CHAR8 zMapName[ 128 ];
if( GetSectorFlagStatus( sSectorX, sSectorY, bSectorZ, SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS ) )
{
//Delete any temp file that is here and toast the flag that say's one exists.
ReSetSectorFlag( sSectorX, sSectorY, bSectorZ, SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS );
// GetMapFileName( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, zTempName, FALSE );
//add the 'e' for 'Enemy preserved' to the front of the map name
// sprintf( zMapName, "%s\\e_%s", MAPS_DIR, zTempName);
GetMapTempFileName( SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, zMapName, sSectorX, sSectorY, bSectorZ );
//Delete the temp file.
FileDelete( zMapName );
}
}
void RemoveCivilianTempFile( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ )
{
//CHAR8 zTempName[ 128 ];
CHAR8 zMapName[ 128 ];
if( GetSectorFlagStatus( sSectorX, sSectorY, bSectorZ, SF_CIV_PRESERVED_TEMP_FILE_EXISTS ) )
{
//Delete any temp file that is here and toast the flag that say's one exists.
ReSetSectorFlag( sSectorX, sSectorY, bSectorZ, SF_CIV_PRESERVED_TEMP_FILE_EXISTS );
//GetMapFileName( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, zTempName, FALSE );
GetMapTempFileName( SF_CIV_PRESERVED_TEMP_FILE_EXISTS, zMapName, sSectorX, sSectorY, bSectorZ );
//Delete the temp file.
FileDelete( zMapName );
}
}
//OLD SAVE METHOD: This is the old way of loading the enemies and civilians
BOOLEAN LoadEnemySoldiersFromTempFile()
{
SOLDIERINITNODE *curr;
SOLDIERCREATE_STRUCT tempDetailedPlacement;
INT32 i;
INT32 slots = 0;
UINT32 uiNumBytesRead;
UINT32 uiTimeStamp;
HWFILE hfile;
INT16 sSectorX, sSectorY;
CHAR8 zMapName[ 128 ];
#ifdef JA2TESTVERSION
CHAR8 zReason[256];
#endif
INT8 bSectorZ;
UINT8 ubSectorID;
UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0;
UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures;
gfRestoringEnemySoldiersFromTempFile = TRUE;
//STEP ONE: Set up the temp file to read from.
//Convert the current sector location into a file name
// GetMapFileName( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, zTempName, FALSE );
//add the 'e' for 'Enemy preserved' to the front of the map name
// sprintf( zMapName, "%s\\e_%s", MAPS_DIR, zTempName);
GetMapTempFileName( SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, zMapName, gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
//Open the file for reading
hfile = FileOpen( zMapName, FILE_ACCESS_READ | FILE_OPEN_EXISTING, FALSE );
if( hfile == 0 )
{ //Error opening map modification file
return FALSE;
}
//STEP TWO: determine whether or not we should use this data.
//because it is the demo, it is automatically used.
FileRead( hfile, &sSectorY, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading sSectorY. KM" );
#endif
goto FAIL_LOAD;
}
if( gWorldSectorY != sSectorY )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- sSectorY mismatch. KM" );
#endif
goto FAIL_LOAD;
}
LoadSoldierInitListLinks( hfile );
//STEP THREE: read the data
FileRead( hfile, &sSectorX, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading sSectorX. KM" );
#endif
goto FAIL_LOAD;
}
if( gWorldSectorX != sSectorX )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- sSectorX mismatch. KM" );
#endif
goto FAIL_LOAD;
}
FileRead( hfile, &slots, 4, &uiNumBytesRead );
if( uiNumBytesRead != 4 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading slots. KM" );
#endif
goto FAIL_LOAD;
}
FileRead( hfile, &uiTimeStamp, 4, &uiNumBytesRead );
if( uiNumBytesRead != 4 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading uiTimeStamp. KM" );
#endif
goto FAIL_LOAD;
}
FileRead( hfile, &bSectorZ, 1, &uiNumBytesRead );
if( uiNumBytesRead != 1 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading bSectorZ. KM" );
#endif
goto FAIL_LOAD;
}
if( GetWorldTotalMin() > uiTimeStamp + 300 )
{ //the file has aged. Use the regular method for adding soldiers.
FileClose( hfile );
RemoveEnemySoldierTempFile( sSectorX, sSectorY, bSectorZ );
gfRestoringEnemySoldiersFromTempFile = FALSE;
return TRUE;
}
if( gbWorldSectorZ != bSectorZ )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- bSectorZ mismatch. KM" );
#endif
goto FAIL_LOAD;
}
if( !slots )
{ //no need to restore the enemy's to the map. This means we are restoring a saved game.
gfRestoringEnemySoldiersFromTempFile = FALSE;
FileClose( hfile );
return TRUE;
}
if( slots < 0 || slots >= 64 )
{ //bad IO!
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- illegal slot value of %d. KM", slots );
#endif
goto FAIL_LOAD;
}
//For all the enemy slots (enemy/creature), clear the fPriorityExistance flag. We will use these flags
//to determine which slots have been modified as we load the data into the map pristine soldier init list.
curr = gSoldierInitHead;
while( curr )
{
if( curr->pBasicPlacement->fPriorityExistance )
{
if( curr->pBasicPlacement->bTeam == ENEMY_TEAM || curr->pBasicPlacement->bTeam == CREATURE_TEAM || curr->pBasicPlacement->bTeam == CIV_TEAM )
{
curr->pBasicPlacement->fPriorityExistance = FALSE;
}
}
curr = curr->next;
}
//get the number of enemies in this sector.
if( bSectorZ )
{
UNDERGROUND_SECTORINFO *pSector;
pSector = FindUnderGroundSector( sSectorX, sSectorY, bSectorZ );
if( !pSector )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- Couldn't find underground sector info for (%d,%d,%d) KM", sSectorX, sSectorY, bSectorZ );
#endif
goto FAIL_LOAD;
}
ubStrategicElites = pSector->ubNumElites;
ubStrategicTroops = pSector->ubNumTroops;
ubStrategicAdmins = pSector->ubNumAdmins;
ubStrategicCreatures = pSector->ubNumCreatures;
}
else
{
SECTORINFO *pSector;
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
ubStrategicCreatures = pSector->ubNumCreatures;
GetNumberOfEnemiesInSector( sSectorX, sSectorY, &ubStrategicAdmins, &ubStrategicTroops, &ubStrategicElites );
}
for( i = 0; i < slots; i++ )
{
if ( !tempDetailedPlacement.Load(hfile, gEnemyPreservedTempFileVersion[SECTOR( sSectorX,sSectorY)], true) )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading tempDetailedPlacment %d. KM", i );
#endif
goto FAIL_LOAD;
}
curr = gSoldierInitHead;
while( curr )
{
if( !curr->pBasicPlacement->fPriorityExistance )
{
if( !curr->pDetailedPlacement || curr->pDetailedPlacement && curr->pDetailedPlacement->ubProfile == NO_PROFILE )
{
if( curr->pBasicPlacement->bTeam == tempDetailedPlacement.bTeam )
{
curr->pBasicPlacement->fPriorityExistance = TRUE;
if( !curr->pDetailedPlacement )
{ //need to upgrade the placement to detailed placement
curr->pBasicPlacement->fDetailedPlacement = TRUE;
curr->pDetailedPlacement = new SOLDIERCREATE_STRUCT(tempDetailedPlacement); //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT );
}
else
{
//now replace the map pristine placement info with the temp map file version..
*curr->pDetailedPlacement = tempDetailedPlacement;
}
curr->pBasicPlacement->fPriorityExistance = TRUE;
curr->pBasicPlacement->ubDirection = curr->pDetailedPlacement->ubDirection;
curr->pBasicPlacement->bOrders = curr->pDetailedPlacement->bOrders;
curr->pBasicPlacement->bAttitude = curr->pDetailedPlacement->bAttitude;
curr->pBasicPlacement->bBodyType = curr->pDetailedPlacement->bBodyType;
curr->pBasicPlacement->fOnRoof = curr->pDetailedPlacement->fOnRoof;
curr->pBasicPlacement->ubSoldierClass = curr->pDetailedPlacement->ubSoldierClass;
curr->pBasicPlacement->ubCivilianGroup = curr->pDetailedPlacement->ubCivilianGroup;
curr->pBasicPlacement->fHasKeys = curr->pDetailedPlacement->fHasKeys;
curr->pBasicPlacement->sStartingGridNo = curr->pDetailedPlacement->sInsertionGridNo;
curr->pBasicPlacement->bPatrolCnt = curr->pDetailedPlacement->bPatrolCnt;
memcpy( curr->pBasicPlacement->sPatrolGrid, curr->pDetailedPlacement->sPatrolGrid,
sizeof( INT16 ) * curr->pBasicPlacement->bPatrolCnt );
if( curr->pBasicPlacement->bTeam == CIV_TEAM )
{
AddPlacementToWorld( curr );
break;
}
else
{
//Add preserved placements as long as they don't exceed the actual population.
switch( curr->pBasicPlacement->ubSoldierClass )
{
case SOLDIER_CLASS_ELITE:
ubNumElites++;
if( ubNumElites < ubStrategicElites )
{
AddPlacementToWorld( curr );
}
break;
case SOLDIER_CLASS_ARMY:
ubNumTroops++;
if( ubNumTroops < ubStrategicTroops )
{
AddPlacementToWorld( curr );
}
break;
case SOLDIER_CLASS_ADMINISTRATOR:
ubNumAdmins++;
if( ubNumAdmins < ubStrategicAdmins )
{
AddPlacementToWorld( curr );
}
break;
case SOLDIER_CLASS_CREATURE:
ubNumCreatures++;
if( ubNumCreatures < ubStrategicCreatures )
{
AddPlacementToWorld( curr );
}
break;
}
break;
}
}
}
}
curr = curr->next;
}
}
FileRead( hfile, &ubSectorID, 1, &uiNumBytesRead );
if( uiNumBytesRead != 1 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading ubSectorID. KM" );
#endif
goto FAIL_LOAD;
}
if( ubSectorID != SECTOR( sSectorX, sSectorY ) )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- ubSectorID mismatch. KM" );
#endif
goto FAIL_LOAD;
}
//now add any extra enemies that have arrived since the temp file was made.
if( ubStrategicTroops > ubNumTroops || ubStrategicElites > ubNumElites || ubStrategicAdmins > ubNumAdmins )
{
ubStrategicTroops = ( ubStrategicTroops > ubNumTroops ) ? ubStrategicTroops - ubNumTroops : 0;
ubStrategicElites = ( ubStrategicElites > ubNumElites ) ? ubStrategicElites - ubNumElites : 0;
ubStrategicAdmins = ( ubStrategicAdmins > ubNumAdmins ) ? ubStrategicAdmins - ubNumAdmins : 0;
AddSoldierInitListEnemyDefenceSoldiers( ubStrategicAdmins, ubStrategicTroops, ubStrategicElites );
}
if( ubStrategicCreatures > ubNumCreatures )
{
ubStrategicCreatures; //not sure if this wil ever happen. If so, needs to be handled.
}
//successful
FileClose( hfile );
return TRUE;
FAIL_LOAD:
//The temp file load failed either because of IO problems related to hacking/logic, or
//various checks failed for hacker validation. If we reach this point, the "error: exit game"
//dialog would appear in a non-testversion.
FileClose( hfile );
#ifdef JA2TESTVERSION
AssertMsg( 0, zReason );
#endif
return FALSE;
}
#ifdef OBSOLETE_CODE
//OLD SAVE METHOD: This is the older way of saving the civilian and the enemies placement into a temp file
BOOLEAN SaveEnemySoldiersToTempFile( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubFirstIdTeam, UINT8 ubLastIdTeam, BOOLEAN fAppendToFile )
{
SOLDIERINITNODE *curr;
SOLDIERTYPE *pSoldier;
INT32 i;
INT32 slots = 0;
INT32 iSlotsAlreadyInUse=0;
UINT32 uiNumBytesWritten;
UINT32 uiTimeStamp;
HWFILE hfile;
SCHEDULENODE *pSchedule;
CHAR8 zMapName[ 128 ];
UINT8 ubSectorID;
//STEP ONE: Prep the soldiers for saving...
//modify the map's soldier init list to reflect the changes to the member's still alive...
for( i = gTacticalStatus.Team[ ubFirstIdTeam ].bFirstID; i <= gTacticalStatus.Team[ ubLastIdTeam ].bLastID; i++ )
{
pSoldier = MercPtrs[ i ];
if( pSoldier->bActive /*&& pSoldier->bInSector*/ && pSoldier->stats.bLife )
{ //soldier is valid, so find the matching soldier init list entry for modification.
curr = gSoldierInitHead;
while( curr && curr->pSoldier != pSoldier )
{
curr = curr->next;
}
if( curr && curr->pSoldier == pSoldier && pSoldier->ubProfile == NO_PROFILE )
{ //found a match.
if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME) )
{
if( !curr->pDetailedPlacement )
{ //need to upgrade the placement to detailed placement
curr->pBasicPlacement->fDetailedPlacement = TRUE;
curr->pDetailedPlacement = new SOLDIERCREATE_STRUCT; //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT );
}
(*curr->pDetailedPlacement) = (*pSoldier);
//If the soldier has a real schedule (not a default schedule), then store it.
//All other cases should be 0.
curr->pDetailedPlacement->ubScheduleID = 0;
if( pSoldier->ubScheduleID )
{
pSchedule = GetSchedule( pSoldier->ubScheduleID );
if( pSchedule && !(pSchedule->usFlags & SCHEDULE_FLAGS_TEMPORARY) )
{
curr->pDetailedPlacement->ubScheduleID = pSoldier->ubScheduleID;
}
}
//we don't want the player to think that all the enemies start in the exact position when we
//left the map, so randomize the start locations either current position or original position.
if( PreRandom( 2 ) )
{ //use current position
curr->pDetailedPlacement->fOnRoof = pSoldier->pathing.bLevel;
curr->pDetailedPlacement->sInsertionGridNo = pSoldier->sGridNo;
}
else
{ //use original position
curr->pDetailedPlacement->fOnRoof = curr->pBasicPlacement->fOnRoof;
curr->pDetailedPlacement->sInsertionGridNo = curr->pBasicPlacement->sStartingGridNo;
}
}
//DONE, now increment the counter, so we know how many there are.
slots++;
}
}
}
if( !slots )
{ //No need to save anything, so return successfully
RemoveEnemySoldierTempFile( sSectorX, sSectorY, bSectorZ );
return TRUE;
}
//STEP TWO: Set up the temp file to write to.
//Convert the current sector location into a file name
// GetMapFileName( sSectorX, sSectorY, bSectorZ, zTempName, FALSE );
//add the 'e' for 'Enemy preserved' to the front of the map name
// sprintf( zMapName, "%s\\e_%s", MAPS_DIR, zTempName);
GetMapTempFileName( SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, zMapName, sSectorX, sSectorY, bSectorZ );
//if the file doesnt exist
if( FileSize( zMapName ) == 0 )
{
//set it so we are not appending
fAppendToFile = FALSE;
}
//if we are to append to the file
if( fAppendToFile )
{
//Open the file for writing, Create it if it doesnt exist
hfile = FileOpen( zMapName, FILE_ACCESS_READ | FILE_OPEN_ALWAYS, FALSE );
if( hfile == 0 )
{ //Error opening map modification file
return FALSE;
}
//advance for bytes and read the #of slots already used
FileSeek( hfile, 4, FILE_SEEK_FROM_START );
FileRead( hfile, &iSlotsAlreadyInUse, 4, &uiNumBytesWritten );
if( uiNumBytesWritten != 4 )
{
goto FAIL_SAVE;
}
FileClose( hfile );
//Open the file for writing, Create it if it doesnt exist
hfile = FileOpen( zMapName, FILE_ACCESS_WRITE | FILE_OPEN_ALWAYS, FALSE );
if( hfile == 0 )
{ //Error opening map modification file
return FALSE;
}
slots += iSlotsAlreadyInUse;
//advance for bytes and read the #of slots already used
FileSeek( hfile, 4, FILE_SEEK_FROM_START );
FileWrite( hfile, &slots, 4, &uiNumBytesWritten );
if( uiNumBytesWritten != 4 )
{
goto FAIL_SAVE;
}
FileSeek( hfile, 0, FILE_SEEK_FROM_END );
}
else
{
//Open the file for writing, Create it if it doesnt exist
hfile = FileOpen( zMapName, FILE_ACCESS_WRITE | FILE_OPEN_ALWAYS, FALSE );
if( hfile == 0 )
{ //Error opening map modification file
return FALSE;
}
}
//if we are to append to the file
if( !fAppendToFile )
{
FileWrite( hfile, &sSectorY, 2, &uiNumBytesWritten );
if( uiNumBytesWritten != 2 )
{
goto FAIL_SAVE;
}
//STEP THREE: Save the data
SaveSoldierInitListLinks( hfile );
FileWrite( hfile, &sSectorX, 2, &uiNumBytesWritten );
if( uiNumBytesWritten != 2 )
{
goto FAIL_SAVE;
}
//This check may appear confusing. It is intended to abort if the player is saving the game. It is only
//supposed to preserve the links to the placement list, so when we finally do leave the level with enemies remaining,
//we will need the links that are only added when the map is loaded, and are normally lost when restoring a save.
if( gTacticalStatus.uiFlags & LOADING_SAVED_GAME )
{
slots = 0;
}
FileWrite( hfile, &slots, 4, &uiNumBytesWritten );
if( uiNumBytesWritten != 4 )
{
goto FAIL_SAVE;
}
uiTimeStamp = GetWorldTotalMin();
FileWrite( hfile, &uiTimeStamp, 4, &uiNumBytesWritten );
if( uiNumBytesWritten != 4 )
{
goto FAIL_SAVE;
}
FileWrite( hfile, &bSectorZ, 1, &uiNumBytesWritten );
if( uiNumBytesWritten != 1 )
{
goto FAIL_SAVE;
}
}
if( gTacticalStatus.uiFlags & LOADING_SAVED_GAME )
{
//if we are saving the game, we don't need to preserve the soldier information, just
//preserve the links to the placement list.
slots = 0;
FileClose( hfile );
SetSectorFlag( sSectorX, sSectorY, bSectorZ, SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS );
return TRUE;
}
for( i = gTacticalStatus.Team[ ubFirstIdTeam ].bFirstID; i <= gTacticalStatus.Team[ ubLastIdTeam ].bLastID; i++ )
{
pSoldier = MercPtrs[ i ];
if( pSoldier->bActive /*&& pSoldier->bInSector*/ && pSoldier->stats.bLife )
{ //soldier is valid, so find the matching soldier init list entry for modification.
curr = gSoldierInitHead;
while( curr && curr->pSoldier != pSoldier )
{
curr = curr->next;
}
if( curr && curr->pSoldier == pSoldier && pSoldier->ubProfile == NO_PROFILE )
{ //found a match.
if ( !curr->pDetailedPlacement->Save(hfile, FALSE) )
{
goto FAIL_SAVE;
}
}
}
}
//if we are to append to the file
if( !fAppendToFile )
{
ubSectorID = SECTOR( sSectorX, sSectorY );
FileWrite( hfile, &ubSectorID, 1, &uiNumBytesWritten );
if( uiNumBytesWritten != 1 )
{
goto FAIL_SAVE;
}
}
FileClose( hfile );
SetSectorFlag( sSectorX, sSectorY, bSectorZ, SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS );
return TRUE;
FAIL_SAVE:
FileClose( hfile );
return FALSE;
}
#endif
BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile()
{
SOLDIERINITNODE *curr;
SOLDIERCREATE_STRUCT tempDetailedPlacement;
INT32 i;
INT32 slots = 0;
UINT32 uiNumBytesRead;
UINT32 uiTimeStamp;
HWFILE hfile;
INT16 sSectorX, sSectorY;
CHAR8 zMapName[ 128 ];
#ifdef JA2TESTVERSION
CHAR8 zReason[256];
#endif
INT8 bSectorZ;
UINT8 ubSectorID;
UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0;
UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures;
gfRestoringEnemySoldiersFromTempFile = TRUE;
//STEP ONE: Set up the temp file to read from.
//Convert the current sector location into a file name
// GetMapFileName( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, zTempName, FALSE );
//add the 'e' for 'Enemy preserved' to the front of the map name
// sprintf( zMapName, "%s\\e_%s", MAPS_DIR, zTempName);
GetMapTempFileName( SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, zMapName, gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
//Count the number of enemies ( elites, regulars, admins and creatures ) that are in the temp file.
if( gbWorldSectorZ )
{
UNDERGROUND_SECTORINFO *pSector;
pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
if( !pSector )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- Couldn't find underground sector info for (%d,%d,%d) KM", gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
#endif
goto FAIL_LOAD;
}
}
else
{
SECTORINFO *pSector;
pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
ubNumElites = pSector->ubNumElites;
ubNumTroops = pSector->ubNumTroops;
ubNumAdmins = pSector->ubNumAdmins;
ubNumCreatures = pSector->ubNumCreatures;
}
if( !( gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
{
// Get the number of enemies form the temp file
CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( &ubStrategicElites, &ubStrategicTroops, &ubStrategicAdmins, &ubStrategicCreatures );
//If any of the counts differ from what is in memory
if( ubStrategicElites != ubNumElites || ubStrategicTroops != ubNumTroops || ubStrategicAdmins != ubNumAdmins || ubStrategicCreatures != ubNumCreatures )
{
//remove the file
RemoveEnemySoldierTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
return( TRUE );
}
}
//reset
ubNumElites = ubNumTroops = ubNumAdmins = ubNumCreatures = 0;
//Open the file for reading
hfile = FileOpen( zMapName, FILE_ACCESS_READ | FILE_OPEN_EXISTING, FALSE );
if( hfile == 0 )
{ //Error opening map modification file
return FALSE;
}
//STEP TWO: determine whether or not we should use this data.
//because it is the demo, it is automatically used.
FileRead( hfile, &sSectorY, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading sSectorY. KM" );
#endif
goto FAIL_LOAD;
}
if( gWorldSectorY != sSectorY )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- sSectorY mismatch. KM" );
#endif
goto FAIL_LOAD;
}
// LoadSoldierInitListLinks( hfile );
NewWayOfLoadingEnemySoldierInitListLinks( hfile );
//STEP THREE: read the data
FileRead( hfile, &sSectorX, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading sSectorX. KM" );
#endif
goto FAIL_LOAD;
}
if( gWorldSectorX != sSectorX )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- sSectorX mismatch. KM" );
#endif
goto FAIL_LOAD;
}
FileRead( hfile, &slots, 4, &uiNumBytesRead );
if( uiNumBytesRead != 4 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading slots. KM" );
#endif
goto FAIL_LOAD;
}
FileRead( hfile, &uiTimeStamp, 4, &uiNumBytesRead );
if( uiNumBytesRead != 4 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading uiTimeStamp. KM" );
#endif
goto FAIL_LOAD;
}
FileRead( hfile, &bSectorZ, 1, &uiNumBytesRead );
if( uiNumBytesRead != 1 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading bSectorZ. KM" );
#endif
goto FAIL_LOAD;
}
if( gbWorldSectorZ != bSectorZ )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- bSectorZ mismatch. KM" );
#endif
goto FAIL_LOAD;
}
if( GetWorldTotalMin() > uiTimeStamp + 300 )
{ //the file has aged. Use the regular method for adding soldiers.
FileClose( hfile );
RemoveEnemySoldierTempFile( sSectorX, sSectorY, bSectorZ );
gfRestoringEnemySoldiersFromTempFile = FALSE;
return TRUE;
}
if( !slots )
{ //no need to restore the enemy's to the map. This means we are restoring a saved game.
gfRestoringEnemySoldiersFromTempFile = FALSE;
FileClose( hfile );
return TRUE;
}
if( slots < 0 || slots >= 64 )
{ //bad IO!
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- illegal slot value of %d. KM", slots );
#endif
goto FAIL_LOAD;
}
//For all the enemy slots (enemy/creature), clear the fPriorityExistance flag. We will use these flags
//to determine which slots have been modified as we load the data into the map pristine soldier init list.
curr = gSoldierInitHead;
while( curr )
{
if( curr->pBasicPlacement->fPriorityExistance )
{
if( curr->pBasicPlacement->bTeam == ENEMY_TEAM || curr->pBasicPlacement->bTeam == CREATURE_TEAM )
{
curr->pBasicPlacement->fPriorityExistance = FALSE;
}
}
curr = curr->next;
}
//get the number of enemies in this sector.
if( bSectorZ )
{
UNDERGROUND_SECTORINFO *pSector;
pSector = FindUnderGroundSector( sSectorX, sSectorY, bSectorZ );
if( !pSector )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- Couldn't find underground sector info for (%d,%d,%d) KM", sSectorX, sSectorY, bSectorZ );
#endif
goto FAIL_LOAD;
}
ubStrategicElites = pSector->ubNumElites;
ubStrategicTroops = pSector->ubNumTroops;
ubStrategicAdmins = pSector->ubNumAdmins;
ubStrategicCreatures = pSector->ubNumCreatures;
}
else
{
SECTORINFO *pSector;
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
ubStrategicCreatures = pSector->ubNumCreatures;
GetNumberOfEnemiesInSector( sSectorX, sSectorY, &ubStrategicAdmins, &ubStrategicTroops, &ubStrategicElites );
}
for( i = 0; i < slots; i++ )
{
if ( !tempDetailedPlacement.Load(hfile, gEnemyPreservedTempFileVersion[SECTOR(sSectorX, sSectorY)], true) )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading tempDetailedPlacment %d. KM", i );
#endif
goto FAIL_LOAD;
}
curr = gSoldierInitHead;
while( curr )
{
if( !curr->pBasicPlacement->fPriorityExistance )
{
if( curr->pBasicPlacement->bTeam == tempDetailedPlacement.bTeam )
{
curr->pBasicPlacement->fPriorityExistance = TRUE;
if( !curr->pDetailedPlacement )
{ //need to upgrade the placement to detailed placement
curr->pBasicPlacement->fDetailedPlacement = TRUE;
curr->pDetailedPlacement = new SOLDIERCREATE_STRUCT(tempDetailedPlacement); //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT );
}
else
{
*curr->pDetailedPlacement = tempDetailedPlacement;
}
curr->pBasicPlacement->fPriorityExistance = TRUE;
curr->pBasicPlacement->ubDirection = curr->pDetailedPlacement->ubDirection;
curr->pBasicPlacement->bOrders = curr->pDetailedPlacement->bOrders;
curr->pBasicPlacement->bAttitude = curr->pDetailedPlacement->bAttitude;
curr->pBasicPlacement->bBodyType = curr->pDetailedPlacement->bBodyType;
curr->pBasicPlacement->fOnRoof = curr->pDetailedPlacement->fOnRoof;
curr->pBasicPlacement->ubSoldierClass = curr->pDetailedPlacement->ubSoldierClass;
curr->pBasicPlacement->ubCivilianGroup = curr->pDetailedPlacement->ubCivilianGroup;
curr->pBasicPlacement->fHasKeys = curr->pDetailedPlacement->fHasKeys;
curr->pBasicPlacement->sStartingGridNo = curr->pDetailedPlacement->sInsertionGridNo;
curr->pBasicPlacement->bPatrolCnt = curr->pDetailedPlacement->bPatrolCnt;
memcpy( curr->pBasicPlacement->sPatrolGrid, curr->pDetailedPlacement->sPatrolGrid,
sizeof( INT16 ) * curr->pBasicPlacement->bPatrolCnt );
//Add preserved placements as long as they don't exceed the actual population.
switch( curr->pBasicPlacement->ubSoldierClass )
{
case SOLDIER_CLASS_ELITE:
ubNumElites++;
if( ubNumElites <= ubStrategicElites )
{
//def: AddPlacementToWorld( curr );
}
break;
case SOLDIER_CLASS_ARMY:
ubNumTroops++;
if( ubNumTroops <= ubStrategicTroops )
{
//def: AddPlacementToWorld( curr );
}
break;
case SOLDIER_CLASS_ADMINISTRATOR:
ubNumAdmins++;
if( ubNumAdmins <= ubStrategicAdmins )
{
//def: AddPlacementToWorld( curr );
}
break;
case SOLDIER_CLASS_CREATURE:
ubNumCreatures++;
if( ubNumCreatures <= ubStrategicCreatures )
{
//def: AddPlacementToWorld( curr );
}
break;
}
break;
}
}
curr = curr->next;
}
}
FileRead( hfile, &ubSectorID, 1, &uiNumBytesRead );
if( uiNumBytesRead != 1 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading ubSectorID. KM" );
#endif
goto FAIL_LOAD;
}
if( ubSectorID != SECTOR( sSectorX, sSectorY ) )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- ubSectorID mismatch. KM" );
#endif
goto FAIL_LOAD;
}
//now add any extra enemies that have arrived since the temp file was made.
if( ubStrategicTroops > ubNumTroops || ubStrategicElites > ubNumElites || ubStrategicAdmins > ubNumAdmins )
{
ubStrategicTroops = ( ubStrategicTroops > ubNumTroops ) ? ubStrategicTroops - ubNumTroops : 0;
ubStrategicElites = ( ubStrategicElites > ubNumElites ) ? ubStrategicElites - ubNumElites : 0;
ubStrategicAdmins = ( ubStrategicAdmins > ubNumAdmins ) ? ubStrategicAdmins - ubNumAdmins : 0;
AddSoldierInitListEnemyDefenceSoldiers( ubStrategicAdmins, ubStrategicTroops, ubStrategicElites );
}
if( ubStrategicCreatures > ubNumCreatures )
{
ubStrategicCreatures; //not sure if this wil ever happen. If so, needs to be handled.
}
//set the number of enemies in the sector
if( bSectorZ )
{
UNDERGROUND_SECTORINFO *pSector;
pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
if( !pSector )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- Couldn't find underground sector info for (%d,%d,%d) KM", sSectorX, sSectorY, bSectorZ );
#endif
goto FAIL_LOAD;
/*
pSector->ubElitesInBattle = ubStrategicElites;
pSector->ubTroopsInBattle = ubStrategicTroops;
pSector->ubAdminsInBattle = ubStrategicAdmins;
pSector->ubCreaturesInBattle = ubStrategicCreatures;
*/
}
}
else
{
SECTORINFO *pSector;
pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
/*
pSector->ubElitesInBattle = ubStrategicElites;
pSector->ubTroopsInBattle = ubStrategicTroops;
pSector->ubAdminsInBattle = ubStrategicAdmins;
pSector->ubCreaturesInBattle = ubStrategicCreatures;
*/
}
//if in battle, what about the ubNumInBAttle
//successful
FileClose( hfile );
return TRUE;
FAIL_LOAD:
//The temp file load failed either because of IO problems related to hacking/logic, or
//various checks failed for hacker validation. If we reach this point, the "error: exit game"
//dialog would appear in a non-testversion.
FileClose( hfile );
#ifdef JA2TESTVERSION
AssertMsg( 0, zReason );
#endif
return FALSE;
}
BOOLEAN NewWayOfLoadingCiviliansFromTempFile()
{
SOLDIERINITNODE *curr, *temp;
SOLDIERCREATE_STRUCT tempDetailedPlacement;
INT32 i;
INT32 slots = 0;
UINT32 uiNumBytesRead;
UINT32 uiTimeStamp;
UINT32 uiTimeSinceLastLoaded;
HWFILE hfile;
INT16 sSectorX, sSectorY;
// CHAR8 zTempName[ 128 ];
CHAR8 zMapName[ 128 ];
#ifdef JA2TESTVERSION
CHAR8 zReason[256];
#endif
INT8 bSectorZ;
UINT8 ubSectorID;
BOOLEAN fDeleted;
// UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures;
gfRestoringCiviliansFromTempFile = TRUE;
//STEP ONE: Set up the temp file to read from.
//Convert the current sector location into a file name
//GetMapFileName( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, zTempName, FALSE );
//add the 'e' for 'Enemy preserved' to the front of the map name
//sprintf( zMapName, "%s\\c_%s", MAPS_DIR, zTempName);
GetMapTempFileName( SF_CIV_PRESERVED_TEMP_FILE_EXISTS, zMapName, gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
//Open the file for reading
hfile = FileOpen( zMapName, FILE_ACCESS_READ | FILE_OPEN_EXISTING, FALSE );
if( hfile == 0 )
{ //Error opening map modification file
return FALSE;
}
//STEP TWO: determine whether or not we should use this data.
//because it is the demo, it is automatically used.
FileRead( hfile, &sSectorY, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- EOF while reading sSectorY. KM" );
#endif
goto FAIL_LOAD;
}
if( gWorldSectorY != sSectorY )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- sSectorY mismatch. KM" );
#endif
goto FAIL_LOAD;
}
//LoadSoldierInitListLinks( hfile );
NewWayOfLoadingCivilianInitListLinks( hfile );
//STEP THREE: read the data
FileRead( hfile, &sSectorX, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- EOF while reading sSectorX. KM" );
#endif
goto FAIL_LOAD;
}
if( gWorldSectorX != sSectorX )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- sSectorX mismatch. KM" );
#endif
goto FAIL_LOAD;
}
FileRead( hfile, &slots, 4, &uiNumBytesRead );
if( uiNumBytesRead != 4 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- EOF while reading slots. KM" );
#endif
goto FAIL_LOAD;
}
FileRead( hfile, &uiTimeStamp, 4, &uiNumBytesRead );
if( uiNumBytesRead != 4 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- EOF while reading uiTimeStamp. KM" );
#endif
goto FAIL_LOAD;
}
uiTimeSinceLastLoaded = GetWorldTotalMin() - uiTimeStamp;
FileRead( hfile, &bSectorZ, 1, &uiNumBytesRead );
if( uiNumBytesRead != 1 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- EOF while reading bSectorZ. KM" );
#endif
goto FAIL_LOAD;
}
if( gbWorldSectorZ != bSectorZ )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- bSectorZ mismatch. KM" );
#endif
goto FAIL_LOAD;
}
if( !slots )
{
//no need to restore the enemy's to the map. This means we are restoring a saved game.
gfRestoringCiviliansFromTempFile = FALSE;
FileClose( hfile );
return TRUE;
}
if( slots < 0 || slots >= 64 )
{
//bad IO!
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- illegal slot value of %d. KM", slots );
#endif
goto FAIL_LOAD;
}
//For all the enemy slots (enemy/creature), clear the fPriorityExistance flag. We will use these flags
//to determine which slots have been modified as we load the data into the map pristine soldier init list.
curr = gSoldierInitHead;
while( curr )
{
if( curr->pBasicPlacement->fPriorityExistance )
{
if( curr->pBasicPlacement->bTeam == CIV_TEAM )
{
curr->pBasicPlacement->fPriorityExistance = FALSE;
}
}
curr = curr->next;
}
for( i = 0; i < slots; i++ )
{
if ( !tempDetailedPlacement.Load(hfile, gCivPreservedTempFileVersion[SECTOR(sSectorX, sSectorY)], true) )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- EOF while reading tempDetailedPlacment %d. KM", i );
#endif
goto FAIL_LOAD;
}
curr = gSoldierInitHead;
while( curr )
{
if( !curr->pBasicPlacement->fPriorityExistance )
{
if( !curr->pDetailedPlacement || curr->pDetailedPlacement && curr->pDetailedPlacement->ubProfile == NO_PROFILE )
{
if( curr->pBasicPlacement->bTeam == tempDetailedPlacement.bTeam )
{
curr->pBasicPlacement->fPriorityExistance = TRUE;
if( !curr->pDetailedPlacement )
{
//need to upgrade the placement to detailed placement
curr->pDetailedPlacement = new SOLDIERCREATE_STRUCT;
}
//now replace the map pristine placement info with the temp map file version..
*curr->pDetailedPlacement = tempDetailedPlacement;
curr->pBasicPlacement->fPriorityExistance = TRUE;
curr->pBasicPlacement->ubDirection = curr->pDetailedPlacement->ubDirection;
curr->pBasicPlacement->bOrders = curr->pDetailedPlacement->bOrders;
curr->pBasicPlacement->bAttitude = curr->pDetailedPlacement->bAttitude;
curr->pBasicPlacement->bBodyType = curr->pDetailedPlacement->bBodyType;
curr->pBasicPlacement->fOnRoof = curr->pDetailedPlacement->fOnRoof;
curr->pBasicPlacement->ubSoldierClass = curr->pDetailedPlacement->ubSoldierClass;
curr->pBasicPlacement->ubCivilianGroup = curr->pDetailedPlacement->ubCivilianGroup;
curr->pBasicPlacement->fHasKeys = curr->pDetailedPlacement->fHasKeys;
curr->pBasicPlacement->sStartingGridNo = curr->pDetailedPlacement->sInsertionGridNo;
curr->pBasicPlacement->bPatrolCnt = curr->pDetailedPlacement->bPatrolCnt;
memcpy( curr->pBasicPlacement->sPatrolGrid, curr->pDetailedPlacement->sPatrolGrid,
sizeof( INT16 ) * curr->pBasicPlacement->bPatrolCnt );
if( curr->pDetailedPlacement->bLife < curr->pDetailedPlacement->bLifeMax )
{ //Add 4 life for every hour that passes.
INT32 iNewLife;
iNewLife = curr->pDetailedPlacement->bLife + uiTimeSinceLastLoaded / 15;
iNewLife = min( curr->pDetailedPlacement->bLifeMax, iNewLife );
curr->pDetailedPlacement->bLife = (INT8)iNewLife;
}
if( curr->pBasicPlacement->bTeam == CIV_TEAM )
{
//def: AddPlacementToWorld( curr );
break;
}
}
}
}
curr = curr->next;
}
}
// now remove any non-priority placement which matches the conditions!
curr = gSoldierInitHead;
fDeleted = FALSE;
while( curr )
{
if( !curr->pBasicPlacement->fPriorityExistance )
{
if( !curr->pDetailedPlacement || curr->pDetailedPlacement && curr->pDetailedPlacement->ubProfile == NO_PROFILE )
{
if( curr->pBasicPlacement->bTeam == tempDetailedPlacement.bTeam )
{
// Save pointer to the next guy in the list
// and after deleting, set the 'curr' to that guy
temp = curr->next;
RemoveSoldierNodeFromInitList( curr );
curr = temp;
fDeleted = TRUE;
}
}
}
if ( fDeleted )
{
// we've already done our pointer update so don't advance the pointer
fDeleted = FALSE;
}
else
{
curr = curr->next;
}
}
FileRead( hfile, &ubSectorID, 1, &uiNumBytesRead );
if( uiNumBytesRead != 1 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- EOF while reading ubSectorID. KM" );
#endif
goto FAIL_LOAD;
}
/*
if( ubSectorID != SECTOR( sSectorX, sSectorY ) )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- ubSectorID mismatch. KM" );
#endif
goto FAIL_LOAD;
}
*/
//successful
FileClose( hfile );
return TRUE;
FAIL_LOAD:
//The temp file load failed either because of IO problems related to hacking/logic, or
//various checks failed for hacker validation. If we reach this point, the "error: exit game"
//dialog would appear in a non-testversion.
FileClose( hfile );
#ifdef JA2TESTVERSION
AssertMsg( 0, zReason );
#endif
return FALSE;
}
//If we are saving a game and we are in the sector, we will need to preserve the links between the
//soldiers and the soldier init list. Otherwise, the temp file will be deleted.
BOOLEAN NewWayOfSavingEnemyAndCivliansToTempFile( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, BOOLEAN fEnemy, BOOLEAN fValidateOnly )
{
SOLDIERINITNODE *curr;
SOLDIERTYPE *pSoldier;
INT32 i;
INT32 slots = 0;
UINT32 uiNumBytesWritten;
UINT32 uiTimeStamp;
HWFILE hfile;
// CHAR8 zTempName[ 128 ];
CHAR8 zMapName[ 128 ];
UINT8 ubSectorID;
UINT8 ubStartID=0;
UINT8 ubEndID = 0;
//if we are saving the enemy info to the enemy temp file
if( fEnemy )
{
ubStartID = ENEMY_TEAM;
ubEndID = CREATURE_TEAM;
}
//else its the civilian team
else
{
ubStartID = CIV_TEAM;
ubEndID = CIV_TEAM;
}
//STEP ONE: Prep the soldiers for saving...
//modify the map's soldier init list to reflect the changes to the members still alive...
for( i = gTacticalStatus.Team[ ubStartID ].bFirstID; i <= gTacticalStatus.Team[ ubEndID ].bLastID; i++ )
{
pSoldier = MercPtrs[ i ];
//make sure the person is active, alive, in the sector, and is not a profiled person
if( pSoldier->bActive /*&& pSoldier->bInSector*/ && pSoldier->stats.bLife && pSoldier->ubProfile == NO_PROFILE )
{ //soldier is valid, so find the matching soldier init list entry for modification.
curr = gSoldierInitHead;
while( curr && curr->pSoldier != pSoldier )
{
curr = curr->next;
}
if( curr && curr->pSoldier == pSoldier && pSoldier->ubProfile == NO_PROFILE )
{ //found a match.
if( !fValidateOnly )
{
if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME) )
{
if( !curr->pDetailedPlacement )
{ //need to upgrade the placement to detailed placement
curr->pBasicPlacement->fDetailedPlacement = TRUE;
curr->pDetailedPlacement = new SOLDIERCREATE_STRUCT; //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT );
}
*curr->pDetailedPlacement = *pSoldier;
//we don't want the player to think that all the enemies start in the exact position when we
//left the map, so randomize the start locations either current position or original position.
if( PreRandom( 2 ) )
{
//use current position, which is already copied over
}
else
{
//use original position
curr->pDetailedPlacement->fOnRoof = curr->pBasicPlacement->fOnRoof;
curr->pDetailedPlacement->sInsertionGridNo = curr->pBasicPlacement->sStartingGridNo;
}
}
}
//DONE, now increment the counter, so we know how many there are.
slots++;
}
}
}
if( !slots )
{
if( fEnemy )
{
//No need to save anything, so return successfully
RemoveEnemySoldierTempFile( sSectorX, sSectorY, bSectorZ );
return TRUE;
}
else
{
//No need to save anything, so return successfully
RemoveCivilianTempFile( sSectorX, sSectorY, bSectorZ );
return( TRUE );
}
}
if( fValidateOnly )
{
return( TRUE );
}
//STEP TWO: Set up the temp file to write to.
//Convert the current sector location into a file name
//GetMapFileName( sSectorX, sSectorY, bSectorZ, zTempName, FALSE );
if( fEnemy )
{
//add the 'e' for 'Enemy preserved' to the front of the map name
//sprintf( zMapName, "%s\\e_%s", MAPS_DIR, zTempName);
GetMapTempFileName( SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, zMapName, sSectorX, sSectorY, bSectorZ );
}
else
{
//add the 'e' for 'Enemy preserved' to the front of the map name
//sprintf( zMapName, "%s\\c_%s", MAPS_DIR, zTempName);
GetMapTempFileName( SF_CIV_PRESERVED_TEMP_FILE_EXISTS, zMapName, sSectorX, sSectorY, bSectorZ );
}
//Open the file for writing, Create it if it doesnt exist
hfile = FileOpen( zMapName, FILE_ACCESS_WRITE | FILE_OPEN_ALWAYS, FALSE );
if( hfile == 0 )
{ //Error opening map modification file
return FALSE;
}
FileWrite( hfile, &sSectorY, 2, &uiNumBytesWritten );
if( uiNumBytesWritten != 2 )
{
goto FAIL_SAVE;
}
//STEP THREE: Save the data
//this works for both civs and enemies
SaveSoldierInitListLinks( hfile );
FileWrite( hfile, &sSectorX, 2, &uiNumBytesWritten );
if( uiNumBytesWritten != 2 )
{
goto FAIL_SAVE;
}
//This check may appear confusing. It is intended to abort if the player is saving the game. It is only
//supposed to preserve the links to the placement list, so when we finally do leave the level with enemies remaining,
//we will need the links that are only added when the map is loaded, and are normally lost when restoring a save.
if( gTacticalStatus.uiFlags & LOADING_SAVED_GAME )
{
slots = 0;
}
FileWrite( hfile, &slots, 4, &uiNumBytesWritten );
if( uiNumBytesWritten != 4 )
{
goto FAIL_SAVE;
}
uiTimeStamp = GetWorldTotalMin();
FileWrite( hfile, &uiTimeStamp, 4, &uiNumBytesWritten );
if( uiNumBytesWritten != 4 )
{
goto FAIL_SAVE;
}
FileWrite( hfile, &bSectorZ, 1, &uiNumBytesWritten );
if( uiNumBytesWritten != 1 )
{
goto FAIL_SAVE;
}
if( gTacticalStatus.uiFlags & LOADING_SAVED_GAME )
{
//if we are saving the game, we don't need to preserve the soldier information, just
//preserve the links to the placement list.
slots = 0;
FileClose( hfile );
if( fEnemy )
{
SetSectorFlag( sSectorX, sSectorY, bSectorZ, SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS );
}
else
{
SetSectorFlag( sSectorX, sSectorY, bSectorZ, SF_CIV_PRESERVED_TEMP_FILE_EXISTS );
}
return TRUE;
}
for( i = gTacticalStatus.Team[ ubStartID ].bFirstID; i <= gTacticalStatus.Team[ ubEndID ].bLastID; i++ )
{
pSoldier = MercPtrs[ i ];
// CJC: note that bInSector is not required; the civ could be offmap!
if( pSoldier->bActive /*&& pSoldier->bInSector*/ && pSoldier->stats.bLife )
{
//soldier is valid, so find the matching soldier init list entry for modification.
curr = gSoldierInitHead;
while( curr && curr->pSoldier != pSoldier )
{
curr = curr->next;
}
if( curr && curr->pSoldier == pSoldier && pSoldier->ubProfile == NO_PROFILE )
{
//found a match.
if ( !curr->pDetailedPlacement->Save(hfile, FALSE) )
{
goto FAIL_SAVE;
}
}
}
}
ubSectorID = SECTOR( sSectorX, sSectorY );
FileWrite( hfile, &ubSectorID, 1, &uiNumBytesWritten );
if( uiNumBytesWritten != 1 )
{
goto FAIL_SAVE;
}
FileClose( hfile );
if( fEnemy )
{
SetSectorFlag( sSectorX, sSectorY, bSectorZ, SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS );
gEnemyPreservedTempFileVersion[SECTOR(sSectorX, sSectorY)] = SAVE_GAME_VERSION;
}
else
{
SetSectorFlag( sSectorX, sSectorY, bSectorZ, SF_CIV_PRESERVED_TEMP_FILE_EXISTS );
gCivPreservedTempFileVersion[SECTOR(sSectorX, sSectorY)] = SAVE_GAME_VERSION;
}
return TRUE;
FAIL_SAVE:
FileClose( hfile );
return FALSE;
}
BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( UINT8 *pubNumElites, UINT8 *pubNumRegulars, UINT8 *pubNumAdmins, UINT8 *pubNumCreatures )
{
// SOLDIERINITNODE *curr;
SOLDIERCREATE_STRUCT tempDetailedPlacement;
INT32 i;
INT32 slots = 0;
UINT32 uiNumBytesRead;
UINT32 uiTimeStamp;
HWFILE hfile;
INT16 sSectorX, sSectorY;
CHAR8 zMapName[ 128 ];
#ifdef JA2TESTVERSION
CHAR8 zReason[256];
#endif
INT8 bSectorZ;
UINT8 ubSectorID;
// UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0;
// UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures;
//make sure the variables are initialized
*pubNumElites = 0;
*pubNumRegulars = 0;
*pubNumAdmins = 0;
*pubNumCreatures = 0;
//STEP ONE: Set up the temp file to read from.
//Convert the current sector location into a file name
// GetMapFileName( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, zTempName, FALSE );
//add the 'e' for 'Enemy preserved' to the front of the map name
// sprintf( zMapName, "%s\\e_%s", MAPS_DIR, zTempName);
GetMapTempFileName( SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, zMapName, gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
//Open the file for reading
hfile = FileOpen( zMapName, FILE_ACCESS_READ | FILE_OPEN_EXISTING, FALSE );
if( hfile == 0 )
{ //Error opening map modification file
return FALSE;
}
//STEP TWO: determine whether or not we should use this data.
//because it is the demo, it is automatically used.
FileRead( hfile, &sSectorY, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- EOF while reading sSectorY. KM" );
#endif
goto FAIL_LOAD;
}
if( gWorldSectorY != sSectorY )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- sSectorY mismatch. KM" );
#endif
goto FAIL_LOAD;
}
// LoadSoldierInitListLinks( hfile );
LookAtButDontProcessEnemySoldierInitListLinks( hfile );
//STEP THREE: read the data
FileRead( hfile, &sSectorX, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- EOF while reading sSectorX. KM" );
#endif
goto FAIL_LOAD;
}
if( gWorldSectorX != sSectorX )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- sSectorX mismatch. KM" );
#endif
goto FAIL_LOAD;
}
FileRead( hfile, &slots, 4, &uiNumBytesRead );
if( uiNumBytesRead != 4 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- EOF while reading slots. KM" );
#endif
goto FAIL_LOAD;
}
FileRead( hfile, &uiTimeStamp, 4, &uiNumBytesRead );
if( uiNumBytesRead != 4 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- EOF while reading uiTimeStamp. KM" );
#endif
goto FAIL_LOAD;
}
FileRead( hfile, &bSectorZ, 1, &uiNumBytesRead );
if( uiNumBytesRead != 1 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- EOF while reading bSectorZ. KM" );
#endif
goto FAIL_LOAD;
}
if( gbWorldSectorZ != bSectorZ )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- bSectorZ mismatch. KM" );
#endif
goto FAIL_LOAD;
}
if( !slots )
{
//no need to restore the enemy's to the map. This means we are restoring a saved game.
FileClose( hfile );
return TRUE;
}
if( slots < 0 || slots >= 64 )
{ //bad IO!
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- illegal slot value of %d. KM", slots );
#endif
goto FAIL_LOAD;
}
/*
//get the number of enemies in this sector.
if( bSectorZ )
{
UNDERGROUND_SECTORINFO *pSector;
pSector = FindUnderGroundSector( sSectorX, sSectorY, bSectorZ );
if( !pSector )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- Couldn't find underground sector info for (%d,%d,%d) KM", sSectorX, sSectorY, bSectorZ );
#endif
goto FAIL_LOAD;
}
ubStrategicElites = pSector->ubNumElites;
ubStrategicTroops = pSector->ubNumTroops;
ubStrategicAdmins = pSector->ubNumAdmins;
ubStrategicCreatures = pSector->ubNumCreatures;
}
else
{
SECTORINFO *pSector;
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
ubStrategicCreatures = pSector->ubNumCreatures;
GetNumberOfEnemiesInSector( sSectorX, sSectorY, &ubStrategicAdmins, &ubStrategicTroops, &ubStrategicElites );
}
*/
for( i = 0; i < slots; i++ )
{
if ( !tempDetailedPlacement.Load(hfile, gEnemyPreservedTempFileVersion[SECTOR( sSectorX,sSectorY)], true) )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- EOF while reading tempDetailedPlacment %d. KM", i );
#endif
goto FAIL_LOAD;
}
//increment the current type of soldier
switch( tempDetailedPlacement.ubSoldierClass )
{
case SOLDIER_CLASS_ELITE:
(*pubNumElites)++;
break;
case SOLDIER_CLASS_ARMY:
(*pubNumRegulars)++;
break;
case SOLDIER_CLASS_ADMINISTRATOR:
(*pubNumAdmins)++;
break;
case SOLDIER_CLASS_CREATURE:
(*pubNumCreatures)++;
break;
}
/*
while( curr )
{
if( !curr->pBasicPlacement->fPriorityExistance )
{
if( curr->pBasicPlacement->bTeam == tempDetailedPlacement.bTeam )
{
curr->pBasicPlacement->fPriorityExistance = TRUE;
if( !curr->pDetailedPlacement )
{ //need to upgrade the placement to detailed placement
curr->pDetailedPlacement = new SOLDIERCREATE_STRUCT;
}
//now replace the map pristine placement info with the temp map file version..
*curr->pDetailedPlacement = tempDetailedPlacement;
curr->pBasicPlacement->fPriorityExistance = TRUE;
curr->pBasicPlacement->ubDirection = curr->pDetailedPlacement->ubDirection;
curr->pBasicPlacement->bOrders = curr->pDetailedPlacement->bOrders;
curr->pBasicPlacement->bAttitude = curr->pDetailedPlacement->bAttitude;
curr->pBasicPlacement->bBodyType = curr->pDetailedPlacement->bBodyType;
curr->pBasicPlacement->fOnRoof = curr->pDetailedPlacement->fOnRoof;
curr->pBasicPlacement->ubSoldierClass = curr->pDetailedPlacement->ubSoldierClass;
curr->pBasicPlacement->ubCivilianGroup = curr->pDetailedPlacement->ubCivilianGroup;
curr->pBasicPlacement->fHasKeys = curr->pDetailedPlacement->fHasKeys;
curr->pBasicPlacement->usStartingGridNo = curr->pDetailedPlacement->sInsertionGridNo;
curr->pBasicPlacement->bPatrolCnt = curr->pDetailedPlacement->bPatrolCnt;
memcpy( curr->pBasicPlacement->sPatrolGrid, curr->pDetailedPlacement->sPatrolGrid,
sizeof( INT16 ) * curr->pBasicPlacement->bPatrolCnt );
//Add preserved placements as long as they don't exceed the actual population.
switch( curr->pBasicPlacement->ubSoldierClass )
{
case SOLDIER_CLASS_ELITE:
ubNumElites++;
if( ubNumElites <= ubStrategicElites )
{
AddPlacementToWorld( curr );
}
break;
case SOLDIER_CLASS_ARMY:
ubNumTroops++;
if( ubNumTroops <= ubStrategicTroops )
{
AddPlacementToWorld( curr );
}
break;
case SOLDIER_CLASS_ADMINISTRATOR:
ubNumAdmins++;
if( ubNumAdmins <= ubStrategicAdmins )
{
AddPlacementToWorld( curr );
}
break;
case SOLDIER_CLASS_CREATURE:
ubNumCreatures++;
if( ubNumCreatures <= ubStrategicCreatures )
{
AddPlacementToWorld( curr );
}
break;
}
break;
}
}
curr = curr->next;
}
*/
}
FileRead( hfile, &ubSectorID, 1, &uiNumBytesRead );
if( uiNumBytesRead != 1 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- EOF while reading ubSectorID. KM" );
#endif
goto FAIL_LOAD;
}
if( ubSectorID != SECTOR( sSectorX, sSectorY ) )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- ubSectorID mismatch. KM" );
#endif
goto FAIL_LOAD;
}
//successful
FileClose( hfile );
return TRUE;
FAIL_LOAD:
//The temp file load failed either because of IO problems related to hacking/logic, or
//various checks failed for hacker validation. If we reach this point, the "error: exit game"
//dialog would appear in a non-testversion.
FileClose( hfile );
#ifdef JA2TESTVERSION
AssertMsg( 0, zReason );
#endif
return FALSE;
}