KeyValues* VMFExporter::GetViewSettings() { KeyValues *pKeys = new KeyValues( "viewsettings" ); pKeys->SetBool( "bSnapToGrid", true ); pKeys->SetBool( "bShowGrid", true ); pKeys->SetBool( "bShowLogicalGrid", false ); pKeys->SetInt( "nGridSpacing", ASW_TILE_SIZE ); pKeys->SetBool( "bShow3DGrid", false ); return pKeys; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CEditorSystem::CopySelection() { ClearCopyCommands(); if( !IsAnythingSelected() ) return; Vector vCopyOffset(64.0f, 64.0f, 0.0f ); for( int i = 0; i < m_hSelectedEntities.Count(); i++ ) { if( !m_hSelectedEntities[i] ) continue; CWarsFlora *pFlora = dynamic_cast<CWarsFlora *>( m_hSelectedEntities[i].Get() ); if( pFlora ) { KeyValues *pOperation = CreateFloraCreateCommand( pFlora, &vCopyOffset ); pOperation->SetBool( "select", true ); m_SelectionCopyCommands.AddToTail( pOperation ); } else { Warning( "CEditorSystem::CopySelection: Trying to copy an unsupported entity\n" ); } } }
//----------------------------------------------------------------------------- // Purpose: Saves the version information chunk. // Input : *pFile - // Output : Returns ChunkFile_Ok on success, an error code on failure. //----------------------------------------------------------------------------- KeyValues* VMFExporter::GetVersionInfo() { KeyValues *pKeys = new KeyValues( "versioninfo" ); pKeys->SetInt( "editorversion", 400 ); pKeys->SetInt( "editorbuild", 3900 ); pKeys->SetInt( "mapversion", 1 ); pKeys->SetInt( "formatversion", 100 ); pKeys->SetBool( "prefab", false ); return pKeys; }
bool CLevelTheme::SaveTheme(const char *pszThemeName) { char szFullFileName[MAX_PATH]; Q_snprintf(szFullFileName, sizeof(szFullFileName), "tilegen/themes/%s.theme", pszThemeName); KeyValues *pThemeKeyValues = new KeyValues( pszThemeName ); pThemeKeyValues->SetString("ThemeName", m_szName); pThemeKeyValues->SetString("ThemeDescription", m_szDescription); pThemeKeyValues->SetBool( "VMFTweak", m_bRequiresVMFTweak ); pThemeKeyValues->SetBool( "SkipErrorCheck", m_bSkipErrorCheck ); char buffer[128]; Q_snprintf( buffer, sizeof( buffer ), "%f %f %f", m_vecAmbientLight.x, m_vecAmbientLight.y, m_vecAmbientLight.z ); pThemeKeyValues->SetString( "AmbientLight", buffer ); if (!pThemeKeyValues->SaveToFile(g_pFullFileSystem, szFullFileName, "GAME")) { Msg("Error: Failed to save theme %s\n", szFullFileName); return false; } // TODO: check the room templates folder for this theme exists return true; }
bool CRoomTemplate::SaveRoomTemplate() { if (!m_pLevelTheme) return false; char szThemeDirName[MAX_PATH]; Q_snprintf(szThemeDirName, sizeof(szThemeDirName), "tilegen/roomtemplates/%s", m_pLevelTheme->m_szName); g_pFullFileSystem->CreateDirHierarchy( szThemeDirName, "GAME" ); char szFullFileName[MAX_PATH]; Q_snprintf( szFullFileName, sizeof(szFullFileName), "tilegen/roomtemplates/%s/%s.roomtemplate", m_pLevelTheme->m_szName, m_FullName ); KeyValues *pRoomTemplateKeyValues = new KeyValues( m_FullName ); pRoomTemplateKeyValues->SetInt( "TilesX", m_nTilesX ); pRoomTemplateKeyValues->SetInt( "TilesY", m_nTilesY ); pRoomTemplateKeyValues->SetInt( "SpawnWeight", m_nSpawnWeight ); pRoomTemplateKeyValues->SetString( "RoomTemplateDescription", m_Description ); pRoomTemplateKeyValues->SetString( "Soundscape", m_Soundscape ); pRoomTemplateKeyValues->SetInt( "TileType", m_nTileType ); // exits int iExits = m_Exits.Count(); for (int i=0; i<iExits; i++) { KeyValues *pkvSubSection = new KeyValues("EXIT"); pkvSubSection->SetInt("XPos", m_Exits[i]->m_iXPos); pkvSubSection->SetInt("YPos", m_Exits[i]->m_iYPos); pkvSubSection->SetInt("ExitDirection", (int) m_Exits[i]->m_ExitDirection); pkvSubSection->SetInt("ZChange", m_Exits[i]->m_iZChange); pkvSubSection->SetString("ExitTag", m_Exits[i]->m_szExitTag); pkvSubSection->SetBool("ChokeGrow", m_Exits[i]->m_bChokepointGrowSource); pRoomTemplateKeyValues->AddSubKey(pkvSubSection); } // tags KeyValues *pkvSubSection = new KeyValues("Tags"); for ( int i=0; i<GetNumTags(); i++ ) { pkvSubSection->AddSubKey( new KeyValues( "tag", NULL, GetTag( i ) ) ); } pRoomTemplateKeyValues->AddSubKey(pkvSubSection); if (!pRoomTemplateKeyValues->SaveToFile(g_pFullFileSystem, szFullFileName, "GAME")) { Msg("Error: Failed to save room template %s\n", szFullFileName); return false; } return true; }
void FinishClientPutInServer( CHL2MP_Player *pPlayer ) { pPlayer->InitialSpawn(); //BB: we dont want players to spawn immediately when joining the server, we want them to auto spectate //pPlayer->Spawn(); pPlayer->ChangeTeam( TEAM_SPECTATOR ); char sName[128]; Q_strncpy( sName, pPlayer->GetPlayerName(), sizeof( sName ) ); // First parse the name and remove any %'s for ( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ ) { // Replace it with a space if ( *pApersand == '%' ) *pApersand = ' '; } // notify other clients of player joining the game UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "#Game_connected", sName[0] != 0 ? sName : "<unconnected>" ); if ( HL2MPRules()->IsTeamplay() == true ) { ClientPrint( pPlayer, HUD_PRINTTALK, "You are on team %s1\n", pPlayer->GetTeam()->GetName() ); } const ConVar *hostname = cvar->FindVar( "hostname" ); const char *title = (hostname) ? hostname->GetString() : "MESSAGE OF THE DAY"; KeyValues *data = new KeyValues("data"); data->SetString( "title", title ); // info panel title data->SetString( "type", "1" ); // show userdata from stringtable entry data->SetString( "msg", "motd" ); // use this stringtable entry data->SetBool( "unload", sv_motd_unload_on_dismissal.GetBool() ); //BB: Display the team selection panel... pPlayer->ShowViewPortPanel( PANEL_TEAM, true, data ); pPlayer->ShowViewPortPanel( PANEL_INFO, true, data ); data->deleteThis(); }
// loop through all the maps checking filters FOR_EACH_VEC(m_vecMaps, i) { mapdisplay_t &map = m_vecMaps[i]; mapstruct_t* mapinfo = &map.m_mMap; //DevLog("CURRENTLY FILTERING %s\n", mapinfo->m_szMapName); if (!CheckPrimaryFilters(*mapinfo) || !CheckSecondaryFilters(*mapinfo))//MOM_TODO: change this to just one filter check? { //Failed filters, remove the map map.m_bDoNotRefresh = true; if (m_pGameList->IsValidItemID(map.m_iListID)) { m_pGameList->SetItemVisible(map.m_iListID, false); } } else if (BShowMap(map)) { map.m_bDoNotRefresh = false; if (!m_pGameList->IsValidItemID(map.m_iListID)) { //DevLog("ADDING MAP TO LIST! %s\n ", mapinfo->m_szMapName); KeyValues *kv = new KeyValues("Map"); kv->SetString("name", mapinfo->m_szMapName); kv->SetString("map", mapinfo->m_szMapName); kv->SetInt("gamemode", mapinfo->m_iGameMode); kv->SetInt("difficulty", mapinfo->m_iDifficulty); kv->SetInt("MapLayout", ((int)mapinfo->m_bHasStages) + 2);//+ 2 so the picture sets correctly kv->SetBool("HasCompleted", mapinfo->m_bCompleted); kv->SetString("time", mapinfo->m_szBestTime); map.m_iListID = m_pGameList->AddItem(kv, NULL, false, false); kv->deleteThis(); } // make sure the map is visible m_pGameList->SetItemVisible(map.m_iListID, true); } }
static void saveZonFile(const char* szMapName) { KeyValues* zoneKV = new KeyValues(szMapName); CBaseEntity* pEnt = gEntList.FindEntityByClassname(NULL, "trigger_momentum_*"); while (pEnt) { KeyValues* subKey = NULL; if (pEnt->ClassMatches("trigger_momentum_timer_start")) { CTriggerTimerStart* pTrigger = dynamic_cast<CTriggerTimerStart*>(pEnt); subKey = new KeyValues("start"); if (pTrigger) { subKey->SetFloat("leavespeed", pTrigger->GetMaxLeaveSpeed()); subKey->SetBool("limitingspeed", pTrigger->IsLimitingSpeed()); } } else if (pEnt->ClassMatches("trigger_momentum_timer_stop")) { subKey = new KeyValues("end"); } else if (pEnt->ClassMatches("trigger_momentum_timer_checkpoint")) { CTriggerCheckpoint* pTrigger = dynamic_cast<CTriggerCheckpoint*>(pEnt); if (pTrigger) { subKey = new KeyValues("checkpoint"); subKey->SetInt("number", pTrigger->GetCheckpointNumber()); } } else if (pEnt->ClassMatches("trigger_momentum_onehop")) { CTriggerOnehop* pTrigger = dynamic_cast<CTriggerOnehop*>(pEnt); if (pTrigger) { subKey = new KeyValues("onehop"); //subKey->SetInt("destination", pTrigger->GetDestinationIndex()); subKey->SetBool("stop", pTrigger->ShouldStopPlayer()); subKey->SetBool("resetang", pTrigger->ShouldResetAngles()); subKey->SetFloat("hold", pTrigger->GetHoldTeleportTime()); subKey->SetString("destinationname", pTrigger->m_target.ToCStr()); } } else if (pEnt->ClassMatches("trigger_momentum_resetonehop")) { subKey = new KeyValues("resetonehop"); } else if (pEnt->ClassMatches("trigger_momentum_teleport_checkpoint")) { CTriggerTeleportCheckpoint* pTrigger = dynamic_cast<CTriggerTeleportCheckpoint*>(pEnt); if (pTrigger) { subKey = new KeyValues("checkpoint_teleport"); //subKey->SetInt("destination", pTrigger->GetDestinationCheckpointNumber()); subKey->SetBool("stop", pTrigger->ShouldStopPlayer()); subKey->SetBool("resetang", pTrigger->ShouldResetAngles()); subKey->SetString("destinationname", pTrigger->m_target.ToCStr()); } } else if (pEnt->ClassMatches("trigger_momentum_multihop")) { CTriggerMultihop* pTrigger = dynamic_cast<CTriggerMultihop*>(pEnt); if (pTrigger) { subKey = new KeyValues("multihop"); //subKey->SetInt("destination", pTrigger->GetDestinationIndex()); subKey->SetBool("stop", pTrigger->ShouldStopPlayer()); subKey->SetFloat("hold", pTrigger->GetHoldTeleportTime()); subKey->SetBool("resetang", pTrigger->ShouldResetAngles()); subKey->SetString("destinationname", pTrigger->m_target.ToCStr()); } } else if (pEnt->ClassMatches("trigger_momentum_timer_stage")) { CTriggerStage *pTrigger = dynamic_cast<CTriggerStage*>(pEnt); if (pTrigger) { subKey = new KeyValues("stage"); subKey->SetInt("number", pTrigger->GetStageNumber()); } } if (subKey) { subKey->SetFloat("xPos", pEnt->GetAbsOrigin().x); subKey->SetFloat("yPos", pEnt->GetAbsOrigin().y); subKey->SetFloat("zPos", pEnt->GetAbsOrigin().z); subKey->SetFloat("xRot", pEnt->GetAbsAngles().x); subKey->SetFloat("yRot", pEnt->GetAbsAngles().y); subKey->SetFloat("zRot", pEnt->GetAbsAngles().z); subKey->SetFloat("xScaleMins", pEnt->WorldAlignMins().x); subKey->SetFloat("yScaleMins", pEnt->WorldAlignMins().y); subKey->SetFloat("zScaleMins", pEnt->WorldAlignMins().z); subKey->SetFloat("xScaleMaxs", pEnt->WorldAlignMaxs().x); subKey->SetFloat("yScaleMaxs", pEnt->WorldAlignMaxs().y); subKey->SetFloat("zScaleMaxs", pEnt->WorldAlignMaxs().z); zoneKV->AddSubKey(subKey); } pEnt = gEntList.FindEntityByClassname(pEnt, "trigger_momentum_*"); } if (zoneKV->GetFirstSubKey())//not empty { char zoneFilePath[MAX_PATH]; Q_strcpy(zoneFilePath, "maps/"); Q_strcat(zoneFilePath, szMapName, MAX_PATH); Q_strncat(zoneFilePath, ".zon", MAX_PATH); zoneKV->SaveToFile(filesystem, zoneFilePath, "MOD"); zoneKV->deleteThis(); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CEditorSystem::DoSelect( CHL2WarsPlayer *pPlayer ) { #ifndef CLIENT_DLL // Sync from client return; #endif // CLIENT_DLL Vector vPos = pPlayer->Weapon_ShootPosition(); const Vector &vMouseAim = pPlayer->GetMouseAim(); const Vector &vCamOffset = pPlayer->GetCameraOffset(); Vector vStartPos, vEndPos; vStartPos = vPos + vCamOffset; vEndPos = vStartPos + (vMouseAim * MAX_TRACE_LENGTH); //NDebugOverlay::Line( vStartPos, vEndPos, 0, 255, 0, true, 4.0f ); Ray_t pickerRay; pickerRay.Init( vStartPos, vEndPos ); CWarsFlora *pBest = NULL; float fBestDistance = 0; #ifdef CLIENT_DLL for( CBaseEntity *pEntity = ClientEntityList().FirstBaseEntity(); pEntity; pEntity = ClientEntityList().NextBaseEntity( pEntity ) ) #else for( CBaseEntity *pEntity = gEntList.FirstEnt(); pEntity != NULL; pEntity = gEntList.NextEnt( pEntity ) ) #endif // CLIENT_DLL { CWarsFlora *pFlora = dynamic_cast<CWarsFlora *>( pEntity ); if( pFlora ) { // Prefer testing against hitboxes // If no hitboxes available, use the bounding box trace_t trace; bool bTestedHitBoxes = pFlora->TestHitboxes( pickerRay, MASK_SOLID, trace ); if( bTestedHitBoxes ) { if( trace.DidHit() ) { float fDistance = trace.endpos.DistTo( vStartPos ); if( !pBest || fDistance < fBestDistance ) { pBest = pFlora; fBestDistance = fDistance; } } } else { CBaseTrace trace2; if ( IntersectRayWithBox( pickerRay, pFlora->GetAbsOrigin() + pFlora->CollisionProp()->OBBMins(), pFlora->GetAbsOrigin() + pFlora->CollisionProp()->OBBMaxs(), 0.5f, &trace2 ) ) { float fDistance = trace2.endpos.DistTo( vStartPos ); if( !pBest || fDistance < fBestDistance ) { pBest = pFlora; fBestDistance = fDistance; } } } } } if( pBest ) { if( !IsSelected( pBest ) ) { Select( pBest ); KeyValues *pOperation = new KeyValues( "data" ); pOperation->SetString("operation", "select"); KeyValues *pFloraKey = new KeyValues( "flora", "uuid", pBest->GetFloraUUID() ); pFloraKey->SetBool( "select", true ); pOperation->AddSubKey( pFloraKey ); warseditorstorage->QueueServerCommand( pOperation ); } else { Deselect( pBest ); KeyValues *pOperation = new KeyValues( "data" ); pOperation->SetString("operation", "select"); KeyValues *pFloraKey = new KeyValues( "flora", "uuid", pBest->GetFloraUUID() ); pFloraKey->SetBool( "select", false ); pOperation->AddSubKey( pFloraKey ); warseditorstorage->QueueServerCommand( pOperation ); } //NDebugOverlay::Box( pBest->GetAbsOrigin(), -Vector(8, 8, 8), Vector(8, 8, 8), 0, 255, 0, 255, 5.0f); } }
// 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; }