#include "Types.h" #include "MemMan.h" #include "message.h" #include "Items.h" #include "Handle Items.h" #include "StrategicMap.h" #include "Tactical Save.h" #include #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" #include "Animation Control.h" #include 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 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& 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& 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 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& pWorldItem, BOOLEAN fOverWrite) { UINT32 uiLoop; UINT32 uiLastItemPos; UINT32 uiNumberOfItems; std::vector 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 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); PruneWorldItems(); std::vector 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 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 ) { EraseDirectory( MAPS_DIR ); 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 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::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= 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; cntubQuoteActionID = 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 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 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! ConvertGridNoToCenterCellXY(sGridNo, &sXPos, &sYPos); Corpse.ubBodyType = pSoldier->ubBodyType; Corpse.sGridNo = sGridNo; Corpse.dXPos = (FLOAT)( sXPos ); Corpse.dYPos = (FLOAT)( 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 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() { 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); } }