mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Added missing #includes Added LUA scripting and console Changed the way tracers are visualized, so they work more like real tracers instead of a light fountain Fixed signedness of many grid variables used in GetMouseMapPos calls Fixed enemy weapon choosing: Sometimes a mortar is chosen but later rejected, but the grenade class was not reset. Caused assertion failure Added checks so enemies don't try to chuck RPG grenades with their hands Now possible to shoot a someone in the head if he's in water Fixed InitSightArrays to also clear soldier interrupt duel points. This was causing an assertion failure elsewhere in the code because the interrupt list still had soldiers on it sometimes when this function was called. Soldiers are much less willing to forfeit their turn over an attempt to use more APs than they have Removed early setting of muzzle flash. This would allow enemies to get an interrupt before you even fired. Fixed item dropping by AI. If AI tried to drop something while standing it would cause deadlock Change to greatly speed up closing the sector inventory window in an unloaded sector Added conditional compile flag to always give robot weapon ready advantage, even for 360 degree sighting Check builddefines.h for the conditional flags. Of greatest interest might be LUA_CONSOLE. This will cause the game to bring up a command console when run. However this console is severely lacking in many areas. If anybody knows of an open-source terminal/console that could be used instead, it would be appreciated. The existing console does bad things when you try to close it, and since it counts as a separate app, it pauses the game while it has focus. LUA scripting is very limited, basically just proof of concept. There is one global variable, the Soldiers array. An array index gives you the soldier in that slot in the currently loaded sector. The soldier has a few things that can be accessed: name (short name); fullname (long name); grid (current grid #, can be changed); walkto(grid) (function to walk to another grid); runto(grid) (function to run to another grid) git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@924 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2179 lines
71 KiB
C++
2179 lines
71 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 );
|
|
|
|
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++ )
|
|
{
|
|
FileRead( hfile, &tempDetailedPlacement, sizeof( SOLDIERCREATE_STRUCT ), &uiNumBytesRead );
|
|
if( uiNumBytesRead != sizeof( SOLDIERCREATE_STRUCT ) )
|
|
{
|
|
#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->pDetailedPlacement = (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->pBasicPlacement->fPriorityExistance = TRUE;
|
|
curr->pBasicPlacement->bDirection = curr->pDetailedPlacement->bDirection;
|
|
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->bDirection * 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;
|
|
curr->pDetailedPlacement = (SOLDIERCREATE_STRUCT*)MemAlloc( sizeof( SOLDIERCREATE_STRUCT ) );
|
|
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;
|
|
|
|
//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->bDirection = pSoldier->bDirection;
|
|
|
|
//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
|
|
memcpy( curr->pDetailedPlacement->Inv, pSoldier->inv, sizeof( OBJECTTYPE ) * NUM_INV_SLOTS );
|
|
}
|
|
|
|
//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.
|
|
FileWrite( hfile, curr->pDetailedPlacement, sizeof( SOLDIERCREATE_STRUCT ), &uiNumBytesWritten );
|
|
if( uiNumBytesWritten != sizeof( SOLDIERCREATE_STRUCT ) )
|
|
{
|
|
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->bDirection * 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++ )
|
|
{
|
|
FileRead( hfile, &tempDetailedPlacement, sizeof( SOLDIERCREATE_STRUCT ), &uiNumBytesRead );
|
|
if( uiNumBytesRead != sizeof( SOLDIERCREATE_STRUCT ) )
|
|
{
|
|
#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->pDetailedPlacement = (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->pBasicPlacement->fPriorityExistance = TRUE;
|
|
curr->pBasicPlacement->bDirection = curr->pDetailedPlacement->bDirection;
|
|
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->bDirection * 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++ )
|
|
{
|
|
FileRead( hfile, &tempDetailedPlacement, sizeof( SOLDIERCREATE_STRUCT ), &uiNumBytesRead );
|
|
if( uiNumBytesRead != sizeof( SOLDIERCREATE_STRUCT ) )
|
|
{
|
|
#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 = (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->pBasicPlacement->fPriorityExistance = TRUE;
|
|
curr->pBasicPlacement->bDirection = curr->pDetailedPlacement->bDirection;
|
|
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->bDirection * 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;
|
|
curr->pDetailedPlacement = (SOLDIERCREATE_STRUCT*)MemAlloc( sizeof( SOLDIERCREATE_STRUCT ) );
|
|
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->bDirection = pSoldier->bDirection;
|
|
|
|
//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
|
|
memcpy( curr->pDetailedPlacement->Inv, pSoldier->inv, sizeof( OBJECTTYPE ) * NUM_INV_SLOTS );
|
|
}
|
|
}
|
|
|
|
//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.
|
|
FileWrite( hfile, curr->pDetailedPlacement, sizeof( SOLDIERCREATE_STRUCT ), &uiNumBytesWritten );
|
|
if( uiNumBytesWritten != sizeof( SOLDIERCREATE_STRUCT ) )
|
|
{
|
|
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->bDirection * 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++ )
|
|
{
|
|
FileRead( hfile, &tempDetailedPlacement, sizeof( SOLDIERCREATE_STRUCT ), &uiNumBytesRead );
|
|
if( uiNumBytesRead != sizeof( SOLDIERCREATE_STRUCT ) )
|
|
{
|
|
#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;
|
|
}
|
|
|
|
|
|
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 )
|
|
{
|
|
curr->pBasicPlacement->fPriorityExistance = TRUE;
|
|
if( !curr->pDetailedPlacement )
|
|
{ //need to upgrade the placement to detailed placement
|
|
curr->pDetailedPlacement = (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->pBasicPlacement->fPriorityExistance = TRUE;
|
|
curr->pBasicPlacement->bDirection = curr->pDetailedPlacement->bDirection;
|
|
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->bDirection * 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;
|
|
}
|
|
|
|
|
|
|