//------------------------------------------------------------------------- /* Copyright (C) 1997, 2005 - 3D Realms Entertainment This file is part of Shadow Warrior version 1.2 Shadow Warrior is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Original Source: 1997 - Frank Maddin and Jim Norwood Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms */ //------------------------------------------------------------------------- #include "ns.h" #define MAIN #define QUIET #include "build.h" #include "names2.h" #include "panel.h" #include "game.h" #include "tags.h" #include "lists.h" #include "interpolate.h" #include "interpso.h" #include "network.h" #include "jsector.h" #include "parent.h" //#define FILE_TYPE 1 #include "weapon.h" #include "misc.h" #include "player.h" #include "i_specialpaths.h" #include "savegamehelp.h" #include "raze_music.h" #include "mapinfo.h" //void TimerFunc(task * Task); BEGIN_SW_NS // This cannot have a namespace declaration #include "saveable.h" /* ////////////////////////////////////////////////////////////////////////////// TO DO ////////////////////////////////////////////////////////////////////////////// */ void InitLevelGlobals(void); extern int lastUpdate; extern char SaveGameDescr[10][80]; extern short Bunny_Count; extern bool NewGame; extern int GodMode; extern int FinishTimer; extern int FinishAnim; extern int GameVersion; //extern short Zombies; extern bool serpwasseen; extern bool sumowasseen; extern bool zillawasseen; extern short BossSpriteNum[3]; #define PANEL_SAVE 1 #define ANIM_SAVE 1 extern STATE s_NotRestored[]; OrgTileListP otlist[] = {&orgwalllist, &orgwalloverlist, &orgsectorceilinglist, &orgsectorfloorlist}; int PanelSpriteToNdx(PLAYERp pp, PANEL_SPRITEp psprite) { short ndx = 0; PANEL_SPRITEp psp=NULL, next=NULL; TRAVERSE(&pp->PanelSpriteList, psp, next) { if (psp == psprite) return ndx; ndx++; } // special case for pointing to the list head if ((LIST)psprite == (LIST)&pp->PanelSpriteList) return 9999; return -1; } PANEL_SPRITEp PanelNdxToSprite(PLAYERp pp, int ndx) { short count = 0; PANEL_SPRITEp psp, next; if (ndx == -1) return NULL; if (ndx == 9999) return (PANEL_SPRITEp)&pp->PanelSpriteList; TRAVERSE(&pp->PanelSpriteList, psp, next) { if (count == ndx) return psp; count++; } return NULL; } int SaveSymDataInfo(MFILE_WRITE fil, void *ptr) { saveddatasym sym; if (Saveable_FindDataSym(ptr, &sym)) { FILE *fp; assert(false); fp = fopen("savegame symbols missing.txt", "a"); if (fp) { fprintf(fp,"data %p - reference variable xdim at %p\n",ptr, &xdim); fclose(fp); } return 1; } MWRITE(&sym, sizeof(sym), 1, fil); return 0; } static int SaveSymCodeInfo_raw(MFILE_WRITE fil, void *ptr) { savedcodesym sym; if (Saveable_FindCodeSym(ptr, &sym)) { FILE *fp; assert(false); fp = fopen("savegame symbols missing.txt", "a"); if (fp) { fprintf(fp,"code %p - reference function SaveSymDataInfo at %p\n",ptr, SaveSymDataInfo); fclose(fp); } return 1; } MWRITE(&sym, sizeof(sym), 1, fil); return 0; } template static int SaveSymCodeInfo(MFILE_WRITE fil, T * ptr) { return SaveSymCodeInfo_raw(fil, (void *)ptr); } int LoadSymDataInfo(MFILE_READ fil, void **ptr) { saveddatasym sym; MREAD(&sym, sizeof(sym), 1, fil); return Saveable_RestoreDataSym(&sym, ptr); } int LoadSymCodeInfo(MFILE_READ fil, void **ptr) { savedcodesym sym; MREAD(&sym, sizeof(sym), 1, fil); return Saveable_RestoreCodeSym(&sym, ptr); } bool GameInterface::SaveGame() { MFILE_WRITE fil; int i,j; short ndx; PLAYER tp; PLAYERp pp; SECT_USERp sectu; USER tu; USERp u; ANIM tanim; ANIMp a; PANEL_SPRITE tpanel_sprite; PANEL_SPRITEp psp,cur,next; SECTOR_OBJECTp sop; int saveisshot=0; OrgTileP otp, next_otp; Saveable_Init(); // workaround until the level info here has been transitioned. fil = WriteSavegameChunk("snapshot.sw"); MWRITE(&Skill,sizeof(Skill),1,fil); MWRITE(&numplayers,sizeof(numplayers),1,fil); MWRITE(&myconnectindex,sizeof(myconnectindex),1,fil); MWRITE(&connecthead,sizeof(connecthead),1,fil); MWRITE(connectpoint2,sizeof(connectpoint2),1,fil); MWRITE(&crouch_toggle,sizeof(crouch_toggle),1,fil); //save players info pp = &tp; for (i = 0; i < numplayers; i++) { memcpy(&tp, &Player[i], sizeof(PLAYER)); // this does not point to global data - this is allocated link list based // save this inside the structure #if PANEL_SAVE pp->CurWpn = (PANEL_SPRITEp)(intptr_t)PanelSpriteToNdx(&Player[i], pp->CurWpn); for (ndx = 0; ndx < MAX_WEAPONS; ndx++) pp->Wpn[ndx] = (PANEL_SPRITEp)(intptr_t)PanelSpriteToNdx(&Player[i], pp->Wpn[ndx]); pp->Chops = (PANEL_SPRITEp)(intptr_t)PanelSpriteToNdx(&Player[i], pp->Chops); #endif MWRITE(&tp, sizeof(PLAYER),1,fil); ////// saveisshot |= SaveSymDataInfo(fil, pp->remote_sprite); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->remote.sop_control); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->sop_remote); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->sop); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->hi_sectp); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->lo_sectp); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->hi_sp); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->lo_sp); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->last_camera_sp); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->SpriteP); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->UnderSpriteP); assert(!saveisshot); saveisshot |= SaveSymCodeInfo(fil, pp->DoPlayerAction); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->sop_control); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, pp->sop_riding); assert(!saveisshot); } #if PANEL_SAVE // local copy psp = &tpanel_sprite; for (i = 0; i < numplayers; i++) { unsigned j; pp = &Player[i]; ndx = 0; TRAVERSE(&pp->PanelSpriteList, cur, next) { // this is a HEADER MWRITE(&ndx, sizeof(ndx),1,fil); memcpy(psp, cur, sizeof(PANEL_SPRITE)); // Panel Sprite - save in structure psp->sibling = (PANEL_SPRITEp)(intptr_t)PanelSpriteToNdx(pp, cur->sibling); MWRITE(psp, sizeof(PANEL_SPRITE),1,fil); saveisshot |= SaveSymDataInfo(fil, psp->PlayerP); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, psp->State); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, psp->RetractState); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, psp->PresentState); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, psp->ActionState); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, psp->RestState); assert(!saveisshot); saveisshot |= SaveSymCodeInfo(fil, psp->PanelSpriteFunc); assert(!saveisshot); for (j = 0; j < SIZ(psp->over); j++) { saveisshot |= SaveSymDataInfo(fil, psp->over[j].State); assert(!saveisshot); } ndx++; } // store -1 when done for player ndx = -1; MWRITE(&ndx, sizeof(ndx),1,fil); } #endif //Sector User information for (i = 0; i < numsectors; i++) { sectu = SectUser[i]; ndx = i; if (sectu) { // write header MWRITE(&ndx,sizeof(ndx),1,fil); MWRITE(sectu,sizeof(SECT_USER),1,fil); } else { // write trailer ndx = -1; MWRITE(&ndx,sizeof(ndx),1,fil); } } //User information for (i = 0; i < MAXSPRITES; i++) { ndx = i; if (User[i]) { // write header MWRITE(&ndx,sizeof(ndx),1,fil); memcpy(&tu, User[i], sizeof(USER)); u = &tu; MWRITE(u,sizeof(USER),1,fil); #if 0 if (u->WallShade) { MWRITE(u->WallShade, sizeof(*u->WallShade) * u->WallCount, 1, fil); } if (u->rotator) { MWRITE(u->rotator,sizeof(*u->rotator),1,fil); if (u->rotator->origx) MWRITE(u->rotator->origx,sizeof(*u->rotator->origx)*u->rotator->num_walls,1,fil); if (u->rotator->origy) MWRITE(u->rotator->origy,sizeof(*u->rotator->origy)*u->rotator->num_walls,1,fil); } #endif saveisshot |= SaveSymDataInfo(fil, u->WallP); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->State); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->Rot); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->StateStart); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->StateEnd); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->StateFallOverride); assert(!saveisshot); saveisshot |= SaveSymCodeInfo(fil, u->ActorActionFunc); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->ActorActionSet); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->Personality); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->Attrib); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->sop_parent); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->hi_sectp); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->lo_sectp); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->hi_sp); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->lo_sp); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->SpriteP); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->PlayerP); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, u->tgt_sp); assert(!saveisshot); } } ndx = -1; MWRITE(&ndx,sizeof(ndx),1,fil); // // Sector object // MWRITE(SectorObject, sizeof(SectorObject),1,fil); for (ndx = 0; ndx < (short)SIZ(SectorObject); ndx++) { sop = &SectorObject[ndx]; saveisshot |= SaveSymCodeInfo(fil, sop->PreMoveAnimator); assert(!saveisshot); saveisshot |= SaveSymCodeInfo(fil, sop->PostMoveAnimator); assert(!saveisshot); saveisshot |= SaveSymCodeInfo(fil, sop->Animator); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, sop->controller); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, sop->sp_child); assert(!saveisshot); } MWRITE(SineWaveFloor, sizeof(SineWaveFloor),1,fil); MWRITE(SineWall, sizeof(SineWall),1,fil); MWRITE(SpringBoard, sizeof(SpringBoard),1,fil); MWRITE(Track, sizeof(Track),1,fil); for (i = 0; i < MAX_TRACKS; i++) { ASSERT(Track[i].TrackPoint); if (Track[i].NumPoints == 0) MWRITE(Track[i].TrackPoint, sizeof(TRACK_POINT),1,fil); else MWRITE(Track[i].TrackPoint, Track[i].NumPoints * sizeof(TRACK_POINT),1,fil); } MWRITE(&Player[myconnectindex].input,sizeof(Player[myconnectindex].input),1,fil); MWRITE(&screenpeek,sizeof(screenpeek),1,fil); MWRITE(&randomseed, sizeof(randomseed), 1, fil); // do all sector manipulation structures #if ANIM_SAVE #if 1 MWRITE(&AnimCnt,sizeof(AnimCnt),1,fil); for (i = 0, a = &tanim; i < AnimCnt; i++) { intptr_t offset; memcpy(a,&Anim[i],sizeof(ANIM)); // maintain compatibility with sinking boat which points to user data for (j=0; jptr >= bp && (uint8_t*)a->ptr < bp + sizeof(USER)) { offset = (intptr_t)((uint8_t*)a->ptr - bp); // offset from user data a->ptr = (int *)-2; break; } } } if ((intptr_t)a->ptr != -2) { for (j=0; jptr >= bp && (uint8_t*)a->ptr < bp + sizeof(SECT_USER)) { offset = (intptr_t)((uint8_t*)a->ptr - bp); // offset from user data a->ptr = (int *)-3; break; } } } } MWRITE(a,sizeof(ANIM),1,fil); if ((intptr_t)a->ptr == -2 || (intptr_t)a->ptr == -3) { MWRITE(&j, sizeof(j),1,fil); MWRITE(&offset, sizeof(offset),1,fil); } else { saveisshot |= SaveSymDataInfo(fil, a->ptr); assert(!saveisshot); } saveisshot |= SaveSymCodeInfo(fil, a->callback); assert(!saveisshot); saveisshot |= SaveSymDataInfo(fil, a->callbackdata); assert(!saveisshot); } #else ndx = 0; for (i = AnimCnt - 1, a = &tanim; i >= 0; i--) { // write header MWRITE(&ndx,sizeof(ndx),1,fil); memcpy(a,&Anim[i],sizeof(ANIM)); MWRITE(a,sizeof(ANIM),1,fil); saveisshot |= SaveSymDataInfo(fil, a->ptr); saveisshot |= SaveSymCodeInfo(fil, a->callback); saveisshot |= SaveSymDataInfo(fil, a->callbackdata); ndx++; } // write trailer ndx = -1; MWRITE(&ndx,sizeof(ndx),1,fil); #endif #endif MWRITE(&NormalVisibility,sizeof(NormalVisibility),1,fil); MWRITE(&MoveSkip2,sizeof(MoveSkip2),1,fil); MWRITE(&MoveSkip4,sizeof(MoveSkip4),1,fil); MWRITE(&MoveSkip8,sizeof(MoveSkip8),1,fil); // SO interpolations saveisshot |= so_writeinterpolations(fil); assert(!saveisshot); // parental lock for (i = 0; i < (int)SIZ(otlist); i++) { ndx = 0; TRAVERSE(otlist[i], otp, next_otp) { MWRITE(&ndx,sizeof(ndx),1,fil); MWRITE(&otp,sizeof(*otp),1,fil); ndx++; } ndx = -1; MWRITE(&ndx, sizeof(ndx),1,fil); } // mirror MWRITE(mirror,sizeof(mirror),1,fil); MWRITE(&mirrorcnt,sizeof(mirrorcnt),1,fil); MWRITE(&mirrorinview,sizeof(mirrorinview),1,fil); // queue MWRITE(&StarQueueHead,sizeof(StarQueueHead),1,fil); MWRITE(StarQueue,sizeof(StarQueue),1,fil); MWRITE(&HoleQueueHead,sizeof(HoleQueueHead),1,fil); MWRITE(HoleQueue,sizeof(HoleQueue),1,fil); MWRITE(&WallBloodQueueHead,sizeof(WallBloodQueueHead),1,fil); MWRITE(WallBloodQueue,sizeof(WallBloodQueue),1,fil); MWRITE(&FloorBloodQueueHead,sizeof(FloorBloodQueueHead),1,fil); MWRITE(FloorBloodQueue,sizeof(FloorBloodQueue),1,fil); MWRITE(&GenericQueueHead,sizeof(GenericQueueHead),1,fil); MWRITE(GenericQueue,sizeof(GenericQueue),1,fil); MWRITE(&LoWangsQueueHead,sizeof(LoWangsQueueHead),1,fil); MWRITE(LoWangsQueue,sizeof(LoWangsQueue),1,fil); MWRITE(&PlayClock,sizeof(PlayClock),1,fil); MWRITE(&TotalKillable,sizeof(TotalKillable),1,fil); // game settings MWRITE(&gNet,sizeof(gNet),1,fil); MWRITE(&gs,sizeof(gs),1,fil); MWRITE(&LevelSecrets,sizeof(LevelSecrets),1,fil); MWRITE(&Bunny_Count,sizeof(Bunny_Count),1,fil); MWRITE(&GodMode,sizeof(GodMode),1,fil); MWRITE(&FinishTimer,sizeof(FinishTimer),1,fil); MWRITE(&FinishAnim,sizeof(FinishAnim),1,fil); MWRITE(&serpwasseen, sizeof(serpwasseen), 1, fil); MWRITE(&sumowasseen, sizeof(sumowasseen), 1, fil); MWRITE(&zillawasseen, sizeof(zillawasseen), 1, fil); MWRITE(BossSpriteNum, sizeof(BossSpriteNum), 1, fil); //MWRITE(&Zombies, sizeof(Zombies), 1, fil); return !saveisshot; } bool GameInterface::LoadGame() { MFILE_READ fil; int i,j,saveisshot=0; short ndx,SpriteNum,sectnum; PLAYERp pp = NULL; USERp u; SECTOR_OBJECTp sop; SECT_USERp sectu; ANIMp a; PANEL_SPRITEp psp,next; OrgTileP otp; Saveable_Init(); auto filr = ReadSavegameChunk("snapshot.sw"); if (!filr.isOpen()) return false; fil = &filr; MREAD(&Skill,sizeof(Skill),1,fil); MREAD(&numplayers, sizeof(numplayers),1,fil); MREAD(&myconnectindex,sizeof(myconnectindex),1,fil); MREAD(&connecthead,sizeof(connecthead),1,fil); MREAD(connectpoint2,sizeof(connectpoint2),1,fil); MREAD(&crouch_toggle,sizeof(crouch_toggle),1,fil); //save players //MREAD(Player,sizeof(PLAYER), numplayers,fil); //save players info for (auto& pp : Player) { pp.cookieTime = 0; memset(pp.cookieQuote, 0, sizeof(pp.cookieQuote)); } for (i = 0; i < numplayers; i++) { pp = &Player[i]; MREAD(pp, sizeof(*pp), 1, fil); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->remote_sprite); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->remote.sop_control); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->sop_remote); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->sop); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->hi_sectp); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->lo_sectp); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->hi_sp); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->lo_sp); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->last_camera_sp); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->SpriteP); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->UnderSpriteP); saveisshot |= LoadSymCodeInfo(fil, (void **)&pp->DoPlayerAction); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->sop_control); saveisshot |= LoadSymDataInfo(fil, (void **)&pp->sop_riding); if (saveisshot) { MCLOSE_READ(fil); return false; } } #if PANEL_SAVE for (i = 0; i < numplayers; i++) { int j; pp = &Player[i]; INITLIST(&pp->PanelSpriteList); while (true) { MREAD(&ndx, sizeof(ndx),1,fil); if (ndx == -1) break; psp = (PANEL_SPRITEp)CallocMem(sizeof(PANEL_SPRITE), 1); ASSERT(psp); MREAD(psp, sizeof(PANEL_SPRITE),1,fil); INSERT_TAIL(&pp->PanelSpriteList,psp); saveisshot |= LoadSymDataInfo(fil, (void **)&psp->PlayerP); saveisshot |= LoadSymDataInfo(fil, (void **)&psp->State); saveisshot |= LoadSymDataInfo(fil, (void **)&psp->RetractState); saveisshot |= LoadSymDataInfo(fil, (void **)&psp->PresentState); saveisshot |= LoadSymDataInfo(fil, (void **)&psp->ActionState); saveisshot |= LoadSymDataInfo(fil, (void **)&psp->RestState); saveisshot |= LoadSymCodeInfo(fil, (void **)&psp->PanelSpriteFunc); if (saveisshot) { MCLOSE_READ(fil); return false; } for (j = 0; j < (int)SIZ(psp->over); j++) { saveisshot |= LoadSymDataInfo(fil, (void **)&psp->over[j].State); if (saveisshot) { MCLOSE_READ(fil); return false; } } } } #endif //Sector User information for (i = 0; i < numsectors; i++) { MREAD(§num,sizeof(sectnum),1,fil); if (sectnum != -1) { SectUser[sectnum] = sectu = (SECT_USERp)CallocMem(sizeof(SECT_USER), 1); MREAD(sectu,sizeof(SECT_USER),1,fil); } } //User information memset(User, 0, sizeof(User)); MREAD(&SpriteNum, sizeof(SpriteNum),1,fil); while (SpriteNum != -1) { User[SpriteNum] = u = NewUser(); // We need to be careful with allocated content in User when loading a binary save state. // This needs to be refactored out ASAP. u->rotator.Clear(); MREAD(u,sizeof(USER),1,fil); memset((void*)&u->rotator, 0, sizeof(u->rotator)); #if 0 if (u->WallShade) { u->WallShade = (int8_t*)CallocMem(u->WallCount * sizeof(*u->WallShade), 1); MREAD(u->WallShade, sizeof(*u->WallShade) * u->WallCount, 1, fil); } if (u->rotator) { u->rotator.Alloc(); MREAD(u->rotator,sizeof(*u->rotator),1,fil); if (u->rotator->origx) { u->rotator->origx = (int*)CallocMem(u->rotator->num_walls * sizeof(*u->rotator->origx), 1); MREAD(u->rotator->origx,sizeof(*u->rotator->origx)*u->rotator->num_walls,1,fil); } if (u->rotator->origy) { u->rotator->origy = (int*)CallocMem(u->rotator->num_walls * sizeof(*u->rotator->origy), 1); MREAD(u->rotator->origy,sizeof(*u->rotator->origy)*u->rotator->num_walls,1,fil); } } #endif saveisshot |= LoadSymDataInfo(fil, (void **)&u->WallP); saveisshot |= LoadSymDataInfo(fil, (void **)&u->State); saveisshot |= LoadSymDataInfo(fil, (void **)&u->Rot); saveisshot |= LoadSymDataInfo(fil, (void **)&u->StateStart); saveisshot |= LoadSymDataInfo(fil, (void **)&u->StateEnd); saveisshot |= LoadSymDataInfo(fil, (void **)&u->StateFallOverride); saveisshot |= LoadSymCodeInfo(fil, (void **)&u->ActorActionFunc); saveisshot |= LoadSymDataInfo(fil, (void **)&u->ActorActionSet); saveisshot |= LoadSymDataInfo(fil, (void **)&u->Personality); saveisshot |= LoadSymDataInfo(fil, (void **)&u->Attrib); saveisshot |= LoadSymDataInfo(fil, (void **)&u->sop_parent); saveisshot |= LoadSymDataInfo(fil, (void **)&u->hi_sectp); saveisshot |= LoadSymDataInfo(fil, (void **)&u->lo_sectp); saveisshot |= LoadSymDataInfo(fil, (void **)&u->hi_sp); saveisshot |= LoadSymDataInfo(fil, (void **)&u->lo_sp); saveisshot |= LoadSymDataInfo(fil, (void **)&u->SpriteP); saveisshot |= LoadSymDataInfo(fil, (void **)&u->PlayerP); saveisshot |= LoadSymDataInfo(fil, (void **)&u->tgt_sp); if (saveisshot) { MCLOSE_READ(fil); return false; } MREAD(&SpriteNum,sizeof(SpriteNum),1,fil); } MREAD(SectorObject, sizeof(SectorObject),1,fil); for (ndx = 0; ndx < (short)SIZ(SectorObject); ndx++) { sop = &SectorObject[ndx]; saveisshot |= LoadSymCodeInfo(fil, (void **)&sop->PreMoveAnimator); saveisshot |= LoadSymCodeInfo(fil, (void **)&sop->PostMoveAnimator); saveisshot |= LoadSymCodeInfo(fil, (void **)&sop->Animator); saveisshot |= LoadSymDataInfo(fil, (void **)&sop->controller); saveisshot |= LoadSymDataInfo(fil, (void **)&sop->sp_child); if (saveisshot) { MCLOSE_READ(fil); return false; } } MREAD(SineWaveFloor, sizeof(SineWaveFloor),1,fil); MREAD(SineWall, sizeof(SineWall),1,fil); MREAD(SpringBoard, sizeof(SpringBoard),1,fil); MREAD(Track, sizeof(Track),1,fil); for (i = 0; i < MAX_TRACKS; i++) { if (Track[i].NumPoints == 0) { Track[i].TrackPoint = (TRACK_POINTp)CallocMem(sizeof(TRACK_POINT), 1); MREAD(Track[i].TrackPoint, sizeof(TRACK_POINT),1,fil); } else { Track[i].TrackPoint = (TRACK_POINTp)CallocMem(Track[i].NumPoints * sizeof(TRACK_POINT), 1); MREAD(Track[i].TrackPoint, Track[i].NumPoints * sizeof(TRACK_POINT),1,fil); } } MREAD(&Player[myconnectindex].input,sizeof(Player[myconnectindex].input),1,fil); MREAD(&screenpeek,sizeof(screenpeek),1,fil); MREAD(&randomseed, sizeof(randomseed), 1, fil); // do all sector manipulation structures #if ANIM_SAVE #if 1 MREAD(&AnimCnt,sizeof(AnimCnt),1,fil); for (i = 0; i < AnimCnt; i++) { a = &Anim[i]; MREAD(a,sizeof(ANIM),1,fil); if ((intptr_t)a->ptr == -2) { // maintain compatibility with sinking boat which points to user data int offset; MREAD(&j, sizeof(j),1,fil); MREAD(&offset, sizeof(offset),1,fil); a->ptr = (int *)(((char *)User[j]) + offset); } else if ((intptr_t)a->ptr == -3) { // maintain compatibility with sinking boat which points to user data int offset; MREAD(&j, sizeof(j),1,fil); MREAD(&offset, sizeof(offset),1,fil); a->ptr = (int *)(((char *)SectUser[j]) + offset); } else { saveisshot |= LoadSymDataInfo(fil, (void **)&a->ptr); } saveisshot |= LoadSymCodeInfo(fil, (void **)&a->callback); saveisshot |= LoadSymDataInfo(fil, (void **)&a->callbackdata); if (saveisshot) { MCLOSE_READ(fil); return false; } } #else AnimCnt = 0; for (i = MAXANIM - 1; i >= 0; i--) { a = &Anim[i]; MREAD(&ndx,sizeof(ndx),1,fil); if (ndx == -1) break; AnimCnt++; MREAD(a,sizeof(ANIM),1,fil); saveisshot |= LoadSymDataInfo(fil, (void **)&a->ptr); saveisshot |= LoadSymCodeInfo(fil, (void **)&a->callback); saveisshot |= LoadSymDataInfo(fil, (void **)&a->callbackdata); if (saveisshot) { MCLOSE_READ(fil); return false; } } #endif #endif MREAD(&NormalVisibility,sizeof(NormalVisibility),1,fil); MREAD(&MoveSkip2,sizeof(MoveSkip2),1,fil); MREAD(&MoveSkip4,sizeof(MoveSkip4),1,fil); MREAD(&MoveSkip8,sizeof(MoveSkip8),1,fil); // SO interpolations saveisshot |= so_readinterpolations(fil); if (saveisshot) { MCLOSE_READ(fil); return false; } // parental lock for (i = 0; i < (int)SIZ(otlist); i++) { INITLIST(otlist[i]); while (true) { MREAD(&ndx, sizeof(ndx),1,fil); if (ndx == -1) break; otp = (OrgTileP)CallocMem(sizeof(*otp), 1); ASSERT(otp); MREAD(otp, sizeof(*otp),1,fil); INSERT_TAIL(otlist[i],otp); } } // mirror MREAD(mirror,sizeof(mirror),1,fil); MREAD(&mirrorcnt,sizeof(mirrorcnt),1,fil); MREAD(&mirrorinview,sizeof(mirrorinview),1,fil); // queue MREAD(&StarQueueHead,sizeof(StarQueueHead),1,fil); MREAD(StarQueue,sizeof(StarQueue),1,fil); MREAD(&HoleQueueHead,sizeof(HoleQueueHead),1,fil); MREAD(HoleQueue,sizeof(HoleQueue),1,fil); MREAD(&WallBloodQueueHead,sizeof(WallBloodQueueHead),1,fil); MREAD(WallBloodQueue,sizeof(WallBloodQueue),1,fil); MREAD(&FloorBloodQueueHead,sizeof(FloorBloodQueueHead),1,fil); MREAD(FloorBloodQueue,sizeof(FloorBloodQueue),1,fil); MREAD(&GenericQueueHead,sizeof(GenericQueueHead),1,fil); MREAD(GenericQueue,sizeof(GenericQueue),1,fil); MREAD(&LoWangsQueueHead,sizeof(LoWangsQueueHead),1,fil); MREAD(LoWangsQueue,sizeof(LoWangsQueue),1,fil); // init timing vars before PlayClock is read MREAD(&PlayClock,sizeof(PlayClock),1,fil); MREAD(&TotalKillable,sizeof(TotalKillable),1,fil); // game settings MREAD(&gNet,sizeof(gNet),1,fil); MREAD(&gs,sizeof(gs),1,fil); MREAD(&LevelSecrets,sizeof(LevelSecrets),1,fil); MREAD(&Bunny_Count,sizeof(Bunny_Count),1,fil); MREAD(&GodMode,sizeof(GodMode),1,fil); MREAD(&FinishTimer,sizeof(FinishTimer),1,fil); MREAD(&FinishAnim,sizeof(FinishAnim),1,fil); MREAD(&serpwasseen, sizeof(serpwasseen), 1, fil); MREAD(&sumowasseen, sizeof(sumowasseen), 1, fil); MREAD(&zillawasseen, sizeof(zillawasseen), 1, fil); MREAD(BossSpriteNum, sizeof(BossSpriteNum), 1, fil); //MREAD(&Zombies, sizeof(Zombies), 1, fil); MCLOSE_READ(fil); //!!IMPORTANT - this POST stuff will not work here now becaus it does actual reads // // POST processing of info MREAD in // #if PANEL_SAVE for (i = 0; i < numplayers; i++) { pp = &Player[i]; TRAVERSE(&pp->PanelSpriteList, psp, next) { // dont need to set Next and Prev this was done // when sprites were inserted // sibling is the only PanelSprite (malloced ptr) in the PanelSprite struct psp->sibling = PanelNdxToSprite(pp, (int)(intptr_t)psp->sibling); } } #endif DoTheCache(); // this is ok - just duplicating sector list with pointers for (sop = SectorObject; sop < &SectorObject[SIZ(SectorObject)]; sop++) { for (i = 0; i < sop->num_sectors; i++) sop->sectp[i] = §or[sop->sector[i]]; } //!!Again this will not work here //restore players info for (i = 0; i < numplayers; i++) { #if PANEL_SAVE pp->CurWpn = PanelNdxToSprite(pp, (int)(intptr_t)pp->CurWpn); for (ndx = 0; ndx < MAX_WEAPONS; ndx++) pp->Wpn[ndx] = PanelNdxToSprite(pp, (int)(intptr_t)pp->Wpn[ndx]); pp->Chops = PanelNdxToSprite(pp, (int)(intptr_t)pp->Chops); #endif } { int SavePlayClock = PlayClock; InitTimingVars(); PlayClock = SavePlayClock; } InitNetVars(); screenpeek = myconnectindex; Mus_ResumeSaved(); if (snd_ambience) StartAmbientSound(); TRAVERSE_CONNECT(i) { Player[i].StartColor = 0; } // this is not a new game ShadowWarrior::NewGame = false; DoPlayerDivePalette(Player+myconnectindex); DoPlayerNightVisionPalette(Player+myconnectindex); InitLevelGlobals(); return true; } END_SW_NS