#include "cbase.h" #include "asw_campaign_save.h" #include "asw_campaign_info.h" #include "asw_player.h" #include "asw_gamerules.h" #include "filesystem.h" #include "missionchooser/iasw_mission_chooser.h" #include "missionchooser/iasw_mission_chooser_source.h" #include "asw_marine_resource.h" #include "asw_game_resource.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" LINK_ENTITY_TO_CLASS( asw_campaign_save, CASW_Campaign_Save ); ConVar asw_custom_skill_points( "asw_custom_skill_points", "0", FCVAR_ARCHIVE, "If set, marines will start with no skill points and will spend them as they progress through the campaign." ); void ASWSendProxy_String_tToString( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ) { string_t *pString = (string_t*)pData; pOut->m_pString = (char*)STRING( *pString ); } IMPLEMENT_SERVERCLASS_ST(CASW_Campaign_Save, DT_ASW_Campaign_Save) SendPropString(SENDINFO(m_CampaignName)), SendPropInt(SENDINFO(m_iCurrentPosition)), SendPropInt(SENDINFO(m_iNumMissionsComplete)), SendPropArray3( SENDINFO_ARRAY3( m_MissionComplete ), SendPropInt( SENDINFO_ARRAY( m_MissionComplete ), 8, SPROP_UNSIGNED ) ), SendPropArray3( SENDINFO_ARRAY3( m_NumRetries ), SendPropInt( SENDINFO_ARRAY( m_NumRetries ), 9, SPROP_UNSIGNED ) ), SendPropArray3( SENDINFO_ARRAY3( m_bMarineWounded ), SendPropBool( SENDINFO_ARRAY( m_bMarineWounded ) ) ), SendPropArray3( SENDINFO_ARRAY3( m_bMarineDead ), SendPropBool( SENDINFO_ARRAY( m_bMarineDead ) ) ), SendPropArray( SendPropString( SENDINFO_ARRAY( m_MissionsCompleteNames ), 0, ASWSendProxy_String_tToString ), m_MissionsCompleteNames ), SendPropArray( SendPropString( SENDINFO_ARRAY( m_Medals ), 0, ASWSendProxy_String_tToString ), m_Medals ), SendPropBool(SENDINFO(m_bMultiplayerGame)), SendPropString(SENDINFO(m_DateTime)), SendPropArray3( SENDINFO_ARRAY3( m_NumVotes ), SendPropInt( SENDINFO_ARRAY( m_NumVotes ), 8, SPROP_UNSIGNED ) ), SendPropFloat( SENDINFO(m_fVoteEndTime) ), SendPropBool( SENDINFO( m_bFixedSkillPoints ) ), END_SEND_TABLE() BEGIN_DATADESC( CASW_Campaign_Save ) DEFINE_THINKFUNC( MoveThink ), DEFINE_THINKFUNC( VoteEndThink ), DEFINE_FIELD( m_bNextMissionVoteEnded, FIELD_BOOLEAN ) END_DATADESC() CASW_Campaign_Save::CASW_Campaign_Save() { m_iVersion = ASW_CURRENT_SAVE_VERSION; m_CampaignName.GetForModify()[0] = 0; m_iCurrentPosition = 0; m_iNumMissionsComplete = 0; m_iInitialNumMissionsComplete = 0; m_iNumPlayers = 0; m_bMultiplayerGame = false; m_CurrentSaveFileName = NULL_STRING; m_DateTime.GetForModify()[0] = 0; m_iLowestSkillLevelPlayed = 0; m_PlayerIDs.Purge(); m_PlayerNames.Purge(); m_fVoteEndTime = 0; m_bFixedSkillPoints = true; m_iMoveDestination = -1; for (int i=0;iLoadFromFile(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)); } } // 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;iGetString(buffer)); m_LastCommanders[i] = stringID; Q_snprintf(buffer, sizeof(buffer), "Slot%d", i); m_LastMarineResourceSlot[i] = pkvSubSection->GetInt(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; iSetInt("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; MarineIDSetInt("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(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;kGetPlayerName(); bFound = false; for (int k=0;kSetInt("NumPlayers", m_PlayerNames.Count()); // write out player names for (int i=0; iSetString("PlayerName", STRING(m_PlayerNames[i])); pSaveKeyValues->AddSubKey(pSubSection); } // write out player IDs for (int i=0; iSetString("DataBlock", STRING(m_PlayerIDs[i])); pSaveKeyValues->AddSubKey(pSubSection); } // write out last commanders section pSubSection = new KeyValues("COMM"); for (int i=0;iSetString(buffer, STRING(m_LastCommanders[i])); Q_snprintf(buffer, sizeof(buffer), "Slot%d", i); pSubSection->SetInt( buffer, m_LastMarineResourceSlot[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; } void CASW_Campaign_Save::UpdateLastCommanders() { // save which marines the players have selected // add which marines he has selected CASW_Game_Resource *pGameResource = ASWGameResource(); if ( !pGameResource ) return; // first check there were some marines selected (i.e. we're not in the campaign lobby map) int iNumMarineResources = 0; for (int i=0;iGetMaxMarineResources();i++) { if (pGameResource->GetMarineResource(i)) iNumMarineResources++; } if ( iNumMarineResources <= 0 ) return; char buffer[256]; for (int i=0;iGetMaxMarineResources();k++) { CASW_Marine_Resource *pMR = pGameResource->GetMarineResource(k); if (pMR && pMR->GetProfileIndex() == i && pMR->GetCommander()) { CASW_Player *pPlayer = pMR->GetCommander(); if (pPlayer) { // store the commander who has this marine Q_snprintf(buffer, sizeof(buffer), "%s%s",pPlayer->GetPlayerName(), pPlayer->GetASWNetworkID()); m_LastCommanders[i] = AllocPooledString(buffer); m_LastMarineResourceSlot[i] = k; bFound = true; break; } } } if (!bFound) { m_LastCommanders[i] = AllocPooledString(""); m_LastMarineResourceSlot[i] = 0; } } } void CASW_Campaign_Save::DebugInfo() { Msg("Savegame contents:\n"); Msg(" Version: %d\n", m_iVersion); Msg(" Lowest Skill Level Played: %d\n", m_iLowestSkillLevelPlayed); Msg(" Campaign Name: %s\n", m_CampaignName.Get()); Msg(" Current Position: %d\n", m_iCurrentPosition); Msg(" Num Missions Complete: %d\n", m_iNumMissionsComplete); Msg(" Initial Num Missions Complete: %d\n", m_iInitialNumMissionsComplete); Msg( "Num deaths: %d\n", m_iNumDeaths); Msg(" ["); for (int i=0;i=0 && iMissionGetSkillLevel(); if (iSkill < m_iLowestSkillLevelPlayed || m_iLowestSkillLevelPlayed == 0) m_iLowestSkillLevelPlayed = iSkill; } } } void CASW_Campaign_Save::MoveTo(int iMission) { if (iMission>=0 && iMissionLocalMissionSource()) return false; return missionchooser->LocalMissionSource()->ASW_Campaign_CreateNewSaveGame(szFileName, iFileNameMaxLen, szCampaignName, bMultiplayerGame, szStartingMission); } int CASW_Campaign_Save::ShouldTransmit( const CCheckTransmitInfo *pInfo ) { return FL_EDICT_ALWAYS; } void CASW_Campaign_Save::IncreaseRetries() { if (m_iCurrentPosition <0 || m_iCurrentPosition >= ASW_MAX_MISSIONS_PER_CAMPAIGN) return; int current = m_NumRetries[m_iCurrentPosition]; m_NumRetries.Set(m_iCurrentPosition, current+1); } int CASW_Campaign_Save::GetRetries() { if (m_iCurrentPosition <0 || m_iCurrentPosition >= ASW_MAX_MISSIONS_PER_CAMPAIGN) return -1; return m_NumRetries[m_iCurrentPosition]; } void CASW_Campaign_Save::IncreaseMarineSkill( int nProfileIndex, int nSkillSlot ) { if (nProfileIndex < 0 || nProfileIndex >= ASW_NUM_MARINE_PROFILES) return; if (nSkillSlot < 0 || nSkillSlot >= ASW_NUM_SKILL_SLOTS) return; m_iMarineSkill[nProfileIndex][nSkillSlot]++; } void CASW_Campaign_Save::ReduceMarineSkill(int nProfileIndex, int nSkillSlot) { if (nProfileIndex < 0 || nProfileIndex >= ASW_NUM_MARINE_PROFILES) return; if (nSkillSlot < 0 || nSkillSlot >= ASW_NUM_SKILL_SLOTS) return; m_iMarineSkill[nProfileIndex][nSkillSlot]--; } void CASW_Campaign_Save::ReviveMarine(int nProfileIndex) { if (nProfileIndex < 0 || nProfileIndex >= ASW_NUM_MARINE_PROFILES) return; if (IsMarineAlive(nProfileIndex)) // don't revive ones already alive! return; // revive SetMarineDead(nProfileIndex, false); SetMarineWounded(nProfileIndex, false); // reset skills for (int i=0;i= ASW_NUM_MARINE_PROFILES) return 0; return m_iParasitesKilled[nProfileIndex]; } void CASW_Campaign_Save::AddParasitesKilled(int nProfileIndex, int iParasitesKilled) { if (nProfileIndex < 0 || nProfileIndex >= ASW_NUM_MARINE_PROFILES) return; m_iParasitesKilled[nProfileIndex] += iParasitesKilled; } void CASW_Campaign_Save::SetMarineWounded(int nProfileIndex, bool bWounded) { if (nProfileIndex < 0 || nProfileIndex >= ASW_NUM_MARINE_PROFILES) return; m_bMarineWounded.Set(nProfileIndex, bWounded); } void CASW_Campaign_Save::SetMarineDead(int nProfileIndex, bool bDead) { if (nProfileIndex < 0 || nProfileIndex >= ASW_NUM_MARINE_PROFILES) return; m_bMarineDead.Set(nProfileIndex, bDead); } void CASW_Campaign_Save::RevertSkillsToUndoState(int nProfileIndex) { if (nProfileIndex < 0 || nProfileIndex >= ASW_NUM_MARINE_PROFILES) return; for (int k=0;kGetCampaignInfo()) return; CASW_Campaign_Info *pCI = ASWGameRules()->GetCampaignInfo(); if ( !pCI ) return; CASW_Campaign_Info::CASW_Campaign_Mission_t *pMission = pCI->GetMission( iMission ); if (!pMission) return; if (iMission != m_iMoveDestination) { m_iMoveDestination = iMission; SetThink( &CASW_Campaign_Save::MoveThink ); SetNextThink(gpGlobals->curtime + 0.1f); } } void CASW_Campaign_Save::MoveThink() { if (m_iMoveDestination != -1) { if (m_iMoveDestination == m_iCurrentPosition) { Msg("arrived!\n"); // notify game rules that we've arrived, so it can do any mission launching it desires if (ASWGameRules()) ASWGameRules()->RequestCampaignLaunchMission(m_iCurrentPosition); } else { // build a route to the dest from current position bool bRoute = BuildCampaignRoute(m_iMoveDestination, m_iCurrentPosition); if (!bRoute) { Msg("Couldn't build route to dest\n"); SetThink(NULL); } else { // we've got a route, move ourselves to the next step in the route campaign_route_node_t* pNode = FindMissionInClosedList(m_iRouteDest); if (pNode) pNode = FindMissionInClosedList(pNode->iParentMission); MoveTo(pNode->iMission); SetNextThink(gpGlobals->curtime + 1.0f); // move again in 1 second } } } } float CASW_Campaign_Save::EstimateCost(CASW_Campaign_Info *pCI, int iStart, int iEnd) { // heuristic for A* CASW_Campaign_Info::CASW_Campaign_Mission_t* pMission = pCI->GetMission(iStart); CASW_Campaign_Info::CASW_Campaign_Mission_t* pEndMission = pCI->GetMission(iEnd); if (!pMission || !pEndMission) return 9000; float diff_x = pEndMission->m_iLocationX - pMission->m_iLocationX; float diff_y = pEndMission->m_iLocationY - pMission->m_iLocationY; return (sqrt((diff_x * diff_x) + (diff_y * diff_y))); } bool CASW_Campaign_Save::BuildCampaignRoute(int iStart, int iEnd) { if (!ASWGameRules() || !ASWGameRules()->GetCampaignInfo()) return false; CASW_Campaign_Info *pCI = ASWGameRules()->GetCampaignInfo(); if (iStart < 0 || iStart >= pCI->GetNumMissions()) return false; if (iEnd < 0 || iEnd >= pCI->GetNumMissions()) return false; // do A* m_ClosedList.Purge(); m_OpenList.Purge(); m_iRouteDest = iEnd; m_iRouteStart = iStart; // add starting mission to the open list campaign_route_node_t start_node; start_node.iMission = iStart; start_node.iParentMission = iStart; start_node.g = 0; start_node.h = EstimateCost(pCI, iStart, iEnd); start_node.f = start_node.g + start_node.h; m_OpenList.AddToTail(start_node); int iOverflow = 0; while (iOverflow < 1000) { // find the lowest node on the open list int iLowestF = -1; float fLowestF_Value = 99999; //Msg("%d nodes in open list\n", m_OpenList.Count()); for (int i=0;iGetMission(iCurrentMission); if (!pMission) { //Msg("Failed to get current mission in BuildCampaignRoute\n"); return false; } //Msg("Current mission (%d) has %d links\n", iCurrentMission, pMission->m_Links.Count()); for (int i=0;im_Links.Count();i++) { int iOtherMission = pMission->m_Links[i]; //Msg("other mission[%d] is %d\n", i, iOtherMission); CASW_Campaign_Info::CASW_Campaign_Mission_t *pOtherMission = pCI->GetMission(pMission->m_Links[i]); if (!pOtherMission) continue; // check if it's on the open list int iOnOpenList = -1; for (int k=0;kiMission != m_iRouteStart) { Msg("Node %d: Mission %d (Cost %f)\n", iCount++, pNode->iMission, pNode->f); pNode = FindMissionInClosedList(pNode->iParentMission); } } void ASW_TestRoute_cc(const CCommand &args) { if ( args.ArgC() < 3 ) { Warning( "Usage: ASW_TestRoute [start mission index] [end mission index]\n" ); return; } if (!ASWGameRules() || !ASWGameRules()->GetCampaignSave()) { Msg("Must be playing a campaign game!\n"); return; } int iStart = atoi(args[1]); int iEnd = atoi(args[2]); CASW_Campaign_Save* pSave = ASWGameRules()->GetCampaignSave(); bool bFound = pSave->BuildCampaignRoute(iStart, iEnd); if (bFound) { Msg("Found route:\n"); pSave->DebugBuiltRoute(); } else { Msg("No route found!\n"); } } ConCommand ASW_TestRoute( "ASW_TestRoute", ASW_TestRoute_cc, "Tests loading a savegame", FCVAR_CHEAT ); void ASW_TestLoad_cc(const CCommand &args) { if ( args.ArgC() < 2 ) { Warning( "You must specify the name of the saved campaign game to resume playing.\n" ); return; } CASW_Campaign_Save *pSave = new CASW_Campaign_Save(); if (!pSave->LoadGameFromFile(args[1])) { Msg("LoadGameFromFile failed!\n"); } else pSave->DebugInfo(); } ConCommand ASW_TestLoad( "ASW_TestLoad", ASW_TestLoad_cc, "Tests loading a savegame", FCVAR_CHEAT ); void CASW_Campaign_Save::StartingCampaignVote() { if (!ASWGameRules()) return; CASW_Game_Resource *pGameResource = ASWGameResource(); if (!pGameResource) return; // clear votes and ready m_fVoteEndTime = 0; m_bNextMissionVoteEnded = false; for (int i=0;im_bPlayerReady.Set(i, false); } } void CASW_Campaign_Save::ForceNextMissionLaunch() { if (!m_fVoteEndTime != 0) { m_fVoteEndTime = gpGlobals->curtime + 6.0f; } SetThink( &CASW_Campaign_Save::VoteEndThink ); SetNextThink( m_fVoteEndTime ); } void CASW_Campaign_Save::VoteEndThink() { SetThink(NULL); VoteEnded(); } void CASW_Campaign_Save::VoteEnded() { if (!ASWGameRules()) return; if (!ASWGameRules()->GetCampaignInfo()) return; Msg("CampVote ended\n"); m_bNextMissionVoteEnded = true; CASW_Campaign_Info *pCI = ASWGameRules()->GetCampaignInfo(); // decide which mission to launch // find the highest voted launchable, int iHighestMission = -1; int iHighestVotes = -1; CUtlVector Draws; for (int i=0;iGetNumMissions();i++) { //CASW_Campaign_Info::CASW_Campaign_Mission_t* pMission = pCI-> if (m_MissionComplete[i] != 0) // already complete continue; if (!IsMissionLinkedToACompleteMission(i, pCI) || i <= 0) // launchable continue; if (m_NumVotes[i] > iHighestVotes) { iHighestVotes = m_NumVotes[i]; Draws.Purge(); Draws.AddToTail(i); iHighestMission = i; } else if (m_NumVotes[i] == iHighestVotes) { Draws.AddToTail(i); } } int iMission = iHighestMission; Msg("highest mission is %d draws is %d\n", iMission, Draws.Count()); if (Draws.Count() > 1) { // some missions have equal votes, pick one at random int iPick = random->RandomInt(0, Draws.Count() - 1); iMission = Draws[iPick]; } Msg("Moving to %d\n", iMission); // move there ASWGameRules()->RequestCampaignMove(iMission); } void CASW_Campaign_Save::PlayerDisconnected(CASW_Player *pPlayer) { if (!ASWGameRules() || !pPlayer) return; if (ASWGameRules()->GetGameState() != ASW_GS_CAMPAIGNMAP) return; CASW_Game_Resource *pGameResource = ASWGameResource(); if (!pGameResource) return; if (m_bNextMissionVoteEnded) // don't allow votes if the mission has already been chosen return; // if player is ready, that means he's already voted or a spectator int iPlayer = pPlayer->entindex() -1 ; if (iPlayer<0 ||iPlayer>ASW_MAX_READY_PLAYERS-1) return; if (pGameResource->IsPlayerReady(pPlayer->entindex())) { // subtract his old vote int iVotedFor = pGameResource->m_iCampaignVote[iPlayer]; if (iVotedFor >=0 && iVotedFor < ASW_MAX_MISSIONS_PER_CAMPAIGN) { int iVotes = m_NumVotes[iVotedFor] - 1; m_NumVotes.Set(iVotedFor, iVotes); } } // check for ending the vote if (pGameResource->AreAllOtherPlayersReady(pPlayer->entindex())) { if ( gpGlobals->maxClients > 1 ) { if (!m_fVoteEndTime != 0) { m_fVoteEndTime = gpGlobals->curtime + 4.0f; } SetThink( &CASW_Campaign_Save::VoteEndThink ); SetNextThink( m_fVoteEndTime ); } else { VoteEnded(); } } } void CASW_Campaign_Save::PlayerVote(CASW_Player* pPlayer, int iMission) { if (!ASWGameRules() || !pPlayer || pPlayer->m_bRequestedSpectator) return; if (ASWGameRules()->GetGameState() != ASW_GS_CAMPAIGNMAP) return; CASW_Game_Resource *pGameResource = ASWGameResource(); if (!pGameResource) return; if (m_bNextMissionVoteEnded) // don't allow votes if the mission has already been chosen return; // if player is ready, that means he's already voted or a spectator int iPlayer = pPlayer->entindex() -1 ; if (iPlayer<0 ||iPlayer>ASW_MAX_READY_PLAYERS-1) return; if (pGameResource->IsPlayerReady(pPlayer->entindex())) { // subtract his old vote int iVotedFor = pGameResource->m_iCampaignVote[iPlayer]; if (iVotedFor >=0 && iVotedFor < ASW_MAX_MISSIONS_PER_CAMPAIGN) { int iVotes = m_NumVotes[iVotedFor] - 1; m_NumVotes.Set(iVotedFor, iVotes); } } if (iMission < 0 || iMission >= ASW_MAX_MISSIONS_PER_CAMPAIGN) return; // don't allow vote for this mission if this mission was already completed, or if it's the dropzone if (m_MissionComplete[iMission] != 0 || iMission <= 0) return; // make sure the mission they want to vote for is reachable if (!IsMissionLinkedToACompleteMission(iMission, ASWGameRules()->GetCampaignInfo())) return; // add his vote to the chosen map pGameResource->m_iCampaignVote[iPlayer] = iMission; int iVotes = m_NumVotes[iMission] + 1; m_NumVotes.Set(iMission, iVotes); // flag him as ready pGameResource->m_bPlayerReady.Set(iPlayer, true); if (pGameResource->AreAllOtherPlayersReady(pPlayer->entindex())) { if ( gpGlobals->maxClients > 1 ) { if (!m_fVoteEndTime != 0) { m_fVoteEndTime = gpGlobals->curtime + 4.0f; } SetThink( &CASW_Campaign_Save::VoteEndThink ); SetNextThink( m_fVoteEndTime ); } else { VoteEnded(); } } } void CASW_Campaign_Save::PlayerSpectating(CASW_Player* pPlayer) { if (!ASWGameRules() || !pPlayer) return; if (ASWGameRules()->GetGameState() != ASW_GS_CAMPAIGNMAP) return; CASW_Game_Resource *pGameResource = ASWGameResource(); if (!pGameResource) return; if (m_bNextMissionVoteEnded) // don't allow votes if the mission has already been chosen return; pPlayer->m_bRequestedSpectator = true; // if player is ready, that means he's already voted or a spectator int iPlayer = pPlayer->entindex() -1 ; if (iPlayer<0 ||iPlayer>ASW_MAX_READY_PLAYERS-1) return; if (pGameResource->IsPlayerReady(pPlayer->entindex())) { // subtract his old vote int iVotedFor = pGameResource->m_iCampaignVote[iPlayer]; if (iVotedFor >=0 && iVotedFor < ASW_MAX_MISSIONS_PER_CAMPAIGN) { int iVotes = m_NumVotes[iVotedFor] - 1; m_NumVotes.Set(iVotedFor, iVotes); } } // clear his chosen mission and flag him as ready pGameResource->m_iCampaignVote[iPlayer] = -1; pGameResource->m_bPlayerReady.Set(iPlayer, true); if (pGameResource->AreAllOtherPlayersReady(pPlayer->entindex())) { if ( gpGlobals->maxClients > 1 ) { if (!m_fVoteEndTime != 0) { m_fVoteEndTime = gpGlobals->curtime + 4.0f; } SetThink( &CASW_Campaign_Save::VoteEndThink ); SetNextThink( m_fVoteEndTime ); } else { VoteEnded(); } } } void CASW_Campaign_Save::SelectDefaultNextCampaignMission() { if ( !ASWGameRules() || !ASWGameResource() ) return; CASW_Campaign_Info *pInfo = ASWGameRules()->GetCampaignInfo(); if ( !pInfo ) return; // find the first valid mission selection in our list for ( int i = 1; i < pInfo->GetNumMissions(); i++ ) // skip first dummy entry { if ( !m_MissionComplete[i] && IsMissionLinkedToACompleteMission( i, pInfo ) ) { ASWGameResource()->m_iNextCampaignMission = i; return; } } } void CASW_Campaign_Save::OnMarineKilled() { m_iNumDeaths++; SaveGameToFile(); }