avp/3dc/avp/savegame.c
Rebellion Developments 218ca90543 Import Aliens vs Predator - Gold (Build 116)
Source code release, imported from:
https://www.gamefront.com/games/aliens-vs-predator-3/file/avp-gold-complete-source-code

All text files were converted to Unix format.
2019-08-19 05:45:17 +02:00

1374 lines
No EOL
32 KiB
C

#include "3dc.h"
#include "inline.h"
#include "module.h"
#include "stratdef.h"
#include "gamedef.h"
#include "bh_types.h"
#include "comp_shp.h"
#include "dynblock.h"
#include "bh_alien.h"
#include "pvisible.h"
#include "bh_pred.h"
#include "bh_xeno.h"
#include "bh_paq.h"
#include "bh_queen.h"
#include "bh_marin.h"
#include "bh_fhug.h"
#include "bh_debri.h"
#include "bh_plachier.h"
#include "plat_shp.h"
#include "psnd.h"
#include "lighting.h"
#include "pldnet.h"
#include "bh_dummy.h"
#include "bh_videoscreen.h"
#include "bh_plift.h"
#include "bh_ldoor.h"
#include "AvP_Menus.h"
#include "game_statistics.h"
#include "AvP_UserProfile.h"
#include "savegame.h"
#include "huffman.hpp"
#include "smacker.h"
#define UseLocalAssert Yes
#include "ourasert.h"
static struct
{
char* BufferStart;
char* BufferPos;
int BufferSize;
int BufferSpaceLeft;
int BufferSpaceUsed;
} SaveInfo = {0,0,0,0,0};
static struct
{
char* BufferStart;
char* BufferPos;
int BufferSize;
int BufferSpaceLeft;
} LoadInfo = {0,0,0,0};
int LoadGameRequest = SAVELOAD_REQUEST_NONE; //slot number of game to be loaded
int SaveGameRequest = SAVELOAD_REQUEST_NONE; //slot number of game to be saved
#define NUM_SAVES_FOR_EASY_MODE 8
#define NUM_SAVES_FOR_MEDIUM_MODE 4
#define NUM_SAVES_FOR_HARD_MODE 2
int NumberOfSavesLeft;
static void SaveStrategies();
static void LoadStrategy(SAVE_BLOCK_STRATEGY_HEADER* header);
static void SaveDeadStrategies();
static void LoadDeadStrategy(SAVE_BLOCK_HEADER* block);
static void LoadMiscGlobalStuff(SAVE_BLOCK_HEADER* header);
static void SaveMiscGlobalStuff();
/*---------------------------------------------**
** externs for all the load and save functions **
**---------------------------------------------*/
extern void LoadStrategy_LiftDoor(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_LiftDoor(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_ProxDoor(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_ProxDoor(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_SwitchDoor(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_SwitchDoor(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_PlatformLift(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_PlatformLift(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_BinarySwitch(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_BinarySwitch(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_LinkSwitch(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_LinkSwitch(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Generator(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Generator(STRATEGYBLOCK* sbPtr);
extern void LoadHiveSettings(SAVE_BLOCK_HEADER* header);
extern void SaveHiveSettings();
extern void LoadStrategy_InanimateObject(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_InanimateObject(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_LightFx(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_LightFx(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_PlacedSound(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_PlacedSound(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Message(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Message(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_MissionComplete(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_MissionComplete(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_TrackObject(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_TrackObject(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Fan(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Fan(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_PlacedLight(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_PlacedLight(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_VideoScreen(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_VideoScreen(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_DeathVolume(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_DeathVolume(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_ParticleGenerator(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_ParticleGenerator(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_SelfDestruct(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_SelfDestruct(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Alien(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Alien(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Corpse(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Corpse(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_FaceHugger(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_FaceHugger(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Marine(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Marine(STRATEGYBLOCK* sbPtr);
extern void LoadMarineSquadState(SAVE_BLOCK_HEADER* header);
extern void SaveMarineSquadState();
extern void LoadStrategy_PlacedHierarchy(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_PlacedHierarchy(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Predator(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Predator(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Xenoborg(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Xenoborg(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Queen(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Queen(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Player(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Player(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Autogun(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Autogun(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_HierarchicalDebris(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_HierarchicalDebris(STRATEGYBLOCK* sbPtr);
extern void Load_Decals(SAVE_BLOCK_HEADER* header);
extern void Save_Decals();
extern void Load_Particles(SAVE_BLOCK_HEADER* header);
extern void Save_Particles();
extern void Load_VolumetricExplosions(SAVE_BLOCK_HEADER* header);
extern void Save_VolumetricExplosions();
extern void Load_PheromoneTrails(SAVE_BLOCK_HEADER* header);
extern void Save_PheromoneTrails();
extern void Load_LightElements(SAVE_BLOCK_HEADER* header);
extern void Save_LightElements();
extern void Load_MessageHistory(SAVE_BLOCK_HEADER* header);
extern void Save_MessageHistory();
extern void LoadStrategy_Grenade(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Grenade(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_FlareGrenade(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_FlareGrenade(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_ProxGrenade(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_ProxGrenade(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Rocket(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Rocket(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_PPPlasmaBolt(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_PPPlasmaBolt(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_PredatorEnergyBolt(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_PredatorEnergyBolt(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_PulseGrenade(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_PulseGrenade(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_ClusterGrenade(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_ClusterGrenade(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Molotov(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Molotov(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_PredatorDisc(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_PredatorDisc(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_SpearBolt(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_SpearBolt(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Grapple(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Grapple(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_Debris(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Debris(STRATEGYBLOCK* sbPtr);
extern void LoadLevelHeader(SAVE_BLOCK_HEADER* header);
extern void SaveLevelHeader();
extern void Load_WeaponsCGlobals(SAVE_BLOCK_HEADER* header);
extern void Save_WeaponsCGlobals();
extern void Load_SoundState_NoRef(SAVE_BLOCK_HEADER* header);
extern void Save_SoundsWithNoReference();
extern void LoadStrategy_Frisbee(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_Frisbee(STRATEGYBLOCK* sbPtr);
extern void LoadStrategy_FrisbeeEnergyBolt(SAVE_BLOCK_STRATEGY_HEADER* header);
extern void SaveStrategy_FrisbeeEnergyBolt(STRATEGYBLOCK* sbPtr);
extern int DebuggingCommandsActive;
/*-----------------------------------------------------**
** end of externs for all the load and save functions **
**-----------------------------------------------------*/
extern void DisplaySavesLeft();
/*
Functions for converting between ai modules and their indeces.
They don't really belong here , but they are only used by loading/saving at
the moment.
*/
struct aimodule * GetPointerFromAIModuleIndex(int index)
{
if(index>=0 && index<AIModuleArraySize)
{
return &AIModuleArray[index];
}
else
{
return NULL;
}
}
int GetIndexFromAIModulePointer(struct aimodule* module)
{
if(module)
return module->m_index;
else
return -1;
}
void* GetPointerForSaveBlock(unsigned int size)
{
void* retPointer;
//see if we need to enlarge the buffer to allow for this block
if(size > SaveInfo.BufferSpaceLeft)
{
//need more space
int spaceNeeded = SaveInfo.BufferSpaceUsed + size;
//buffer incremented in lots of 100000 bytes (more or less)
int newBufferSize = ((spaceNeeded /100000)+1)*100000;
//allocate the memory
SaveInfo.BufferStart = (char*) realloc(SaveInfo.BufferStart,newBufferSize);
//correct the position etc.
SaveInfo.BufferPos = SaveInfo.BufferStart + SaveInfo.BufferSpaceUsed;
SaveInfo.BufferSpaceLeft += (newBufferSize - SaveInfo.BufferSize);
SaveInfo.BufferSize = newBufferSize;
}
//get the pointer to the next part of the save buffer
retPointer = (void*)SaveInfo.BufferPos;
SaveInfo.BufferSpaceUsed += size;
SaveInfo.BufferSpaceLeft -= size;
SaveInfo.BufferPos += size;
return retPointer;
}
static void InitSaveGame()
{
SaveInfo.BufferPos = SaveInfo.BufferStart;
SaveInfo.BufferSpaceLeft = SaveInfo.BufferSize;
SaveInfo.BufferSpaceUsed = 0;
}
static BOOL SaveGameAllowed()
{
PLAYER_STATUS *playerStatusPtr;
//can't save in multiplayer (or skirmish)
if(AvP.Network != I_No_Network) return FALSE;
//check player's state
if(!Player) return FALSE;
if(!Player->ObStrategyBlock) return FALSE;
if(!Player->ObStrategyBlock->SBdataptr) return FALSE;
playerStatusPtr = (PLAYER_STATUS*)Player->ObStrategyBlock->SBdataptr;
//player must be alive , and not face hugged
if(!playerStatusPtr->IsAlive) return FALSE;
if(playerStatusPtr->MyFaceHugger) return FALSE;
//cheating?
if(DebuggingCommandsActive || CheatMode_Active!=CHEATMODE_NONACTIVE)
{
NewOnScreenMessage(GetTextString(TEXTSTRING_SAVEGAME_NOTALLOWED));
return FALSE;
}
//now check the number of saves left
//first some validation
if(NumberOfSavesLeft<0) NumberOfSavesLeft =0;
switch(AvP.Difficulty)
{
case I_Easy :
if(NumberOfSavesLeft > NUM_SAVES_FOR_EASY_MODE)
NumberOfSavesLeft = NUM_SAVES_FOR_EASY_MODE;
break;
case I_Medium :
if(NumberOfSavesLeft > NUM_SAVES_FOR_MEDIUM_MODE)
NumberOfSavesLeft = NUM_SAVES_FOR_MEDIUM_MODE;
break;
case I_Hard :
case I_Impossible :
if(NumberOfSavesLeft > NUM_SAVES_FOR_HARD_MODE)
NumberOfSavesLeft = NUM_SAVES_FOR_HARD_MODE;
break;
}
if(!NumberOfSavesLeft)
{
NewOnScreenMessage(GetTextString(TEXTSTRING_SAVEGAME_NOSAVESLEFT));
return FALSE;
}
NumberOfSavesLeft--;
//saving is allowed then
return TRUE;
}
void SaveGame()
{
char filename[100];
HANDLE file;
DWORD bytes_written;
int headerLength;
HuffmanPackage *packagePtr;
//make sure there is a save request
if(SaveGameRequest == SAVELOAD_REQUEST_NONE) return;
if(SaveGameRequest<0 || SaveGameRequest>=NUMBER_OF_SAVE_SLOTS)
{
SaveGameRequest = SAVELOAD_REQUEST_NONE;
return;
}
//check that we are allowed to save at this point
if(!SaveGameAllowed())
{
//cancel request
SaveGameRequest = SAVELOAD_REQUEST_NONE;
return;
}
InitSaveGame();
SaveLevelHeader();
headerLength = SaveInfo.BufferSpaceUsed;
SaveDeadStrategies();
SaveStrategies();
SaveHiveSettings();
SaveMarineSquadState();
SaveMiscGlobalStuff();
Save_SoundsWithNoReference();
//save particles etc.
Save_Decals();
Save_Particles();
Save_VolumetricExplosions();
Save_PheromoneTrails();
Save_LightElements();
Save_MessageHistory();
Save_WeaponsCGlobals();
//get the filename
GetFilenameForSaveSlot(SaveGameRequest,filename);
//clear the save request
SaveGameRequest = SAVELOAD_REQUEST_NONE;
//write the file
file = CreateFile(filename,GENERIC_WRITE, 0, 0, CREATE_ALWAYS,FILE_FLAG_RANDOM_ACCESS, 0);
if (file == INVALID_HANDLE_VALUE)
{
GLOBALASSERT("Error saving file"==0);
return;
}
WriteFile(file,SaveInfo.BufferStart,headerLength,&bytes_written,0);
packagePtr = HuffmanCompression(SaveInfo.BufferStart+headerLength,SaveInfo.BufferSpaceUsed-headerLength);
WriteFile(file,packagePtr,packagePtr->CompressedDataSize+sizeof(HuffmanPackage),&bytes_written,0);
CloseHandle(file);
NewOnScreenMessage(GetTextString(TEXTSTRING_SAVEGAME_GAMESAVED));
DisplaySavesLeft();
}
static void EndLoadGame()
{
if(LoadInfo.BufferStart)
{
DeallocateMem(LoadInfo.BufferStart);
}
LoadInfo.BufferStart = NULL;
LoadInfo.BufferPos = NULL;
LoadInfo.BufferSize = 0;
LoadInfo.BufferSpaceLeft = 0;
}
extern SAVE_SLOT_HEADER SaveGameSlot[];
extern int AlienEpisodeToPlay;
extern int MarineEpisodeToPlay;
extern int PredatorEpisodeToPlay;
BOOL ValidateLevelForLoadGameRequest(SAVE_SLOT_HEADER* save_slot)
{
//see if we will need to change level
if(save_slot->Species != AvP.PlayerType) return FALSE;
//probably need to reload if in cheat mode
if(CheatMode_Active!=CHEATMODE_NONACTIVE) return FALSE;
switch(save_slot->Species)
{
case I_Marine :
if(save_slot->Episode != MarineEpisodeToPlay) return FALSE;;
break;
case I_Alien :
if(save_slot->Episode != AlienEpisodeToPlay) return FALSE;
break;
case I_Predator :
if(save_slot->Episode != PredatorEpisodeToPlay) return FALSE;
break;
}
//certainly need to change level if in multiplayer (or skirmish)
if(AvP.Network != I_No_Network) return FALSE;
return TRUE;
}
void LoadSavedGame()
{
SAVE_SLOT_HEADER* save_slot;
char filename[100];
HANDLE file;
BOOL terminal_error = FALSE;
unsigned int bytes_read;
if(LoadGameRequest == SAVELOAD_REQUEST_NONE) return;
if(LoadGameRequest<0 || LoadGameRequest>=NUMBER_OF_SAVE_SLOTS)
{
LoadGameRequest = SAVELOAD_REQUEST_NONE;
return;
}
//get the save_slot
save_slot = &SaveGameSlot[LoadGameRequest];
//make sure the slot is being used
ScanSaveSlots();
if(!save_slot->SlotUsed) return;
///make sure we're on the right level etc.
if(!ValidateLevelForLoadGameRequest(save_slot))
{
AvP.MainLoopRunning = FALSE;
return;
}
{
extern int GlobalFrameCounter;
if(!GlobalFrameCounter) return;
}
//set the difficulty level and restart the level
AvP.Difficulty = save_slot->Difficulty;
RestartLevel();
//get the filename for the save slot
GetFilenameForSaveSlot(LoadGameRequest,filename);
//we can now clear the load request
LoadGameRequest = SAVELOAD_REQUEST_NONE;
//load the file
file = CreateFile(filename,GENERIC_READ, 0, 0, OPEN_EXISTING,FILE_FLAG_RANDOM_ACCESS, 0);
if(file==INVALID_HANDLE_VALUE)
{
//failed to load
EndLoadGame();
return;
}
LoadInfo.BufferSize = GetFileSize(file,0);
if(!LoadInfo.BufferSize)
{
CloseHandle(file);
EndLoadGame();
return;
}
//allocate buffer , and read file into memory
LoadInfo.BufferStart = (char*) AllocateMem(LoadInfo.BufferSize);
ReadFile(file,LoadInfo.BufferStart,LoadInfo.BufferSize,(LPDWORD)&bytes_read,0);
CloseHandle(file);
LoadInfo.BufferPos = LoadInfo.BufferStart;
LoadInfo.BufferSpaceLeft = LoadInfo.BufferSize;
// attempt to access level header
{
//read the next header
SAVE_BLOCK_HEADER* header = (SAVE_BLOCK_HEADER*) LoadInfo.BufferPos;
if(header->size>LoadInfo.BufferSpaceLeft)
{
//oh dear, dodgy file
GLOBALASSERT("Invalid save game header size"==0);
terminal_error = TRUE;
}
else
{
//go to the next header
LoadInfo.BufferPos += header->size;
LoadInfo.BufferSpaceLeft -= header->size;
switch(header->type)
{
case SaveBlock_MainHeader :
LoadLevelHeader(header);
break;
default:
GLOBALASSERT("Unrecognized save block type"==0);
terminal_error = TRUE;
break;
}
}
}
if (!terminal_error)
{
if (!strncmp (LoadInfo.BufferPos, "REBCRIF1", 8))
{
char *uncompressedBufferPtr = (char*)HuffmanDecompress((HuffmanPackage*)(LoadInfo.BufferPos));
LoadInfo.BufferSpaceLeft = ((HuffmanPackage*)LoadInfo.BufferPos)->UncompressedDataSize;
DeallocateMem(LoadInfo.BufferStart);
LoadInfo.BufferStart=uncompressedBufferPtr;
LoadInfo.BufferPos = LoadInfo.BufferStart;
}
else
{
terminal_error = TRUE;
}
}
//go through loading things
while(LoadInfo.BufferSpaceLeft && !terminal_error)
{
//read the next header
SAVE_BLOCK_HEADER* header = (SAVE_BLOCK_HEADER*) LoadInfo.BufferPos;
if(header->size>LoadInfo.BufferSpaceLeft)
{
//oh dear, dodgy file
GLOBALASSERT("Invalid save game header size"==0);
terminal_error = TRUE;
break;
}
//go to the next header
LoadInfo.BufferPos += header->size;
LoadInfo.BufferSpaceLeft -= header->size;
switch(header->type)
{
case SaveBlock_MainHeader :
LoadLevelHeader(header);
break;
case SaveBlock_DeadStrategy :
LoadDeadStrategy(header);
break;
case SaveBlock_Strategy :
LoadStrategy((SAVE_BLOCK_STRATEGY_HEADER*) header);
break;
case SaveBlock_Track :
//all these should be used up by the various strategy loaders
GLOBALASSERT("Unexpected track save block"==0);
break;
case SaveBlock_Hierarchy :
//all these should be used up by the various strategy loaders
GLOBALASSERT("Unexpected hierarchy save block"==0);
break;
case SaveBlock_HierarchySection :
//all these should be used up by the various strategy loaders
GLOBALASSERT("Unexpected hierarchy section save block"==0);
break;
case SaveBlock_HierarchyTween :
//all these should be used up by the various strategy loaders
GLOBALASSERT("Unexpected hierarchy tween save block"==0);
break;
case SaveBlock_HierarchyDecals :
//all these should be used up by the various strategy loaders
GLOBALASSERT("Unexpected hierarchy decal save block"==0);
break;
case SaveBlock_HierarchyDelta :
//all these should be used up by the various strategy loaders
GLOBALASSERT("Unexpected hierarchy delta save block"==0);
break;
case SaveBlock_GlobalHive :
LoadHiveSettings(header);
break;
case SaveBlock_MiscGlobal :
LoadMiscGlobalStuff(header);
break;
case SaveBlock_MarineSquad :
LoadMarineSquadState(header);
break;
case SaveBlock_Particles :
Load_Particles(header);
break;
case SaveBlock_Decals :
Load_Decals(header);
break;
case SaveBlock_PheromoneTrail :
Load_PheromoneTrails(header);
break;
case SaveBlock_VolumetricExplosions :
Load_VolumetricExplosions(header);
break;
case SaveBlock_LightElements :
Load_LightElements(header);
break;
case SaveBlock_MessageHistory :
Load_MessageHistory(header);
break;
case SaveBlock_WeaponsCGlobals :
Load_WeaponsCGlobals(header);
break;
case SaveBlock_SoundState :
Load_SoundState_NoRef(header);
break;
default :
GLOBALASSERT("Unrecognized save block type"==0);
terminal_error = TRUE;
break;
}
}
if(terminal_error)
{
//the save file was screwed , restart the level to be on the safe side
RestartLevel();
NewOnScreenMessage(GetTextString(TEXTSTRING_SAVEGAME_ERRORLOADING));
}
EndLoadGame();
RemoveDestroyedStrategyBlocks();
//make sure all the containing modules are set properly
{
extern int NumActiveStBlocks;
extern STRATEGYBLOCK *ActiveStBlockList[];
int sbIndex = 0;
STRATEGYBLOCK *sbPtr;
/* loop thro' the strategy block list, looking for objects that need to have
their visibilities managed ... */
while(sbIndex < NumActiveStBlocks)
{
sbPtr = ActiveStBlockList[sbIndex++];
if(sbPtr->maintainVisibility && sbPtr->DynPtr)
{
MODULE* newModule;
newModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (sbPtr->containingModule));
if(newModule) sbPtr->containingModule = newModule;
}
}
}
AllNewModuleHandler();
DoObjectVisibilities();
ResetFrameCounter();
if(!terminal_error)
{
NewOnScreenMessage(GetTextString(TEXTSTRING_SAVEGAME_GAMELOADED));
DisplaySavesLeft();
}
}
SAVE_BLOCK_HEADER* GetNextBlockIfOfType(SAVE_BLOCK_TYPE type)
{
SAVE_BLOCK_HEADER* header;
GLOBALASSERT(LoadInfo.BufferPos);
if(LoadInfo.BufferSpaceLeft==0)
{
//no more blocks left
return 0;
}
//look at the next header in the buffer
header = (SAVE_BLOCK_HEADER*) LoadInfo.BufferPos;
if(header->size>LoadInfo.BufferSpaceLeft)
{
//oh dear, dodgy file
GLOBALASSERT("Invalid save game header size"==0);
return 0;
}
//see if the header is of the type that we are after
if(header->type == type)
{
//okay , advance the buffer position , and return this header
LoadInfo.BufferPos += header->size;
LoadInfo.BufferSpaceLeft -= header->size;
return header;
}
else
{
//out of luck
return 0;
}
}
static void SaveStrategies()
{
int i;
for(i=0;i<NumActiveStBlocks;i++)
{
STRATEGYBLOCK* sbPtr = ActiveStBlockList[i];
switch(sbPtr->I_SBtype)
{
case I_BehaviourMarinePlayer :
SaveStrategy_Player(sbPtr);
break;
case I_BehaviourLiftDoor :
SaveStrategy_LiftDoor(sbPtr);
break;
case I_BehaviourProximityDoor :
SaveStrategy_ProxDoor(sbPtr);
break;
case I_BehaviourSwitchDoor :
SaveStrategy_SwitchDoor(sbPtr);
break;
case I_BehaviourPlatform :
SaveStrategy_PlatformLift(sbPtr);
break;
case I_BehaviourBinarySwitch :
SaveStrategy_BinarySwitch(sbPtr);
break;
case I_BehaviourLinkSwitch :
SaveStrategy_LinkSwitch(sbPtr);
break;
case I_BehaviourGenerator :
SaveStrategy_Generator(sbPtr);
break;
case I_BehaviourInanimateObject :
SaveStrategy_InanimateObject(sbPtr);
break;
case I_BehaviourLightFX :
SaveStrategy_LightFx(sbPtr);
break;
case I_BehaviourPlacedSound :
SaveStrategy_PlacedSound(sbPtr);
break;
case I_BehaviourMessage :
SaveStrategy_Message(sbPtr);
break;
case I_BehaviourMissionComplete :
SaveStrategy_MissionComplete(sbPtr);
break;
case I_BehaviourTrackObject :
SaveStrategy_TrackObject(sbPtr);
break;
case I_BehaviourFan :
SaveStrategy_Fan(sbPtr);
break;
case I_BehaviourPlacedLight :
SaveStrategy_PlacedLight(sbPtr);
break;
case I_BehaviourVideoScreen :
SaveStrategy_VideoScreen(sbPtr);
break;
case I_BehaviourSelfDestruct :
SaveStrategy_SelfDestruct(sbPtr);
break;
case I_BehaviourParticleGenerator :
SaveStrategy_ParticleGenerator(sbPtr);
break;
case I_BehaviourDeathVolume :
SaveStrategy_DeathVolume(sbPtr);
break;
case I_BehaviourAlien :
SaveStrategy_Alien(sbPtr);
break;
case I_BehaviourNetCorpse :
SaveStrategy_Corpse(sbPtr);
break;
case I_BehaviourFaceHugger :
SaveStrategy_FaceHugger(sbPtr);
break;
case I_BehaviourMarine :
SaveStrategy_Marine(sbPtr);
break;
case I_BehaviourPlacedHierarchy :
SaveStrategy_PlacedHierarchy(sbPtr);
break;
case I_BehaviourPredator :
SaveStrategy_Predator(sbPtr);
break;
case I_BehaviourXenoborg :
SaveStrategy_Xenoborg(sbPtr);
break;
case I_BehaviourQueenAlien :
SaveStrategy_Queen(sbPtr);
break;
case I_BehaviourAutoGun :
SaveStrategy_Autogun(sbPtr);
break;
case I_BehaviourHierarchicalFragment :
SaveStrategy_HierarchicalDebris(sbPtr);
break;
case I_BehaviourGrenade :
SaveStrategy_Grenade(sbPtr);
break;
case I_BehaviourFlareGrenade :
SaveStrategy_FlareGrenade(sbPtr);
break;
case I_BehaviourProximityGrenade :
SaveStrategy_ProxGrenade(sbPtr);
break;
case I_BehaviourRocket :
SaveStrategy_Rocket(sbPtr);
break;
case I_BehaviourPPPlasmaBolt :
SaveStrategy_PPPlasmaBolt(sbPtr);
break;
case I_BehaviourPredatorEnergyBolt :
SaveStrategy_PredatorEnergyBolt(sbPtr);
break;
case I_BehaviourFrisbeeEnergyBolt :
SaveStrategy_FrisbeeEnergyBolt(sbPtr);
break;
case I_BehaviourPulseGrenade :
SaveStrategy_PulseGrenade(sbPtr);
break;
case I_BehaviourClusterGrenade :
SaveStrategy_ClusterGrenade(sbPtr);
break;
case I_BehaviourMolotov :
SaveStrategy_Molotov(sbPtr);
break;
case I_BehaviourPredatorDisc_SeekTrack :
SaveStrategy_PredatorDisc(sbPtr);
break;
case I_BehaviourSpeargunBolt :
SaveStrategy_SpearBolt(sbPtr);
break;
case I_BehaviourGrapplingHook :
SaveStrategy_Grapple(sbPtr);
break;
case I_BehaviourFragment :
SaveStrategy_Debris(sbPtr);
break;
case I_BehaviourFrisbee :
SaveStrategy_Frisbee(sbPtr);
break;
}
}
}
static void LoadStrategy(SAVE_BLOCK_STRATEGY_HEADER* header)
{
switch(header->bhvr_type)
{
case I_BehaviourMarinePlayer :
LoadStrategy_Player(header);
break;
case I_BehaviourLiftDoor :
LoadStrategy_LiftDoor(header);
break;
case I_BehaviourProximityDoor :
LoadStrategy_ProxDoor(header);
break;
case I_BehaviourSwitchDoor :
LoadStrategy_SwitchDoor(header);
break;
case I_BehaviourPlatform :
LoadStrategy_PlatformLift(header);
break;
case I_BehaviourBinarySwitch :
LoadStrategy_BinarySwitch(header);
break;
case I_BehaviourLinkSwitch :
LoadStrategy_LinkSwitch(header);
break;
case I_BehaviourGenerator :
LoadStrategy_Generator(header);
break;
case I_BehaviourInanimateObject :
LoadStrategy_InanimateObject(header);
break;
case I_BehaviourLightFX :
LoadStrategy_LightFx(header);
break;
case I_BehaviourPlacedSound :
LoadStrategy_PlacedSound(header);
break;
case I_BehaviourMessage :
LoadStrategy_Message(header);
break;
case I_BehaviourMissionComplete :
LoadStrategy_MissionComplete(header);
break;
case I_BehaviourTrackObject :
LoadStrategy_TrackObject(header);
break;
case I_BehaviourFan :
LoadStrategy_Fan(header);
break;
case I_BehaviourPlacedLight :
LoadStrategy_PlacedLight(header);
break;
case I_BehaviourVideoScreen :
LoadStrategy_VideoScreen(header);
break;
case I_BehaviourSelfDestruct :
LoadStrategy_SelfDestruct(header);
break;
case I_BehaviourParticleGenerator :
LoadStrategy_ParticleGenerator(header);
break;
case I_BehaviourDeathVolume :
LoadStrategy_DeathVolume(header);
break;
case I_BehaviourAlien :
LoadStrategy_Alien(header);
break;
case I_BehaviourNetCorpse :
LoadStrategy_Corpse(header);
break;
case I_BehaviourFaceHugger :
LoadStrategy_FaceHugger(header);
break;
case I_BehaviourMarine :
LoadStrategy_Marine(header);
break;
case I_BehaviourPlacedHierarchy :
LoadStrategy_PlacedHierarchy(header);
break;
case I_BehaviourPredator :
LoadStrategy_Predator(header);
break;
case I_BehaviourXenoborg :
LoadStrategy_Xenoborg(header);
break;
case I_BehaviourQueenAlien :
LoadStrategy_Queen(header);
break;
case I_BehaviourAutoGun :
LoadStrategy_Autogun(header);
break;
case I_BehaviourHierarchicalFragment :
LoadStrategy_HierarchicalDebris(header);
break;
case I_BehaviourGrenade :
LoadStrategy_Grenade(header);
break;
case I_BehaviourFlareGrenade :
LoadStrategy_FlareGrenade(header);
break;
case I_BehaviourProximityGrenade :
LoadStrategy_ProxGrenade(header);
break;
case I_BehaviourRocket :
LoadStrategy_Rocket(header);
break;
case I_BehaviourPPPlasmaBolt :
LoadStrategy_PPPlasmaBolt(header);
break;
case I_BehaviourPredatorEnergyBolt :
LoadStrategy_PredatorEnergyBolt(header);
break;
case I_BehaviourFrisbeeEnergyBolt :
LoadStrategy_FrisbeeEnergyBolt(header);
break;
case I_BehaviourPulseGrenade :
LoadStrategy_PulseGrenade(header);
break;
case I_BehaviourClusterGrenade :
LoadStrategy_ClusterGrenade(header);
break;
case I_BehaviourMolotov :
LoadStrategy_Molotov(header);
break;
case I_BehaviourPredatorDisc_SeekTrack :
LoadStrategy_PredatorDisc(header);
break;
case I_BehaviourSpeargunBolt :
LoadStrategy_SpearBolt(header);
break;
case I_BehaviourGrapplingHook :
LoadStrategy_Grapple(header);
break;
case I_BehaviourFragment :
LoadStrategy_Debris(header);
break;
case I_BehaviourFrisbee :
LoadStrategy_Frisbee(header);
break;
}
}
/*------------------------------------**
** Loading and saving dead strategies **
**------------------------------------*/
typedef struct dead_strategy_save_block
{
SAVE_BLOCK_HEADER header;
char SBname[SB_NAME_LENGTH];
}DEAD_STRATEGY_SAVE_BLOCK;
static void SaveDeadStrategies()
{
extern STRATEGYBLOCK FreeStBlockData[];
int i;
STRATEGYBLOCK* sbPtr = &FreeStBlockData[0];
//search for all the strategies that existed at the start , and have been destroyed
for(i=0;i<maxstblocks;i++ , sbPtr++)
{
if(sbPtr->SBflags.destroyed_but_preserved)
{
DEAD_STRATEGY_SAVE_BLOCK* block;
GET_SAVE_BLOCK_POINTER(block);
block->header.type = SaveBlock_DeadStrategy;
block->header.size = sizeof(*block);
COPY_NAME(block->SBname,sbPtr->SBname);
}
}
}
static void LoadDeadStrategy(SAVE_BLOCK_HEADER* header)
{
DEAD_STRATEGY_SAVE_BLOCK* block = (DEAD_STRATEGY_SAVE_BLOCK*) header;
STRATEGYBLOCK* sbPtr = FindSBWithName(block->SBname);
if(sbPtr)
{
DestroyAnyStrategyBlock(sbPtr);
}
}
/*--------------------------------------------------------------------------------**
** Loading and saving miscellaneos global rubbish that has nowhere else to live **
**--------------------------------------------------------------------------------*/
extern unsigned int IncrementalSBname;
extern int PlayersMaxHeightWhilstNotInContactWithGround;
typedef struct misc_global_save_block
{
SAVE_BLOCK_HEADER header;
unsigned int IncrementalSBname;
AvP_GameStats CurrentGameStatistics;
int PlayersMaxHeightWhilstNotInContactWithGround;
int NumberOfSavesLeft;
int FMV_MessageNumber;
int FMV_FrameNumber;
}MISC_GLOBAL_SAVE_BLOCK;
static void LoadMiscGlobalStuff(SAVE_BLOCK_HEADER* header)
{
MISC_GLOBAL_SAVE_BLOCK* block;
block = (MISC_GLOBAL_SAVE_BLOCK*) header;
if(block->header.size != sizeof(*block)) return;
IncrementalSBname = block->IncrementalSBname;
CurrentGameStatistics = block->CurrentGameStatistics;
PlayersMaxHeightWhilstNotInContactWithGround = block->PlayersMaxHeightWhilstNotInContactWithGround;
NumberOfSavesLeft = block-> NumberOfSavesLeft;
StartFMVAtFrame(block->FMV_MessageNumber,block->FMV_FrameNumber);
}
static void SaveMiscGlobalStuff()
{
MISC_GLOBAL_SAVE_BLOCK* block;
block = GetPointerForSaveBlock(sizeof(*block));
//fill in the header
block->header.type = SaveBlock_MiscGlobal;
block->header.size = sizeof(*block);
block->IncrementalSBname = IncrementalSBname;
block->CurrentGameStatistics = CurrentGameStatistics;
block->PlayersMaxHeightWhilstNotInContactWithGround = PlayersMaxHeightWhilstNotInContactWithGround;
block->NumberOfSavesLeft = NumberOfSavesLeft;
GetFMVInformation(&block->FMV_MessageNumber,&block->FMV_FrameNumber);
}
extern void DisplaySavesLeft()
{
char text [100];
sprintf(text, "%s: %d",GetTextString(TEXTSTRING_SAVEGAME_SAVESLEFT),NumberOfSavesLeft);
NewOnScreenMessage(text);
}
extern void ResetNumberOfSaves()
{
switch(AvP.Difficulty)
{
case I_Easy :
NumberOfSavesLeft = NUM_SAVES_FOR_EASY_MODE;
break;
case I_Medium :
NumberOfSavesLeft = NUM_SAVES_FOR_MEDIUM_MODE;
break;
case I_Hard :
case I_Impossible :
NumberOfSavesLeft = NUM_SAVES_FOR_HARD_MODE;
break;
}
}