mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Adds timing logs to savegame function, similar to how we already had in loading a save file. Uses a global struct for unloaded sectors' inventory instead of using map item temp files every time unloaded inventory is accessed. From timing loading and saving functions with a save that has dozens of sectors with hundreds of items each, saving is a little bit slower than before, because map item temp files have to be written to disk just before the save, when that wasn't the case before (from ~0.3 s -> ~0.5s). It is offset by a decrease in loading a game (from ~1.1s -> 0.745s), once an older save is saved at least once. Any unloaded sector inventory access during gameplay is considerably faster and for example the autoresolve lag when militia is using sector equipment is completely gone for me. Preserves save game compatibility git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@9277 3b4a5df2-a311-0410-b5c6-a8a6f20db521
3214 lines
96 KiB
C++
3214 lines
96 KiB
C++
#ifdef PRECOMPILEDHEADERS
|
|
#include "Tactical All.h"
|
|
#include "Enemy Soldier Save.h"
|
|
#else
|
|
#include "Types.h"
|
|
#include "MemMan.h"
|
|
#include "message.h"
|
|
#include "Items.h"
|
|
#include "Handle Items.h"
|
|
#include "StrategicMap.h"
|
|
#include "Tactical Save.h"
|
|
#include <stdio.h>
|
|
#include "Campaign Types.h"
|
|
#include "SaveLoadGame.h"
|
|
#include "WorldDef.h"
|
|
#include "rotting corpses.h"
|
|
#include "OverHead.h"
|
|
#include "Keys.h"
|
|
#include "Soldier Create.h"
|
|
#include "Soldier Profile.h"
|
|
#include "Isometric Utils.h"
|
|
#include "Soldier Add.h"
|
|
#include "Npc.h"
|
|
#include "Ai.h"
|
|
#include "Game Clock.h"
|
|
#include "Animation Control.h"
|
|
#include "Map Information.h"
|
|
#include "SaveLoadMap.h"
|
|
#include "debug.h"
|
|
#include "Random.h"
|
|
#include "quests.h"
|
|
#include "Animated ProgressBar.h"
|
|
#include "Text.h"
|
|
#include "meanwhile.h"
|
|
#include "Enemy Soldier Save.h"
|
|
#include "SmokeEffects.h"
|
|
#include "LightEffects.h"
|
|
#include "PATHAI.H"
|
|
#include "GameVersion.h"
|
|
#include "strategic.h"
|
|
#include "Map Screen Interface Map.h"
|
|
#include "Strategic Status.h"
|
|
#include "Soldier macros.h"
|
|
#include "sgp.h"
|
|
#include "MessageBoxScreen.h"
|
|
#include "screenids.h"
|
|
#include "Queen Command.h"
|
|
#include "Map Screen Interface Map Inventory.h"
|
|
#endif
|
|
#include "Animation Control.h"
|
|
#include <vfs/Core/vfs.h>
|
|
BOOLEAN gfWasInMeanwhile = FALSE;
|
|
|
|
|
|
//forward declarations of common classes to eliminate includes
|
|
class OBJECTTYPE;
|
|
class SOLDIERTYPE;
|
|
extern WorldItems gAllWorldItems;
|
|
void SaveWorldItemsToTempFiles();
|
|
void LoadWorldItemsFromTempFiles(INT16 sMapX, INT16 sMapY, INT8 bMapZ);
|
|
void ClearAllWorldItems(void);
|
|
bool LoadWorldItemsFromSavedGame(HWFILE hFile, INT16 x, INT16 y, INT8 z);
|
|
bool SaveWorldItemsToSavedGame(HWFILE hFile, INT16 x, INT16 y, INT8 z);
|
|
void PruneWorldItems(void);
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// Global Defines
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
|
|
//dnl ch46 031009
|
|
// It's used for save info from the NPCQuoteInfo class that can change.
|
|
class TempNPCQuoteInfoSave
|
|
{
|
|
public:
|
|
UINT16 usFlags;
|
|
INT16 sRequiredItem;
|
|
INT32 sRequiredGridNo;
|
|
INT32 usGoToGridNo;
|
|
};
|
|
|
|
#define NPC_TEMP_QUOTE_FILE "Temp\\NpcQuote.tmp"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// Global Variables
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
|
|
extern NPCQuoteInfo * gpNPCQuoteInfoArray[NUM_PROFILES];
|
|
|
|
extern UINT32 guiJA2EncryptionSet;
|
|
extern UINT8 gubEncryptionArray1[ BASE_NUMBER_OF_ROTATION_ARRAYS * 3 ][ NEW_ROTATION_ARRAY_SIZE ];
|
|
extern UINT8 gubEncryptionArray2[ BASE_NUMBER_OF_ROTATION_ARRAYS * 3 ][ NEW_ROTATION_ARRAY_SIZE ];
|
|
extern UINT8 gubEncryptionArray3[ BASE_NUMBER_OF_ROTATION_ARRAYS * 3 ][ NEW_ROTATION_ARRAY_SIZE ];
|
|
extern UINT8 gubEncryptionArray4[ BASE_NUMBER_OF_ROTATION_ARRAYS * 3 ][ NEW_ROTATION_ARRAY_SIZE ];
|
|
|
|
INT32 giErrorMessageBox = 0;
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// Function Prototypes
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
void TempFileLoadErrorMessageReturnCallback( UINT8 ubRetVal );
|
|
|
|
BOOLEAN SaveWorldItemsToTempItemFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ, UINT32 uiNumberOfItems, WORLDITEM *pData );
|
|
BOOLEAN RetrieveTempFileFromSavedGame( HWFILE hFile, UINT32 uiType, INT16 sMapX, INT16 sMapY, INT8 bMapZ );
|
|
|
|
BOOLEAN AddTempFileToSavedGame( HWFILE hFile, UINT32 uiType, INT16 sMapX, INT16 sMapY, INT8 bMapZ );
|
|
|
|
|
|
BOOLEAN SaveRottingCorpsesToTempCorpseFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ, std::vector<ROTTING_CORPSE_DEFINITION> aCorpseDefVector );
|
|
BOOLEAN LoadRottingCorpsesFromTempCorpseFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ );
|
|
|
|
void LoadNPCInformationFromProfileStruct();
|
|
void SaveNPCInformationToProfileStruct( );
|
|
|
|
BOOLEAN DoesTempFileExistsForMap( UINT32 uiType, INT16 sMapX, INT16 sMapY, INT8 bMapZ );
|
|
|
|
|
|
INT16 GetSoldierIDFromAnyMercID(UINT8 ubMercID);
|
|
|
|
|
|
BOOLEAN SetUnderGroundSectorFlag( INT16 sSectorX, INT16 sSectorY, UINT8 ubSectorZ, UINT32 uiFlagToSet );
|
|
BOOLEAN GetUnderGroundSectorFlagStatus( INT16 sSectorX, INT16 sSectorY, UINT8 ubSectorZ, UINT32 uiFlagToCheck );
|
|
|
|
BOOLEAN LoadAndAddWorldItemsFromTempFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ );
|
|
|
|
BOOLEAN InitTempNpcQuoteInfoForNPCFromTempFile();
|
|
BOOLEAN SaveTempNpcQuoteInfoForNPCToTempFile( UINT8 ubNpcId );
|
|
BOOLEAN LoadTempNpcQuoteInfoForNPCFromTempFile( UINT8 ubNpcId );
|
|
UINT32 GetLastTimePlayerWasInSector();
|
|
UINT32 GetLastTimePlayerWasInSector(INT16 sMapX, INT16 sMapY, INT8 sMapZ); // Flugente: get time for another sector
|
|
void SetLastTimePlayerWasInSector();
|
|
void SetLastTimePlayerWasInSector(INT16 sMapX, INT16 sMapY, INT8 sMapZ); // Flugente: set last time sector was visited
|
|
|
|
|
|
extern void InitLoadedWorld( );
|
|
extern void ReduceAmmoDroppedByNonPlayerSoldiers( SOLDIERTYPE *pSoldier, INT32 iInvSlot );
|
|
|
|
extern void StripEnemyDetailedPlacementsIfSectorWasPlayerLiberated();
|
|
|
|
#ifdef JA2BETAVERSION
|
|
extern BOOLEAN ValidateSoldierInitLinks( UINT8 ubCode );
|
|
#endif
|
|
|
|
|
|
UINT32 UpdateLoadedSectorsItemInventory( INT16 sMapX, INT16 sMapY, INT8 bMapZ, UINT32 uiNumberOfItems );
|
|
|
|
//ppp
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// Functions
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
// SaveMapTempFilesToSavedGameFile() Looks for and opens all Map Modification files. It add each mod file to the save game file.
|
|
BOOLEAN SaveMapTempFilesToSavedGameFile( HWFILE hFile )
|
|
{
|
|
UNDERGROUND_SECTORINFO *TempNode = gpUndergroundSectorInfoHead;
|
|
INT16 sMapX;
|
|
INT16 sMapY;
|
|
|
|
// Save all the global world items to temp files
|
|
SaveWorldItemsToTempFiles();
|
|
|
|
//
|
|
//Loop though all the array elements to see if there is a data file to be saved
|
|
//
|
|
|
|
// Lesh: try to fix save/reload havok
|
|
//First look through the above ground sectors
|
|
for( sMapY=1; sMapY<=16; sMapY++ )
|
|
{
|
|
for( sMapX=1; sMapX<=16; sMapX++ )
|
|
{
|
|
//Save the Temp Item Files to the saved game file
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_ITEM_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_ITEM_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
// Save the Rotting Corpse Temp file to the saved game file
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_ROTTING_CORPSE_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_ROTTING_CORPSE_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Save the Map Modifications Temp file to the saved game file
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_MAP_MODIFICATIONS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_MAP_MODIFICATIONS_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
//Save the Door Table temp file to the saved game file
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_DOOR_TABLE_TEMP_FILES_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_DOOR_TABLE_TEMP_FILES_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
//Save the revealed status temp file to the saved game file
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_REVEALED_STATUS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_REVEALED_STATUS_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
//Save the door status temp file to the saved game file
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_DOOR_STATUS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_DOOR_STATUS_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_CIV_PRESERVED_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_CIV_PRESERVED_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_LIGHTING_EFFECTS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_LIGHTING_EFFECTS_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//if any other file is to be saved
|
|
}
|
|
}
|
|
|
|
|
|
//then look throught all the underground sectors
|
|
while( TempNode )
|
|
{
|
|
if( TempNode->uiFlags & SF_ITEM_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_ITEM_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_ROTTING_CORPSE_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_ROTTING_CORPSE_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
// Save the Map Modifications Temp file to the saved game file
|
|
if( TempNode->uiFlags & SF_MAP_MODIFICATIONS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_MAP_MODIFICATIONS_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//Save the door table to the saved game file
|
|
if( TempNode->uiFlags & SF_DOOR_TABLE_TEMP_FILES_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_DOOR_TABLE_TEMP_FILES_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
//Save the revealed status temp file to the saved game file
|
|
if( TempNode->uiFlags & SF_REVEALED_STATUS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_REVEALED_STATUS_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
//Save the door status temp file to the saved game file
|
|
if( TempNode->uiFlags & SF_DOOR_STATUS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_DOOR_STATUS_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_CIV_PRESERVED_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_CIV_PRESERVED_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_LIGHTING_EFFECTS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !AddTempFileToSavedGame( hFile, SF_LIGHTING_EFFECTS_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
//ttt
|
|
|
|
|
|
TempNode = TempNode->next;
|
|
}
|
|
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
extern int gEnemyPreservedTempFileVersion[256];
|
|
extern int gCivPreservedTempFileVersion[256];
|
|
|
|
// LoadMapTempFilesFromSavedGameFile() loads all the temp files from the saved game file and writes them into the temp directory
|
|
BOOLEAN LoadMapTempFilesFromSavedGameFile( HWFILE hFile )
|
|
{
|
|
UNDERGROUND_SECTORINFO *TempNode = gpUndergroundSectorInfoHead;
|
|
UINT32 uiPercentage;
|
|
UINT32 iCounter = 0;
|
|
|
|
// HACK FOR GABBY
|
|
if ( guiCurrentSaveGameVersion < 81 && (gTacticalStatus.uiFlags & LOADING_SAVED_GAME) )
|
|
{
|
|
if ( gMercProfiles[ GABBY ].bMercStatus != MERC_IS_DEAD )
|
|
{
|
|
// turn off alternate flags for the sectors he could be in
|
|
// randomly place him in one of the two possible sectors
|
|
SectorInfo[ SECTOR( 14, MAP_ROW_L ) ].uiFlags &= ~SF_USE_ALTERNATE_MAP;
|
|
SectorInfo[ SECTOR( 8, MAP_ROW_L ) ].uiFlags &= ~SF_USE_ALTERNATE_MAP;
|
|
|
|
if ( Random( 2 ) )
|
|
{
|
|
SectorInfo[ SECTOR( 11, MAP_ROW_H ) ].uiFlags |= SF_USE_ALTERNATE_MAP;
|
|
gMercProfiles[ GABBY ].sSectorX = 11;
|
|
gMercProfiles[ GABBY ].sSectorY = MAP_ROW_H;
|
|
}
|
|
else
|
|
{
|
|
SectorInfo[ SECTOR( 4, MAP_ROW_I ) ].uiFlags |= SF_USE_ALTERNATE_MAP;
|
|
gMercProfiles[ GABBY ].sSectorX = 4;
|
|
gMercProfiles[ GABBY ].sSectorY = MAP_ROW_I;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Preparation for loading item temp files
|
|
ClearAllWorldItems();
|
|
//
|
|
//Loop though all the array elements to see if there is a data file to be loaded
|
|
//
|
|
|
|
//First look through the above ground sectors
|
|
for ( INT16 sMapY = 1; sMapY < MAP_WORLD_Y - 1; ++sMapY )
|
|
{
|
|
for ( INT16 sMapX = 1; sMapX < MAP_WORLD_X - 1; ++sMapX )
|
|
{
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_ITEM_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_ITEM_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
// Load world items from map temp files into global struct
|
|
LoadWorldItemsFromTempFiles(sMapX, sMapY, 0);
|
|
}
|
|
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_ROTTING_CORPSE_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_ROTTING_CORPSE_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_MAP_MODIFICATIONS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_MAP_MODIFICATIONS_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_DOOR_TABLE_TEMP_FILES_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_DOOR_TABLE_TEMP_FILES_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
//Get the revealed status temp file From the saved game file
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_REVEALED_STATUS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_REVEALED_STATUS_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
//Get the revealed status temp file From the saved game file
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_DOOR_STATUS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_DOOR_STATUS_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
gEnemyPreservedTempFileVersion[SECTOR( sMapX,sMapY)] = guiCurrentSaveGameVersion;
|
|
}
|
|
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_CIV_PRESERVED_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_CIV_PRESERVED_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
|
|
if ( guiCurrentSaveGameVersion < 78 && (gTacticalStatus.uiFlags & LOADING_SAVED_GAME) )
|
|
{
|
|
CHAR8 pMapName[ 128 ];
|
|
|
|
// KILL IT!!! KILL KIT!!!! IT IS CORRUPTED!!!
|
|
GetMapTempFileName( SF_CIV_PRESERVED_TEMP_FILE_EXISTS, pMapName, sMapX, sMapY, 0 );
|
|
FileDelete( pMapName );
|
|
|
|
// turn off the flag
|
|
SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags &= (~SF_CIV_PRESERVED_TEMP_FILE_EXISTS);
|
|
}
|
|
|
|
gCivPreservedTempFileVersion[SECTOR( sMapX,sMapY)] = guiCurrentSaveGameVersion;
|
|
}
|
|
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & SF_LIGHTING_EFFECTS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_LIGHTING_EFFECTS_TEMP_FILE_EXISTS, sMapX, sMapY, 0 ) )
|
|
return FALSE;
|
|
}
|
|
|
|
//if any other file is to be saved
|
|
|
|
++iCounter;
|
|
|
|
//update the progress bar
|
|
uiPercentage = (iCounter * 100) / (255);
|
|
|
|
RenderProgressBar( 0, uiPercentage );
|
|
}
|
|
}
|
|
|
|
//then look throught all the underground sectors
|
|
while( TempNode )
|
|
{
|
|
if( TempNode->uiFlags & SF_ITEM_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_ITEM_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
|
|
//sync up the temp file data to the sector structure data
|
|
LoadWorldItemsFromTempFiles(TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ);
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_ROTTING_CORPSE_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_ROTTING_CORPSE_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_MAP_MODIFICATIONS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_MAP_MODIFICATIONS_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_DOOR_TABLE_TEMP_FILES_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_DOOR_TABLE_TEMP_FILES_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
//Get the revealed status temp file From the saved game file
|
|
if( TempNode->uiFlags & SF_REVEALED_STATUS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_REVEALED_STATUS_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
//Get the revealed status temp file From the saved game file
|
|
if( TempNode->uiFlags & SF_DOOR_STATUS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_DOOR_STATUS_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_CIV_PRESERVED_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_CIV_PRESERVED_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
|
|
if ( guiCurrentSaveGameVersion < 78 && (gTacticalStatus.uiFlags & LOADING_SAVED_GAME) )
|
|
{
|
|
CHAR8 pMapName[ 128 ];
|
|
|
|
// KILL IT!!! KILL KIT!!!! IT IS CORRUPTED!!!
|
|
GetMapTempFileName( SF_CIV_PRESERVED_TEMP_FILE_EXISTS, pMapName, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ );
|
|
FileDelete( pMapName );
|
|
|
|
// turn off the flag
|
|
TempNode->uiFlags &= (~SF_CIV_PRESERVED_TEMP_FILE_EXISTS);
|
|
}
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
if( TempNode->uiFlags & SF_LIGHTING_EFFECTS_TEMP_FILE_EXISTS )
|
|
{
|
|
if ( !RetrieveTempFileFromSavedGame( hFile, SF_LIGHTING_EFFECTS_TEMP_FILE_EXISTS, TempNode->ubSectorX, TempNode->ubSectorY, TempNode->ubSectorZ ) )
|
|
return FALSE;
|
|
}
|
|
|
|
TempNode = TempNode->next;
|
|
}
|
|
//ttt
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
BOOLEAN UpdateENEMYTempFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
|
{
|
|
NewWayOfSavingEnemyAndCivliansToTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, TRUE, TRUE );
|
|
NewWayOfSavingEnemyAndCivliansToTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, FALSE, TRUE );
|
|
LoadWorldItemsFromTempItemFile( sMapX, sMapY, bMapZ, pTotalSectorList );
|
|
int backup = guiCurrentSaveGameVersion;
|
|
guiCurrentSaveGameVersion = SAVE_GAME_VERSION;
|
|
SaveWorldItemsToTempItemFile( sMapX, sMapY, bMapZ, uiTotalNumberOfItems, pTotalSectorList);
|
|
guiCurrentSaveGameVersion = backup;
|
|
}
|
|
|
|
|
|
BOOLEAN UpdateCIVTempFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
|
{
|
|
LoadWorldItemsFromTempItemFile( sMapX, sMapY, bMapZ, pTotalSectorList );
|
|
int backup = guiCurrentSaveGameVersion;
|
|
guiCurrentSaveGameVersion = SAVE_GAME_VERSION;
|
|
SaveWorldItemsToTempItemFile( sMapX, sMapY, bMapZ, uiTotalNumberOfItems, pTotalSectorList);
|
|
guiCurrentSaveGameVersion = backup;
|
|
return TRUE;
|
|
}
|
|
*/
|
|
|
|
BOOLEAN SaveWorldItemsToTempItemFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ, UINT32 uiNumberOfItems, std::vector<WORLDITEM>& pData)
|
|
{
|
|
HWFILE hFile;
|
|
UINT32 uiNumBytesWritten=0;
|
|
CHAR8 zMapName[ 128 ];
|
|
|
|
GetMapTempFileName( SF_ITEM_TEMP_FILE_EXISTS, zMapName, sMapX, sMapY, bMapZ );
|
|
|
|
//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 );
|
|
}
|
|
|
|
//Save the size of the ITem table
|
|
FileWrite( hFile, &uiNumberOfItems, sizeof( UINT32 ), &uiNumBytesWritten );
|
|
if( uiNumBytesWritten != sizeof( UINT32 ) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
//if there are items to save..
|
|
for (unsigned int x = 0; x < uiNumberOfItems; ++x)
|
|
{
|
|
//Save the ITem array
|
|
if ( !pData[x].Save(hFile, FALSE) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
FileClose( hFile );
|
|
|
|
SetSectorFlag( sMapX, sMapY, bMapZ, SF_ITEM_TEMP_FILE_EXISTS );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN LoadWorldItemsFromTempItemFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ, std::vector<WORLDITEM>& pData )//dnl ch75 271013
|
|
{
|
|
UINT32 uiNumBytesRead=0;
|
|
HWFILE hFile;
|
|
CHAR8 zMapName[ 128 ];
|
|
UINT32 uiNumberOfItems=0;
|
|
|
|
GetMapTempFileName( SF_ITEM_TEMP_FILE_EXISTS, zMapName, sMapX, sMapY, bMapZ );
|
|
|
|
|
|
//Check to see if the file exists
|
|
if( !FileExists( zMapName ) )
|
|
{
|
|
//If the file doesnt exists, its no problem.
|
|
return( TRUE );
|
|
}
|
|
|
|
//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 );
|
|
}
|
|
|
|
|
|
// Load the size of the World ITem table
|
|
FileRead( hFile, &uiNumberOfItems, sizeof( UINT32 ), &uiNumBytesRead );
|
|
if( uiNumBytesRead != sizeof( UINT32 ) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
|
|
// Load the World ITem table
|
|
for (unsigned int x = 0; x < uiNumberOfItems; ++x)
|
|
{
|
|
if ( !pData[x].Load(hFile) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
FileClose( hFile );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN GetNumberOfWorldItemsFromTempItemFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ, UINT32 *pSizeOfData, BOOLEAN fIfEmptyCreate )
|
|
{
|
|
UINT32 uiNumBytesRead=0;
|
|
HWFILE hFile;
|
|
CHAR8 zMapName[ 128 ];
|
|
UINT32 uiNumberOfItems=0;
|
|
|
|
GetMapTempFileName( SF_ITEM_TEMP_FILE_EXISTS, zMapName, sMapX, sMapY, bMapZ );
|
|
|
|
|
|
//Check if the file DOESNT exists
|
|
if( !FileExistsNoDB( zMapName ) )
|
|
{
|
|
if( fIfEmptyCreate )
|
|
{
|
|
//ADB: I don't know why we are initing 10 WORLDITEMS then saving them, but that's what the code was.
|
|
WORLDITEM TempWorldItems[ 10 ];
|
|
uiNumberOfItems = 10;
|
|
UINT32 uiNumBytesWritten=0;
|
|
|
|
//If the file doesnt exists, create a file that has an initial amount of Items
|
|
hFile = FileOpen( zMapName, FILE_ACCESS_WRITE | FILE_OPEN_ALWAYS, FALSE );
|
|
if( hFile == 0 )
|
|
{
|
|
//Error opening item modification file
|
|
return( FALSE );
|
|
}
|
|
|
|
//write the the number of item in the maps item file
|
|
FileWrite( hFile, &uiNumberOfItems, sizeof( UINT32 ), &uiNumBytesWritten );
|
|
if( uiNumBytesWritten != sizeof( UINT32 ) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
|
|
//write the the number of item in the maps item file
|
|
for (unsigned int x = 0; x < uiNumberOfItems; ++x)
|
|
{
|
|
if ( !TempWorldItems[x].Save(hFile, FALSE) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
//Close the file
|
|
FileClose( hFile );
|
|
}
|
|
else
|
|
{
|
|
// the file doesnt exist
|
|
*pSizeOfData = 0;
|
|
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
|
|
//Open the file for reading, if it exists
|
|
hFile = FileOpen( zMapName, FILE_ACCESS_READ | FILE_OPEN_EXISTING, FALSE );
|
|
if( hFile == 0 )
|
|
{
|
|
//Error opening map modification file
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// Load the size of the World ITem table
|
|
FileRead( hFile, &uiNumberOfItems, sizeof( UINT32 ), &uiNumBytesRead );
|
|
if( uiNumBytesRead != sizeof( UINT32 ) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
|
|
*pSizeOfData = uiNumberOfItems;
|
|
|
|
FileClose( hFile );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
UINT32 GetNumberOfMovableItems( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
|
{
|
|
// not underground!
|
|
if ( bMapZ )
|
|
return 0;
|
|
|
|
// open the inventory of the sector we are taking stuff from
|
|
SECTORINFO *pSectorInfo_Target = &(SectorInfo[SECTOR( sMapX, sMapY )]);
|
|
UINT32 uiTotalNumberOfRealItems_Target = 0;
|
|
|
|
// use the new map
|
|
std::vector<WORLDITEM> pWorldItem_Target;
|
|
|
|
if ( (gWorldSectorX == sMapX) && (gWorldSectorY == sMapY) && (gbWorldSectorZ == bMapZ) )
|
|
{
|
|
uiTotalNumberOfRealItems_Target = guiNumWorldItems;
|
|
pWorldItem_Target = gWorldItems;
|
|
}
|
|
else
|
|
{
|
|
const auto ii = FindWorldItemSector(sMapX, sMapY, bMapZ);
|
|
if (ii != -1)
|
|
{
|
|
uiTotalNumberOfRealItems_Target = gAllWorldItems.NumItems[ii];
|
|
pWorldItem_Target = gAllWorldItems.Items[ii];
|
|
}
|
|
else
|
|
{
|
|
uiTotalNumberOfRealItems_Target = 0;
|
|
}
|
|
}
|
|
|
|
|
|
UINT32 validitems = 0;
|
|
for ( UINT32 uiCount = 0; uiCount < uiTotalNumberOfRealItems_Target; ++uiCount ) // ... for all items in the world ...
|
|
{
|
|
if ( pWorldItem_Target[uiCount].fExists ) // ... if item exists ...
|
|
{
|
|
// test wether item is reachable and allowed to be moved by this assignment
|
|
if ( (pWorldItem_Target[uiCount].usFlags & WORLD_ITEM_REACHABLE) && !(pWorldItem_Target[uiCount].usFlags & WORLD_ITEM_MOVE_ASSIGNMENT_IGNORE) && pWorldItem_Target[uiCount].bVisible > 0 )
|
|
{
|
|
OBJECTTYPE* pObj = &(pWorldItem_Target[uiCount].object); // ... get pointer for this item ...
|
|
|
|
if ( pObj != NULL && pObj->exists( ) ) // ... if pointer is not obviously useless ...
|
|
{
|
|
++validitems;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return validitems;
|
|
}
|
|
|
|
BOOLEAN AddWorldItemsToUnLoadedSector(INT16 sMapX, INT16 sMapY, INT8 bMapZ, INT32 sGridNo, UINT32 uiNumberOfItemsToAdd, std::vector<WORLDITEM>& pWorldItem, BOOLEAN fOverWrite)
|
|
{
|
|
UINT32 uiLoop;
|
|
UINT32 uiLastItemPos;
|
|
UINT32 uiNumberOfItems;
|
|
std::vector<WORLDITEM> pWorldItems;//dnl ch75 271013
|
|
if (uiNumberOfItemsToAdd == 0 && fOverWrite == FALSE)
|
|
{
|
|
//Moa: nothing to do, so get out of here!
|
|
return(TRUE);
|
|
}
|
|
|
|
const auto i = FindWorldItemSector(sMapX, sMapY, bMapZ);
|
|
if (i == -1)
|
|
{
|
|
// Can't find world item sector, add it
|
|
uiNumberOfItems = uiNumberOfItemsToAdd;
|
|
pWorldItems.resize(uiNumberOfItems);
|
|
}
|
|
else
|
|
{
|
|
uiNumberOfItems = gAllWorldItems.NumItems[i];
|
|
pWorldItems = gAllWorldItems.Items[i];
|
|
}
|
|
|
|
//if we are to replace the entire file
|
|
if (fOverWrite)
|
|
{
|
|
//first loop through and mark all entries that they dont exists
|
|
for (UINT32 cnt = 0; cnt < uiNumberOfItems; ++cnt)
|
|
pWorldItems[cnt].fExists = FALSE;
|
|
}
|
|
|
|
uiLastItemPos = 0;
|
|
|
|
//loop through all the objects to add
|
|
for (uiLoop = 0; uiLoop < uiNumberOfItemsToAdd; ++uiLoop)
|
|
{
|
|
// Flugente: only add an item if it exists. Otherwise we will happily add items that are supposed to have been deleted
|
|
if (!pWorldItem[uiLoop].fExists)
|
|
continue;
|
|
|
|
//Loop through the array to see if there is a free spot to add an item to it
|
|
for (; uiLastItemPos < uiNumberOfItems; ++uiLastItemPos)
|
|
{
|
|
if (pWorldItems[uiLastItemPos].fExists == FALSE)
|
|
{
|
|
//We have found a free spot, break
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (uiLastItemPos == (uiNumberOfItems))
|
|
{
|
|
const auto neededAmount = uiNumberOfItemsToAdd - uiLoop;
|
|
uiNumberOfItems += neededAmount;
|
|
pWorldItems.resize(uiNumberOfItems);
|
|
}
|
|
|
|
pWorldItems[uiLastItemPos].fExists = TRUE;
|
|
pWorldItems[uiLastItemPos].sGridNo = pWorldItem[uiLoop].sGridNo;
|
|
pWorldItems[uiLastItemPos].ubLevel = pWorldItem[uiLoop].ubLevel;
|
|
pWorldItems[uiLastItemPos].usFlags = pWorldItem[uiLoop].usFlags;
|
|
pWorldItems[uiLastItemPos].bVisible = pWorldItem[uiLoop].bVisible;
|
|
pWorldItems[uiLastItemPos].bRenderZHeightAboveLevel = pWorldItem[uiLoop].bRenderZHeightAboveLevel;
|
|
|
|
//Check
|
|
if (TileIsOutOfBounds(pWorldItem[uiLoop].sGridNo) && !(pWorldItems[uiLastItemPos].usFlags & WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT))
|
|
{
|
|
pWorldItems[uiLastItemPos].usFlags |= WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT;
|
|
|
|
// Display warning.....
|
|
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Error: Trying to add item ( %d: %s ) to invalid gridno in unloaded sector. Please Report.", pWorldItems[uiLoop].object.usItem, ItemNames[pWorldItems[uiLoop].object.usItem]);
|
|
}
|
|
|
|
|
|
pWorldItems[uiLastItemPos].object = pWorldItem[uiLoop].object;
|
|
}
|
|
|
|
UpdateWorldItems(sMapX, sMapY, bMapZ, uiNumberOfItems, pWorldItems);
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOLEAN AddItemsToUnLoadedSector(INT16 sMapX, INT16 sMapY, INT8 bMapZ, INT32 sGridNo, UINT32 uiNumberOfItemsToAdd, OBJECTTYPE* pObject, UINT8 ubLevel, UINT16 usFlags, INT8 bRenderZHeightAboveLevel, INT8 bVisible, BOOLEAN fReplaceEntireFile)
|
|
{
|
|
if (uiNumberOfItemsToAdd == 0 && fReplaceEntireFile == FALSE)
|
|
{
|
|
//Moa: nothing to do, so get out of here!
|
|
return(TRUE);
|
|
}
|
|
|
|
std::vector<WORLDITEM> pWorldItems;
|
|
UINT32 uiNumberOfItems = 0;
|
|
UINT32 cnt;
|
|
UINT32 uiLoop1 = 0;
|
|
|
|
const auto i = FindWorldItemSector(sMapX, sMapY, bMapZ);
|
|
if (i == -1)
|
|
{
|
|
// Can't find world item sector, add it
|
|
uiNumberOfItems = uiNumberOfItemsToAdd;
|
|
pWorldItems.resize(uiNumberOfItems);
|
|
}
|
|
else
|
|
{
|
|
uiNumberOfItems = gAllWorldItems.NumItems[i];
|
|
pWorldItems = gAllWorldItems.Items[i];
|
|
}
|
|
|
|
if (fReplaceEntireFile)
|
|
{
|
|
//first loop through and mark all entries that they dont exists
|
|
for (cnt = 0; cnt < uiNumberOfItems; cnt++)
|
|
{
|
|
pWorldItems[cnt].fExists = FALSE;
|
|
}
|
|
}
|
|
|
|
UINT16 uiLastFoundSpot = 0;
|
|
//loop through all the objects to add
|
|
for (uiLoop1 = 0; uiLoop1 < uiNumberOfItemsToAdd; uiLoop1++)
|
|
{
|
|
//Loop through the array to see if there is a free spot to add an item to it
|
|
for (cnt = uiLastFoundSpot; cnt < uiNumberOfItems; cnt++)
|
|
{
|
|
if (pWorldItems[cnt].fExists == FALSE)
|
|
{
|
|
// anv: remember first found free spot to not loop through entire inventory again for next added items
|
|
uiLastFoundSpot = cnt;
|
|
//We have found a free spot, break
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cnt == (uiNumberOfItems))
|
|
{
|
|
const auto neededAmount = uiNumberOfItemsToAdd - uiLoop1;
|
|
uiNumberOfItems += neededAmount;
|
|
pWorldItems.resize(uiNumberOfItems);
|
|
}
|
|
|
|
pWorldItems[cnt].fExists = TRUE;
|
|
pWorldItems[cnt].sGridNo = sGridNo;
|
|
pWorldItems[cnt].ubLevel = ubLevel;
|
|
pWorldItems[cnt].usFlags = usFlags;
|
|
pWorldItems[cnt].bVisible = bVisible;
|
|
pWorldItems[cnt].bRenderZHeightAboveLevel = bRenderZHeightAboveLevel;
|
|
|
|
|
|
//Check
|
|
if (TileIsOutOfBounds(sGridNo) && !(pWorldItems[cnt].usFlags & WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT))
|
|
{
|
|
pWorldItems[cnt].usFlags |= WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT;
|
|
|
|
// Display warning.....
|
|
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Error: Trying to add item ( %d: %s ) to invalid gridno in unloaded sector. Please Report.", pWorldItems[cnt].object.usItem, ItemNames[pWorldItems[cnt].object.usItem]);
|
|
}
|
|
|
|
|
|
pWorldItems[cnt].object = pObject[uiLoop1];
|
|
|
|
if ((*pObject)[uiLoop1]->data.sObjectFlag & TAKEN_BY_MILITIA_TABOO_GREEN)
|
|
{
|
|
(*pObject)[uiLoop1]->data.sObjectFlag &= ~TAKEN_BY_MILITIA_TABOO_GREEN;
|
|
pWorldItems[cnt].usFlags |= WORLD_ITEM_TABOO_FOR_MILITIA_EQ_GREEN;
|
|
}
|
|
if ((*pObject)[uiLoop1]->data.sObjectFlag & TAKEN_BY_MILITIA_TABOO_BLUE)
|
|
{
|
|
(*pObject)[uiLoop1]->data.sObjectFlag &= ~TAKEN_BY_MILITIA_TABOO_BLUE;
|
|
pWorldItems[cnt].usFlags |= WORLD_ITEM_TABOO_FOR_MILITIA_EQ_BLUE;
|
|
}
|
|
}
|
|
|
|
UpdateWorldItems(sMapX, sMapY, bMapZ, uiNumberOfItems, pWorldItems);
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
extern BOOLEAN gfInMeanwhile;
|
|
extern BOOLEAN EnableModifiedFileSetCache(BOOLEAN value);
|
|
|
|
BOOLEAN SaveCurrentSectorsInformationToTempItemFile( )
|
|
{
|
|
BOOLEAN fShouldBeInMeanwhile = FALSE;
|
|
if( gfWasInMeanwhile )
|
|
{ //Don't save a temp file for the meanwhile scene map.
|
|
gfWasInMeanwhile = FALSE;
|
|
return TRUE;
|
|
}
|
|
#ifdef JA2UB
|
|
//Ja25v No meanwhiles
|
|
#else
|
|
else if( AreInMeanwhile() )
|
|
{
|
|
gfInMeanwhile = FALSE;
|
|
fShouldBeInMeanwhile = TRUE;
|
|
}
|
|
#endif
|
|
//If we havent been to tactical yet
|
|
if( ( gWorldSectorX == 0 ) && ( gWorldSectorY == 0 ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN cacheResetValue = EnableModifiedFileSetCache(TRUE);
|
|
|
|
//Save the Blood, smell and the revealed status for map elements
|
|
SaveBloodSmellAndRevealedStatesFromMapToTempFile();
|
|
|
|
// sevenfm
|
|
SaveMineFlagFromMapToTempFile();
|
|
|
|
// handle all reachable before save
|
|
HandleAllReachAbleItemsInTheSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
|
|
UpdateWorldItems(gWorldSectorX, gWorldSectorY, gbWorldSectorZ, guiNumWorldItems, gWorldItems);
|
|
|
|
std::vector<ROTTING_CORPSE_DEFINITION> corpsedefvector;
|
|
|
|
//Determine how many rotting corpses there are
|
|
for ( INT32 iCount = 0; iCount < giNumRottingCorpse; ++iCount )
|
|
{
|
|
if ( gRottingCorpse[iCount].fActivated )
|
|
corpsedefvector.push_back( gRottingCorpse[iCount].def );
|
|
}
|
|
|
|
//Save the rotting corpse array to the temp rotting corpse file
|
|
if( !SaveRottingCorpsesToTempCorpseFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, corpsedefvector ) )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("SaveCurrentSectorsInformationToTempItemFile: failed in SaveRottingCorpsesToTempCorpseFile()" ) );
|
|
EnableModifiedFileSetCache(cacheResetValue);
|
|
return( FALSE );
|
|
}
|
|
|
|
//save the Doortable array to the temp door map file
|
|
if( !SaveDoorTableToDoorTableTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("SaveCurrentSectorsInformationToTempItemFile: failed in SaveDoorTableToDoorTableTempFile()" ) );
|
|
EnableModifiedFileSetCache(cacheResetValue);
|
|
return( FALSE );
|
|
}
|
|
|
|
//save the 'revealed'status of the tiles
|
|
if( !SaveRevealedStatusArrayToRevealedTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("SaveCurrentSectorsInformationToTempItemFile: failed in SaveRevealedStatusArrayToRevealedTempFile()" ) );
|
|
EnableModifiedFileSetCache(cacheResetValue);
|
|
return( FALSE );
|
|
}
|
|
|
|
//save the door open status to the saved game file
|
|
if( !SaveDoorStatusArrayToDoorStatusTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("SaveCurrentSectorsInformationToTempItemFile: failed in SaveDoorStatusArrayToDoorStatusTempFile()" ) );
|
|
EnableModifiedFileSetCache(cacheResetValue);
|
|
return( FALSE );
|
|
}
|
|
|
|
//Save the enemies to the temp file
|
|
if( !NewWayOfSavingEnemyAndCivliansToTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, TRUE, FALSE ) )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("SaveCurrentSectorsInformationToTempItemFile: failed in NewWayOfSavingEnemyAndCivliansToTempFile( Enemy, Creature Team )" ) );
|
|
EnableModifiedFileSetCache(cacheResetValue);
|
|
return( FALSE );
|
|
}
|
|
|
|
//Save the civilian info to the temp file
|
|
if( !NewWayOfSavingEnemyAndCivliansToTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, FALSE, FALSE ) )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("SaveCurrentSectorsInformationToTempItemFile: failed in NewWayOfSavingEnemyAndCivliansToTempFile( Civ Team )" ) );
|
|
EnableModifiedFileSetCache(cacheResetValue);
|
|
return( FALSE );
|
|
}
|
|
|
|
//Save the smoke effects info to the temp file
|
|
if( !SaveSmokeEffectsToMapTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("SaveCurrentSectorsInformationToTempItemFile: failed in SaveSmokeEffectsToMapTempFile" ) );
|
|
EnableModifiedFileSetCache(cacheResetValue);
|
|
return( FALSE );
|
|
}
|
|
|
|
//Save the smoke effects info to the temp file
|
|
if( !SaveLightEffectsToMapTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("SaveCurrentSectorsInformationToTempItemFile: failed in SaveLightEffectsToMapTempFile" ) );
|
|
EnableModifiedFileSetCache(cacheResetValue);
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
//ttt
|
|
|
|
//Save any other info here
|
|
|
|
|
|
//Save certain information from the NPC's soldier structure to the Merc structure
|
|
SaveNPCInformationToProfileStruct( );
|
|
|
|
//Save the time the player was last in the sector
|
|
SetLastTimePlayerWasInSector();
|
|
|
|
EnableModifiedFileSetCache(cacheResetValue);
|
|
|
|
#ifdef JA2UB
|
|
//Ja25 no meanwhile
|
|
#else
|
|
if( fShouldBeInMeanwhile )
|
|
{
|
|
gfInMeanwhile = TRUE;
|
|
}
|
|
#endif
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
void HandleAllReachAbleItemsInTheSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ )
|
|
{
|
|
// find out which items in the list are reachable
|
|
UINT32 uiCounter = 0;
|
|
UINT8 ubDir, ubMovementCost;
|
|
BOOLEAN fReachable = FALSE;
|
|
INT32 sGridNo = NOWHERE, sGridNo2 = NOWHERE;
|
|
INT32 sNewLoc;
|
|
|
|
SOLDIERTYPE * pSoldier;
|
|
BOOLEAN fSecondary = FALSE;
|
|
|
|
if ( guiNumWorldItems == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( gMapInformation.sCenterGridNo != -1 )
|
|
{
|
|
sGridNo = gMapInformation.sCenterGridNo;
|
|
}
|
|
else if ( gMapInformation.sNorthGridNo != -1 )
|
|
{
|
|
// use any!
|
|
sGridNo = gMapInformation.sNorthGridNo;
|
|
}
|
|
else if ( gMapInformation.sEastGridNo != -1 )
|
|
{
|
|
// use any!
|
|
sGridNo = gMapInformation.sEastGridNo;
|
|
}
|
|
else if ( gMapInformation.sSouthGridNo != -1 )
|
|
{
|
|
// use any!
|
|
sGridNo = gMapInformation.sSouthGridNo;
|
|
}
|
|
else if ( gMapInformation.sWestGridNo != -1 )
|
|
{
|
|
// use any!
|
|
sGridNo = gMapInformation.sWestGridNo;
|
|
}
|
|
else
|
|
{
|
|
AssertMsg( 0, String( "Map %c%d_b%d does not have any entry points!", 'A' + gWorldSectorY - 1, gWorldSectorX, gbWorldSectorZ ) );
|
|
return;
|
|
}
|
|
|
|
if ( gMapInformation.sIsolatedGridNo != -1 )
|
|
{
|
|
sGridNo2 = gMapInformation.sIsolatedGridNo;
|
|
|
|
for( uiCounter = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; uiCounter <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; ++uiCounter )
|
|
{
|
|
pSoldier = MercPtrs[ uiCounter ];
|
|
if ( pSoldier && pSoldier->bActive && pSoldier->stats.bLife > 0 && pSoldier->sSectorX == sSectorX && pSoldier->sSectorY == sSectorY && pSoldier->bSectorZ == bSectorZ )
|
|
{
|
|
if ( FindBestPath( pSoldier, sGridNo2, pSoldier->pathing.bLevel, WALKING, NO_COPYROUTE, 0 ) )
|
|
{
|
|
fSecondary = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !fSecondary )
|
|
{
|
|
sGridNo2 = NOWHERE;
|
|
}
|
|
}
|
|
|
|
GlobalItemsReachableTest( sGridNo, sGridNo2 );
|
|
|
|
for( uiCounter = 0; uiCounter < guiNumWorldItems; ++uiCounter )
|
|
{
|
|
// reset reachablity
|
|
fReachable = FALSE;
|
|
|
|
// item doesn't exist, ignore it
|
|
if( gWorldItems[ uiCounter ].fExists == FALSE )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// if the item is trapped then flag it as unreachable, period
|
|
if ( gWorldItems[ uiCounter ].object[0]->data.bTrap > 0 )
|
|
{
|
|
fReachable = FALSE;
|
|
}
|
|
else if ( ItemTypeExistsAtLocation( gWorldItems[ uiCounter ].sGridNo, OWNERSHIP, gWorldItems[ uiCounter ].ubLevel, NULL ) )
|
|
{
|
|
fReachable = FALSE;
|
|
}
|
|
else if ( gWorldItems[ uiCounter ].object.usItem == CHALICE )
|
|
{
|
|
fReachable = FALSE;
|
|
}
|
|
else if ( gpWorldLevelData[ gWorldItems[ uiCounter ].sGridNo ].uiFlags & MAPELEMENT_REACHABLE )
|
|
{
|
|
// the gridno itself is reachable so the item is reachable
|
|
fReachable = TRUE;
|
|
}
|
|
else if ( gWorldItems[ uiCounter ].ubLevel > 0 )
|
|
{
|
|
// items on roofs are always reachable
|
|
fReachable = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// check the 4 grids around the item, if any is reachable...then the item is reachable
|
|
for ( ubDir = 0; ubDir < NUM_WORLD_DIRECTIONS; ubDir += 2 )
|
|
{
|
|
sNewLoc = NewGridNo( gWorldItems[ uiCounter ].sGridNo, DirectionInc( ubDir ) );
|
|
if ( sNewLoc != gWorldItems[ uiCounter ].sGridNo )
|
|
{
|
|
// then it's a valid gridno, so test it
|
|
// requires non-wall movement cost from one location to the other!
|
|
if ( gpWorldLevelData[ sNewLoc ].uiFlags & MAPELEMENT_REACHABLE )
|
|
{
|
|
ubMovementCost = gubWorldMovementCosts[ gWorldItems[ uiCounter ].sGridNo ][ gOppositeDirection[ ubDir ] ][ 0 ];
|
|
// if we find a door movement cost, if the door is open the gridno should be accessible itself
|
|
if ( ubMovementCost != TRAVELCOST_DOOR && ubMovementCost != TRAVELCOST_WALL )
|
|
{
|
|
fReachable = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( fReachable )
|
|
{
|
|
gWorldItems[ uiCounter ].usFlags |= WORLD_ITEM_REACHABLE;
|
|
}
|
|
else
|
|
{
|
|
gWorldItems[ uiCounter ].usFlags &= ~( WORLD_ITEM_REACHABLE );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN LoadCurrentSectorsInformationFromTempItemsFile()
|
|
{
|
|
BOOLEAN fUsedTempFile = FALSE;
|
|
|
|
//
|
|
// Load in the sectors ITems
|
|
//
|
|
#ifdef JA2UB
|
|
//Ja25v no meanwhiles
|
|
#else
|
|
if( AreInMeanwhile() )
|
|
{ //There will never be a temp file for the meanwhile scene, so return TRUE. However,
|
|
//set a flag to not save it either!
|
|
gfWasInMeanwhile = TRUE;
|
|
|
|
// OK - this is true except for interrotations - we need that item temp file to be
|
|
// processed!
|
|
if ( GetMeanwhileID() == INTERROGATION )
|
|
{
|
|
//We no longer use item temp files during gameplay, so check for the sector in gAllWorldItems
|
|
if (SectorIsInWorldItems(gWorldSectorX, gWorldSectorY, gbWorldSectorZ))
|
|
{
|
|
if (!LoadAndAddWorldItemsFromTempFile(gWorldSectorX, gWorldSectorY, gbWorldSectorZ))
|
|
return(FALSE);
|
|
}
|
|
gfWasInMeanwhile = FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
//if we are in an above ground sector
|
|
|
|
//If there is a map modifications file, load the data from the temp file
|
|
if ( DoesTempFileExistsForMap( SF_MAP_MODIFICATIONS_TEMP_FILE_EXISTS, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
fUsedTempFile = TRUE;
|
|
if ( !LoadAllMapChangesFromMapTempFileAndApplyThem() )
|
|
return( FALSE );
|
|
}
|
|
|
|
//We no longer use item temp files during gameplay, so check for the sector in gAllWorldItems
|
|
if (SectorIsInWorldItems(gWorldSectorX, gWorldSectorY, gbWorldSectorZ))
|
|
{
|
|
if (!LoadAndAddWorldItemsFromTempFile(gWorldSectorX, gWorldSectorY, gbWorldSectorZ))
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//If there is a rotting corpse temp file, load the data from the temp file
|
|
if( DoesTempFileExistsForMap( SF_ROTTING_CORPSE_TEMP_FILE_EXISTS, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
fUsedTempFile = TRUE;
|
|
if( !LoadRottingCorpsesFromTempCorpseFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
return( FALSE );
|
|
}
|
|
|
|
//if there is a door table temp file, load the data from the temp file
|
|
if( DoesTempFileExistsForMap( SF_DOOR_TABLE_TEMP_FILES_EXISTS, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
fUsedTempFile = TRUE;
|
|
if( !LoadDoorTableFromDoorTableTempFile( ) )
|
|
return( FALSE );
|
|
}
|
|
|
|
//if there is a revealed status temp file, load the data from the temp file
|
|
if( DoesTempFileExistsForMap( SF_REVEALED_STATUS_TEMP_FILE_EXISTS, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
fUsedTempFile = TRUE;
|
|
if( !LoadRevealedStatusArrayFromRevealedTempFile( ) )
|
|
return( FALSE );
|
|
}
|
|
|
|
//if there is a door status temp file, load the data from the temp file
|
|
if( DoesTempFileExistsForMap( SF_DOOR_STATUS_TEMP_FILE_EXISTS, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
fUsedTempFile = TRUE;
|
|
if( !LoadDoorStatusArrayFromDoorStatusTempFile( ) )
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
//if the save is an older version, use the old way of loading it up
|
|
if( guiCurrentSaveGameVersion < 57 )
|
|
{
|
|
if( DoesTempFileExistsForMap( SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
fUsedTempFile = TRUE;
|
|
if( !LoadEnemySoldiersFromTempFile( ) )
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
//else use the new way of loading the enemy and civilian placements
|
|
else
|
|
{
|
|
if( DoesTempFileExistsForMap( SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
fUsedTempFile = TRUE;
|
|
if( !NewWayOfLoadingEnemySoldiersFromTempFile( ) )
|
|
return( FALSE );
|
|
}
|
|
|
|
if( DoesTempFileExistsForMap( SF_CIV_PRESERVED_TEMP_FILE_EXISTS, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
fUsedTempFile = TRUE;
|
|
if( !NewWayOfLoadingCiviliansFromTempFile( ) )
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
if( DoesTempFileExistsForMap( SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
fUsedTempFile = TRUE;
|
|
if( !LoadSmokeEffectsFromMapTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
return( FALSE );
|
|
}
|
|
|
|
if( DoesTempFileExistsForMap( SF_LIGHTING_EFFECTS_TEMP_FILE_EXISTS, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
{
|
|
fUsedTempFile = TRUE;
|
|
if( !LoadLightEffectsFromMapTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) )
|
|
return( FALSE );
|
|
}
|
|
|
|
//ttt
|
|
|
|
// Check to see if any npc are in this sector, if so load up some saved data for them
|
|
LoadNPCInformationFromProfileStruct();
|
|
|
|
//if we are loading a saved game
|
|
// if( gTacticalStatus.uiFlags & LOADING_SAVED_GAME )
|
|
{
|
|
//Init the world since we have modified the map
|
|
InitLoadedWorld();
|
|
}
|
|
|
|
|
|
// Get the last time the player was in the sector
|
|
guiTimeCurrentSectorWasLastLoaded = GetLastTimePlayerWasInSector();
|
|
|
|
if( fUsedTempFile )
|
|
{
|
|
// ValidateSoldierInitLinks( 3 );
|
|
}
|
|
|
|
|
|
StripEnemyDetailedPlacementsIfSectorWasPlayerLiberated();
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
void SetLastTimePlayerWasInSector()
|
|
{
|
|
if( !gbWorldSectorZ )
|
|
SectorInfo[ SECTOR( gWorldSectorX,gWorldSectorY) ].uiTimeCurrentSectorWasLastLoaded = GetWorldTotalMin();
|
|
else if( gbWorldSectorZ > 0 )
|
|
{
|
|
UNDERGROUND_SECTORINFO *pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
//loop through and look for the right underground sector
|
|
while( pTempNode )
|
|
{
|
|
if( ( pTempNode->ubSectorX == gWorldSectorX ) &&
|
|
( pTempNode->ubSectorY == gWorldSectorY ) &&
|
|
( pTempNode->ubSectorZ == gbWorldSectorZ ) )
|
|
{
|
|
//set the flag indicating that ther is a temp item file exists for the sector
|
|
pTempNode->uiTimeCurrentSectorWasLastLoaded = GetWorldTotalMin();
|
|
return; //break out
|
|
}
|
|
pTempNode = pTempNode->next;
|
|
}
|
|
#ifdef JA2TESTVERSION
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_TESTVERSION, L"Failed to Set the 'uiTimeCurrentSectorWasLastLoaded' for an underground sector" );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Flugente: set last time sector was visited
|
|
void SetLastTimePlayerWasInSector(INT16 sMapX, INT16 sMapY, INT8 sMapZ)
|
|
{
|
|
if( !sMapZ )
|
|
SectorInfo[ SECTOR( sMapX,sMapY) ].uiTimeCurrentSectorWasLastLoaded = GetWorldTotalMin();
|
|
else if( sMapZ > 0 )
|
|
{
|
|
UNDERGROUND_SECTORINFO *pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
//loop through and look for the right underground sector
|
|
while( pTempNode )
|
|
{
|
|
if( ( pTempNode->ubSectorX == sMapX ) &&
|
|
( pTempNode->ubSectorY == sMapY ) &&
|
|
( pTempNode->ubSectorZ == sMapZ ) )
|
|
{
|
|
//set the flag indicating that ther is a temp item file exists for the sector
|
|
pTempNode->uiTimeCurrentSectorWasLastLoaded = GetWorldTotalMin();
|
|
return; //break out
|
|
}
|
|
pTempNode = pTempNode->next;
|
|
}
|
|
#ifdef JA2TESTVERSION
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_TESTVERSION, L"Failed to Set the 'uiTimeCurrentSectorWasLastLoaded' for an underground sector" );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
UINT32 GetLastTimePlayerWasInSector()
|
|
{
|
|
if( !gbWorldSectorZ )
|
|
return( SectorInfo[ SECTOR( gWorldSectorX,gWorldSectorY) ].uiTimeCurrentSectorWasLastLoaded );
|
|
else if( gbWorldSectorZ > 0 )
|
|
{
|
|
UNDERGROUND_SECTORINFO *pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
//loop through and look for the right underground sector
|
|
while( pTempNode )
|
|
{
|
|
if( ( pTempNode->ubSectorX == gWorldSectorX ) &&
|
|
( pTempNode->ubSectorY == gWorldSectorY ) &&
|
|
( pTempNode->ubSectorZ == gbWorldSectorZ ) )
|
|
{
|
|
//set the flag indicating that ther is a temp item file exists for the sector
|
|
return( pTempNode->uiTimeCurrentSectorWasLastLoaded );
|
|
}
|
|
pTempNode = pTempNode->next;
|
|
}
|
|
|
|
#ifdef JA2TESTVERSION
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_TESTVERSION, L"Failed to Get the 'uiTimeCurrentSectorWasLastLoaded' from an underground sector" );
|
|
#endif
|
|
|
|
return( 0 );
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
// Flugente: get time for another sector
|
|
UINT32 GetLastTimePlayerWasInSector(INT16 sMapX, INT16 sMapY, INT8 sMapZ)
|
|
{
|
|
if( !sMapZ )
|
|
return( SectorInfo[ SECTOR( sMapX,sMapY) ].uiTimeCurrentSectorWasLastLoaded );
|
|
else if( sMapZ > 0 )
|
|
{
|
|
UNDERGROUND_SECTORINFO *pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
//loop through and look for the right underground sector
|
|
while( pTempNode )
|
|
{
|
|
if( ( pTempNode->ubSectorX == sMapX ) &&
|
|
( pTempNode->ubSectorY == sMapY ) &&
|
|
( pTempNode->ubSectorZ == sMapZ ) )
|
|
{
|
|
//set the flag indicating that ther is a temp item file exists for the sector
|
|
return( pTempNode->uiTimeCurrentSectorWasLastLoaded );
|
|
}
|
|
pTempNode = pTempNode->next;
|
|
}
|
|
|
|
#ifdef JA2TESTVERSION
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_TESTVERSION, L"Failed to Get the 'uiTimeCurrentSectorWasLastLoaded' from an underground sector" );
|
|
#endif
|
|
|
|
return( 0 );
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN LoadAndAddWorldItemsFromTempFile(INT16 sMapX, INT16 sMapY, INT8 bMapZ)
|
|
{
|
|
UINT32 uiNumberOfItems = 0;
|
|
std::vector<WORLDITEM> pWorldItems;
|
|
|
|
//Get the number of items from the file
|
|
const auto i = FindWorldItemSector(sMapX, sMapY, bMapZ);
|
|
if (i == -1)
|
|
{
|
|
//Error getting the numbers of the items from the sector. Create placeholder items.
|
|
//This is what the original code did
|
|
uiNumberOfItems = 10;
|
|
pWorldItems.resize(uiNumberOfItems);
|
|
}
|
|
else
|
|
{
|
|
uiNumberOfItems = gAllWorldItems.NumItems[i];
|
|
pWorldItems= gAllWorldItems.Items[i];
|
|
}
|
|
|
|
if (uiNumberOfItems == 0)
|
|
{
|
|
//if there are no items in the temp, the player might have cleared all of them out, check to see
|
|
//If we have already been to the sector
|
|
if (GetSectorFlagStatus(sMapX, sMapY, bMapZ, SF_ALREADY_LOADED))
|
|
{
|
|
//
|
|
//Completly replace the current sectors item table because all the items SHOULD be in the temp file!!
|
|
//
|
|
|
|
//Destroy the current sectors item table
|
|
TrashWorldItems();
|
|
}
|
|
|
|
//there are no items in the file
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
//If we have already been to the sector
|
|
if (GetSectorFlagStatus(sMapX, sMapY, bMapZ, SF_ALREADY_LOADED))
|
|
{
|
|
//
|
|
//Completly replace the current sectors item table because all the items SHOULD be in the temp file!!
|
|
//
|
|
|
|
//Destroy the current sectors item table
|
|
TrashWorldItems();
|
|
|
|
//Add each item to the pool, handle below, outside of the if
|
|
}
|
|
|
|
//
|
|
//Append the items in the file with to the current sectors item table
|
|
//
|
|
|
|
//Loop through all the items loaded from the file
|
|
INT32 sNewGridNo;
|
|
for (UINT32 cnt = 0; cnt < uiNumberOfItems; cnt++)
|
|
{
|
|
//If the item in the array is valid
|
|
if (pWorldItems[cnt].fExists)
|
|
{
|
|
//Check the flags to see if we have to find a gridno to place the items at
|
|
if (pWorldItems[cnt].usFlags & WOLRD_ITEM_FIND_SWEETSPOT_FROM_GRIDNO)
|
|
{
|
|
sNewGridNo = FindNearestAvailableGridNoForItem(pWorldItems[cnt].sGridNo, 5);
|
|
|
|
if (TileIsOutOfBounds(sNewGridNo))
|
|
sNewGridNo = FindNearestAvailableGridNoForItem(pWorldItems[cnt].sGridNo, 15);
|
|
|
|
if (!TileIsOutOfBounds(sNewGridNo))
|
|
{
|
|
pWorldItems[cnt].sGridNo = sNewGridNo;
|
|
}
|
|
}
|
|
|
|
//If the item has an invalid gridno, use the maps entry point
|
|
if (pWorldItems[cnt].usFlags & WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT)
|
|
{
|
|
pWorldItems[cnt].sGridNo = gMapInformation.sCenterGridNo;
|
|
|
|
// if we move the item, recalculate the height
|
|
pWorldItems[cnt].bRenderZHeightAboveLevel = -1;
|
|
}
|
|
|
|
//add the item to the world
|
|
AddItemToPool(pWorldItems[cnt].sGridNo, &pWorldItems[cnt].object, pWorldItems[cnt].bVisible, pWorldItems[cnt].ubLevel, pWorldItems[cnt].usFlags, pWorldItems[cnt].bRenderZHeightAboveLevel, pWorldItems[cnt].soldierID);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN AddTempFileToSavedGame( HWFILE hFile, UINT32 uiType, INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
|
{
|
|
CHAR8 zMapName[ 128 ];
|
|
|
|
GetMapTempFileName( uiType, zMapName, sMapX, sMapY, bMapZ );
|
|
|
|
//Save the map temp file to the saved game file
|
|
if( !SaveFilesToSavedGame( zMapName, hFile ) )
|
|
return( FALSE );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN RetrieveTempFileFromSavedGame( HWFILE hFile, UINT32 uiType, INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
|
{
|
|
CHAR8 zMapName[ 128 ];
|
|
|
|
GetMapTempFileName( uiType, zMapName, sMapX, sMapY, bMapZ );
|
|
|
|
//Load the map temp file from the saved game file
|
|
if( !LoadFilesFromSavedGame( zMapName, hFile ) )
|
|
return( FALSE );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
//Deletes the Temp map Directory
|
|
BOOLEAN InitTacticalSave( BOOLEAN fCreateTempDir )
|
|
{
|
|
#ifndef USE_VFS
|
|
UINT32 uiRetVal;
|
|
|
|
//If the Map Temp directory exists, removes the temp files
|
|
uiRetVal = FileGetAttributes( MAPS_DIR );
|
|
if( uiRetVal != 0xFFFFFFFF )
|
|
{
|
|
if( uiRetVal & FILE_ATTRIBUTES_DIRECTORY )
|
|
{
|
|
//Erase the directory
|
|
if( !EraseDirectory( MAPS_DIR ) )
|
|
{
|
|
//error erasing the temporary maps directory
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( !MakeFileManDirectory( MAPS_DIR ) )
|
|
{
|
|
//Erro creating the temp map directory
|
|
AssertMsg( 0, "Error creating the Temp Directory.");
|
|
}
|
|
}
|
|
#else
|
|
EraseDirectory( MAPS_DIR );
|
|
#endif
|
|
if( fCreateTempDir )
|
|
{
|
|
//Create the initial temp file for the Npc Quote Info
|
|
InitTempNpcQuoteInfoForNPCFromTempFile();
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN SaveRottingCorpsesToTempCorpseFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ, std::vector<ROTTING_CORPSE_DEFINITION> aCorpseDefVector )
|
|
{
|
|
HWFILE hFile;
|
|
UINT32 uiNumBytesWritten=0;
|
|
CHAR8 zMapName[ 128 ];
|
|
|
|
// if we have no corpses at all, we have nothing to write - erase the 'corpse file exists flag', the next time we add a corpse, a new file will be created
|
|
if ( aCorpseDefVector.empty() )
|
|
{
|
|
ReSetSectorFlag( sMapX, sMapY, bMapZ, SF_ROTTING_CORPSE_TEMP_FILE_EXISTS );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
GetMapTempFileName( SF_ROTTING_CORPSE_TEMP_FILE_EXISTS, zMapName, sMapX, sMapY, bMapZ );
|
|
|
|
//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 );
|
|
}
|
|
|
|
UINT32 uiNumberOfCorpses = aCorpseDefVector.size();
|
|
|
|
//Save the number of the Rotting Corpses array table
|
|
FileWrite( hFile, &uiNumberOfCorpses, sizeof( UINT32 ), &uiNumBytesWritten );
|
|
if( uiNumBytesWritten != sizeof( UINT32 ) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
|
|
//Loop through all the carcases in the array and save the active ones
|
|
for( std::vector<ROTTING_CORPSE_DEFINITION>::iterator it = aCorpseDefVector.begin(); it != aCorpseDefVector.end(); ++it )
|
|
{
|
|
//Save the RottingCorpse info array
|
|
FileWrite( hFile, &(*it), sizeof( ROTTING_CORPSE_DEFINITION ), &uiNumBytesWritten );
|
|
if ( uiNumBytesWritten != sizeof( ROTTING_CORPSE_DEFINITION ) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
FileClose( hFile );
|
|
|
|
// Set the flag indicating that there is a rotting corpse Temp File
|
|
SetSectorFlag( sMapX, sMapY, bMapZ, SF_ROTTING_CORPSE_TEMP_FILE_EXISTS );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN DeleteTempItemMapFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
|
{
|
|
CHAR8 zMapName[ 128 ];
|
|
GetMapTempFileName( SF_ITEM_TEMP_FILE_EXISTS, zMapName, sMapX, sMapY, bMapZ );
|
|
|
|
//Check to see if the file exists
|
|
if( !FileExists( zMapName ) )
|
|
{
|
|
//If the file doesnt exists, its no problem.
|
|
return( TRUE );
|
|
}
|
|
FileDelete(zMapName);
|
|
|
|
// the sector info flag being reset
|
|
ReSetSectorFlag( sMapX, sMapY, bMapZ, SF_ITEM_TEMP_FILE_EXISTS );
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN LoadRottingCorpsesFromTempCorpseFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
|
{
|
|
HWFILE hFile;
|
|
UINT32 uiNumBytesRead=0;
|
|
CHAR8 zMapName[ 128 ];
|
|
UINT32 uiNumberOfCorpses=0;
|
|
UINT32 cnt;
|
|
ROTTING_CORPSE_DEFINITION def;
|
|
INT8 bTownId;
|
|
|
|
//Delete the existing rotting corpse array
|
|
RemoveCorpses( );
|
|
|
|
GetMapTempFileName( SF_ROTTING_CORPSE_TEMP_FILE_EXISTS, zMapName, sMapX, sMapY, bMapZ );
|
|
|
|
//Check to see if the file exists
|
|
if( !FileExists( zMapName ) )
|
|
{
|
|
//If the file doesnt exists, its no problem.
|
|
return( TRUE );
|
|
}
|
|
|
|
//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 );
|
|
}
|
|
|
|
// Load the number of Rotting corpses
|
|
FileRead( hFile, &uiNumberOfCorpses, sizeof( UINT32 ), &uiNumBytesRead );
|
|
if( uiNumBytesRead != sizeof( UINT32 ) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
|
|
// WANNE: If we get wrong data (very high value) from the temp file, we assume we have wrong value and therefore set corpses to 0 which will not crash the game!
|
|
if (uiNumberOfCorpses > 10000)
|
|
uiNumberOfCorpses = 0;
|
|
|
|
// Get town ID for use later....
|
|
bTownId = GetTownIdForSector( gWorldSectorX, gWorldSectorY );
|
|
|
|
for( cnt=0; cnt<uiNumberOfCorpses; ++cnt )
|
|
{
|
|
// Load the Rotting corpses info
|
|
FileRead( hFile, &def, sizeof( ROTTING_CORPSE_DEFINITION ), &uiNumBytesRead );
|
|
if( uiNumBytesRead != sizeof( ROTTING_CORPSE_DEFINITION ) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
|
|
//Check the flags to see if we have to find a gridno to place the rotting corpses at
|
|
if( def.usFlags & ROTTING_CORPSE_FIND_SWEETSPOT_FROM_GRIDNO )
|
|
{
|
|
def.sGridNo = FindNearestAvailableGridNoForCorpse( &def, 5 );
|
|
|
|
if (TileIsOutOfBounds(def.sGridNo))
|
|
{
|
|
def.sGridNo = FindNearestAvailableGridNoForCorpse(&def, 15);
|
|
if (TileIsOutOfBounds(def.sGridNo))
|
|
{
|
|
//shadooow: if we still have invalid gridno skip adding this corpse, it will crash otherwise
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else if( def.usFlags & ROTTING_CORPSE_USE_NORTH_ENTRY_POINT )
|
|
{
|
|
def.sGridNo = gMapInformation.sNorthGridNo;
|
|
}
|
|
else if( def.usFlags & ROTTING_CORPSE_USE_SOUTH_ENTRY_POINT )
|
|
{
|
|
def.sGridNo = gMapInformation.sSouthGridNo;
|
|
}
|
|
else if( def.usFlags & ROTTING_CORPSE_USE_EAST_ENTRY_POINT )
|
|
{
|
|
def.sGridNo = gMapInformation.sEastGridNo;
|
|
}
|
|
else if( def.usFlags & ROTTING_CORPSE_USE_WEST_ENTRY_POINT )
|
|
{
|
|
def.sGridNo = gMapInformation.sWestGridNo;
|
|
}
|
|
//Recalculate the dx,dy info
|
|
def.dXPos = CenterX( def.sGridNo );
|
|
def.dYPos = CenterY( def.sGridNo );
|
|
// If not from loading a save....
|
|
if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
|
|
{
|
|
// ATE: Don't place corpses if
|
|
// a ) in a town and b) indoors
|
|
if ( gbWorldSectorZ == 0 )
|
|
{
|
|
if ( bTownId != BLANK_SECTOR )
|
|
{
|
|
// Are we indoors?
|
|
if( FloorAtGridNo( def.sGridNo ) )
|
|
{
|
|
// OK, finally, check TOC vs game time to see if at least some time has passed
|
|
if ( ( GetWorldTotalMin( ) - def.uiTimeOfDeath ) >= 30 )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//add the rotting corpse info
|
|
if( AddRottingCorpse( &def ) == -1 )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Failed to add a corpse to GridNo # %d", def.sGridNo ) );
|
|
/*
|
|
Assert( 0 );
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
*/
|
|
}
|
|
}
|
|
|
|
FileClose( hFile );
|
|
|
|
//Check to see if we have to start decomposing the corpses
|
|
HandleRottingCorpses( );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
void SaveNPCInformationToProfileStruct( )
|
|
{
|
|
UINT32 cnt;
|
|
SOLDIERTYPE * pSoldier;
|
|
MERCPROFILESTRUCT * pProfile;
|
|
|
|
//Loop through the active NPC's
|
|
|
|
// Only do this on save now... on traversal this is handled in the strategic code
|
|
if ( !( gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
for ( cnt = 0; cnt < guiNumMercSlots; cnt++)
|
|
{
|
|
pSoldier = MercSlots[ cnt ];
|
|
|
|
//if it is an active NPC
|
|
if ( pSoldier && pSoldier->ubProfile != NO_PROFILE && pSoldier->bTeam == CIV_TEAM )
|
|
{
|
|
//Save Temp Npc Quote Info array
|
|
SaveTempNpcQuoteInfoForNPCToTempFile( pSoldier->ubProfile );
|
|
|
|
pProfile = &(gMercProfiles[ pSoldier->ubProfile ]);
|
|
|
|
pProfile->ubQuoteActionID = pSoldier->ubQuoteActionID;
|
|
pProfile->ubQuoteRecord = pSoldier->ubQuoteRecord;
|
|
|
|
// if the merc is NOT added due to flag set, return
|
|
if ( pProfile->ubMiscFlags2 & PROFILE_MISC_FLAG2_DONT_ADD_TO_SECTOR )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( pProfile->ubMiscFlags3 & PROFILE_MISC_FLAG3_PERMANENT_INSERTION_CODE )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pProfile->fUseProfileInsertionInfo = TRUE;
|
|
pProfile->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
|
|
//if ( gTacticalStatus.uiFlags & LOADING_SAVED_GAME )
|
|
//{
|
|
// if we are saving the game, save the NPC's current location
|
|
pProfile->usStrategicInsertionData = pSoldier->sGridNo;
|
|
//}
|
|
/*
|
|
else
|
|
{
|
|
// If the NPC is moving, save the final destination, else save the current location
|
|
if ( pSoldier->pathing.sFinalDestination != pSoldier->sGridNo )
|
|
{
|
|
pProfile->usStrategicInsertionData = pSoldier->pathing.sFinalDestination;
|
|
}
|
|
else
|
|
{
|
|
pProfile->usStrategicInsertionData = pSoldier->sGridNo;
|
|
}
|
|
}
|
|
*/
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
extern void EVENT_SetSoldierPositionAndMaybeFinalDestAndMaybeNotDestination( SOLDIERTYPE *pSoldier, FLOAT dNewXPos, FLOAT dNewYPos, BOOLEAN fUpdateDest, BOOLEAN fUpdateFinalDest );
|
|
|
|
void LoadNPCInformationFromProfileStruct()
|
|
{
|
|
//UINT32 cnt;
|
|
//INT16 sSoldierID;
|
|
//SOLDIERTYPE * pSoldier;
|
|
|
|
// CJC: disabled this Dec 21, 1998 as unnecessary (and messing up quote files for recruited/escorted NPCs
|
|
return;
|
|
/* commented out the disabled code (jonathanl)
|
|
for ( cnt = FIRST_RPC; cnt < NUM_PROFILES; cnt++ )
|
|
{
|
|
if ( gMercProfiles[ cnt ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED )
|
|
{
|
|
// don't load
|
|
continue;
|
|
}
|
|
|
|
sSoldierID = GetSoldierIDFromAnyMercID( (UINT8)cnt );
|
|
|
|
//if the soldier is not loaded, return
|
|
if( sSoldierID == -1 )
|
|
continue;
|
|
|
|
//if we cant get a pointer to the soldier, continue
|
|
if( !GetSoldier( &pSoldier, sSoldierID ) )
|
|
continue;
|
|
|
|
// load quote info if it exists
|
|
if ( gMercProfiles[ cnt ].ubMiscFlags & PROFILE_MISC_FLAG_TEMP_NPC_QUOTE_DATA_EXISTS )
|
|
{
|
|
LoadTempNpcQuoteInfoForNPCFromTempFile( (UINT8)cnt );
|
|
}
|
|
|
|
// load insertion info
|
|
//if ( gMercProfiles[ cnt ] )
|
|
//{
|
|
// pSoldier->ubInsertionCode = pProfile->ubStrategicInsertionCode;
|
|
// pSoldier->usInsertionData = pProfile->usStrategicInsertionData;
|
|
//}
|
|
|
|
}
|
|
*/
|
|
|
|
/*
|
|
INT16 sX, sY;
|
|
UINT16 cnt;
|
|
SOLDIERTYPE *pSoldier;
|
|
INT16 sSoldierID;
|
|
INT16 sXPos, sYPos;
|
|
|
|
sXPos = sYPos = 0;
|
|
|
|
//Loop through the active NPC's
|
|
// cnt = gTacticalStatus.Team[ OUR_TEAM ].bLastID + 1;
|
|
for(cnt=FIRST_RPC; cnt<NUM_PROFILES; cnt++)
|
|
{
|
|
if ( gMercProfiles[ cnt ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED )
|
|
{
|
|
// don't load
|
|
continue;
|
|
}
|
|
|
|
sSoldierID = GetSoldierIDFromAnyMercID( (UINT8)cnt );
|
|
|
|
//if the soldier is not loaded, return
|
|
if( sSoldierID == -1 )
|
|
continue;
|
|
|
|
//if we cant get a pointer to the soldier, continue
|
|
if( !GetSoldier( &pSoldier, sSoldierID ) )
|
|
continue;
|
|
|
|
pSoldier->ubQuoteActionID = gMercProfiles[ cnt ].ubQuoteActionID;
|
|
pSoldier->ubQuoteRecord = gMercProfiles[ cnt ].ubQuoteRecord;
|
|
|
|
if( gMercProfiles[ cnt ].fUseProfileInsertionInfo == PROFILE_USE_GRIDNO )
|
|
{
|
|
sX = CenterX( gMercProfiles[ cnt ].sGridNo );
|
|
sY = CenterY( gMercProfiles[ cnt ].sGridNo );
|
|
|
|
//Load the Temp Npc Quote Info array
|
|
|
|
//if the NPC has been recruited, continue
|
|
if( gMercProfiles[ cnt ].ubMiscFlags & PROFILE_MISC_FLAG_TEMP_NPC_QUOTE_DATA_EXISTS )
|
|
LoadTempNpcQuoteInfoForNPCFromTempFile( (UINT8)cnt );
|
|
|
|
//if the NPC has been recruited, continue
|
|
if( gMercProfiles[ cnt ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED )
|
|
continue;
|
|
|
|
//If the NPC was supposed to do something when they reached their target destination
|
|
if( pSoldier->sGridNo == pSoldier->pathing.sFinalDestination )
|
|
{
|
|
if (pSoldier->ubQuoteRecord && pSoldier->ubQuoteActionID == QUOTE_ACTION_ID_CHECKFORDEST )
|
|
{
|
|
//the mercs gridno has to be the same as the final destination
|
|
pSoldier->EVENT_SetSoldierPosition( (FLOAT) sX, (FLOAT) sY );
|
|
|
|
NPCReachedDestination( pSoldier, FALSE );
|
|
}
|
|
}
|
|
|
|
//If the NPC's gridno is not nowhere, set him to that position
|
|
//if( !TileIsOutOfBounds(gMercProfiles[ cnt ].sGridNo) )
|
|
if(!TileIsOutOfBounds(gMercProfiles[ cnt ].sGridNo))
|
|
{
|
|
if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
|
|
{
|
|
//Set the NPC's destination
|
|
pSoldier->pathing.sDestination = gMercProfiles[ cnt ].sGridNo;
|
|
pSoldier->pathing.sDestXPos = sXPos;
|
|
pSoldier->pathing.sDestYPos = sYPos;
|
|
|
|
// We have moved to a diferent sector and are returning to it, therefore the merc should be in the final dest
|
|
EVENT_SetSoldierPositionAndMaybeFinalDestAndMaybeNotDestination( pSoldier, (FLOAT) sX, (FLOAT) sY, FALSE, TRUE );
|
|
}
|
|
|
|
//else we are saving
|
|
else
|
|
{
|
|
|
|
//Set the NPC's position
|
|
// pSoldier->EVENT_SetSoldierPosition( (FLOAT) sX, (FLOAT) sY );
|
|
EVENT_SetSoldierPositionAndMaybeFinalDestAndMaybeNotDestination( pSoldier, (FLOAT) sX, (FLOAT) sY, FALSE, FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
//else if we are NOT to use the gridno, dont use it but reset the flag
|
|
else if( gMercProfiles[ cnt ].fUseProfileInsertionInfo == PROFILE_DONT_USE_GRIDNO )
|
|
{
|
|
gMercProfiles[ cnt ].fUseProfileInsertionInfo = PROFILE_NOT_SET;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
BOOLEAN DoesTempFileExistsForMap( UINT32 uiType, INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
|
{
|
|
UNDERGROUND_SECTORINFO *TempNode = gpUndergroundSectorInfoHead;
|
|
|
|
if( bMapZ == 0 )
|
|
{
|
|
return( (SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags & uiType) ? 1 : 0 );
|
|
}
|
|
else
|
|
{
|
|
while( TempNode )
|
|
{
|
|
if( TempNode->ubSectorX == sMapX && TempNode->ubSectorY == sMapY && TempNode->ubSectorZ == bMapZ )
|
|
{
|
|
return( (TempNode->uiFlags & uiType ) ? 1 : 0 );
|
|
}
|
|
TempNode = TempNode->next;
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
INT16 GetSoldierIDFromAnyMercID(UINT8 ubMercID)
|
|
{
|
|
UINT16 cnt;
|
|
UINT8 ubLastTeamID;
|
|
SOLDIERTYPE *pTeamSoldier;
|
|
|
|
cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID;
|
|
|
|
ubLastTeamID = TOTAL_SOLDIERS;
|
|
|
|
// look for all mercs on the same team,
|
|
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= ubLastTeamID; cnt++,pTeamSoldier++)
|
|
{
|
|
if( pTeamSoldier->bActive )
|
|
{
|
|
if ( pTeamSoldier->ubProfile == ubMercID )
|
|
{
|
|
return( cnt );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( -1 );
|
|
}
|
|
|
|
|
|
|
|
|
|
//Initializes the NPC temp array
|
|
BOOLEAN InitTempNpcQuoteInfoForNPCFromTempFile()
|
|
{
|
|
UINT32 uiNumBytesWritten;
|
|
UINT8 ubCnt;
|
|
TempNPCQuoteInfoSave TempNpcQuote[ NUM_NPC_QUOTE_RECORDS ];
|
|
UINT32 uiSizeOfTempArray = sizeof( TempNPCQuoteInfoSave ) * NUM_NPC_QUOTE_RECORDS;
|
|
UINT16 usCnt1;
|
|
HWFILE hFile;
|
|
|
|
|
|
//Open the temp npc file
|
|
hFile = FileOpen( NPC_TEMP_QUOTE_FILE, FILE_ACCESS_WRITE | FILE_OPEN_ALWAYS, FALSE );
|
|
if( hFile == 0 )
|
|
{
|
|
//Error opening temp npc quote info
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
//loop through all the npc accounts and write the temp array to disk
|
|
//for( usCnt1=0; usCnt1< ( GASTON-FIRST_RPC ); usCnt1++)
|
|
//new profiles by Jazz
|
|
for( usCnt1=0; usCnt1< NUM_PROFILES; usCnt1++)
|
|
{
|
|
|
|
memset( TempNpcQuote, 0, uiSizeOfTempArray );
|
|
|
|
//Loop through and build the temp array to save
|
|
for( ubCnt=0; ubCnt<NUM_NPC_QUOTE_RECORDS; ubCnt++ )
|
|
{
|
|
if( gpNPCQuoteInfoArray[ usCnt1 ] )
|
|
{
|
|
TempNpcQuote[ ubCnt ].usFlags = gpNPCQuoteInfoArray[ usCnt1 ][ ubCnt ].fFlags;
|
|
TempNpcQuote[ ubCnt ].sRequiredItem = gpNPCQuoteInfoArray[ usCnt1 ][ ubCnt ].sRequiredItem;
|
|
TempNpcQuote[ ubCnt ].usGoToGridNo = gpNPCQuoteInfoArray[ usCnt1 ][ ubCnt ].usGoToGridNo;
|
|
}
|
|
}
|
|
|
|
//Save the array to a temp file
|
|
FileWrite( hFile, TempNpcQuote, uiSizeOfTempArray, &uiNumBytesWritten );
|
|
if( uiNumBytesWritten != uiSizeOfTempArray )
|
|
{
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
FileClose( hFile );
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN SaveTempNpcQuoteInfoForNPCToTempFile( UINT8 ubNpcId )
|
|
{
|
|
UINT32 uiNumBytesWritten;
|
|
UINT8 ubCnt;
|
|
TempNPCQuoteInfoSave TempNpcQuote[ NUM_NPC_QUOTE_RECORDS ];
|
|
UINT32 uiSizeOfTempArray = sizeof( TempNPCQuoteInfoSave ) * NUM_NPC_QUOTE_RECORDS;
|
|
UINT32 uiSpotInFile = ubNpcId - FIRST_RPC;
|
|
HWFILE hFile=0;
|
|
|
|
//if there are records to save
|
|
if( gpNPCQuoteInfoArray[ ubNpcId ] )
|
|
{
|
|
|
|
hFile = FileOpen( NPC_TEMP_QUOTE_FILE, FILE_ACCESS_WRITE | FILE_OPEN_ALWAYS, FALSE );
|
|
if( hFile == 0 )
|
|
{
|
|
//Error opening temp npc quote info
|
|
return( FALSE );
|
|
}
|
|
|
|
memset( TempNpcQuote, 0, uiSizeOfTempArray );
|
|
|
|
//Loop through and build the temp array to save
|
|
for( ubCnt=0; ubCnt<NUM_NPC_QUOTE_RECORDS; ubCnt++ )
|
|
{
|
|
TempNpcQuote[ ubCnt ].usFlags = gpNPCQuoteInfoArray[ ubNpcId ][ ubCnt ].fFlags;
|
|
TempNpcQuote[ ubCnt ].sRequiredItem = gpNPCQuoteInfoArray[ ubNpcId ][ ubCnt ].sRequiredItem;
|
|
TempNpcQuote[ ubCnt ].usGoToGridNo = gpNPCQuoteInfoArray[ ubNpcId ][ ubCnt ].usGoToGridNo;
|
|
}
|
|
|
|
//Seek to the correct spot in the file
|
|
FileSeek( hFile, uiSpotInFile * uiSizeOfTempArray, FILE_SEEK_FROM_START );
|
|
|
|
//Save the array to a temp file
|
|
FileWrite( hFile, TempNpcQuote, uiSizeOfTempArray, &uiNumBytesWritten );
|
|
if( uiNumBytesWritten != uiSizeOfTempArray )
|
|
{
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
|
|
//Set the fact that the merc has the temp npc quote data
|
|
gMercProfiles[ ubNpcId ].ubMiscFlags |= PROFILE_MISC_FLAG_TEMP_NPC_QUOTE_DATA_EXISTS;
|
|
|
|
FileClose( hFile );
|
|
}
|
|
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN LoadTempNpcQuoteInfoForNPCFromTempFile( UINT8 ubNpcId )
|
|
{
|
|
UINT32 uiNumBytesRead;
|
|
UINT8 ubCnt;
|
|
TempNPCQuoteInfoSave TempNpcQuote[ NUM_NPC_QUOTE_RECORDS ];
|
|
UINT32 uiSizeOfTempArray = sizeof( TempNPCQuoteInfoSave ) * NUM_NPC_QUOTE_RECORDS;
|
|
UINT32 uiSpotInFile = ubNpcId - FIRST_RPC;
|
|
HWFILE hFile;
|
|
|
|
|
|
//Init the array
|
|
memset( TempNpcQuote, 0, uiSizeOfTempArray );
|
|
|
|
|
|
//If there isnt already memory allocated, allocate memory to hold the array
|
|
if( gpNPCQuoteInfoArray[ ubNpcId ] == NULL )
|
|
{
|
|
gpNPCQuoteInfoArray[ ubNpcId ] = (NPCQuoteInfo *) MemAlloc( sizeof( NPCQuoteInfo ) * NUM_NPC_QUOTE_RECORDS );
|
|
if( gpNPCQuoteInfoArray[ ubNpcId ] == NULL )
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
hFile = FileOpen( NPC_TEMP_QUOTE_FILE, FILE_ACCESS_READ | FILE_OPEN_ALWAYS, FALSE );
|
|
if( hFile == 0 )
|
|
{
|
|
//Error opening temp npc quote info
|
|
return( FALSE );
|
|
}
|
|
|
|
//Seek to the correct spot in the file
|
|
FileSeek( hFile, uiSpotInFile * uiSizeOfTempArray, FILE_SEEK_FROM_START );
|
|
|
|
//Save the array to a temp file
|
|
FileRead( hFile, TempNpcQuote, uiSizeOfTempArray, &uiNumBytesRead );
|
|
if( uiNumBytesRead != uiSizeOfTempArray )
|
|
{
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
|
|
//Loop through and build the temp array to save
|
|
for( ubCnt=0; ubCnt<NUM_NPC_QUOTE_RECORDS; ubCnt++ )
|
|
{
|
|
gpNPCQuoteInfoArray[ ubNpcId ][ ubCnt ].fFlags = TempNpcQuote[ ubCnt ].usFlags;
|
|
gpNPCQuoteInfoArray[ ubNpcId ][ ubCnt ].sRequiredItem = TempNpcQuote[ ubCnt ].sRequiredItem;
|
|
gpNPCQuoteInfoArray[ ubNpcId ][ ubCnt ].usGoToGridNo = TempNpcQuote[ ubCnt ].usGoToGridNo;
|
|
}
|
|
|
|
FileClose( hFile );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ChangeNpcToDifferentSector( UINT8 ubNpcId, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ )
|
|
{
|
|
if (gMercProfiles[ ubNpcId ].ubMiscFlags2 & PROFILE_MISC_FLAG2_LEFT_COUNTRY)
|
|
{
|
|
// override location, this person is OUTTA here
|
|
sSectorX = 0;
|
|
sSectorY = 0;
|
|
bSectorZ = 0;
|
|
}
|
|
// Carmen no longer traverses out, he is temporarily removed instead
|
|
|
|
gMercProfiles[ ubNpcId ].sSectorX = sSectorX;
|
|
gMercProfiles[ ubNpcId ].sSectorY = sSectorY;
|
|
gMercProfiles[ ubNpcId ].bSectorZ = bSectorZ;
|
|
|
|
gMercProfiles[ ubNpcId ].fUseProfileInsertionInfo = FALSE;
|
|
|
|
/*
|
|
if (!gMercProfiles[ ubNpcId ].ubMiscFlags2 & PROFILE_MISC_FLAG2_DONT_ADD_TO_SECTOR)
|
|
{
|
|
gMercProfiles[ ubNpcId ].fUseProfileInsertionInfo = PROFILE_DONT_USE_GRIDNO;
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN AddRottingCorpseToUnloadedSectorsRottingCorpseFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ, ROTTING_CORPSE_DEFINITION *pRottingCorpseDef )
|
|
{
|
|
HWFILE hFile;
|
|
UINT32 uiNumberOfCorpses;
|
|
CHAR8 zMapName[ 128 ];
|
|
UINT32 uiNumBytesRead;
|
|
|
|
ROTTING_CORPSE_DEFINITION def;
|
|
std::vector<ROTTING_CORPSE_DEFINITION> corpsedefvector;
|
|
|
|
// Flugente 2018-08-15: the old method of reading and writing in the same file at the same time is faulty.
|
|
// We instead open the existing file if it exists, take it's contents, and write them with the new corpse to a new file
|
|
|
|
GetMapTempFileName( SF_ROTTING_CORPSE_TEMP_FILE_EXISTS, zMapName, sMapX, sMapY, bMapZ );
|
|
|
|
if ( DoesTempFileExistsForMap( SF_ROTTING_CORPSE_TEMP_FILE_EXISTS, sMapX, sMapY, bMapZ ) && FileExists( zMapName ) )
|
|
{
|
|
//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 );
|
|
}
|
|
|
|
// Load the number of Rotting corpses
|
|
FileRead( hFile, &uiNumberOfCorpses, sizeof( UINT32 ), &uiNumBytesRead );
|
|
if ( uiNumBytesRead != sizeof( UINT32 ) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
FileClose( hFile );
|
|
return( FALSE );
|
|
}
|
|
|
|
// load existing corpses
|
|
for ( UINT32 cnt = 0; cnt < uiNumberOfCorpses; ++cnt )
|
|
{
|
|
// Load the Rotting corpses info
|
|
FileRead( hFile, &def, sizeof( ROTTING_CORPSE_DEFINITION ), &uiNumBytesRead );
|
|
if ( uiNumBytesRead != sizeof( ROTTING_CORPSE_DEFINITION ) )
|
|
{
|
|
//Error Writing size of array to disk
|
|
continue;
|
|
}
|
|
|
|
corpsedefvector.push_back( def );
|
|
}
|
|
|
|
FileClose( hFile );
|
|
}
|
|
|
|
corpsedefvector.push_back( *pRottingCorpseDef );
|
|
|
|
// create the file anew
|
|
SaveRottingCorpsesToTempCorpseFile( sMapX, sMapY, bMapZ, corpsedefvector );
|
|
|
|
// Flugente: update number of corpses in this sector
|
|
if ( !bMapZ )
|
|
{
|
|
SECTORINFO *pSectorInfo = &( SectorInfo[SECTOR( sMapX, sMapY )] );
|
|
|
|
if ( pSectorInfo )
|
|
pSectorInfo->usNumCorpses = corpsedefvector.size();
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN SetUnderGroundSectorFlag( INT16 sSectorX, INT16 sSectorY, UINT8 ubSectorZ, UINT32 uiFlagToSet )
|
|
{
|
|
UNDERGROUND_SECTORINFO *pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
//loop through and look for the right underground sector
|
|
while( pTempNode )
|
|
{
|
|
if( ( pTempNode->ubSectorX == (UINT8)sSectorX ) &&
|
|
( pTempNode->ubSectorY == (UINT8)sSectorY ) &&
|
|
( pTempNode->ubSectorZ == ubSectorZ ) )
|
|
{
|
|
//set the flag indicating that ther is a temp item file exists for the sector
|
|
pTempNode->uiFlags |= uiFlagToSet;
|
|
|
|
return( TRUE );
|
|
}
|
|
pTempNode = pTempNode->next;
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN ReSetUnderGroundSectorFlag( INT16 sSectorX, INT16 sSectorY, UINT8 ubSectorZ, UINT32 uiFlagToSet )
|
|
{
|
|
UNDERGROUND_SECTORINFO *pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
//loop through and look for the right underground sector
|
|
while( pTempNode )
|
|
{
|
|
if( ( pTempNode->ubSectorX == (UINT8)sSectorX ) &&
|
|
( pTempNode->ubSectorY == (UINT8)sSectorY ) &&
|
|
( pTempNode->ubSectorZ == ubSectorZ ) )
|
|
{
|
|
//set the flag indicating that ther is a temp item file exists for the sector
|
|
pTempNode->uiFlags &= ~( uiFlagToSet );
|
|
|
|
return( TRUE );
|
|
}
|
|
pTempNode = pTempNode->next;
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN GetUnderGroundSectorFlagStatus( INT16 sSectorX, INT16 sSectorY, UINT8 ubSectorZ, UINT32 uiFlagToCheck )
|
|
{
|
|
UNDERGROUND_SECTORINFO *pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
pTempNode = gpUndergroundSectorInfoHead;
|
|
|
|
//loop through and look for the right underground sector
|
|
while( pTempNode )
|
|
{
|
|
if( ( pTempNode->ubSectorX == (UINT8)sSectorX ) &&
|
|
( pTempNode->ubSectorY == (UINT8)sSectorY ) &&
|
|
( pTempNode->ubSectorZ == ubSectorZ ) )
|
|
{
|
|
//set the flag indicating that ther is a temp item file exists for the sector
|
|
if( pTempNode->uiFlags & uiFlagToCheck )
|
|
return( TRUE );
|
|
else
|
|
return( FALSE );
|
|
}
|
|
pTempNode = pTempNode->next;
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
BOOLEAN SetSectorFlag( INT16 sMapX, INT16 sMapY, UINT8 bMapZ, UINT32 uiFlagToSet )
|
|
{
|
|
if( uiFlagToSet == SF_ALREADY_VISITED )
|
|
{
|
|
|
|
// HEADROCK HAM 3.5: This is no longer required at all.
|
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
// HEADROCK HAM 3.4: Externalized. Hidden facilities listed on the facility array will be
|
|
// added to the sector info now, upon the first visit.
|
|
|
|
/*for(UINT32 cnt=0; (gFacilityLocations[cnt].uiSectorID >= 0 && gFacilityLocations[cnt].uiSectorID <= 256); cnt++ )
|
|
{
|
|
// Does the current record match the current sector?
|
|
if (gFacilityLocations[cnt].uiSectorID == SECTOR( sMapX, sMapY ))
|
|
{
|
|
// Is the current record set to be revealed?
|
|
if (gFacilityLocations[cnt].fHidden == 1)
|
|
{
|
|
// Reveal the facility.
|
|
SectorInfo[ SECTOR( sMapX, sMapY) ].uiFacilitiesFlags |= (1 << (gFacilityLocations[cnt].uiFacilityType - 1));
|
|
}
|
|
}
|
|
}*/
|
|
|
|
|
|
// HEADROCK HAM 3.4: Externalized.
|
|
/*
|
|
// do certain things when particular sectors are visited
|
|
if ( ( sMapX == TIXA_SECTOR_X ) && ( sMapY == TIXA_SECTOR_Y ) )
|
|
{
|
|
// Tixa prison (not seen until Tixa visited)
|
|
SectorInfo[ SEC_J9 ].uiFacilitiesFlags |= SFCF_PRISON;
|
|
}
|
|
|
|
if ( ( sMapX == GUN_RANGE_X ) && ( sMapY == GUN_RANGE_Y ) && ( bMapZ == GUN_RANGE_Z ) )
|
|
{
|
|
// Alma shooting range (not seen until sector visited)
|
|
SectorInfo[ SEC_H13 ].uiFacilitiesFlags |= SFCF_GUN_RANGE;
|
|
SectorInfo[ SEC_H14 ].uiFacilitiesFlags |= SFCF_GUN_RANGE;
|
|
SectorInfo[ SEC_I13 ].uiFacilitiesFlags |= SFCF_GUN_RANGE;
|
|
SectorInfo[ SEC_I14 ].uiFacilitiesFlags |= SFCF_GUN_RANGE;
|
|
}*/
|
|
|
|
if ( !GetSectorFlagStatus( sMapX, sMapY, bMapZ, SF_ALREADY_VISITED ) )
|
|
{
|
|
// increment daily counter of sectors visited
|
|
gStrategicStatus.ubNumNewSectorsVisitedToday++;
|
|
if ( gStrategicStatus.ubNumNewSectorsVisitedToday == NEW_SECTORS_EQUAL_TO_ACTIVITY )
|
|
{
|
|
// visited enough to count as an active day
|
|
UpdateLastDayOfPlayerActivity( (UINT16) GetWorldDay() );
|
|
}
|
|
|
|
for ( UINT8 i = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; i <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; i++ )
|
|
{
|
|
if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife && !(MercPtrs[ i ]->flags.uiStatusFlags & SOLDIER_VEHICLE) && MercPtrs[ i ]->ubProfile != NO_PROFILE &&
|
|
MercPtrs[ i ]->sSectorX == sMapX && MercPtrs[ i ]->sSectorY == sMapY && MercPtrs[ i ]->bSectorZ == bMapZ && !MercPtrs[ i ]->flags.fBetweenSectors &&
|
|
MercPtrs[ i ]->bAssignment != IN_TRANSIT && MercPtrs[ i ]->bAssignment != ASSIGNMENT_DEAD )
|
|
{
|
|
gMercProfiles[ MercPtrs[ i ]->ubProfile ].records.usSectorsDiscovered++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( bMapZ == 0 )
|
|
SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags |= uiFlagToSet;
|
|
else
|
|
SetUnderGroundSectorFlag( sMapX, sMapY, bMapZ, uiFlagToSet );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN ReSetSectorFlag( INT16 sMapX, INT16 sMapY, UINT8 bMapZ, UINT32 uiFlagToSet )
|
|
{
|
|
if( bMapZ == 0 )
|
|
SectorInfo[ SECTOR( sMapX,sMapY) ].uiFlags &= ~( uiFlagToSet );
|
|
else
|
|
ReSetUnderGroundSectorFlag( sMapX, sMapY, bMapZ, uiFlagToSet );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN GetSectorFlagStatus( INT16 sMapX, INT16 sMapY, UINT8 bMapZ, UINT32 uiFlagToSet )
|
|
{
|
|
if( bMapZ == 0 )
|
|
return( (SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFlags & uiFlagToSet ) ? 1 : 0 );
|
|
else
|
|
return( (GetUnderGroundSectorFlagStatus( sMapX, sMapY, bMapZ, uiFlagToSet ) ) ? 1 : 0 );
|
|
}
|
|
|
|
BOOLEAN AddDeadSoldierToUnLoadedSector( INT16 sMapX, INT16 sMapY, UINT8 bMapZ, SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiFlags )
|
|
{
|
|
UINT32 uiNumberOfItems;
|
|
std::vector<WORLDITEM> pWorldItems;//dnl ch75 271013
|
|
UINT8 i;
|
|
UINT8 bCount=0;
|
|
UINT16 uiFlagsForWorldItems=0;
|
|
UINT16 usFlagsForRottingCorpse=0;
|
|
ROTTING_CORPSE_DEFINITION Corpse;
|
|
INT16 sXPos, sYPos;
|
|
UINT32 uiDeathAnim;
|
|
UINT32 uiPossibleDeathAnims[] = { GENERIC_HIT_DEATH,
|
|
FALLBACK_HIT_DEATH,
|
|
PRONE_HIT_DEATH,
|
|
FLYBACK_HIT_DEATH };
|
|
//setup the flags for the items and the rotting corpses
|
|
if( uiFlags & ADD_DEAD_SOLDIER_USE_GRIDNO )
|
|
{
|
|
uiFlagsForWorldItems = 0;
|
|
usFlagsForRottingCorpse = 0;
|
|
}
|
|
|
|
else if( uiFlags & ADD_DEAD_SOLDIER_TO_SWEETSPOT )
|
|
{
|
|
uiFlagsForWorldItems |= WOLRD_ITEM_FIND_SWEETSPOT_FROM_GRIDNO | WORLD_ITEM_REACHABLE;
|
|
usFlagsForRottingCorpse |= ROTTING_CORPSE_FIND_SWEETSPOT_FROM_GRIDNO;
|
|
}
|
|
else
|
|
AssertMsg( 0, "ERROR!! Flag not is Switch statement");
|
|
|
|
//
|
|
//Create an array of objects from the mercs inventory
|
|
//
|
|
|
|
//go through and and find out how many items there are
|
|
uiNumberOfItems = 0;
|
|
UINT8 invsize = pSoldier->inv.size();
|
|
for ( i = 0; i < invsize; ++i )
|
|
{
|
|
if( pSoldier->inv[ i ].exists() == true )
|
|
{
|
|
// Flugente: if we don't want items to drop in autoresolve, this is the place to set that
|
|
if ( pSoldier->bTeam != gbPlayerNum && !gGameExternalOptions.fNPCAutoresolveItemDrop )
|
|
{
|
|
// mark it undroppable...
|
|
pSoldier->inv[i].fFlags |= OBJECT_UNDROPPABLE;
|
|
}
|
|
|
|
//if the item can be dropped
|
|
if( !( pSoldier->inv[ i ].fFlags & OBJECT_UNDROPPABLE ) || pSoldier->bTeam == gbPlayerNum )
|
|
{
|
|
++uiNumberOfItems;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If a robot, don't drop anything...
|
|
if ( AM_A_ROBOT( pSoldier ) )
|
|
{
|
|
uiNumberOfItems = 0;
|
|
}
|
|
|
|
//if there are items to add
|
|
if( uiNumberOfItems )
|
|
{
|
|
//allocate memory for the world item array
|
|
pWorldItems.resize(uiNumberOfItems);//dnl ch75 271013
|
|
|
|
//loop through all the soldiers items and add them to the world item array
|
|
bCount = 0;
|
|
for ( i = 0; i < invsize; ++i )
|
|
{
|
|
if( pSoldier->inv[ i ].exists() == true )
|
|
{
|
|
//if the item can be dropped
|
|
if( !(pSoldier->inv[ i ].fFlags & OBJECT_UNDROPPABLE) || pSoldier->bTeam == gbPlayerNum )
|
|
{
|
|
ReduceAmmoDroppedByNonPlayerSoldiers( pSoldier, i );
|
|
|
|
pWorldItems[ bCount ].fExists = TRUE;
|
|
pWorldItems[ bCount ].sGridNo = sGridNo;
|
|
pWorldItems[ bCount ].ubLevel = (UINT8)pSoldier->pathing.bLevel;
|
|
pWorldItems[ bCount ].usFlags = uiFlagsForWorldItems;
|
|
pWorldItems[ bCount ].bVisible = TRUE;
|
|
pWorldItems[ bCount ].bRenderZHeightAboveLevel = 0;
|
|
|
|
if ( Item[pSoldier->inv[i].usItem].damageable ) // Madd: drop crappier items on higher difficulty levels
|
|
{
|
|
// silversurfer: externalized this
|
|
//pSoldier->inv[i][0]->data.objectStatus -= (gGameOptions.ubDifficultyLevel - 1) * Random(20);
|
|
pSoldier->inv[i][0]->data.objectStatus -= Random( zDiffSetting[gGameOptions.ubDifficultyLevel].usLootStatusModifier );
|
|
pSoldier->inv[i][0]->data.objectStatus = max(pSoldier->inv[i][0]->data.objectStatus,1); // never below 1%
|
|
}
|
|
pWorldItems[ bCount ].object = pSoldier->inv[i];
|
|
++bCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Add the soldiers items to an unloaded sector
|
|
AddWorldItemsToUnLoadedSector( sMapX, sMapY, bMapZ, sGridNo, uiNumberOfItems, pWorldItems, FALSE );
|
|
|
|
//CHRISL: Now that we've copied the dead soldiers items to pWorldItems, we need to actually remove the items from the dead soldier. Otherwise we have
|
|
// actually duplicated the items and there's a chance that these duplicated items will again find their way to sector.
|
|
for ( i = 0; i < invsize; ++i )
|
|
{
|
|
if( pSoldier->inv[ i ].exists() == true )
|
|
{
|
|
pSoldier->inv[i].initialize();
|
|
}
|
|
}
|
|
}
|
|
|
|
DropKeysInKeyRing( pSoldier, sGridNo, pSoldier->pathing.bLevel, 1, FALSE, 0, TRUE );
|
|
|
|
//
|
|
//Convert the soldier into a rottng corpse
|
|
//
|
|
|
|
memset( &Corpse, 0, sizeof( ROTTING_CORPSE_DEFINITION ) );
|
|
|
|
// Setup some values!
|
|
Corpse.ubBodyType = pSoldier->ubBodyType;
|
|
Corpse.sGridNo = sGridNo;
|
|
|
|
ConvertGridNoToXY( sGridNo, &sXPos, &sYPos );
|
|
|
|
Corpse.dXPos = (FLOAT)( CenterX( sXPos ) );
|
|
Corpse.dYPos = (FLOAT)( CenterY( sYPos ) );
|
|
Corpse.sHeightAdjustment = pSoldier->sHeightAdjustment;
|
|
Corpse.bVisible = TRUE;
|
|
|
|
SET_PALETTEREP_ID ( Corpse.HeadPal, pSoldier->HeadPal );
|
|
SET_PALETTEREP_ID ( Corpse.VestPal, pSoldier->VestPal );
|
|
SET_PALETTEREP_ID ( Corpse.SkinPal, pSoldier->SkinPal );
|
|
SET_PALETTEREP_ID ( Corpse.PantsPal, pSoldier->PantsPal );
|
|
|
|
Corpse.ubDirection = pSoldier->ubDirection;
|
|
|
|
// Set time of death
|
|
Corpse.uiTimeOfDeath = GetWorldTotalMin( );
|
|
|
|
//if the dead body shot be the result of a Jfk headshot, set it
|
|
if( uiFlags & ADD_DEAD_SOLDIER__USE_JFK_HEADSHOT_CORPSE )
|
|
uiDeathAnim = JFK_HITDEATH;
|
|
|
|
//else chose a random death sequence
|
|
else
|
|
uiDeathAnim = uiPossibleDeathAnims[ Random( 4 ) ];
|
|
|
|
|
|
// Set type
|
|
Corpse.ubType = (UINT8)gubAnimSurfaceCorpseID[ pSoldier->ubBodyType][ uiDeathAnim ];
|
|
|
|
Corpse.usFlags |= usFlagsForRottingCorpse;
|
|
|
|
//Add the rotting corpse info to the sectors unloaded rotting corpse file
|
|
AddRottingCorpseToUnloadedSectorsRottingCorpseFile( sMapX, sMapY, bMapZ, &Corpse);
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN SaveTempNpcQuoteArrayToSaveGameFile( HWFILE hFile )
|
|
{
|
|
return( SaveFilesToSavedGame( NPC_TEMP_QUOTE_FILE, hFile ) );
|
|
}
|
|
|
|
BOOLEAN LoadTempNpcQuoteArrayToSaveGameFile( HWFILE hFile )
|
|
{
|
|
return( LoadFilesFromSavedGame( NPC_TEMP_QUOTE_FILE, hFile ) );
|
|
}
|
|
|
|
void TempFileLoadErrorMessageReturnCallback( UINT8 ubRetVal )
|
|
{
|
|
gfProgramIsRunning = FALSE;
|
|
}
|
|
|
|
//if you call this function, make sure you return TRUE (if applicable) to make the game
|
|
//think it succeeded the load. This sets up the dialog for the game exit, after the hacker
|
|
//message appears.
|
|
void InitExitGameDialogBecauseFileHackDetected()
|
|
{
|
|
SGPRect CenteringRect= {0, 0, 639, 479 };
|
|
|
|
// do message box and return
|
|
giErrorMessageBox = DoMessageBox( MSG_BOX_BASIC_STYLE, pAntiHackerString[ ANTIHACKERSTR_EXITGAME ],
|
|
GAME_SCREEN, MSG_BOX_FLAG_OK, TempFileLoadErrorMessageReturnCallback, &CenteringRect );
|
|
}
|
|
|
|
// CHRISL: New Checksum for LBENODE
|
|
UINT32 LBENODEChecksum( LBENODE * pNode )
|
|
{
|
|
UINT32 uiChecksum = 1;
|
|
UINT32 uiLoop;
|
|
|
|
uiChecksum += (pNode->lbeClass + 1);
|
|
uiChecksum *= (pNode->lbeIndex +1);
|
|
uiChecksum += (pNode->ubID +1);
|
|
|
|
UINT32 invsize = pNode->inv.size();
|
|
for ( uiLoop = 0; uiLoop < invsize; ++uiLoop )
|
|
{
|
|
uiChecksum += pNode->inv[ uiLoop ].usItem;
|
|
}
|
|
|
|
return( uiChecksum );
|
|
}
|
|
|
|
|
|
//UINT8 gubEncryptionArray4[ BASE_NUMBER_OF_ROTATION_ARRAYS * 3 ][ NEW_ROTATION_ARRAY_SIZE ] =
|
|
UINT8 * GetRotationArray( void )
|
|
{
|
|
// based on guiJA2EncryptionSet
|
|
if ( guiJA2EncryptionSet < BASE_NUMBER_OF_ROTATION_ARRAYS * 6 )
|
|
{
|
|
if ( guiJA2EncryptionSet < BASE_NUMBER_OF_ROTATION_ARRAYS * 3 )
|
|
{
|
|
return( gubEncryptionArray1[ guiJA2EncryptionSet % (BASE_NUMBER_OF_ROTATION_ARRAYS * 3) ]);
|
|
}
|
|
else
|
|
{
|
|
return( gubEncryptionArray2[ guiJA2EncryptionSet % (BASE_NUMBER_OF_ROTATION_ARRAYS * 3) ]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( guiJA2EncryptionSet < BASE_NUMBER_OF_ROTATION_ARRAYS * 9 )
|
|
{
|
|
return( gubEncryptionArray3[ guiJA2EncryptionSet % (BASE_NUMBER_OF_ROTATION_ARRAYS * 3) ]);
|
|
}
|
|
else
|
|
{
|
|
return( gubEncryptionArray4[ guiJA2EncryptionSet % (BASE_NUMBER_OF_ROTATION_ARRAYS * 3) ]);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN NewJA2EncryptedFileRead( HWFILE hFile, PTR pDest, UINT32 uiBytesToRead, UINT32 *puiBytesRead )
|
|
{
|
|
UINT32 uiLoop;
|
|
UINT8 ubArrayIndex = 0;
|
|
UINT8 ubLastByte = 0;
|
|
UINT8 ubLastByteForNextLoop;
|
|
BOOLEAN fRet;
|
|
UINT8 * pMemBlock;
|
|
UINT8 * pubRotationArray;
|
|
|
|
pubRotationArray = GetRotationArray();
|
|
|
|
fRet = FileRead( hFile, pDest, uiBytesToRead, puiBytesRead );
|
|
if ( fRet )
|
|
{
|
|
pMemBlock = (UINT8 *)pDest;
|
|
for ( uiLoop = 0; uiLoop < *puiBytesRead; uiLoop++ )
|
|
{
|
|
ubLastByteForNextLoop = pMemBlock[ uiLoop ];
|
|
pMemBlock[ uiLoop ] -= (ubLastByte + pubRotationArray[ ubArrayIndex ]);
|
|
ubArrayIndex++;
|
|
if ( ubArrayIndex >= NEW_ROTATION_ARRAY_SIZE )
|
|
{
|
|
ubArrayIndex = 0;
|
|
}
|
|
ubLastByte = ubLastByteForNextLoop;
|
|
}
|
|
}
|
|
|
|
return( fRet );
|
|
}
|
|
|
|
|
|
BOOLEAN NewJA2EncryptedFileWrite( HWFILE hFile, PTR pDest, UINT32 uiBytesToWrite, UINT32 *puiBytesWritten )
|
|
{
|
|
UINT32 uiLoop;
|
|
UINT8 ubArrayIndex = 0;
|
|
UINT8 ubLastByte = 0;//, ubTemp;
|
|
UINT8 * pMemBlock;
|
|
BOOLEAN fRet;
|
|
UINT8 * pubRotationArray;
|
|
|
|
pMemBlock = (UINT8 *) MemAlloc( uiBytesToWrite );
|
|
|
|
if ( !pMemBlock )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
memset( pMemBlock, 0, uiBytesToWrite );
|
|
|
|
pubRotationArray = GetRotationArray();
|
|
|
|
memcpy( pMemBlock, pDest, uiBytesToWrite );
|
|
for ( uiLoop = 0; uiLoop < uiBytesToWrite; uiLoop++ )
|
|
{
|
|
pMemBlock[ uiLoop ] += ubLastByte + pubRotationArray[ ubArrayIndex ];
|
|
ubArrayIndex++;
|
|
if ( ubArrayIndex >= NEW_ROTATION_ARRAY_SIZE )
|
|
{
|
|
ubArrayIndex = 0;
|
|
}
|
|
ubLastByte = pMemBlock[ uiLoop ];
|
|
}
|
|
|
|
fRet = FileWrite( hFile, pMemBlock, uiBytesToWrite, puiBytesWritten );
|
|
|
|
MemFree( pMemBlock );
|
|
|
|
return( fRet );
|
|
|
|
}
|
|
|
|
|
|
#define ROTATION_ARRAY_SIZE 46
|
|
UINT8 ubRotationArray[46] = { 132, 235, 125, 99, 15, 220, 140, 89, 205, 132, 254, 144, 217, 78, 156, 58, 215, 76, 163, 187, 55, 49, 65, 48, 156, 140, 201, 68, 184, 13, 45, 69, 102, 185, 122, 225, 23, 250, 160, 220, 114, 240, 64, 175, 057, 233 };
|
|
|
|
BOOLEAN JA2EncryptedFileRead( HWFILE hFile, PTR pDest, UINT32 uiBytesToRead, UINT32 *puiBytesRead )
|
|
{
|
|
UINT32 uiLoop;
|
|
UINT8 ubArrayIndex = 0;
|
|
//UINT8 ubLastNonBlank = 0;
|
|
UINT8 ubLastByte = 0;
|
|
UINT8 ubLastByteForNextLoop;
|
|
BOOLEAN fRet;
|
|
UINT8 * pMemBlock;
|
|
|
|
fRet = FileRead( hFile, pDest, uiBytesToRead, puiBytesRead );
|
|
if ( fRet )
|
|
{
|
|
pMemBlock = (UINT8 *)pDest;
|
|
for ( uiLoop = 0; uiLoop < *puiBytesRead; uiLoop++ )
|
|
{
|
|
ubLastByteForNextLoop = pMemBlock[ uiLoop ];
|
|
pMemBlock[ uiLoop ] -= (ubLastByte + ubRotationArray[ ubArrayIndex ]);
|
|
ubArrayIndex++;
|
|
if ( ubArrayIndex >= ROTATION_ARRAY_SIZE )
|
|
{
|
|
ubArrayIndex = 0;
|
|
}
|
|
ubLastByte = ubLastByteForNextLoop;
|
|
}
|
|
}
|
|
|
|
return( fRet );
|
|
}
|
|
|
|
|
|
BOOLEAN JA2EncryptedFileWrite( HWFILE hFile, PTR pDest, UINT32 uiBytesToWrite, UINT32 *puiBytesWritten )
|
|
{
|
|
UINT32 uiLoop;
|
|
UINT8 ubArrayIndex = 0;
|
|
//UINT8 ubLastNonBlank = 0;
|
|
UINT8 ubLastByte = 0;//, ubTemp;
|
|
UINT8 * pMemBlock;
|
|
BOOLEAN fRet;
|
|
|
|
pMemBlock = (UINT8 *) MemAlloc( uiBytesToWrite );
|
|
|
|
if ( !pMemBlock )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
memset( pMemBlock, 0, uiBytesToWrite );
|
|
|
|
|
|
memcpy( pMemBlock, pDest, uiBytesToWrite );
|
|
for ( uiLoop = 0; uiLoop < uiBytesToWrite; uiLoop++ )
|
|
{
|
|
//ubTemp = pMemBlock[ uiLoop ];
|
|
pMemBlock[ uiLoop ] += ubLastByte + ubRotationArray[ ubArrayIndex ];
|
|
ubArrayIndex++;
|
|
if ( ubArrayIndex >= ROTATION_ARRAY_SIZE )
|
|
{
|
|
ubArrayIndex = 0;
|
|
}
|
|
ubLastByte = pMemBlock[ uiLoop ];
|
|
/*
|
|
if ( pMemBlock[ uiLoop ] )
|
|
{
|
|
// store last non blank
|
|
ubLastNonBlank = pMemBlock[ uiLoop ];
|
|
|
|
pMemBlock[ uiLoop ] += ubRotationArray[ ubArrayIndex ];
|
|
ubArrayIndex++;
|
|
if ( ubArrayIndex >= ROTATION_ARRAY_SIZE )
|
|
{
|
|
ubArrayIndex = 0;
|
|
}
|
|
}
|
|
else // zero byte
|
|
{
|
|
pMemBlock[ uiLoop ] = ubLastNonBlank + ubRotationArray[ ubArrayIndex ];
|
|
ubArrayIndex++;
|
|
if ( ubArrayIndex >= ROTATION_ARRAY_SIZE )
|
|
{
|
|
ubArrayIndex = 0;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
fRet = FileWrite( hFile, pMemBlock, uiBytesToWrite, puiBytesWritten );
|
|
|
|
MemFree( pMemBlock );
|
|
|
|
return( fRet );
|
|
|
|
}
|
|
|
|
void GetMapTempFileName( UINT32 uiType, STR pMapName, INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
|
{
|
|
CHAR zTempName[512];
|
|
|
|
//Convert the current sector location into a file name
|
|
GetMapFileName( sMapX,sMapY, bMapZ, zTempName, FALSE, FALSE );
|
|
|
|
switch( uiType )
|
|
{
|
|
case SF_ITEM_TEMP_FILE_EXISTS:
|
|
sprintf( pMapName, "%s\\i_%s", MAPS_DIR, zTempName);
|
|
break;
|
|
|
|
case SF_ROTTING_CORPSE_TEMP_FILE_EXISTS:
|
|
sprintf( pMapName, "%s\\r_%s", MAPS_DIR, zTempName);
|
|
break;
|
|
|
|
case SF_MAP_MODIFICATIONS_TEMP_FILE_EXISTS:
|
|
sprintf( pMapName, "%s\\m_%s", MAPS_DIR, zTempName);
|
|
break;
|
|
|
|
case SF_DOOR_TABLE_TEMP_FILES_EXISTS:
|
|
sprintf( pMapName, "%s\\d_%s", MAPS_DIR, zTempName);
|
|
break;
|
|
|
|
case SF_REVEALED_STATUS_TEMP_FILE_EXISTS:
|
|
sprintf( pMapName, "%s\\v_%s", MAPS_DIR, zTempName);
|
|
break;
|
|
|
|
case SF_DOOR_STATUS_TEMP_FILE_EXISTS:
|
|
sprintf( pMapName, "%s\\ds_%s", MAPS_DIR, zTempName);
|
|
break;
|
|
|
|
case SF_ENEMY_PRESERVED_TEMP_FILE_EXISTS:
|
|
sprintf( pMapName, "%s\\e_%s", MAPS_DIR, zTempName);
|
|
break;
|
|
|
|
case SF_CIV_PRESERVED_TEMP_FILE_EXISTS:
|
|
// NB save game version 0 is "saving game"
|
|
if ( (gTacticalStatus.uiFlags & LOADING_SAVED_GAME) && guiCurrentSaveGameVersion != 0 && guiCurrentSaveGameVersion < 78 )
|
|
{
|
|
sprintf( pMapName, "%s\\c_%s", MAPS_DIR, zTempName);
|
|
}
|
|
else
|
|
{
|
|
sprintf( pMapName, "%s\\cc_%s", MAPS_DIR, zTempName);
|
|
}
|
|
break;
|
|
|
|
case SF_SMOKE_EFFECTS_TEMP_FILE_EXISTS:
|
|
sprintf( pMapName, "%s\\sm_%s", MAPS_DIR, zTempName);
|
|
break;
|
|
|
|
case SF_LIGHTING_EFFECTS_TEMP_FILE_EXISTS:
|
|
sprintf( pMapName, "%s\\l_%s", MAPS_DIR, zTempName);
|
|
break;
|
|
|
|
default:
|
|
Assert( 0 );
|
|
break;
|
|
}
|
|
}
|
|
|
|
UINT32 GetNumberOfVisibleWorldItemsFromSectorStructureForSector( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
|
{
|
|
UINT32 uiNumberOfItems=0;
|
|
UNDERGROUND_SECTORINFO *pSector=NULL;
|
|
|
|
//if the sector is above ground
|
|
if( bMapZ == 0 )
|
|
{
|
|
uiNumberOfItems = SectorInfo[ SECTOR( sMapX, sMapY ) ].uiNumberOfWorldItemsInTempFileThatCanBeSeenByPlayer;
|
|
}
|
|
else
|
|
{
|
|
//find the underground sector
|
|
pSector = FindUnderGroundSector( sMapX, sMapY, bMapZ );
|
|
if( pSector != NULL )
|
|
{
|
|
//get the number of items
|
|
uiNumberOfItems = pSector->uiNumberOfWorldItemsInTempFileThatCanBeSeenByPlayer;
|
|
}
|
|
}
|
|
|
|
//if there is a sector loaded
|
|
if( gfWorldLoaded )
|
|
{
|
|
//and it is the sector we are interested in
|
|
if( sMapX == gWorldSectorX && sMapY == gWorldSectorY && bMapZ == gbWorldSectorZ )
|
|
{
|
|
//since items might have been added, update
|
|
uiNumberOfItems = UpdateLoadedSectorsItemInventory( sMapX, sMapY, bMapZ, uiNumberOfItems );
|
|
}
|
|
}
|
|
|
|
|
|
return( uiNumberOfItems );
|
|
}
|
|
|
|
void SetNumberOfVisibleWorldItemsInSectorStructureForSector( INT16 sMapX, INT16 sMapY, INT8 bMapZ, UINT32 uiNumberOfItems )
|
|
{
|
|
//if the sector is above ground
|
|
if( bMapZ == 0 )
|
|
{
|
|
SectorInfo[SECTOR( sMapX, sMapY )].uiNumberOfWorldItemsInTempFileThatCanBeSeenByPlayer = uiNumberOfItems;
|
|
}
|
|
else
|
|
{
|
|
//find the underground sector
|
|
UNDERGROUND_SECTORINFO* pSector = FindUnderGroundSector( sMapX, sMapY, bMapZ );
|
|
if( pSector != NULL )
|
|
{
|
|
//get the number of items
|
|
pSector->uiNumberOfWorldItemsInTempFileThatCanBeSeenByPlayer = uiNumberOfItems ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
UINT32 UpdateLoadedSectorsItemInventory( INT16 sMapX, INT16 sMapY, INT8 bMapZ, UINT32 uiNumberOfItems )
|
|
{
|
|
UINT32 uiCounter;
|
|
UINT32 uiItemCounter=0;
|
|
|
|
if( !gfWorldLoaded )
|
|
return( 0 );
|
|
|
|
//loop through all the world items
|
|
for( uiCounter= 0; uiCounter < guiNumWorldItems; uiCounter++ )
|
|
{
|
|
//if the item CAN be visible in mapscreen sector inventory
|
|
if( IsMapScreenWorldItemVisibleInMapInventory( &gWorldItems[ uiCounter ] ) )
|
|
{
|
|
//increment
|
|
uiItemCounter += gWorldItems[ uiCounter ].object.ubNumberOfObjects;
|
|
}
|
|
}
|
|
|
|
//if the item count is DIFFERENT
|
|
if( uiItemCounter != uiNumberOfItems )
|
|
{
|
|
//Update the value in the sector info struct
|
|
SetNumberOfVisibleWorldItemsInSectorStructureForSector( sMapX, sMapY, bMapZ, uiItemCounter );
|
|
}
|
|
|
|
//return the number of items
|
|
return( uiItemCounter );
|
|
}
|
|
|
|
// We no longer use map item temp files except during loading and saving a game to preserve savegame compatibility.
|
|
// LoadWorldItemsFromTempFiles & SaveWorldItemsToTempFiles are used to read and write world items to and from temp files into the global world items struct gAllWorldItems that is used during gameplay
|
|
void LoadWorldItemsFromTempFiles(INT16 sMapX, INT16 sMapY, INT8 bMapZ)
|
|
{
|
|
UINT32 nItems = 0;
|
|
std::vector<WORLDITEM> Items;
|
|
|
|
const BOOLEAN fReturn = GetNumberOfWorldItemsFromTempItemFile(sMapX, sMapY, bMapZ, &(nItems), FALSE);
|
|
if (fReturn == FALSE)
|
|
{
|
|
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("GetNumberOfWorldItemsFromTempItemFile failed"));
|
|
Assert(fReturn);
|
|
}
|
|
|
|
if (nItems > 0)
|
|
{
|
|
Items.resize(nItems);
|
|
LoadWorldItemsFromTempItemFile(sMapX, sMapY, bMapZ, Items);
|
|
UpdateWorldItems(sMapX, sMapY, bMapZ, nItems, Items);
|
|
}
|
|
}
|
|
|
|
void SaveWorldItemsToTempFiles()
|
|
{
|
|
PruneWorldItems();
|
|
for (size_t i = 0; i < gAllWorldItems.sectors.size(); i++)
|
|
{
|
|
const auto x = gAllWorldItems.sectors[i].x;
|
|
const auto y = gAllWorldItems.sectors[i].y;
|
|
const auto z = gAllWorldItems.sectors[i].z;
|
|
const auto nItems = gAllWorldItems.NumItems[i];
|
|
auto Items = gAllWorldItems.Items[i];
|
|
|
|
SaveWorldItemsToTempItemFile(x, y, (INT8)z, nItems, Items);
|
|
}
|
|
}
|