// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // $Id:$ // // Copyright (C) 1993-1996 by id Software, Inc. // // This source is available for distribution and/or modification // only under the terms of the DOOM Source Code License as // published by id Software. All rights reserved. // // The source is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License // for more details. // // $Log:$ // // DESCRIPTION: // Archiving: SaveGame I/O. // //----------------------------------------------------------------------------- #include "doom_config.h" #include "i_system.h" #include "z_zone.h" #include "p_local.h" #include "doomstat.h" // State. #include "r_state.h" // State. // Pads save_p to a 4-byte boundary // so that the load/save works on SGI&Gecko. #define PADSAVEP() save_p += (4 - ((long long)save_p & 3)) & 3 byte* save_p; // TODO: [pd] We are loading/saving raw pointers. It will not work with saves from 32bits system. We need to rewrite those functions. // // P_ArchivePlayers // void P_ArchivePlayers(void) { int i; int j; player_t* dest; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; PADSAVEP(); dest = (player_t*)save_p; doom_memcpy(dest, &players[i], sizeof(player_t)); save_p += 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); } } } } // // P_UnArchivePlayers // void P_UnArchivePlayers(void) { int i; int j; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; PADSAVEP(); doom_memcpy(&players[i], save_p, sizeof(player_t)); save_p += sizeof(player_t); // will be set when unarc thinker players[i].mo = 0; players[i].message = 0; players[i].attacker = 0; for (j = 0; j < NUMPSPRITES; j++) { if (players[i].psprites[j].state) { players[i].psprites[j].state = &states[(long long)players[i].psprites[j].state]; } } } } // // P_ArchiveWorld // void P_ArchiveWorld(void) { int i; int j; sector_t* sec; line_t* li; side_t* si; short* put; put = (short*)save_p; // do sectors for (i = 0, sec = sectors; i < numsectors; i++, sec++) { *put++ = sec->floorheight >> FRACBITS; *put++ = sec->ceilingheight >> FRACBITS; *put++ = sec->floorpic; *put++ = sec->ceilingpic; *put++ = sec->lightlevel; *put++ = sec->special; // needed? *put++ = sec->tag; // needed? } // do lines for (i = 0, li = lines; i < numlines; i++, li++) { *put++ = li->flags; *put++ = li->special; *put++ = li->tag; for (j = 0; j < 2; j++) { if (li->sidenum[j] == -1) continue; si = &sides[li->sidenum[j]]; *put++ = si->textureoffset >> FRACBITS; *put++ = si->rowoffset >> FRACBITS; *put++ = si->toptexture; *put++ = si->bottomtexture; *put++ = si->midtexture; } } save_p = (byte*)put; } // // P_UnArchiveWorld // void P_UnArchiveWorld(void) { int i; int j; sector_t* sec; line_t* li; side_t* si; short* get; get = (short*)save_p; // 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++; } } save_p = (byte*)get; } // // Thinkers // typedef enum { tc_end, tc_mobj } thinkerclass_t; // // P_ArchiveThinkers // void P_ArchiveThinkers(void) { thinker_t* th; mobj_t* mobj; // save off the current thinkers for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (th->function.acp1 == (actionf_p1)P_MobjThinker) { *save_p++ = tc_mobj; PADSAVEP(); mobj = (mobj_t*)save_p; doom_memcpy(mobj, th, sizeof(*mobj)); save_p += sizeof(*mobj); mobj->state = (state_t*)(mobj->state - states); if (mobj->player) mobj->player = (player_t*)((mobj->player - players) + 1); continue; } // I_Error ("P_ArchiveThinkers: Unknown thinker function"); } // add a terminating marker *save_p++ = tc_end; } // // P_UnArchiveThinkers // void P_UnArchiveThinkers(void) { byte tclass; thinker_t* currentthinker; thinker_t* next; mobj_t* mobj; // remove all the current thinkers currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { next = currentthinker->next; if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker) P_RemoveMobj((mobj_t*)currentthinker); else Z_Free(currentthinker); currentthinker = next; } P_InitThinkers(); // read in saved thinkers while (1) { tclass = *save_p++; switch (tclass) { case tc_end: return; // end of list case tc_mobj: PADSAVEP(); mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, 0); doom_memcpy(mobj, save_p, sizeof(*mobj)); save_p += sizeof(*mobj); mobj->state = &states[(long long)mobj->state]; mobj->target = 0; if (mobj->player) { mobj->player = &players[(long long)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.acp1 = (actionf_p1)P_MobjThinker; P_AddThinker(&mobj->thinker); break; default: { //I_Error("Error: Unknown tclass %i in savegame", tclass); doom_strcpy(error_buf, "Error: Unknown tclass "); doom_concat(error_buf, doom_itoa(tclass, 10)); doom_concat(error_buf, " in savegame"); I_Error(error_buf); } } } } // // P_ArchiveSpecials // enum { tc_ceiling, tc_door, tc_floor, tc_plat, tc_flash, tc_strobe, tc_glow, tc_endspecials } specials_e; // // Things to handle: // // 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 // void P_ArchiveSpecials(void) { thinker_t* th; ceiling_t* ceiling; vldoor_t* door; floormove_t* floor; plat_t* plat; lightflash_t* flash; strobe_t* strobe; glow_t* glow; int i; // save off the current thinkers for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (th->function.acv == (actionf_v)0) { for (i = 0; i < MAXCEILINGS; i++) if (activeceilings[i] == (ceiling_t*)th) break; if (i < MAXCEILINGS) { *save_p++ = tc_ceiling; PADSAVEP(); ceiling = (ceiling_t*)save_p; doom_memcpy(ceiling, th, sizeof(*ceiling)); save_p += sizeof(*ceiling); ceiling->sector = (sector_t*)(ceiling->sector - sectors); } continue; } if (th->function.acp1 == (actionf_p1)T_MoveCeiling) { *save_p++ = tc_ceiling; PADSAVEP(); ceiling = (ceiling_t*)save_p; doom_memcpy(ceiling, th, sizeof(*ceiling)); save_p += sizeof(*ceiling); ceiling->sector = (sector_t*)(ceiling->sector - sectors); continue; } if (th->function.acp1 == (actionf_p1)T_VerticalDoor) { *save_p++ = tc_door; PADSAVEP(); door = (vldoor_t*)save_p; doom_memcpy(door, th, sizeof(*door)); save_p += sizeof(*door); door->sector = (sector_t*)(door->sector - sectors); continue; } if (th->function.acp1 == (actionf_p1)T_MoveFloor) { *save_p++ = tc_floor; PADSAVEP(); floor = (floormove_t*)save_p; doom_memcpy(floor, th, sizeof(*floor)); save_p += sizeof(*floor); floor->sector = (sector_t*)(floor->sector - sectors); continue; } if (th->function.acp1 == (actionf_p1)T_PlatRaise) { *save_p++ = tc_plat; PADSAVEP(); plat = (plat_t*)save_p; doom_memcpy(plat, th, sizeof(*plat)); save_p += sizeof(*plat); plat->sector = (sector_t*)(plat->sector - sectors); continue; } if (th->function.acp1 == (actionf_p1)T_LightFlash) { *save_p++ = tc_flash; PADSAVEP(); flash = (lightflash_t*)save_p; doom_memcpy(flash, th, sizeof(*flash)); save_p += sizeof(*flash); flash->sector = (sector_t*)(flash->sector - sectors); continue; } if (th->function.acp1 == (actionf_p1)T_StrobeFlash) { *save_p++ = tc_strobe; PADSAVEP(); strobe = (strobe_t*)save_p; doom_memcpy(strobe, th, sizeof(*strobe)); save_p += sizeof(*strobe); strobe->sector = (sector_t*)(strobe->sector - sectors); continue; } if (th->function.acp1 == (actionf_p1)T_Glow) { *save_p++ = tc_glow; PADSAVEP(); glow = (glow_t*)save_p; doom_memcpy(glow, th, sizeof(*glow)); save_p += sizeof(*glow); glow->sector = (sector_t*)(glow->sector - sectors); continue; } } // add a terminating marker *save_p++ = tc_endspecials; } // // P_UnArchiveSpecials // void P_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 = *save_p++; switch (tclass) { case tc_endspecials: return; // end of list case tc_ceiling: PADSAVEP(); ceiling = Z_Malloc(sizeof(*ceiling), PU_LEVEL, 0); doom_memcpy(ceiling, save_p, sizeof(*ceiling)); save_p += sizeof(*ceiling); ceiling->sector = §ors[(long long)ceiling->sector]; ceiling->sector->specialdata = ceiling; if (ceiling->thinker.function.acp1) ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling; P_AddThinker(&ceiling->thinker); P_AddActiveCeiling(ceiling); break; case tc_door: PADSAVEP(); door = Z_Malloc(sizeof(*door), PU_LEVEL, 0); doom_memcpy(door, save_p, sizeof(*door)); save_p += sizeof(*door); door->sector = §ors[(long long)door->sector]; door->sector->specialdata = door; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; P_AddThinker(&door->thinker); break; case tc_floor: PADSAVEP(); floor = Z_Malloc(sizeof(*floor), PU_LEVEL, 0); doom_memcpy(floor, save_p, sizeof(*floor)); save_p += sizeof(*floor); floor->sector = §ors[(long long)floor->sector]; floor->sector->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor; P_AddThinker(&floor->thinker); break; case tc_plat: PADSAVEP(); plat = Z_Malloc(sizeof(*plat), PU_LEVEL, 0); doom_memcpy(plat, save_p, sizeof(*plat)); save_p += sizeof(*plat); plat->sector = §ors[(long long)plat->sector]; plat->sector->specialdata = plat; if (plat->thinker.function.acp1) plat->thinker.function.acp1 = (actionf_p1)T_PlatRaise; P_AddThinker(&plat->thinker); P_AddActivePlat(plat); break; case tc_flash: PADSAVEP(); flash = Z_Malloc(sizeof(*flash), PU_LEVEL, 0); doom_memcpy(flash, save_p, sizeof(*flash)); save_p += sizeof(*flash); flash->sector = §ors[(long long)flash->sector]; flash->thinker.function.acp1 = (actionf_p1)T_LightFlash; P_AddThinker(&flash->thinker); break; case tc_strobe: PADSAVEP(); strobe = Z_Malloc(sizeof(*strobe), PU_LEVEL, 0); doom_memcpy(strobe, save_p, sizeof(*strobe)); save_p += sizeof(*strobe); strobe->sector = §ors[(long long)strobe->sector]; strobe->thinker.function.acp1 = (actionf_p1)T_StrobeFlash; P_AddThinker(&strobe->thinker); break; case tc_glow: PADSAVEP(); glow = Z_Malloc(sizeof(*glow), PU_LEVEL, 0); doom_memcpy(glow, save_p, sizeof(*glow)); save_p += sizeof(*glow); glow->sector = §ors[(long long)glow->sector]; glow->thinker.function.acp1 = (actionf_p1)T_Glow; P_AddThinker(&glow->thinker); break; default: { //I_Error("Error: P_UnarchiveSpecials:Unknown tclass %i " // "in savegame", tclass); doom_strcpy(error_buf, "Error: P_UnarchiveSpecials:Unknown tclass "); doom_concat(error_buf, doom_itoa(tclass, 10)); doom_concat(error_buf, " in savegame"); I_Error(error_buf); } } } }