int CASW_Mission_Chooser_Source_Local::GetNumMissionsInCampaign( int iCampaignIndex )
{
	if (!m_bBuiltMapList)
		BuildMapList();

	ASW_Mission_Chooser_Mission* pCampaign = GetCampaign( iCampaignIndex );
	if ( !pCampaign )
		return 0;

	KeyValues *pCampaignDetails = GetCampaignDetails( pCampaign->m_szMissionName );
	if ( !pCampaignDetails )
		return 0;

	CUtlVector<KeyValues*> aMissionKeys;
	bool bSkippedFirst = false;
	for ( KeyValues *pMission = pCampaignDetails->GetFirstSubKey(); pMission; pMission = pMission->GetNextKey() )
	{
		if ( !Q_stricmp( pMission->GetName(), "MISSION" ) )
		{
			if ( !bSkippedFirst )
			{
				bSkippedFirst = true;
			}
			else
			{
				aMissionKeys.AddToTail( pMission );
			}
		}
	}

	return aMissionKeys.Count();
}
void CASW_Mission_Chooser_Source_Local::FindMissionsInCampaign( int iCampaignIndex, int nMissionOffset, int iNumSlots )
{
	if (!m_bBuiltMapList)
		BuildMapList();

	ASW_Mission_Chooser_Mission* pCampaign = GetCampaign( iCampaignIndex );
	if ( !pCampaign )
		return;

	KeyValues *pCampaignDetails = GetCampaignDetails( pCampaign->m_szMissionName );
	if ( !pCampaignDetails )
		return;

	CUtlVector<KeyValues*> aMissionKeys;
	bool bSkippedFirst = false;
	for ( KeyValues *pMission = pCampaignDetails->GetFirstSubKey(); pMission; pMission = pMission->GetNextKey() )
	{
		if ( !Q_stricmp( pMission->GetName(), "MISSION" ) )
		{
			if ( !bSkippedFirst )
			{
				bSkippedFirst = true;
			}
			else
			{
				aMissionKeys.AddToTail( pMission );
			}
		}
	}
	
	int max_items = aMissionKeys.Count();
	for ( int stored=0;stored<iNumSlots;stored++ )
	{
		int realoffset = nMissionOffset;
		if ( realoffset >= max_items || realoffset < 0 )
		{
			// no more missions...
			Q_snprintf( m_missions[stored].m_szMissionName, sizeof( m_missions[stored].m_szMissionName ), "" );
		}
		else
		{
			Q_snprintf( m_missions[stored].m_szMissionName, sizeof( m_missions[stored].m_szMissionName ), "%s", aMissionKeys[realoffset]->GetString( "MapName" ) );
		}
		nMissionOffset++;
	}
}
const char* CASW_Mission_Chooser_Source_Local::GetCampaignSaveIntroMap(const char *szSaveName)
{
	// check the save file exists
	char stripped[MAX_PATH];
	V_StripExtension( szSaveName, stripped, MAX_PATH );
	char tempfile[MAX_PATH];
	Q_snprintf( tempfile, sizeof( tempfile ), "save/%s.campaignsave", stripped );
	if (!g_pFullFileSystem->FileExists(tempfile))
		return NULL;

	KeyValues *pSaveKeyValues = new KeyValues( szSaveName );
	KeyValues::AutoDelete saveKeyValuesAutoDelete( pSaveKeyValues );
	const char* pszCampaign = NULL;
	if (pSaveKeyValues->LoadFromFile(g_pFullFileSystem, tempfile))
		pszCampaign = pSaveKeyValues->GetString("CampaignName");

	if (!pszCampaign)
		return NULL;

	// now read in the campaign txt and find the intro map name
	KeyValues *pCampaignKeyValues = GetCampaignDetails( pszCampaign );
	if (pCampaignKeyValues)
	{
		KeyValues *pMission = pCampaignKeyValues->FindKey("MISSION");
		Assert(pMission);
		if (pMission)
		{
			pMission = pMission->GetNextKey();
			Assert(pMission && !Q_stricmp(pMission->GetName(), "MISSION"));
			if (pMission && !Q_stricmp(pMission->GetName(), "MISSION"))
			{
				Assert(pMission->GetString("MapName", NULL));
				return pMission->GetString("MapName", NULL);
			}
		}
	}

	return NULL;
}
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), "%02d/%02d/%02d %02d:%02d", month, day, year, hour, minute);

	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;
}