//----------------------------------------------------------------------------- // Saves/loads from file //----------------------------------------------------------------------------- bool CVcdBlockDoc::LoadFromFile( const char *pFileName ) { Assert( !m_hVMFRoot.Get() ); Assert( !m_hEditRoot.Get() ); CAppDisableUndoScopeGuard guard( "CVcdBlockDoc::LoadFromFile", NOTIFY_CHANGE_OTHER ); SetDirty( false ); if ( !pFileName[0] ) return false; // Construct VMF file name from the BSP const char *pGame = Q_stristr( pFileName, "\\game\\" ); if ( !pGame ) { pGame = Q_stristr( pFileName, "\\content\\" ); if ( !pGame ) return false; } // Compute the map name const char *pMaps = Q_stristr( pFileName, "\\maps\\" ); if ( !pMaps ) return false; // Build map name char mapname[ 256 ]; Q_StripExtension( pFileName, mapname, sizeof(mapname) ); char *pszFileName = (char*)Q_UnqualifiedFileName(mapname); int nLen = (int)( (size_t)pGame - (size_t)pFileName ) + 1; Q_strncpy( m_pVMFFileName, pFileName, nLen ); Q_strncat( m_pVMFFileName, "\\content\\", sizeof(m_pVMFFileName) ); Q_strncat( m_pVMFFileName, pGame + 6, sizeof(m_pVMFFileName) ); Q_SetExtension( m_pVMFFileName, ".vmf", sizeof(m_pVMFFileName) ); // Make sure new entities start with ids at 0 CDmeVMFEntity::SetNextEntityId( 0 ); // Build the Edit file name Q_StripExtension( m_pVMFFileName, m_pEditFileName, sizeof(m_pEditFileName) ); Q_strncat( m_pEditFileName, ".vle", sizeof( m_pEditFileName ) ); // Store the BSP file name Q_strncpy( m_pBSPFileName, pFileName, sizeof( m_pBSPFileName ) ); // Set the txt file name. // If we loaded a .bsp, clear out what we're doing // load the Edits file into memory, assign it as our "root" CDmElement *pEdit = NULL; if ( !V_stricmp( Q_GetFileExtension( pFileName ), "vle" ) ) { if ( g_pDataModel->RestoreFromFile( m_pEditFileName, NULL, "vmf", &pEdit ) != DMFILEID_INVALID ) { // If we successfully read the file in, ask it for the max hammer id //int nMaxHammerId = pVMF->GetAttributeValue<int>( "maxHammerId" ); //CDmeVMFEntity::SetNextEntityId( nMaxHammerId + 1 ); m_hEditRoot = pEdit; SetDirty( false ); } } if (pEdit == NULL) { if ( g_pFileSystem->FileExists( m_pEditFileName ) ) { char pBuf[1024]; Q_snprintf( pBuf, sizeof(pBuf), "File %s already exists!\n", m_pEditFileName ); m_pEditFileName[0] = 0; vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Unable to overwrite file!\n", pBuf, g_pVcdBlockTool ); pMessageBox->DoModal( ); return false; } DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( m_pEditFileName ); m_hEditRoot = CreateElement<CDmElement>( "root", fileid ); m_hEditRoot->AddAttribute( "entities", AT_ELEMENT_ARRAY ); g_pDataModel->SetFileRoot( fileid, m_hEditRoot ); SetDirty( true ); } guard.Release(); // tell the engine to actually load the map char cmd[ 256 ]; Q_snprintf( cmd, sizeof( cmd ), "disconnect; map %s\n", pszFileName ); enginetools->Command( cmd ); enginetools->Execute( ); return true; }
// reads in current save data from a keyvalues file bool CASW_Campaign_Save::LoadGameFromFile(const char *szFileName) { // make sure the path and extension are correct char szFullFileName[256]; char tempbuffer[256]; Q_snprintf(tempbuffer, sizeof(tempbuffer), "%s", szFileName); Q_SetExtension( tempbuffer, ".campaignsave", sizeof(tempbuffer) ); const char *pszNoPathName = Q_UnqualifiedFileName(tempbuffer); Q_snprintf(szFullFileName, sizeof(szFullFileName), "save/%s", pszNoPathName); KeyValues *pSaveKeyValues = new KeyValues( szFileName ); if (pSaveKeyValues->LoadFromFile(filesystem, szFullFileName)) { m_CurrentSaveFileName = AllocPooledString(szFullFileName); m_iVersion = pSaveKeyValues->GetInt("Version"); m_iLowestSkillLevelPlayed = pSaveKeyValues->GetInt("SkillLevel"); Q_strncpy( m_CampaignName.GetForModify(), pSaveKeyValues->GetString("CampaignName"), 255 ); m_iCurrentPosition = pSaveKeyValues->GetInt("CurrentPosition"); m_iNumMissionsComplete = pSaveKeyValues->GetInt("NumMissionsComplete"); m_iInitialNumMissionsComplete = pSaveKeyValues->GetInt("InitialNumMissionsComplete"); m_bMultiplayerGame = pSaveKeyValues->GetInt("Multiplayer") != 0; Q_strncpy( m_DateTime.GetForModify(), pSaveKeyValues->GetString("DateTime"), 255 ); m_iNumDeaths = pSaveKeyValues->GetInt("NumDeaths"); m_bFixedSkillPoints = !asw_custom_skill_points.GetBool(); //pSaveKeyValues->GetBool( "FixedSkillPoints", true ); m_iNumPlayers = pSaveKeyValues->GetInt("NumPlayers"); m_PlayerNames.Purge(); m_PlayerIDs.Purge(); // go through each sub section, adding the relevant details KeyValues *pkvSubSection = pSaveKeyValues->GetFirstSubKey(); while ( pkvSubSection ) { // mission details if (Q_stricmp(pkvSubSection->GetName(), "MISSION")==0) { int MissionID = pkvSubSection->GetInt("MissionID"); if (MissionID >=0 && MissionID < ASW_MAX_MISSIONS_PER_CAMPAIGN) { m_MissionComplete.Set(MissionID, pkvSubSection->GetInt("MissionComplete")); m_NumRetries.Set(MissionID, pkvSubSection->GetInt("NumRetries")); } } // marine details if (Q_stricmp(pkvSubSection->GetName(), "MARINE")==0) { int MarineID = pkvSubSection->GetInt("MarineID"); if (MarineID >=0 && MarineID < ASW_NUM_MARINE_PROFILES) { m_iMarineSkill[MarineID][ASW_SKILL_SLOT_0] = pkvSubSection->GetInt("SkillSlot0"); m_iMarineSkill[MarineID][ASW_SKILL_SLOT_1] = pkvSubSection->GetInt("SkillSlot1"); m_iMarineSkill[MarineID][ASW_SKILL_SLOT_2] = pkvSubSection->GetInt("SkillSlot2"); m_iMarineSkill[MarineID][ASW_SKILL_SLOT_3] = pkvSubSection->GetInt("SkillSlot3"); m_iMarineSkill[MarineID][ASW_SKILL_SLOT_4] = pkvSubSection->GetInt("SkillSlot4"); m_iMarineSkill[MarineID][ASW_SKILL_SLOT_SPARE] = pkvSubSection->GetInt("SkillSlotSpare"); m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_0] = pkvSubSection->GetInt("UndoSkillSlot0"); m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_1] = pkvSubSection->GetInt("UndoSkillSlot1"); m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_2] = pkvSubSection->GetInt("UndoSkillSlot2"); m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_3] = pkvSubSection->GetInt("UndoSkillSlot3"); m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_4] = pkvSubSection->GetInt("UndoSkillSlot4"); m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_SPARE] = pkvSubSection->GetInt("UndoSkillSlotSpare"); m_iParasitesKilled[MarineID] = pkvSubSection->GetInt("ParasitesKilled"); m_MissionsCompleteNames.Set(MarineID, AllocPooledString(pkvSubSection->GetString("MissionsCompleted"))); m_Medals.Set(MarineID, AllocPooledString(pkvSubSection->GetString("Medals"))); m_bMarineWounded.Set(MarineID, (pkvSubSection->GetInt("Wounded") == 1)); m_bMarineDead.Set(MarineID, (pkvSubSection->GetInt("Dead") == 1)); //Ch1ckensCoop: Hack to give marines skill points for the first mission in a campaign. I'm too lazy to edit missionchooser. if (m_iCurrentPosition == 1) { m_iMarineSkill[MarineID][ASW_SKILL_SLOT_SPARE] = sk_asw_points_per_mission.GetInt(); m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_SPARE] = sk_asw_points_per_mission.GetInt(); } } } // player name if (Q_stricmp(pkvSubSection->GetName(), "PLAYER")==0) { string_t stringName = AllocPooledString(pkvSubSection->GetString("PlayerName")); m_PlayerNames.AddToTail(stringName); } // player ID if (Q_stricmp(pkvSubSection->GetName(), "DATA")==0) { string_t stringID = AllocPooledString(pkvSubSection->GetString("DataBlock")); m_PlayerIDs.AddToTail(stringID); } // last commanders if (Q_stricmp(pkvSubSection->GetName(), "COMM")==0) { for (int i=0;i<ASW_NUM_MARINE_PROFILES;i++) { char buffer[16]; Q_snprintf(buffer, sizeof(buffer), "Comm%d", i); string_t stringID = AllocPooledString(pkvSubSection->GetString(buffer)); m_LastCommanders[i] = stringID; Q_snprintf(buffer, sizeof(buffer), "Slot%d", i); m_LastMarineResourceSlot[i] = pkvSubSection->GetInt(buffer); //Ch1ckensCoop: Remember primary marines for each player, so we can handle reservations properly. Q_snprintf(buffer, sizeof(buffer), "Primary%d", i); m_LastPrimaryMarines[i] = pkvSubSection->GetBool(buffer); } } pkvSubSection = pkvSubSection->GetNextKey(); } return true; } Msg("Failed to load KeyValues from file %s\n", szFullFileName); return false; }
// saves current save data to a keyvalues file bool CASW_Campaign_Save::SaveGameToFile(const char *szFileName) { // make sure the path and extension are correct char szFullFileName[256]; char tempbuffer[256]; if (szFileName==NULL) { if (m_CurrentSaveFileName == NULL_STRING) { Msg("Error: Couldn't save game to file as we have no name already and you didn't supply one.\n"); return false; } Q_snprintf(szFullFileName, sizeof(szFullFileName), "%s", STRING(m_CurrentSaveFileName)); } else { Q_snprintf(tempbuffer, sizeof(tempbuffer), "%s", szFileName); Q_SetExtension( tempbuffer, ".campaignsave", sizeof(tempbuffer) ); const char *pszNoPathName = Q_UnqualifiedFileName(tempbuffer); Q_snprintf(szFullFileName, sizeof(szFullFileName), "save/%s", pszNoPathName); } // before saving, check if this is actually a completed campaign if (ASWGameRules()) { int iLeft = ASWGameRules()->CampaignMissionsLeft(); if (iLeft <= 0) { Msg("Deleting completed campaign %s", szFullFileName); filesystem->RemoveFile( szFullFileName, "GAME" ); // notify the local mission source that a save has been deleted if (missionchooser && missionchooser->LocalMissionSource()) { const char *pszNoPathName = Q_UnqualifiedFileName(szFullFileName); missionchooser->LocalMissionSource()->NotifySaveDeleted(pszNoPathName); } return true; } } // we don't want completed campaigns lingering on disk KeyValues *pSaveKeyValues = new KeyValues( "CAMPAIGNSAVE" ); pSaveKeyValues->SetInt("Version", m_iVersion); pSaveKeyValues->SetInt("SkillLevel", m_iLowestSkillLevelPlayed); pSaveKeyValues->SetString("CampaignName", m_CampaignName.Get()); pSaveKeyValues->SetInt("CurrentPosition", m_iCurrentPosition); pSaveKeyValues->SetInt("NumMissionsComplete", m_iNumMissionsComplete); pSaveKeyValues->SetInt("InitialNumMissionsComplete", m_iInitialNumMissionsComplete); pSaveKeyValues->SetInt("Multiplayer", m_bMultiplayerGame ? 1 : 0); pSaveKeyValues->SetInt( "NumDeaths", m_iNumDeaths ); pSaveKeyValues->SetBool( "FixedSkillPoints", m_bFixedSkillPoints ); // update date int year, month, dayOfWeek, day, hour, minute, second; missionchooser->GetCurrentTimeAndDate(&year, &month, &dayOfWeek, &day, &hour, &minute, &second); //year = month = dayOfWeek = day = hour = minute = second = 0; Q_snprintf(m_DateTime.GetForModify(), 255, "%02d/%02d/%d %02d:%02d", month, day, year, hour, minute); pSaveKeyValues->SetString("DateTime", m_DateTime.Get()); // write out each mission's status KeyValues *pSubSection; for (int i=0; i<ASW_MAX_MISSIONS_PER_CAMPAIGN; i++) { pSubSection = new KeyValues("MISSION"); pSubSection->SetInt("MissionID", i); pSubSection->SetInt("MissionComplete", m_MissionComplete[i]); pSubSection->SetInt("NumRetries", m_NumRetries[i]); pSaveKeyValues->AddSubKey(pSubSection); } // write out each marine's stats for (int MarineID=0; MarineID<ASW_NUM_MARINE_PROFILES; MarineID++) { pSubSection = new KeyValues("MARINE"); pSubSection->SetInt("MarineID", MarineID); pSubSection->SetInt("SkillSlot0", m_iMarineSkill[MarineID][ASW_SKILL_SLOT_0]); pSubSection->SetInt("SkillSlot1", m_iMarineSkill[MarineID][ASW_SKILL_SLOT_1]); pSubSection->SetInt("SkillSlot2", m_iMarineSkill[MarineID][ASW_SKILL_SLOT_2]); pSubSection->SetInt("SkillSlot3", m_iMarineSkill[MarineID][ASW_SKILL_SLOT_3]); pSubSection->SetInt("SkillSlot4", m_iMarineSkill[MarineID][ASW_SKILL_SLOT_4]); pSubSection->SetInt("SkillSlotSpare", m_iMarineSkill[MarineID][ASW_SKILL_SLOT_SPARE]); pSubSection->SetInt("UndoSkillSlot0", m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_0]); pSubSection->SetInt("UndoSkillSlot1", m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_1]); pSubSection->SetInt("UndoSkillSlot2", m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_2]); pSubSection->SetInt("UndoSkillSlot3", m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_3]); pSubSection->SetInt("UndoSkillSlot4", m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_4]); pSubSection->SetInt("UndoSkillSlotSpare", m_iPreviousMarineSkill[MarineID][ASW_SKILL_SLOT_SPARE]); pSubSection->SetInt("ParasitesKilled", m_iParasitesKilled[MarineID]); pSubSection->SetString("MissionsCompleted", STRING(m_MissionsCompleteNames[MarineID])); pSubSection->SetString("Medals", STRING(m_Medals[MarineID])); int iWound = IsMarineWounded(MarineID) ? 1 : 0; pSubSection->SetInt("Wounded", iWound); int iDead = IsMarineAlive(MarineID) ? 0 : 1; pSubSection->SetInt("Dead", iDead); pSaveKeyValues->AddSubKey(pSubSection); } // check for any new players to add to our list for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CASW_Player* pPlayer = dynamic_cast<CASW_Player*>(UTIL_PlayerByIndex(i)); if ( pPlayer ) { // first check his network ID const char *pszNetworkID = pPlayer->GetASWNetworkID(); // check if it's in our list bool bFound = false; for (int k=0;k<m_PlayerIDs.Count();k++) { const char *p = STRING(m_PlayerIDs[k]); if (!Q_strcmp(p, pszNetworkID)) bFound = true; } if (!bFound) { // add it to the list string_t stringID = AllocPooledString(pszNetworkID); m_PlayerIDs.AddToTail(stringID); } // then check player name const char *pszPlayerName = pPlayer->GetPlayerName(); bFound = false; for (int k=0;k<m_PlayerNames.Count();k++) { const char *p = STRING(m_PlayerNames[k]); if (!Q_strcmp(p, pszPlayerName)) bFound = true; } if (!bFound) { // add it to the list string_t stringName = AllocPooledString(pszPlayerName); m_PlayerNames.AddToTail(stringName); } } } pSaveKeyValues->SetInt("NumPlayers", m_PlayerNames.Count()); // write out player names for (int i=0; i<m_PlayerNames.Count(); i++) { pSubSection = new KeyValues("PLAYER"); pSubSection->SetString("PlayerName", STRING(m_PlayerNames[i])); pSaveKeyValues->AddSubKey(pSubSection); } // write out player IDs for (int i=0; i<m_PlayerIDs.Count(); i++) { pSubSection = new KeyValues("DATA"); pSubSection->SetString("DataBlock", STRING(m_PlayerIDs[i])); pSaveKeyValues->AddSubKey(pSubSection); } // write out last commanders section pSubSection = new KeyValues("COMM"); for (int i=0;i<ASW_NUM_MARINE_PROFILES;i++) { char buffer[16]; Q_snprintf(buffer, sizeof(buffer), "Comm%d", i); pSubSection->SetString(buffer, STRING(m_LastCommanders[i])); Q_snprintf(buffer, sizeof(buffer), "Slot%d", i); pSubSection->SetInt( buffer, m_LastMarineResourceSlot[i] ); //Ch1ckensCoop: Record which marine was primary for reservations. Q_snprintf(buffer, sizeof(buffer), "Primary%d", i); pSubSection->SetBool( buffer, m_LastPrimaryMarines[i] ); } pSaveKeyValues->AddSubKey(pSubSection); if (pSaveKeyValues->SaveToFile(filesystem, szFullFileName)) { if (missionchooser && missionchooser->LocalMissionSource()) { const char *pszNoPathName = Q_UnqualifiedFileName(szFullFileName); missionchooser->LocalMissionSource()->OnSaveUpdated(pszNoPathName); } return true; } return false; }
bool CASW_Mission_Chooser_Source_Local::ASW_Campaign_CreateNewSaveGame(char *szFileName, int iFileNameMaxLen, const char *szCampaignName, bool bMultiplayerGame, const char *szStartingMission) // szFileName arg is the desired filename or NULL for an autogenerated one. Function sets szFileName with the filename used. { if (!szFileName) return false; char stripped[MAX_PATH]; V_StripExtension( szCampaignName, stripped, MAX_PATH ); char szStartingMissionStripped[64]; if ( szStartingMission ) { V_StripExtension( szStartingMission, szStartingMissionStripped, sizeof( szStartingMissionStripped ) ); } else { szStartingMissionStripped[0] = 0; } // check the campaign file exists char campbuffer[MAX_PATH]; Q_snprintf(campbuffer, sizeof(campbuffer), "resource/campaigns/%s.txt", stripped); if (!g_pFullFileSystem->FileExists(campbuffer)) { Msg("No such campaign: %s\n", campbuffer); return false; } // Get the current time and date as a string char szDateTime[256]; int year, month, dayOfWeek, day, hour, minute, second; ASW_System_GetCurrentTimeAndDate(&year, &month, &dayOfWeek, &day, &hour, &minute, &second); Q_snprintf(szDateTime, sizeof(szDateTime), "%04d-%02d-%02dT%02d:%02d:%02d", year, month, day, hour, minute, second); if (szFileName[0] == '\0') { // autogenerate a filename based on the current time and date Q_snprintf(szFileName, iFileNameMaxLen, "%s_save_%02d_%02d_%02d_%02d_%02d_%02d", stripped, year, month, day, hour, minute, second); } // make sure the path and extension are correct Q_SetExtension( szFileName, ".campaignsave", iFileNameMaxLen ); char tempbuffer[256]; Q_snprintf(tempbuffer, sizeof(tempbuffer), "%s", szFileName); const char *pszNoPathName = Q_UnqualifiedFileName(tempbuffer); Msg("Unqualified = %s\n", pszNoPathName); char szFullFileName[256]; Q_snprintf(szFullFileName, sizeof(szFullFileName), "save/%s", pszNoPathName); Msg("Creating new save with filename: %s\n", szFullFileName); KeyValues *pSaveKeyValues = new KeyValues( pszNoPathName ); int nMissionsComplete = 0; if ( szStartingMission && szStartingMission[0] ) { KeyValues *pCampaignDetails = GetCampaignDetails( stripped ); if ( pCampaignDetails ) { int nMissionSections = 0; for ( KeyValues *pMission = pCampaignDetails->GetFirstSubKey(); pMission; pMission = pMission->GetNextKey() ) { if ( !Q_stricmp( pMission->GetName(), "MISSION" ) ) { if ( !Q_stricmp( pMission->GetString( "MapName", "" ), szStartingMissionStripped ) ) { nMissionsComplete = nMissionSections - 1; // skip first dummy mission break; } nMissionSections++; } } } } pSaveKeyValues->SetInt("Version", ASW_CURRENT_SAVE_VERSION); pSaveKeyValues->SetString("CampaignName", stripped); pSaveKeyValues->SetInt("CurrentPosition", nMissionsComplete + 1); // position squad on the first uncompleted mission pSaveKeyValues->SetInt("NumMissionsComplete", nMissionsComplete); pSaveKeyValues->SetInt("InitialNumMissionsComplete", nMissionsComplete); pSaveKeyValues->SetInt("Multiplayer", bMultiplayerGame ? 1 : 0); pSaveKeyValues->SetString("DateTime", szDateTime); pSaveKeyValues->SetInt("NumPlayers", 0); // write out each mission's status KeyValues *pSubSection; for (int i=0; i<ASW_MAX_MISSIONS_PER_CAMPAIGN; i++) { pSubSection = new KeyValues("MISSION"); pSubSection->SetInt("MissionID", i); bool bComplete = ( i != 0 ) && ( i <= nMissionsComplete ); pSubSection->SetInt("MissionComplete", bComplete ? 1 : 0 ); pSaveKeyValues->AddSubKey(pSubSection); } const int nInitialSkillPoints = 0; // write out each marine's stats for (int i=0; i<ASW_NUM_MARINE_PROFILES; i++) { pSubSection = new KeyValues("MARINE"); pSubSection->SetInt("MarineID", i); pSubSection->SetInt("SkillSlot0", 0); pSubSection->SetInt("SkillSlot1", 0); pSubSection->SetInt("SkillSlot2", 0); pSubSection->SetInt("SkillSlot3", 0); pSubSection->SetInt("SkillSlot4", 0); pSubSection->SetInt("SkillSlotSpare", nInitialSkillPoints + nMissionsComplete * ASW_SKILL_POINTS_PER_MISSION ); pSubSection->SetInt("UndoSkillSlot0", 0); pSubSection->SetInt("UndoSkillSlot1", 0); pSubSection->SetInt("UndoSkillSlot2", 0); pSubSection->SetInt("UndoSkillSlot3", 0); pSubSection->SetInt("UndoSkillSlot4", 0); pSubSection->SetInt("UndoSkillSlotSpare", nInitialSkillPoints + nMissionsComplete * ASW_SKILL_POINTS_PER_MISSION ); pSubSection->SetString("MissionsCompleted", ""); pSubSection->SetString("Medals", ""); pSubSection->SetInt("Wounded", 0); pSubSection->SetInt("Dead", 0); pSubSection->SetInt("ParasitesKilled", 0); pSaveKeyValues->AddSubKey(pSubSection); } // players section is empty at first // Create the save sub-directory if (!g_pFullFileSystem->IsDirectory( "save", "MOD" )) { g_pFullFileSystem->CreateDirHierarchy( "save", "MOD" ); } // save it if (pSaveKeyValues->SaveToFile(g_pFullFileSystem, szFullFileName)) { // make sure our save summary list adds this to it, if needed Msg("New save created: %s\n", szFullFileName); NotifyNewSave(pszNoPathName); return true; } Msg("Save to file failed. Filename=%s\n", szFullFileName); return false; }