//-----------------------------------------------------------------------------
// 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;
}
Esempio n. 2
0
// 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;
}
Esempio n. 3
0
// 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;
}