📄 sv_save.c
字号:
//**************************************************************************//**//** sv_save.c : Heretic 2 : Raven Software, Corp.//**//** $RCSfile: sv_save.c,v $//** $Revision: 1.36 $//** $Date: 95/10/17 00:10:02 $//** $Author: bgokey $//**//**************************************************************************// HEADER FILES ------------------------------------------------------------#include "h2def.h"#include "p_local.h"// MACROS ------------------------------------------------------------------#define MAX_TARGET_PLAYERS 512#define MOBJ_NULL -1#define MOBJ_XX_PLAYER -2#define GET_BYTE (*SavePtr.b++)#define GET_WORD (*SavePtr.w++)#define GET_LONG (*SavePtr.l++)#define MAX_MAPS 99#define BASE_SLOT 6#define REBORN_SLOT 7#define REBORN_DESCRIPTION "TEMP GAME"#define MAX_THINKER_SIZE 256// TYPES -------------------------------------------------------------------typedef enum{ ASEG_GAME_HEADER = 101, ASEG_MAP_HEADER, ASEG_WORLD, ASEG_POLYOBJS, ASEG_MOBJS, ASEG_THINKERS, ASEG_SCRIPTS, ASEG_PLAYERS, ASEG_SOUNDS, ASEG_MISC, ASEG_END} gameArchiveSegment_t;typedef enum{ TC_NULL, TC_MOVE_CEILING, TC_VERTICAL_DOOR, TC_MOVE_FLOOR, TC_PLAT_RAISE, TC_INTERPRET_ACS, TC_FLOOR_WAGGLE, TC_LIGHT, TC_PHASE, TC_BUILD_PILLAR, TC_ROTATE_POLY, TC_MOVE_POLY, TC_POLY_DOOR} thinkClass_t;typedef struct{ thinkClass_t tClass; think_t thinkerFunc; void (*mangleFunc)(); void (*restoreFunc)(); size_t size;} thinkInfo_t;typedef struct{ thinker_t thinker; sector_t *sector;} ssthinker_t;// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------void P_SpawnPlayer(mapthing_t *mthing);// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------static void ArchiveWorld(void);static void UnarchiveWorld(void);static void ArchivePolyobjs(void);static void UnarchivePolyobjs(void);static void ArchiveMobjs(void);static void UnarchiveMobjs(void);static void ArchiveThinkers(void);static void UnarchiveThinkers(void);static void ArchiveScripts(void);static void UnarchiveScripts(void);static void ArchivePlayers(void);static void UnarchivePlayers(void);static void ArchiveSounds(void);static void UnarchiveSounds(void);static void ArchiveMisc(void);static void UnarchiveMisc(void);static void SetMobjArchiveNums(void);static void RemoveAllThinkers(void);static void MangleMobj(mobj_t *mobj);static void RestoreMobj(mobj_t *mobj);static int GetMobjNum(mobj_t *mobj);static void SetMobjPtr(int *archiveNum);static void MangleSSThinker(ssthinker_t *sst);static void RestoreSSThinker(ssthinker_t *sst);static void RestoreSSThinkerNoSD(ssthinker_t *sst);static void MangleScript(acs_t *script);static void RestoreScript(acs_t *script);static void RestorePlatRaise(plat_t *plat);static void RestoreMoveCeiling(ceiling_t *ceiling);static void AssertSegment(gameArchiveSegment_t segType);static void ClearSaveSlot(int slot);static void CopySaveSlot(int sourceSlot, int destSlot);static void CopyFile(char *sourceName, char *destName);static boolean ExistingFile(char *name);static void OpenStreamOut(char *fileName);static void CloseStreamOut(void);static void StreamOutBuffer(void *buffer, int size);static void StreamOutByte(byte val);static void StreamOutWord(unsigned short val);static void StreamOutLong(unsigned int val);// EXTERNAL DATA DECLARATIONS ----------------------------------------------extern int ACScriptCount;extern byte *ActionCodeBase;extern acsInfo_t *ACSInfo;// PUBLIC DATA DEFINITIONS -------------------------------------------------char *SavePath;// PRIVATE DATA DEFINITIONS ------------------------------------------------static int MobjCount;static mobj_t **MobjList;static int **TargetPlayerAddrs;static int TargetPlayerCount;static byte *SaveBuffer;static boolean SavingPlayers;static union{ byte *b; short *w; int *l;} SavePtr;static FILE *SavingFP;// This list has been prioritized using frequency estimatesstatic thinkInfo_t ThinkerInfo[] ={ { TC_MOVE_FLOOR, T_MoveFloor, MangleSSThinker, RestoreSSThinker, sizeof(floormove_t) }, { TC_PLAT_RAISE, T_PlatRaise, MangleSSThinker, RestorePlatRaise, sizeof(plat_t) }, { TC_MOVE_CEILING, T_MoveCeiling, MangleSSThinker, RestoreMoveCeiling, sizeof(ceiling_t) }, { TC_LIGHT, T_Light, MangleSSThinker, RestoreSSThinkerNoSD, sizeof(light_t) }, { TC_VERTICAL_DOOR, T_VerticalDoor, MangleSSThinker, RestoreSSThinker, sizeof(vldoor_t) }, { TC_PHASE, T_Phase, MangleSSThinker, RestoreSSThinkerNoSD, sizeof(phase_t) }, { TC_INTERPRET_ACS, T_InterpretACS, MangleScript, RestoreScript, sizeof(acs_t) }, { TC_ROTATE_POLY, T_RotatePoly, NULL, NULL, sizeof(polyevent_t) }, { TC_BUILD_PILLAR, T_BuildPillar, MangleSSThinker, RestoreSSThinker, sizeof(pillar_t) }, { TC_MOVE_POLY, T_MovePoly, NULL, NULL, sizeof(polyevent_t) }, { TC_POLY_DOOR, T_PolyDoor, NULL, NULL, sizeof(polydoor_t) }, { TC_FLOOR_WAGGLE, T_FloorWaggle, MangleSSThinker, RestoreSSThinker, sizeof(floorWaggle_t) }, { // Terminator TC_NULL, NULL, NULL, NULL, 0 }};// CODE --------------------------------------------------------------------//==========================================================================//// SV_SaveGame////==========================================================================void SV_SaveGame(int slot, char *description){ char fileName[100]; char versionText[HXS_VERSION_TEXT_LENGTH]; // Open the output file sprintf(fileName, "%shex6.hxs", SavePath); OpenStreamOut(fileName); // Write game save description StreamOutBuffer(description, HXS_DESCRIPTION_LENGTH); // Write version info memset(versionText, 0, HXS_VERSION_TEXT_LENGTH); strcpy(versionText, HXS_VERSION_TEXT); StreamOutBuffer(versionText, HXS_VERSION_TEXT_LENGTH); // Place a header marker StreamOutLong(ASEG_GAME_HEADER); // Write current map and difficulty StreamOutByte(gamemap); StreamOutByte(gameskill); // Write global script info StreamOutBuffer(WorldVars, sizeof(WorldVars)); StreamOutBuffer(ACSStore, sizeof(ACSStore)); ArchivePlayers(); // Place a termination marker StreamOutLong(ASEG_END); // Close the output file CloseStreamOut(); // Save out the current map SV_SaveMap(true); // true = save player info // Clear all save files at destination slot ClearSaveSlot(slot); // Copy base slot to destination slot CopySaveSlot(BASE_SLOT, slot);}//==========================================================================//// SV_SaveMap////==========================================================================void SV_SaveMap(boolean savePlayers){ char fileName[100]; SavingPlayers = savePlayers; // Open the output file sprintf(fileName, "%shex6%02d.hxs", SavePath, gamemap); OpenStreamOut(fileName); // Place a header marker StreamOutLong(ASEG_MAP_HEADER); // Write the level timer StreamOutLong(leveltime); // Set the mobj archive numbers SetMobjArchiveNums(); ArchiveWorld(); ArchivePolyobjs(); ArchiveMobjs(); ArchiveThinkers(); ArchiveScripts(); ArchiveSounds(); ArchiveMisc(); // Place a termination marker StreamOutLong(ASEG_END); // Close the output file CloseStreamOut();}//==========================================================================//// SV_LoadGame////==========================================================================void SV_LoadGame(int slot){ int i; char fileName[100]; player_t playerBackup[MAXPLAYERS]; mobj_t *mobj; // Copy all needed save files to the base slot if(slot != BASE_SLOT) { ClearSaveSlot(BASE_SLOT); CopySaveSlot(slot, BASE_SLOT); } // Create the name sprintf(fileName, "%shex6.hxs", SavePath); // Load the file M_ReadFile(fileName, &SaveBuffer); // Set the save pointer and skip the description field SavePtr.b = SaveBuffer+HXS_DESCRIPTION_LENGTH; // Check the version text if(strcmp(SavePtr.b, HXS_VERSION_TEXT)) { // Bad version return; } SavePtr.b += HXS_VERSION_TEXT_LENGTH; AssertSegment(ASEG_GAME_HEADER); gameepisode = 1; gamemap = GET_BYTE; gameskill = GET_BYTE; // Read global script info memcpy(WorldVars, SavePtr.b, sizeof(WorldVars)); SavePtr.b += sizeof(WorldVars); memcpy(ACSStore, SavePtr.b, sizeof(ACSStore)); SavePtr.b += sizeof(ACSStore); // Read the player structures UnarchivePlayers(); AssertSegment(ASEG_END); Z_Free(SaveBuffer); // Save player structs for(i = 0; i < MAXPLAYERS; i++) { playerBackup[i] = players[i]; } // Load the current map SV_LoadMap(); // Don't need the player mobj relocation info for load game Z_Free(TargetPlayerAddrs); // Restore player structs inv_ptr = 0; curpos = 0; for(i = 0; i < MAXPLAYERS; i++) { mobj = players[i].mo; players[i] = playerBackup[i]; players[i].mo = mobj; if(i == consoleplayer) { players[i].readyArtifact = players[i].inventory[inv_ptr].type; } }}//==========================================================================//// SV_UpdateRebornSlot//// Copies the base slot to the reborn slot.////==========================================================================void SV_UpdateRebornSlot(void){ ClearSaveSlot(REBORN_SLOT); CopySaveSlot(BASE_SLOT, REBORN_SLOT);}//==========================================================================//// SV_ClearRebornSlot////==========================================================================void SV_ClearRebornSlot(void){ ClearSaveSlot(REBORN_SLOT);}//==========================================================================//// SV_MapTeleport////==========================================================================void SV_MapTeleport(int map, int position){ int i; int j; char fileName[100]; player_t playerBackup[MAXPLAYERS]; mobj_t *targetPlayerMobj; mobj_t *mobj; int inventoryPtr; int currentInvPos; boolean rClass; boolean playerWasReborn; boolean oldWeaponowned[NUMWEAPONS]; int oldKeys; int oldPieces; int bestWeapon; if(!deathmatch) { if(P_GetMapCluster(gamemap) == P_GetMapCluster(map)) { // Same cluster - save map without saving player mobjs SV_SaveMap(false); } else { // Entering new cluster - clear base slot ClearSaveSlot(BASE_SLOT); } } // Store player structs for later rClass = randomclass; randomclass = false; for(i = 0; i < MAXPLAYERS; i++) { playerBackup[i] = players[i]; } // Save some globals that get trashed during the load inventoryPtr = inv_ptr; currentInvPos = curpos; // Only SV_LoadMap() uses TargetPlayerAddrs, so it's NULLed here // for the following check (player mobj redirection) TargetPlayerAddrs = NULL; gamemap = map; sprintf(fileName, "%shex6%02d.hxs", SavePath, gamemap); if(!deathmatch && ExistingFile(fileName)) { // Unarchive map SV_LoadMap(); } else { // New map G_InitNew(gameskill, gameepisode, gamemap); // Destroy all freshly spawned players for(i = 0; i < MAXPLAYERS; i++) { if(playeringame[i]) { P_RemoveMobj(players[i].mo); } } } // Restore player structs targetPlayerMobj = NULL; for(i = 0; i < MAXPLAYERS; i++) { if(!playeringame[i]) { continue; } players[i] = playerBackup[i]; P_ClearMessage(&players[i]); players[i].attacker = NULL; players[i].poisoner = NULL; if(netgame) { if(players[i].playerstate == PST_DEAD) { // In a network game, force all players to be alive players[i].playerstate = PST_REBORN; } if(!deathmatch) { // Cooperative net-play, retain keys and weapons oldKeys = players[i].keys; oldPieces = players[i].pieces; for(j = 0; j < NUMWEAPONS; j++) { oldWeaponowned[j] = players[i].weaponowned[j]; } } } playerWasReborn = (players[i].playerstate == PST_REBORN); if(deathmatch) { memset(players[i].frags, 0, sizeof(players[i].frags)); mobj = P_SpawnMobj(playerstarts[0][i].x<<16, playerstarts[0][i].y<<16, 0, MT_PLAYER_FIGHTER); players[i].mo = mobj; G_DeathMatchSpawnPlayer(i); P_RemoveMobj(mobj); } else { P_SpawnPlayer(&playerstarts[position][i]); } if(playerWasReborn && netgame && !deathmatch) { // Restore keys and weapons when reborn in co-op players[i].keys = oldKeys; players[i].pieces = oldPieces; for(bestWeapon = 0, j = 0; j < NUMWEAPONS; j++) { if(oldWeaponowned[j]) { bestWeapon = j; players[i].weaponowned[j] = true; } } players[i].mana[MANA_1] = 25; players[i].mana[MANA_2] = 25; if(bestWeapon) { // Bring up the best weapon players[i].pendingweapon = bestWeapon; } } if(targetPlayerMobj == NULL) { // The poor sap targetPlayerMobj = players[i].mo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -