📄 sv_save.c
字号:
} } randomclass = rClass; // Redirect anything targeting a player mobj if(TargetPlayerAddrs) { for(i = 0; i < TargetPlayerCount; i++) { *TargetPlayerAddrs[i] = (int)targetPlayerMobj; } Z_Free(TargetPlayerAddrs); } // Destroy all things touching players for(i = 0; i < MAXPLAYERS; i++) { if(playeringame[i]) { P_TeleportMove(players[i].mo, players[i].mo->x, players[i].mo->y); } } // Restore trashed globals inv_ptr = inventoryPtr; curpos = currentInvPos; // Launch waiting scripts if(!deathmatch) { P_CheckACSStore(); } // For single play, save immediately into the reborn slot if(!netgame) { SV_SaveGame(REBORN_SLOT, REBORN_DESCRIPTION); }}//==========================================================================//// SV_GetRebornSlot////==========================================================================int SV_GetRebornSlot(void){ return(REBORN_SLOT);}//==========================================================================//// SV_RebornSlotAvailable//// Returns true if the reborn slot is available.////==========================================================================boolean SV_RebornSlotAvailable(void){ char fileName[100]; sprintf(fileName, "%shex%d.hxs", SavePath, REBORN_SLOT); return ExistingFile(fileName);}//==========================================================================//// SV_LoadMap////==========================================================================void SV_LoadMap(void){ char fileName[100]; // Load a base level G_InitNew(gameskill, gameepisode, gamemap); // Remove all thinkers RemoveAllThinkers(); // Create the name sprintf(fileName, "%shex6%02d.hxs", SavePath, gamemap); // Load the file M_ReadFile(fileName, &SaveBuffer); SavePtr.b = SaveBuffer; AssertSegment(ASEG_MAP_HEADER); // Read the level timer leveltime = GET_LONG; UnarchiveWorld(); UnarchivePolyobjs(); UnarchiveMobjs(); UnarchiveThinkers(); UnarchiveScripts(); UnarchiveSounds(); UnarchiveMisc(); AssertSegment(ASEG_END); // Free mobj list and save buffer Z_Free(MobjList); Z_Free(SaveBuffer);}//==========================================================================//// SV_InitBaseSlot////==========================================================================void SV_InitBaseSlot(void){ ClearSaveSlot(BASE_SLOT);}//==========================================================================//// ArchivePlayers////==========================================================================static void ArchivePlayers(void){ int i; int j; player_t tempPlayer; StreamOutLong(ASEG_PLAYERS); for(i = 0; i < MAXPLAYERS; i++) { StreamOutByte(playeringame[i]); } for(i = 0; i < MAXPLAYERS; i++) { if(!playeringame[i]) { continue; } StreamOutByte(PlayerClass[i]); tempPlayer = players[i]; for(j = 0; j < NUMPSPRITES; j++) { if(tempPlayer.psprites[j].state) { tempPlayer.psprites[j].state = (state_t *)(tempPlayer.psprites[j].state-states); } } StreamOutBuffer(&tempPlayer, sizeof(player_t)); }}//==========================================================================//// UnarchivePlayers////==========================================================================static void UnarchivePlayers(void){ int i, j; AssertSegment(ASEG_PLAYERS); for(i = 0; i < MAXPLAYERS; i++) { playeringame[i] = GET_BYTE; } for(i = 0; i < MAXPLAYERS; i++) { if(!playeringame[i]) { continue; } PlayerClass[i] = GET_BYTE; memcpy(&players[i], SavePtr.b, sizeof(player_t)); SavePtr.b += sizeof(player_t); players[i].mo = NULL; // Will be set when unarc thinker P_ClearMessage(&players[i]); players[i].attacker = NULL; players[i].poisoner = 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; int j; sector_t *sec; line_t *li; side_t *si; StreamOutLong(ASEG_WORLD); 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); StreamOutWord(sec->tag); StreamOutWord(sec->seqType); } for(i = 0, li = lines; i < numlines; i++, li++) { StreamOutWord(li->flags); StreamOutByte(li->special); StreamOutByte(li->arg1); StreamOutByte(li->arg2); StreamOutByte(li->arg3); StreamOutByte(li->arg4); StreamOutByte(li->arg5); 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; int j; sector_t *sec; line_t *li; side_t *si; AssertSegment(ASEG_WORLD); for(i = 0, sec = sectors; i < numsectors; i++, sec++) { sec->floorheight = GET_WORD<<FRACBITS; sec->ceilingheight = GET_WORD<<FRACBITS; sec->floorpic = GET_WORD; sec->ceilingpic = GET_WORD; sec->lightlevel = GET_WORD; sec->special = GET_WORD; sec->tag = GET_WORD; sec->seqType = GET_WORD; sec->specialdata = 0; sec->soundtarget = 0; } for(i = 0, li = lines; i < numlines; i++, li++) { li->flags = GET_WORD; li->special = GET_BYTE; li->arg1 = GET_BYTE; li->arg2 = GET_BYTE; li->arg3 = GET_BYTE; li->arg4 = GET_BYTE; li->arg5 = GET_BYTE; for(j = 0; j < 2; j++) { if(li->sidenum[j] == -1) { continue; } si = &sides[li->sidenum[j]]; si->textureoffset = GET_WORD<<FRACBITS; si->rowoffset = GET_WORD<<FRACBITS; si->toptexture = GET_WORD; si->bottomtexture = GET_WORD; si->midtexture = GET_WORD; } }}//==========================================================================//// SetMobjArchiveNums//// Sets the archive numbers in all mobj structs. Also sets the MobjCount// global. Ignores player mobjs if SavingPlayers is false.////==========================================================================static void SetMobjArchiveNums(void){ mobj_t *mobj; thinker_t *thinker; MobjCount = 0; for(thinker = thinkercap.next; thinker != &thinkercap; thinker = thinker->next) { if(thinker->function == P_MobjThinker) { mobj = (mobj_t *)thinker; if(mobj->player && !SavingPlayers) { // Skipping player mobjs continue; } mobj->archiveNum = MobjCount++; } }}//==========================================================================//// ArchiveMobjs////==========================================================================static void ArchiveMobjs(void){ int count; thinker_t *thinker; mobj_t tempMobj; StreamOutLong(ASEG_MOBJS); StreamOutLong(MobjCount); count = 0; for(thinker = thinkercap.next; thinker != &thinkercap; thinker = thinker->next) { if(thinker->function != P_MobjThinker) { // Not a mobj thinker continue; } if(((mobj_t *)thinker)->player && !SavingPlayers) { // Skipping player mobjs continue; } count++; memcpy(&tempMobj, thinker, sizeof(mobj_t)); MangleMobj(&tempMobj); StreamOutBuffer(&tempMobj, sizeof(mobj_t)); } if(count != MobjCount) { I_Error("ArchiveMobjs: bad mobj count"); }}//==========================================================================//// UnarchiveMobjs////==========================================================================static void UnarchiveMobjs(void){ int i; mobj_t *mobj; AssertSegment(ASEG_MOBJS); TargetPlayerAddrs = Z_Malloc(MAX_TARGET_PLAYERS*sizeof(int *), PU_STATIC, NULL); TargetPlayerCount = 0; MobjCount = GET_LONG; MobjList = Z_Malloc(MobjCount*sizeof(mobj_t *), PU_STATIC, NULL); for(i = 0; i < MobjCount; i++) { MobjList[i] = Z_Malloc(sizeof(mobj_t), PU_LEVEL, NULL); } for(i = 0; i < MobjCount; i++) { mobj = MobjList[i]; memcpy(mobj, SavePtr.b, sizeof(mobj_t)); SavePtr.b += sizeof(mobj_t); mobj->thinker.function = P_MobjThinker; RestoreMobj(mobj); P_AddThinker(&mobj->thinker); } P_CreateTIDList(); P_InitCreatureCorpseQueue(true); // true = scan for corpses}//==========================================================================//// MangleMobj////==========================================================================static void MangleMobj(mobj_t *mobj){ boolean corpse; corpse = mobj->flags&MF_CORPSE; mobj->state = (state_t *)(mobj->state-states); if(mobj->player) { mobj->player = (player_t *)((mobj->player-players)+1); } if(corpse) { mobj->target = (mobj_t *)MOBJ_NULL; } else { mobj->target = (mobj_t *)GetMobjNum(mobj->target); } switch(mobj->type) { // Just special1 case MT_BISH_FX: case MT_HOLY_FX: case MT_DRAGON: case MT_THRUSTFLOOR_UP: case MT_THRUSTFLOOR_DOWN: case MT_MINOTAUR: case MT_SORCFX1: case MT_MSTAFF_FX2: if(corpse) { mobj->special1 = MOBJ_NULL; } else { mobj->special1 = GetMobjNum((mobj_t *)mobj->special1); } break; // Just special2 case MT_LIGHTNING_FLOOR: case MT_LIGHTNING_ZAP: if(corpse) { mobj->special2 = MOBJ_NULL; } else { mobj->special2 = GetMobjNum((mobj_t *)mobj->special2); } break; // Both special1 and special2 case MT_HOLY_TAIL: case MT_LIGHTNING_CEILING: if(corpse) { mobj->special1 = MOBJ_NULL; mobj->special2 = MOBJ_NULL; } else { mobj->special1 = GetMobjNum((mobj_t *)mobj->special1); mobj->special2 = GetMobjNum((mobj_t *)mobj->special2); } break; // Miscellaneous case MT_KORAX: mobj->special1 = 0; // Searching index break; default: break; }}//==========================================================================//// GetMobjNum////==========================================================================static int GetMobjNum(mobj_t *mobj){ if(mobj == NULL) { return MOBJ_NULL; } if(mobj->player && !SavingPlayers) { return MOBJ_XX_PLAYER; } return mobj->archiveNum;}//==========================================================================//// RestoreMobj////==========================================================================static void RestoreMobj(mobj_t *mobj){ mobj->state = &states[(int)mobj->state]; 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; SetMobjPtr((int *)&mobj->target); switch(mobj->type) { // Just special1 case MT_BISH_FX: case MT_HOLY_FX: case MT_DRAGON: case MT_THRUSTFLOOR_UP: case MT_THRUSTFLOOR_DOWN: case MT_MINOTAUR: case MT_SORCFX1: SetMobjPtr(&mobj->special1); break; // Just special2 case MT_LIGHTNING_FLOOR: case MT_LIGHTNING_ZAP: SetMobjPtr(&mobj->special2); break; // Both special1 and special2 case MT_HOLY_TAIL: case MT_LIGHTNING_CEILING: SetMobjPtr(&mobj->special1); SetMobjPtr(&mobj->special2); break; default: break; }}//==========================================================================//// SetMobjPtr////==========================================================================static void SetMobjPtr(int *archiveNum){ if(*archiveNum == MOBJ_NULL) { *archiveNum = 0; return; } if(*archiveNum == MOBJ_XX_PLAYER) { if(TargetPlayerCount == MAX_TARGET_PLAYERS) { I_Error("RestoreMobj: exceeded MAX_TARGET_PLAYERS"); } TargetPlayerAddrs[TargetPlayerCount++] = archiveNum; *archiveNum = 0; return; } *archiveNum = (int)MobjList[*archiveNum];}//==========================================================================//// ArchiveThinkers////==========================================================================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -