ref: 7110aba73616e4f84b933a0db1ff96c4c22a9d6f
dir: /sv_save.c/
//************************************************************************** //** //** sv_save.c //** //************************************************************************** // HEADER FILES ------------------------------------------------------------ #include "h2stdinc.h" #include "doomdef.h" #include "p_local.h" // MACROS ------------------------------------------------------------------ #define SVG_RAM 0 #define SVG_FILE 1 #define SAVEGAMESIZE 0x30000 #define SAVE_GAME_TERMINATOR 0x1d // TYPES ------------------------------------------------------------------- typedef enum { tc_end, tc_mobj } thinkerclass_t; enum { tc_ceiling, tc_door, tc_floor, tc_plat, tc_flash, tc_strobe, tc_glow, tc_endspecials } specials_e; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void ArchivePlayers(void); static void UnarchivePlayers(void); static void ArchiveWorld(void); static void UnarchiveWorld(void); static void ArchiveThinkers(void); static void UnarchiveThinkers(void); static void ArchiveSpecials(void); static void UnarchiveSpecials(void); static void OpenStreamOut(const char *fileName); static void CloseStreamOut(const char *fileName); static void StreamOutBuffer(const void *buffer, int size); static void StreamOutByte(byte val); static void StreamOutWord(unsigned short val); //static void StreamOutLong(unsigned int val); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- // PRIVATE DATA DEFINITIONS ------------------------------------------------ static FILE *SavingFP; static int SaveGameType; static void *SaveBuffer; static byte *SavePtr; // CODE -------------------------------------------------------------------- //========================================================================== // // SV_SaveGame // //========================================================================== void SV_SaveGame(int slot, const char *description) { int i; char fileName[MAX_OSPATH]; char verString[SAVEVERSIONSIZE]; snprintf(fileName, sizeof(fileName), "%s%s%d.hsg", basePath, SAVEGAMENAME, slot); OpenStreamOut(fileName); StreamOutBuffer(description, SAVESTRINGSIZE); memset(verString, 0, sizeof(verString)); sprintf(verString, "version %i", VERSION); StreamOutBuffer(verString, SAVEVERSIONSIZE); StreamOutByte(gameskill); StreamOutByte(gameepisode); StreamOutByte(gamemap); for (i = 0; i < MAXPLAYERS; i++) { StreamOutByte(playeringame[i]); } StreamOutByte(leveltime>>16); StreamOutByte(leveltime>>8); StreamOutByte(leveltime); ArchivePlayers(); ArchiveWorld(); ArchiveThinkers(); ArchiveSpecials(); CloseStreamOut(fileName); } //========================================================================== // // SV_LoadGame // //========================================================================== void SV_LoadGame(int slot) { int i; int a, b, c; char fileName[MAX_OSPATH]; char vcheck[SAVEVERSIONSIZE]; snprintf(fileName, sizeof(fileName), "%s%s%d.hsg", basePath, SAVEGAMENAME, slot); M_ReadFile(fileName, &SaveBuffer); SavePtr = (byte *)SaveBuffer + SAVESTRINGSIZE; // Skip the description field memset(vcheck, 0, sizeof(vcheck)); sprintf(vcheck, "version %i", VERSION); if (strcmp((char *)SavePtr, vcheck) != 0) { // Bad version return; } SavePtr += SAVEVERSIONSIZE; gameskill = *SavePtr++; gameepisode = *SavePtr++; gamemap = *SavePtr++; for (i = 0; i < MAXPLAYERS; i++) { playeringame[i] = *SavePtr++; } // Load a base level G_InitNew(gameskill, gameepisode, gamemap); // Create leveltime a = *SavePtr++; b = *SavePtr++; c = *SavePtr++; leveltime = (a<<16) + (b<<8) + c; // De-archive all the modifications UnarchivePlayers(); UnarchiveWorld(); UnarchiveThinkers(); UnarchiveSpecials(); if (*SavePtr != SAVE_GAME_TERMINATOR) { // Missing savegame termination marker I_Error("Bad savegame"); } Z_Free(SaveBuffer); } //========================================================================== // // ArchivePlayers // //========================================================================== static void ArchivePlayers(void) { int i, j; player_t dest; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) { continue; } memcpy(&dest, &players[i], sizeof(player_t)); for (j = 0; j < NUMPSPRITES; j++) { if (dest.psprites[j].state) { dest.psprites[j].state = (state_t *)(dest.psprites[j].state - states); } } StreamOutBuffer(&dest, sizeof(player_t)); } } //========================================================================== // // UnarchivePlayers // //========================================================================== static void UnarchivePlayers(void) { int i, j; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; memcpy(&players[i], SavePtr, sizeof(player_t)); SavePtr += sizeof(player_t); players[i].mo = NULL; // will be set when unarc thinker players[i].message = NULL; players[i].attacker = NULL; for (j = 0; j < NUMPSPRITES; j++) { if (players[i]. psprites[j].state) players[i].psprites[j].state = &states[(int)players[i].psprites[j].state]; } } } //========================================================================== // // ArchiveWorld // //========================================================================== static void ArchiveWorld(void) { int i, j; sector_t *sec; line_t *li; side_t *si; // Sectors for (i = 0, sec = sectors; i < numsectors; i++, sec++) { StreamOutWord(sec->floorheight>>FRACBITS); StreamOutWord(sec->ceilingheight>>FRACBITS); StreamOutWord(sec->floorpic); StreamOutWord(sec->ceilingpic); StreamOutWord(sec->lightlevel); StreamOutWord(sec->special); // needed? StreamOutWord(sec->tag); // needed? } // Lines for (i = 0, li = lines; i < numlines; i++, li++) { StreamOutWord(li->flags); StreamOutWord(li->special); StreamOutWord(li->tag); for (j = 0; j < 2; j++) { if (li->sidenum[j] == -1) { continue; } si = &sides[li->sidenum[j]]; StreamOutWord(si->textureoffset>>FRACBITS); StreamOutWord(si->rowoffset>>FRACBITS); StreamOutWord(si->toptexture); StreamOutWord(si->bottomtexture); StreamOutWord(si->midtexture); } } } //========================================================================== // // UnarchiveWorld // //========================================================================== static void UnarchiveWorld(void) { int i, j; sector_t *sec; line_t *li; side_t *si; short *get; get = (short *)SavePtr; // // do sectors // for (i = 0, sec = sectors; i < numsectors; i++, sec++) { sec->floorheight = *get++ << FRACBITS; sec->ceilingheight = *get++ << FRACBITS; sec->floorpic = *get++; sec->ceilingpic = *get++; sec->lightlevel = *get++; sec->special = *get++; // needed? sec->tag = *get++; // needed? sec->specialdata = 0; sec->soundtarget = 0; } // // do lines // for (i = 0, li = lines; i < numlines; i++, li++) { li->flags = *get++; li->special = *get++; li->tag = *get++; for (j = 0; j < 2; j++) { if (li->sidenum[j] == -1) continue; si = &sides[li->sidenum[j]]; si->textureoffset = *get++ << FRACBITS; si->rowoffset = *get++ << FRACBITS; si->toptexture = *get++; si->bottomtexture = *get++; si->midtexture = *get++; } } SavePtr = (byte *)get; } //========================================================================== // // ArchiveThinkers // //========================================================================== static void ArchiveThinkers(void) { thinker_t *th; mobj_t mobj; for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (th->function == P_MobjThinker) { StreamOutByte(tc_mobj); memcpy(&mobj, th, sizeof(mobj_t)); mobj.state = (state_t *)(mobj.state - states); if (mobj.player) { mobj.player = (player_t *)((mobj.player - players) + 1); } StreamOutBuffer(&mobj, sizeof(mobj_t)); continue; } //I_Error("P_ArchiveThinkers: Unknown thinker function"); } // Add a terminating marker StreamOutByte(tc_end); } //========================================================================== // // UnarchiveThinkers // //========================================================================== static void UnarchiveThinkers(void) { byte tclass; thinker_t *currentthinker, *next; mobj_t *mobj; // // remove all the current thinkers // currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { next = currentthinker->next; if (currentthinker->function == P_MobjThinker) P_RemoveMobj ((mobj_t *)currentthinker); else Z_Free (currentthinker); currentthinker = next; } P_InitThinkers (); // read in saved thinkers while (1) { tclass = *SavePtr++; switch (tclass) { case tc_end: return; // end of list case tc_mobj: mobj = (mobj_t *) Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); memcpy (mobj, SavePtr, sizeof(*mobj)); SavePtr += sizeof(*mobj); mobj->state = &states[(int)mobj->state]; mobj->target = NULL; if (mobj->player) { mobj->player = &players[(int)mobj->player - 1]; mobj->player->mo = mobj; } P_SetThingPosition (mobj); mobj->info = &mobjinfo[mobj->type]; mobj->floorz = mobj->subsector->sector->floorheight; mobj->ceilingz = mobj->subsector->sector->ceilingheight; mobj->thinker.function = P_MobjThinker; P_AddThinker (&mobj->thinker); break; default: I_Error("Unknown tclass %i in savegame", tclass); } } } //========================================================================== // // ArchiveSpecials // //========================================================================== static void ArchiveSpecials(void) { /* T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list T_VerticalDoor, (vldoor_t: sector_t * swizzle), T_MoveFloor, (floormove_t: sector_t * swizzle), T_LightFlash, (lightflash_t: sector_t * swizzle), T_StrobeFlash, (strobe_t: sector_t *), T_Glow, (glow_t: sector_t *), T_PlatRaise, (plat_t: sector_t *), - active list */ thinker_t *th; ceiling_t ceiling; vldoor_t door; floormove_t floor; plat_t plat; lightflash_t flash; strobe_t strobe; glow_t glow; for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (th->function == T_MoveCeiling) { StreamOutByte(tc_ceiling); memcpy(&ceiling, th, sizeof(ceiling_t)); ceiling.sector = (sector_t *)(ceiling.sector - sectors); StreamOutBuffer(&ceiling, sizeof(ceiling_t)); continue; } if (th->function == T_VerticalDoor) { StreamOutByte(tc_door); memcpy(&door, th, sizeof(vldoor_t)); door.sector = (sector_t *)(door.sector - sectors); StreamOutBuffer(&door, sizeof(vldoor_t)); continue; } if (th->function == T_MoveFloor) { StreamOutByte(tc_floor); memcpy(&floor, th, sizeof(floormove_t)); floor.sector = (sector_t *)(floor.sector - sectors); StreamOutBuffer(&floor, sizeof(floormove_t)); continue; } if (th->function == T_PlatRaise) { StreamOutByte(tc_plat); memcpy(&plat, th, sizeof(plat_t)); plat.sector = (sector_t *)(plat.sector - sectors); StreamOutBuffer(&plat, sizeof(plat_t)); continue; } if (th->function == T_LightFlash) { StreamOutByte(tc_flash); memcpy(&flash, th, sizeof(lightflash_t)); flash.sector = (sector_t *)(flash.sector - sectors); StreamOutBuffer(&flash, sizeof(lightflash_t)); continue; } if (th->function == T_StrobeFlash) { StreamOutByte(tc_strobe); memcpy(&strobe, th, sizeof(strobe_t)); strobe.sector = (sector_t *)(strobe.sector - sectors); StreamOutBuffer(&strobe, sizeof(strobe_t)); continue; } if (th->function == T_Glow) { StreamOutByte(tc_glow); memcpy(&glow, th, sizeof(glow_t)); glow.sector = (sector_t *)(glow.sector - sectors); StreamOutBuffer(&glow, sizeof(glow_t)); continue; } } // Add a terminating marker StreamOutByte(tc_endspecials); } //========================================================================== // // UnarchiveSpecials // //========================================================================== static void UnarchiveSpecials(void) { byte tclass; ceiling_t *ceiling; vldoor_t *door; floormove_t *floor; plat_t *plat; lightflash_t *flash; strobe_t *strobe; glow_t *glow; // read in saved thinkers while (1) { tclass = *SavePtr++; switch (tclass) { case tc_endspecials: return; // end of list case tc_ceiling: ceiling = (ceiling_t *) Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL); memcpy (ceiling, SavePtr, sizeof(*ceiling)); SavePtr += sizeof(*ceiling); ceiling->sector = §ors[(int)ceiling->sector]; ceiling->sector->specialdata = T_MoveCeiling; if (ceiling->thinker.function) ceiling->thinker.function = T_MoveCeiling; P_AddThinker (&ceiling->thinker); P_AddActiveCeiling(ceiling); break; case tc_door: door = (vldoor_t *) Z_Malloc (sizeof(*door), PU_LEVEL, NULL); memcpy (door, SavePtr, sizeof(*door)); SavePtr += sizeof(*door); door->sector = §ors[(int)door->sector]; door->sector->specialdata = door; door->thinker.function = T_VerticalDoor; P_AddThinker (&door->thinker); break; case tc_floor: floor = (floormove_t *) Z_Malloc (sizeof(*floor), PU_LEVEL, NULL); memcpy (floor, SavePtr, sizeof(*floor)); SavePtr += sizeof(*floor); floor->sector = §ors[(int)floor->sector]; floor->sector->specialdata = T_MoveFloor; floor->thinker.function = T_MoveFloor; P_AddThinker (&floor->thinker); break; case tc_plat: plat = (plat_t *) Z_Malloc (sizeof(*plat), PU_LEVEL, NULL); memcpy (plat, SavePtr, sizeof(*plat)); SavePtr += sizeof(*plat); plat->sector = §ors[(int)plat->sector]; plat->sector->specialdata = T_PlatRaise; if (plat->thinker.function) plat->thinker.function = T_PlatRaise; P_AddThinker (&plat->thinker); P_AddActivePlat(plat); break; case tc_flash: flash = (lightflash_t *) Z_Malloc (sizeof(*flash), PU_LEVEL, NULL); memcpy (flash, SavePtr, sizeof(*flash)); SavePtr += sizeof(*flash); flash->sector = §ors[(int)flash->sector]; flash->thinker.function = T_LightFlash; P_AddThinker (&flash->thinker); break; case tc_strobe: strobe = (strobe_t *) Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL); memcpy (strobe, SavePtr, sizeof(*strobe)); SavePtr += sizeof(*strobe); strobe->sector = §ors[(int)strobe->sector]; strobe->thinker.function = T_StrobeFlash; P_AddThinker (&strobe->thinker); break; case tc_glow: glow = (glow_t *) Z_Malloc (sizeof(*glow), PU_LEVEL, NULL); memcpy (glow, SavePtr, sizeof(*glow)); SavePtr += sizeof(*glow); glow->sector = §ors[(int)glow->sector]; glow->thinker.function = T_Glow; P_AddThinker (&glow->thinker); break; default: I_Error("P_UnarchiveSpecials:Unknown tclass %i " "in savegame", tclass); } } } //========================================================================== // // OpenStreamOut // //========================================================================== static void OpenStreamOut(const char *fileName) { MallocFailureOk = true; SaveBuffer = Z_Malloc(SAVEGAMESIZE, PU_STATIC, NULL); SavePtr = (byte *)SaveBuffer; MallocFailureOk = false; if (SaveBuffer == NULL) { // Not enough memory - use file save method SaveGameType = SVG_FILE; SavingFP = fopen(fileName, "wb"); } else { SaveGameType = SVG_RAM; } } //========================================================================== // // CloseStreamOut // //========================================================================== static void CloseStreamOut(const char *fileName) { int length; StreamOutByte(SAVE_GAME_TERMINATOR); if (SaveGameType == SVG_RAM) { length = SavePtr - (byte *)SaveBuffer; if (length > SAVEGAMESIZE) { I_Error("Savegame buffer overrun"); } M_WriteFile(fileName, SaveBuffer, length); Z_Free(SaveBuffer); } else { // SVG_FILE fclose(SavingFP); } } //========================================================================== // // SV_Write // //========================================================================== static void StreamOutBuffer(const void *buffer, int size) { if (SaveGameType == SVG_RAM) { memcpy(SavePtr, buffer, size); SavePtr += size; } else { // SVG_FILE fwrite(buffer, size, 1, SavingFP); } } static void StreamOutByte(byte val) { StreamOutBuffer(&val, sizeof(byte)); } static void StreamOutWord(unsigned short val) { StreamOutBuffer(&val, sizeof(unsigned short)); } /* static void StreamOutLong(unsigned int val) { StreamOutBuffer(&val, sizeof(int)); } */