Files
source/Tactical/Enemy Soldier Save.cpp
T
Overhaul ffc70e9723 Fixed buffer overrun for LUA strings
Made direction variables more consistent as unsigned chars.  Several function prototypes updated for this.
Many memory leaks plugged:  External options, video overlays, laptop file lists, tactical message queue, strategic pathing, autobandage, merc hiring, detailed placements, crate in Drassen, tactical placement
New functions and attributes for soldiers in LUA (still for debugging at best): Soldier.APs (current APs), Soldier.changestance (changes stance, uses game heights)
File catalog ignores .SVN directories (game load speedup)
Fix CTD in mouse regions
JA2 window now refuses to move to negative coords
Checks to prevent DirectX-related infinite loops due to minimizing and task switching
Invading enemies should now appear on the borders even when reinforcements disabled in .ini
Suppression should no longer work on mercs in medium water
Infant/Young creatures use restored spit instead of Molotov
Creatures begin with their 'guns' (spit) 'locked and loaded' (cartridge in chamber)
Further fix to AXP and AlaarDB's weapon ready check:  Now 'firing' is always counted as 'ready'.
Prevent mercs from falling and flying back through obstacles
Check whether battle group is even set before testing its location for battle setup
Burst spread locations now limited to 6, the limit within the soldier struct
Extra burst spread locations zeroed out so that they aren't used unless necessary
Spread code now only shoots at locations in the spread, and will shoot at all 6
Only mercs in the sector where autobandage happens will be made to stand up after it's done
Throwing a grenade at the tail of the plane in Drassen should not result in a CTD
Reset attack busy count when loading a new sector


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1347 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2007-09-11 11:19:03 +00:00

2205 lines
73 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
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;
UINT16 usCheckSum, usFileCheckSum;
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++ )
{
// WDS - Clean up inventory handling
FileRead( hfile, &tempDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT_POD, &uiNumBytesRead );
if( uiNumBytesRead != SIZEOF_SOLDIERCREATE_STRUCT_POD)
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading tempDetailedPlacment %d. KM", i );
#endif
goto FAIL_LOAD;
}
tempDetailedPlacement.CopyOldInventoryToNew();
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 (MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT )) SOLDIERCREATE_STRUCT; //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT );
}
//now replace the map pristine placement info with the temp map file version..
//memcpy( curr->pDetailedPlacement, &tempDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT );
*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 );
FileRead( hfile, &usCheckSum, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading usCheckSum %d. KM", i );
#endif
goto FAIL_LOAD;
}
//verify the checksum equation (anti-hack) -- see save
usFileCheckSum =
curr->pDetailedPlacement->bLife * 7 +
curr->pDetailedPlacement->bLifeMax * 8 -
curr->pDetailedPlacement->bAgility * 2 +
curr->pDetailedPlacement->bDexterity * 1 +
curr->pDetailedPlacement->bExpLevel * 5 -
curr->pDetailedPlacement->bMarksmanship * 9 +
curr->pDetailedPlacement->bMedical * 10 +
curr->pDetailedPlacement->bMechanical * 3 +
curr->pDetailedPlacement->bExplosive * 4 +
curr->pDetailedPlacement->bLeadership * 5 +
curr->pDetailedPlacement->bStrength * 7 +
curr->pDetailedPlacement->bWisdom * 11 +
curr->pDetailedPlacement->bMorale * 7 +
curr->pDetailedPlacement->bAIMorale * 3 -
curr->pDetailedPlacement->bBodyType * 7 +
4 * 6 +
curr->pDetailedPlacement->sSectorX * 7 -
curr->pDetailedPlacement->ubSoldierClass * 4 +
curr->pDetailedPlacement->bTeam * 7 +
curr->pDetailedPlacement->ubDirection * 5 +
curr->pDetailedPlacement->fOnRoof * 17 +
curr->pDetailedPlacement->sInsertionGridNo * 1 +
3;
if( usCheckSum != usFileCheckSum )
{ //Hacker has modified the stats on the enemy placements.
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- checksum for placement %d failed. KM", i );
#endif
goto FAIL_LOAD;
}
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;
}
//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;
UINT16 usCheckSum;
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->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;
// WDS - Clean up inventory handling
curr->pDetailedPlacement = new (MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT )) SOLDIERCREATE_STRUCT; //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT );
//memset( curr->pDetailedPlacement, 0, SIZEOF_SOLDIERCREATE_STRUCT );
curr->pDetailedPlacement->initialize();
}
//Copy over the data of the soldier.
curr->pDetailedPlacement->ubProfile = NO_PROFILE;
curr->pDetailedPlacement->bLife = pSoldier->bLife;
curr->pDetailedPlacement->bLifeMax = pSoldier->bLifeMax;
curr->pDetailedPlacement->bAgility = pSoldier->bAgility;
curr->pDetailedPlacement->bDexterity = pSoldier->bDexterity;
curr->pDetailedPlacement->bExpLevel = pSoldier->bExpLevel;
curr->pDetailedPlacement->bMarksmanship = pSoldier->bMarksmanship;
curr->pDetailedPlacement->bMedical = pSoldier->bMedical;
curr->pDetailedPlacement->bMechanical = pSoldier->bMechanical;
curr->pDetailedPlacement->bExplosive = pSoldier->bExplosive;
curr->pDetailedPlacement->bLeadership = pSoldier->bLeadership;
curr->pDetailedPlacement->bStrength = pSoldier->bStrength;
curr->pDetailedPlacement->bWisdom = pSoldier->bWisdom;
curr->pDetailedPlacement->bAttitude = pSoldier->bAttitude;
curr->pDetailedPlacement->bOrders = pSoldier->bOrders;
curr->pDetailedPlacement->bMorale = pSoldier->bMorale;
curr->pDetailedPlacement->bAIMorale = pSoldier->bAIMorale;
curr->pDetailedPlacement->bBodyType = pSoldier->ubBodyType;
curr->pDetailedPlacement->ubCivilianGroup = pSoldier->ubCivilianGroup;
//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;
}
}
curr->pDetailedPlacement->fHasKeys = pSoldier->bHasKeys;
curr->pDetailedPlacement->sSectorX = pSoldier->sSectorX;
curr->pDetailedPlacement->sSectorY = pSoldier->sSectorY;
curr->pDetailedPlacement->bSectorZ = pSoldier->bSectorZ;
curr->pDetailedPlacement->ubSoldierClass = pSoldier->ubSoldierClass;
curr->pDetailedPlacement->bTeam = pSoldier->bTeam;
curr->pDetailedPlacement->ubDirection = pSoldier->ubDirection;
//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->bLevel;
curr->pDetailedPlacement->sInsertionGridNo = pSoldier->sGridNo;
}
else
{ //use original position
curr->pDetailedPlacement->fOnRoof = curr->pBasicPlacement->fOnRoof;
curr->pDetailedPlacement->sInsertionGridNo = curr->pBasicPlacement->usStartingGridNo;
}
swprintf( curr->pDetailedPlacement->name, pSoldier->name );
//Copy patrol points
curr->pDetailedPlacement->bPatrolCnt = pSoldier->bPatrolCnt;
memcpy( curr->pDetailedPlacement->sPatrolGrid, pSoldier->usPatrolGrid, sizeof( INT16 ) * MAXPATROLGRIDS );
//copy colors for soldier based on the body type.
sprintf( curr->pDetailedPlacement->HeadPal, pSoldier->HeadPal );
sprintf( curr->pDetailedPlacement->VestPal, pSoldier->VestPal );
sprintf( curr->pDetailedPlacement->SkinPal, pSoldier->SkinPal );
sprintf( curr->pDetailedPlacement->PantsPal, pSoldier->PantsPal );
sprintf( curr->pDetailedPlacement->MiscPal, pSoldier->MiscPal );
//copy soldier's inventory
// WDS - Clean up inventory handling
//memcpy( curr->pDetailedPlacement->Inv, pSoldier->inv, sizeof( OBJECTTYPE ) * NUM_INV_SLOTS );
curr->pDetailedPlacement->Inv = pSoldier->inv;
}
//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->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.
// WDS - Clean up inventory handling
curr->pDetailedPlacement->CopyNewInventoryToOld();
FileWrite( hfile, curr->pDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT_POD, &uiNumBytesWritten );
if( uiNumBytesWritten != SIZEOF_SOLDIERCREATE_STRUCT_POD)
{
goto FAIL_SAVE;
}
//insert a checksum equation (anti-hack)
usCheckSum =
curr->pDetailedPlacement->bLife * 7 +
curr->pDetailedPlacement->bLifeMax * 8 -
curr->pDetailedPlacement->bAgility * 2 +
curr->pDetailedPlacement->bDexterity * 1 +
curr->pDetailedPlacement->bExpLevel * 5 -
curr->pDetailedPlacement->bMarksmanship * 9 +
curr->pDetailedPlacement->bMedical * 10 +
curr->pDetailedPlacement->bMechanical * 3 +
curr->pDetailedPlacement->bExplosive * 4 +
curr->pDetailedPlacement->bLeadership * 5 +
curr->pDetailedPlacement->bStrength * 7 +
curr->pDetailedPlacement->bWisdom * 11 +
curr->pDetailedPlacement->bMorale * 7 +
curr->pDetailedPlacement->bAIMorale * 3 -
curr->pDetailedPlacement->bBodyType * 7 +
4 * 6 +
curr->pDetailedPlacement->sSectorX * 7 -
curr->pDetailedPlacement->ubSoldierClass * 4 +
curr->pDetailedPlacement->bTeam * 7 +
curr->pDetailedPlacement->ubDirection * 5 +
curr->pDetailedPlacement->fOnRoof * 17 +
curr->pDetailedPlacement->sInsertionGridNo * 1 +
3;
FileWrite( hfile, &usCheckSum, 2, &uiNumBytesWritten );
if( uiNumBytesWritten != 2 )
{
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;
}
BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile()
{
SOLDIERINITNODE *curr;
SOLDIERCREATE_STRUCT tempDetailedPlacement;
INT32 i;
INT32 slots = 0;
UINT32 uiNumBytesRead;
UINT32 uiTimeStamp;
HWFILE hfile;
INT16 sSectorX, sSectorY;
UINT16 usCheckSum, usFileCheckSum;
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++ )
{
// WDS - Clean up inventory handling
FileRead( hfile, &tempDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT_POD, &uiNumBytesRead );
if( uiNumBytesRead != SIZEOF_SOLDIERCREATE_STRUCT_POD)
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading tempDetailedPlacment %d. KM", i );
#endif
goto FAIL_LOAD;
}
tempDetailedPlacement.CopyOldInventoryToNew();
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->pDetailedPlacement = new (MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT )) SOLDIERCREATE_STRUCT; //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT );
}
//now replace the map pristine placement info with the temp map file version..
//memcpy( curr->pDetailedPlacement, &tempDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT );
*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 );
FileRead( hfile, &usCheckSum, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading usCheckSum %d. KM", i );
#endif
goto FAIL_LOAD;
}
//verify the checksum equation (anti-hack) -- see save
usFileCheckSum =
curr->pDetailedPlacement->bLife * 7 +
curr->pDetailedPlacement->bLifeMax * 8 -
curr->pDetailedPlacement->bAgility * 2 +
curr->pDetailedPlacement->bDexterity * 1 +
curr->pDetailedPlacement->bExpLevel * 5 -
curr->pDetailedPlacement->bMarksmanship * 9 +
curr->pDetailedPlacement->bMedical * 10 +
curr->pDetailedPlacement->bMechanical * 3 +
curr->pDetailedPlacement->bExplosive * 4 +
curr->pDetailedPlacement->bLeadership * 5 +
curr->pDetailedPlacement->bStrength * 7 +
curr->pDetailedPlacement->bWisdom * 11 +
curr->pDetailedPlacement->bMorale * 7 +
curr->pDetailedPlacement->bAIMorale * 3 -
curr->pDetailedPlacement->bBodyType * 7 +
4 * 6 +
curr->pDetailedPlacement->sSectorX * 7 -
curr->pDetailedPlacement->ubSoldierClass * 4 +
curr->pDetailedPlacement->bTeam * 7 +
curr->pDetailedPlacement->ubDirection * 5 +
curr->pDetailedPlacement->fOnRoof * 17 +
curr->pDetailedPlacement->sInsertionGridNo * 1 +
3;
if( usCheckSum != usFileCheckSum )
{ //Hacker has modified the stats on the enemy placements.
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- checksum for placement %d failed. KM", i );
#endif
goto FAIL_LOAD;
}
//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;
UINT16 usCheckSum, usFileCheckSum;
// CHAR8 zTempName[ 128 ];
CHAR8 zMapName[ 128 ];
#ifdef JA2TESTVERSION
CHAR8 zReason[256];
#endif
INT8 bSectorZ;
UINT8 ubSectorID;
UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0;
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++ )
{
// WDS - Clean up inventory handling
FileRead( hfile, &tempDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT_POD, &uiNumBytesRead );
if( uiNumBytesRead != SIZEOF_SOLDIERCREATE_STRUCT_POD)
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- EOF while reading tempDetailedPlacment %d. KM", i );
#endif
goto FAIL_LOAD;
}
tempDetailedPlacement.CopyOldInventoryToNew();
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 (MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT )) SOLDIERCREATE_STRUCT;
}
//now replace the map pristine placement info with the temp map file version..
//memcpy( curr->pDetailedPlacement, &tempDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT );
*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 );
FileRead( hfile, &usCheckSum, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- EOF while reading usCheckSum %d. KM", i );
#endif
goto FAIL_LOAD;
}
//verify the checksum equation (anti-hack) -- see save
usFileCheckSum =
curr->pDetailedPlacement->bLife * 7 +
curr->pDetailedPlacement->bLifeMax * 8 -
curr->pDetailedPlacement->bAgility * 2 +
curr->pDetailedPlacement->bDexterity * 1 +
curr->pDetailedPlacement->bExpLevel * 5 -
curr->pDetailedPlacement->bMarksmanship * 9 +
curr->pDetailedPlacement->bMedical * 10 +
curr->pDetailedPlacement->bMechanical * 3 +
curr->pDetailedPlacement->bExplosive * 4 +
curr->pDetailedPlacement->bLeadership * 5 +
curr->pDetailedPlacement->bStrength * 7 +
curr->pDetailedPlacement->bWisdom * 11 +
curr->pDetailedPlacement->bMorale * 7 +
curr->pDetailedPlacement->bAIMorale * 3 -
curr->pDetailedPlacement->bBodyType * 7 +
4 * 6 +
curr->pDetailedPlacement->sSectorX * 7 -
curr->pDetailedPlacement->ubSoldierClass * 4 +
curr->pDetailedPlacement->bTeam * 7 +
curr->pDetailedPlacement->ubDirection * 5 +
curr->pDetailedPlacement->fOnRoof * 17 +
curr->pDetailedPlacement->sInsertionGridNo * 1 +
3;
if( usCheckSum != usFileCheckSum )
{
//Hacker has modified the stats on the enemy placements.
#ifdef JA2TESTVERSION
sprintf( zReason, "Civilian -- checksum for placement %d failed. KM", i );
#endif
goto FAIL_LOAD;
}
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;
UINT16 usCheckSum;
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 member's 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->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;
// WDS - Clean up inventory handling
curr->pDetailedPlacement = new (MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT )) SOLDIERCREATE_STRUCT;
curr->pDetailedPlacement->initialize();
//memset( curr->pDetailedPlacement, 0, SIZEOF_SOLDIERCREATE_STRUCT );
}
//Copy over the data of the soldier.
curr->pDetailedPlacement->ubProfile = NO_PROFILE;
curr->pDetailedPlacement->bLife = pSoldier->bLife;
curr->pDetailedPlacement->bLifeMax = pSoldier->bLifeMax;
curr->pDetailedPlacement->bAgility = pSoldier->bAgility;
curr->pDetailedPlacement->bDexterity = pSoldier->bDexterity;
curr->pDetailedPlacement->bExpLevel = pSoldier->bExpLevel;
curr->pDetailedPlacement->bMarksmanship = pSoldier->bMarksmanship;
curr->pDetailedPlacement->bMedical = pSoldier->bMedical;
curr->pDetailedPlacement->bMechanical = pSoldier->bMechanical;
curr->pDetailedPlacement->bExplosive = pSoldier->bExplosive;
curr->pDetailedPlacement->bLeadership = pSoldier->bLeadership;
curr->pDetailedPlacement->bStrength = pSoldier->bStrength;
curr->pDetailedPlacement->bWisdom = pSoldier->bWisdom;
curr->pDetailedPlacement->bAttitude = pSoldier->bAttitude;
curr->pDetailedPlacement->bOrders = pSoldier->bOrders;
curr->pDetailedPlacement->bMorale = pSoldier->bMorale;
curr->pDetailedPlacement->bAIMorale = pSoldier->bAIMorale;
curr->pDetailedPlacement->bBodyType = pSoldier->ubBodyType;
curr->pDetailedPlacement->ubCivilianGroup = pSoldier->ubCivilianGroup;
curr->pDetailedPlacement->ubScheduleID = pSoldier->ubScheduleID;
curr->pDetailedPlacement->fHasKeys = pSoldier->bHasKeys;
curr->pDetailedPlacement->sSectorX = pSoldier->sSectorX;
curr->pDetailedPlacement->sSectorY = pSoldier->sSectorY;
curr->pDetailedPlacement->bSectorZ = pSoldier->bSectorZ;
curr->pDetailedPlacement->ubSoldierClass = pSoldier->ubSoldierClass;
curr->pDetailedPlacement->bTeam = pSoldier->bTeam;
curr->pDetailedPlacement->ubDirection = pSoldier->ubDirection;
//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->bLevel;
curr->pDetailedPlacement->sInsertionGridNo = pSoldier->sGridNo;
}
else
{ //use original position
curr->pDetailedPlacement->fOnRoof = curr->pBasicPlacement->fOnRoof;
curr->pDetailedPlacement->sInsertionGridNo = curr->pBasicPlacement->usStartingGridNo;
}
swprintf( curr->pDetailedPlacement->name, pSoldier->name );
//Copy patrol points
curr->pDetailedPlacement->bPatrolCnt = pSoldier->bPatrolCnt;
memcpy( curr->pDetailedPlacement->sPatrolGrid, pSoldier->usPatrolGrid, sizeof( INT16 ) * MAXPATROLGRIDS );
//copy colors for soldier based on the body type.
sprintf( curr->pDetailedPlacement->HeadPal, pSoldier->HeadPal );
sprintf( curr->pDetailedPlacement->VestPal, pSoldier->VestPal );
sprintf( curr->pDetailedPlacement->SkinPal, pSoldier->SkinPal );
sprintf( curr->pDetailedPlacement->PantsPal, pSoldier->PantsPal );
sprintf( curr->pDetailedPlacement->MiscPal, pSoldier->MiscPal );
//copy soldier's inventory
// WDS - Clean up inventory handling
//memcpy( curr->pDetailedPlacement->Inv, pSoldier->inv, sizeof( OBJECTTYPE ) * NUM_INV_SLOTS );
curr->pDetailedPlacement->Inv = pSoldier->inv;
}
}
//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->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.
// WDS - Clean up inventory handling
curr->pDetailedPlacement->CopyNewInventoryToOld();
FileWrite( hfile, curr->pDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT_POD, &uiNumBytesWritten );
if( uiNumBytesWritten != SIZEOF_SOLDIERCREATE_STRUCT_POD )
{
goto FAIL_SAVE;
}
//insert a checksum equation (anti-hack)
usCheckSum =
curr->pDetailedPlacement->bLife * 7 +
curr->pDetailedPlacement->bLifeMax * 8 -
curr->pDetailedPlacement->bAgility * 2 +
curr->pDetailedPlacement->bDexterity * 1 +
curr->pDetailedPlacement->bExpLevel * 5 -
curr->pDetailedPlacement->bMarksmanship * 9 +
curr->pDetailedPlacement->bMedical * 10 +
curr->pDetailedPlacement->bMechanical * 3 +
curr->pDetailedPlacement->bExplosive * 4 +
curr->pDetailedPlacement->bLeadership * 5 +
curr->pDetailedPlacement->bStrength * 7 +
curr->pDetailedPlacement->bWisdom * 11 +
curr->pDetailedPlacement->bMorale * 7 +
curr->pDetailedPlacement->bAIMorale * 3 -
curr->pDetailedPlacement->bBodyType * 7 +
4 * 6 +
curr->pDetailedPlacement->sSectorX * 7 -
curr->pDetailedPlacement->ubSoldierClass * 4 +
curr->pDetailedPlacement->bTeam * 7 +
curr->pDetailedPlacement->ubDirection * 5 +
curr->pDetailedPlacement->fOnRoof * 17 +
curr->pDetailedPlacement->sInsertionGridNo * 1 +
3;
FileWrite( hfile, &usCheckSum, 2, &uiNumBytesWritten );
if( uiNumBytesWritten != 2 )
{
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 );
}
else
{
SetSectorFlag( sSectorX, sSectorY, bSectorZ, SF_CIV_PRESERVED_TEMP_FILE_EXISTS );
}
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;
UINT16 usCheckSum;
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++ )
{
// WDS - Clean up inventory handling
FileRead( hfile, &tempDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT_POD, &uiNumBytesRead );
if( uiNumBytesRead != SIZEOF_SOLDIERCREATE_STRUCT_POD)
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- EOF while reading tempDetailedPlacment %d. KM", i );
#endif
goto FAIL_LOAD;
}
tempDetailedPlacement.CopyOldInventoryToNew();
//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;
}
FileRead( hfile, &usCheckSum, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "Check EnemySoldier -- EOF while reading usCheckSum %d. KM", i );
#endif
goto FAIL_LOAD;
}
/*
while( curr )
{
if( !curr->pBasicPlacement->fPriorityExistance )
{
if( curr->pBasicPlacement->bTeam == tempDetailedPlacement.bTeam )
{
// WDS - Clean up inventory handling
curr->pBasicPlacement->fPriorityExistance = TRUE;
if( !curr->pDetailedPlacement )
{ //need to upgrade the placement to detailed placement
curr->pDetailedPlacement = new (MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT )) SOLDIERCREATE_STRUCT;
}
//now replace the map pristine placement info with the temp map file version..
// memcpy( curr->pDetailedPlacement, &tempDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT );
*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 );
FileRead( hfile, &usCheckSum, 2, &uiNumBytesRead );
if( uiNumBytesRead != 2 )
{
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- EOF while reading usCheckSum %d. KM", i );
#endif
goto FAIL_LOAD;
}
//verify the checksum equation (anti-hack) -- see save
usFileCheckSum =
curr->pDetailedPlacement->bLife * 7 +
curr->pDetailedPlacement->bLifeMax * 8 -
curr->pDetailedPlacement->bAgility * 2 +
curr->pDetailedPlacement->bDexterity * 1 +
curr->pDetailedPlacement->bExpLevel * 5 -
curr->pDetailedPlacement->bMarksmanship * 9 +
curr->pDetailedPlacement->bMedical * 10 +
curr->pDetailedPlacement->bMechanical * 3 +
curr->pDetailedPlacement->bExplosive * 4 +
curr->pDetailedPlacement->bLeadership * 5 +
curr->pDetailedPlacement->bStrength * 7 +
curr->pDetailedPlacement->bWisdom * 11 +
curr->pDetailedPlacement->bMorale * 7 +
curr->pDetailedPlacement->bAIMorale * 3 -
curr->pDetailedPlacement->bBodyType * 7 +
4 * 6 +
curr->pDetailedPlacement->sSectorX * 7 -
curr->pDetailedPlacement->ubSoldierClass * 4 +
curr->pDetailedPlacement->bTeam * 7 +
curr->pDetailedPlacement->ubDirection * 5 +
curr->pDetailedPlacement->fOnRoof * 17 +
curr->pDetailedPlacement->sInsertionGridNo * 1 +
3;
if( usCheckSum != usFileCheckSum )
{ //Hacker has modified the stats on the enemy placements.
#ifdef JA2TESTVERSION
sprintf( zReason, "EnemySoldier -- checksum for placement %d failed. KM", i );
#endif
goto FAIL_LOAD;
}
//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;
}