//------------------------------------------------------------------------- void CGameRulesStandardState::EnterPostGameState( EPostGameState state ) { #ifndef _RELEASE if(g_pGameCVars->g_hud_postgame_debug) { CryLog("HUD PostGame - Entering new state %i from %i after %.2f seconds", (int)state, (int)m_postGameState, m_timeInCurrentPostGameState); } #endif m_timeInCurrentPostGameState = 0.f; m_postGameState = state; switch (m_postGameState) { case ePGS_FinalKillcam: { if (g_pGameCVars->kc_enableWinningKill) { CRecordingSystem* pRecordingSystem = g_pGame->GetRecordingSystem(); if (pRecordingSystem) { if(pRecordingSystem->IsPlaybackQueued()) { if(!pRecordingSystem->PlayWinningKillcam()) { CRY_ASSERT_MESSAGE(false, "There should be a Winning Kill queued up when we get here..."); } } else { CRY_ASSERT_MESSAGE(false, "There should be a Winning Kill queued up when we get here..."); } } } break; } case ePGS_HighlightReel: { bool canPlayHighlightReel = false; //Reset to standard style SHUDEvent postEvent(eHUDEvent_ResetHUDStyle); CHUDEventDispatcher::CallEvent(postEvent); CRecordingSystem* pRecordingSystem = g_pGame->GetRecordingSystem(); if (pRecordingSystem) { if (!(pRecordingSystem->IsPlayingBack() || pRecordingSystem->IsPlaybackQueued())) { canPlayHighlightReel = pRecordingSystem->PlayAllHighlights(false); #ifndef _RELEASE if(g_pGameCVars->g_hud_postgame_debug) { CryLog("HUD PostGame - Could play highlight reel = %s", canPlayHighlightReel ? "True" : "False"); } #endif } } //Change to fixed spectator mode IActor* pLocalActor = g_pGame->GetIGameFramework()->GetClientActor(); IGameRulesSpectatorModule* pSpecMod = g_pGame->GetGameRules()->GetSpectatorModule(); EntityId specEntity = 0; if(pLocalActor && pSpecMod && pSpecMod->ModeIsAvailable(pLocalActor->GetEntityId(), CActor::eASM_Fixed, &specEntity)) { pSpecMod->ChangeSpectatorMode(pLocalActor, CActor::eASM_Fixed, specEntity, true, true); } #ifndef _RELEASE else if(g_pGameCVars->g_hud_postgame_debug) { CryLog("HUD PostGame - Failed to change spectator mode when entering highlight reel"); } #endif if(canPlayHighlightReel) { m_bHasShownHighlightReel = true; } break; } case ePGS_Top3: { g_pGame->GetUI()->ActivateDefaultState(); SHUDEvent scoreboardVisibleEvent( eHUDEvent_MakeMatchEndScoreboardVisible ); scoreboardVisibleEvent.AddData(true); CHUDEventDispatcher::CallEvent(scoreboardVisibleEvent); break; } case ePGS_Scoreboard: { CryLog("HUD PostGame - Activating default state for scoreboard"); // Activating the default state while in this postgame state will cause the scoreboard to show g_pGame->GetUI()->ActivateDefaultState(); break; } } }
//------------------------------------------------------------------------- void CGameRulesStandardState::Update( float frameTime ) { if (gEnv->bServer) { if(m_state == EGRS_Intro) { // We assume there is an intro, if we reach this point and an intro hasnt been registered, we know there isn't one. Onwards and upwards. if(!m_pGameRules->IsIntroSequenceRegistered()) { ChangeState(EGRS_PreGame); } } if (m_state == EGRS_PreGame) { if (m_isStarting) { const float remainingTime = m_pGameRules->GetRemainingStartTimer(); if (remainingTime <= 0.f) { CryLog("CGameRulesStandardState::Update(), starting game"); ChangeState(EGRS_InGame); } } else { bool bOk = true; CGameLobby* pGameLobby = g_pGame->GetGameLobby(); const int numPlayers = m_pGameRules->GetPlayerCount(true); if (pGameLobby) { if (m_isWaitingForOverrideTimer) { //-- test override timer m_startTimerOverrideWait -= frameTime; bOk = (m_startTimerOverrideWait <= 0.0f); if (!bOk) { bOk = true; //-- testing min player count doesn't apply to private games const bool publicGame = !pGameLobby->IsPrivateGame(); const bool onlineGame = pGameLobby->IsOnlineGame(); if (publicGame && onlineGame) { // Start only when we have enough players if (m_pGameRules->GetTeamCount() > 1) { //-- team game, insist at least 1 player per team const int numPlayersPerTeamMin = g_pGameCVars->g_gameRules_startTimerMinPlayersPerTeam; const int numPlayersTeam1 = m_pGameRules->GetTeamPlayerCount(1, true); const int numPlayersTeam2 = m_pGameRules->GetTeamPlayerCount(2, true); bOk = ((numPlayersTeam1 >= numPlayersPerTeamMin) && (numPlayersTeam2 >= numPlayersPerTeamMin)); } else { //-- not a team game, so just insist on minimum 2 players const int numPlayersMin = g_pGameCVars->g_gameRules_startTimerMinPlayers; bOk = (numPlayers >= numPlayersMin); } const int numPlayersInLobby = pGameLobby->GetSessionNames().Size(); bOk |= (numPlayersInLobby == numPlayers); } if (bOk) { //-- Enforce a percentage of lobby players in game before starting countdown bOk = (!gEnv->IsClient() || (g_pGame->GetClientActorId() != 0)) && CheckInitialChannelPlayers(); } } } else { bOk = false; if (numPlayers) { //-- Start the override timer. m_startTimerOverrideWait = g_pGameCVars->g_gameRules_startTimerOverrideWait; m_isWaitingForOverrideTimer = true; } } } if (bOk) { CryLog("CGameRulesStandardState::Update(), we have %i players, starting the game", numPlayers); float startTimeLength = #if !defined(_RELEASE) g_pGameCVars->g_gameRules_skipStartTimer ? 0.0f : #endif g_pGameCVars->g_gameRules_startTimerLength; #if USE_PC_PREMATCH bool bDoPCPrematch = false; CGameRules::EPrematchState prematchState = m_pGameRules->GetPrematchState(); if (prematchState==CGameRules::ePS_Prematch) { int numRequiredPlayers = g_pGameCVars->g_minPlayersForRankedGame - m_pGameRules->GetPlayerCount(true); if ((numRequiredPlayers > 0) || (pGameLobby && pGameLobby->UseLobbyTeamBalancing() && !pGameLobby->IsGameBalanced())) { bDoPCPrematch = true; CPlaylistManager *pPlaylistManager = g_pGame->GetPlaylistManager(); if (pGameLobby && pPlaylistManager) { if (!pGameLobby->IsRankedGame() || pPlaylistManager->IsUsingCustomVariant()) { // Private games don't do prematch bDoPCPrematch = false; } } if (bDoPCPrematch) { // If we are waiting for players on pc, spawn ingame and set a prematch state which waits for players. m_pGameRules->StartPrematch(); startTimeLength = 0.f; } } if (!bDoPCPrematch) { m_pGameRules->SkipPrematch(); } } #endif m_pGameRules->ResetGameStartTimer(startTimeLength); StartCountdown(true); } } } else if (m_state == EGRS_PostGame) { const float prevUpdateStamp = m_timeInPostGame; const float timeInPost = (prevUpdateStamp + frameTime); const float timeToShowHUDMessage = g_pGameCVars->g_gameRules_postGame_HUDMessageTime; const float timeToShowTop3 = g_pGameCVars->g_gameRules_postGame_Top3Time; const float timeToShowScoreboard = g_pGameCVars->g_gameRules_postGame_ScoreboardTime; float killcamLength = m_pGameRules->GameEndedByWinningKill() ? g_pGameCVars->kc_length : 0.f; if (g_pGameCVars->kc_showHighlightsAtEndOfGame) { CRecordingSystem* pRecordingSystem = g_pGame->GetRecordingSystem(); if(pRecordingSystem) { killcamLength += pRecordingSystem->GetHighlightsReelLength(); killcamLength = min(killcamLength, 20.f); } } const float totalPostGameTime = timeToShowHUDMessage + timeToShowTop3 + timeToShowScoreboard + killcamLength; if (timeInPost > totalPostGameTime) { CRecordingSystem* pRecordingSystem = g_pGame->GetRecordingSystem(); if (!pRecordingSystem || (!pRecordingSystem->IsPlaybackQueued() && !pRecordingSystem->IsPlayingBack())) { CGameLobby *pGameLobby = g_pGame->GetGameLobby(); if (pGameLobby) { CryLog("[GameRules] Server trying to return to lobby"); pGameLobby->SvFinishedGame(frameTime); } } else if(pRecordingSystem) { pRecordingSystem->StopHighlightReel(); } } m_timeInPostGame = timeInPost; } } CPlayer * pPlayer = static_cast<CPlayer*>(g_pGame->GetIGameFramework()->GetClientActor()); if((pPlayer && pPlayer->ShouldPlayIntro() || gEnv->bServer) && m_pGameRules->IsIntroSequenceRegistered() && !m_bHaveNotifiedIntroListeners) { // All flowgraph nodes that want to listen, should be created at this point OnIntroStart_NotifyListeners(); } #ifndef _RELEASE if(g_pGameCVars->g_hud_postgame_debug) { const char* stateName = ""; switch(m_state) { case EGRS_Reset: { stateName = "EGRS_Reset"; break;} case EGRS_Intro: { stateName = "EGRS_Intro"; break;} case EGRS_PreGame: { stateName = "EGRS_PreGame"; break;} case EGRS_InGame: { stateName = "EGRS_InGame"; break;} case EGRS_PostGame: { stateName = "EGRS_PostGame"; break;} case EGRS_MAX: { stateName = "EGRS_MAX"; break;} } CryWatch("GameRulesStandardState - State = %s", stateName); if(m_state == EGRS_PostGame) { const char* postGameStateName = ""; switch(m_postGameState) { case ePGS_Unknown: { postGameStateName = "ePGS_Unknown"; break; } case ePGS_Starting: { postGameStateName = "ePGS_Starting"; break; } case ePGS_HudMessage: { postGameStateName = "ePGS_HudMessage"; break; } case ePGS_FinalKillcam: { postGameStateName = "ePGS_FinalKillcam"; break; } case ePGS_HighlightReel: { postGameStateName = "ePGS_HighlightReel"; break; } case ePGS_Top3: { postGameStateName = "ePGS_Top3"; break; } case ePGS_Scoreboard: { postGameStateName = "ePGS_Scoreboard"; break; } } CryWatch("GameRulesStandardState -PostGameState = %s", postGameStateName); } } #endif if (gEnv->IsClient()) { if (m_state == EGRS_PreGame) { if( !gEnv->IsDedicated() ) { if (m_isStarting) { const float timeTillStartInSeconds = m_pGameRules->GetRemainingStartTimer(); SHUDEventWrapper::UpdateGameStartCountdown( ePreGameCountdown_MatchStarting, timeTillStartInSeconds ); } else { SHUDEventWrapper::UpdateGameStartCountdown( ePreGameCountdown_WaitingForPlayers, 0.0f ); } } } else if (m_state == EGRS_InGame && !gEnv->IsDedicated() ) { if (m_introMessageShown == false) // Show only once { CGameRules *pGameRules = g_pGame->GetGameRules(); if (pGameRules && pGameRules->HasGameActuallyStarted()) { if (EntityId localPlayerId = g_pGame->GetIGameFramework()->GetClientActorId()) { int teamId = g_pGame->GetGameRules()->GetTeam(localPlayerId); bool bTeamGame = (pGameRules->GetTeamCount() > 1); IActor *pActor = g_pGame->GetIGameFramework()->GetClientActor(); if (pActor->GetSpectatorMode()==CActor::eASM_None && !pActor->IsDead() && (!bTeamGame || teamId!=0)) { if (IGameRulesPlayerStatsModule *statsModule = pGameRules->GetPlayerStatsModule()) { const SGameRulesPlayerStat *stats = statsModule->GetPlayerStats(localPlayerId); if (stats->deaths <= 0) // Not died ever { if (m_startMatchString.empty() == false) { const char* gamemodeName = g_pGame->GetGameRules()->GetEntity()->GetClass()->GetName(); CryFixedStringT<32> strSignalName; strSignalName.Format("StartGame%s", gamemodeName); TAudioSignalID signalId = g_pGame->GetGameAudio()->GetSignalID(strSignalName); CryFixedStringT<64> localisedStartString = CHUDUtils::LocalizeString( m_startMatchString.c_str() ); if (bTeamGame) { CryFixedStringT<16> strTeamName; strTeamName.Format("@ui_hud_team_%d", teamId); SHUDEventWrapper::TeamMessage(strTeamName.c_str(), teamId, SHUDEventWrapper::SMsgAudio(signalId), false, true); SHUDEventWrapper::SimpleBannerMessage(localisedStartString.c_str(), SHUDEventWrapper::kMsgAudioNULL); } else { SHUDEventWrapper::RoundMessageNotify(localisedStartString.c_str(), SHUDEventWrapper::SMsgAudio(signalId)); } } } } m_introMessageShown = true; // Or not if has already died, but don't check again anyway. } } } } } else if(m_state == EGRS_PostGame && !gEnv->IsDedicated()) { if (!gEnv->bServer) { m_timeInPostGame += frameTime; } m_timeInCurrentPostGameState += frameTime; switch (m_postGameState) { case ePGS_Starting: { CRecordingSystem* pRecordingSystem = g_pGame->GetRecordingSystem(); if (pRecordingSystem != NULL && (pRecordingSystem->IsPlayingBack() || pRecordingSystem->IsPlaybackQueued())) { // Currently showing a killcam, skip to the killcam stage of the postgame flow EnterPostGameState(ePGS_FinalKillcam); } else { if (m_pGameRules->GetRoundsModule()) { EnterPostGameState(ePGS_Top3); } else { EnterPostGameState(ePGS_HudMessage); } } break; } case ePGS_HudMessage: { if (m_timeInCurrentPostGameState > g_pGameCVars->g_gameRules_postGame_HUDMessageTime) { EnterPostGameState(ePGS_FinalKillcam); } break; } case ePGS_FinalKillcam: { CRecordingSystem* pRecordingSystem = g_pGame->GetRecordingSystem(); if (!pRecordingSystem || !(pRecordingSystem->IsPlayingBack() || (pRecordingSystem->IsPlaybackQueued() && pRecordingSystem->HasWinningKillcam()))) { EnterPostGameState(ePGS_Top3); } #ifndef _RELEASE else if(g_pGameCVars->g_hud_postgame_debug && pRecordingSystem) { CryWatch("PostGameState - Waiting for final killcam to end:"); CryWatch("IsPlaybackQueued: %s, IsPlayingBack: %s", pRecordingSystem->IsPlaybackQueued() ? "True" : "False", pRecordingSystem->IsPlayingBack() ? "True" : "False"); } #endif break; } case ePGS_HighlightReel: { CRecordingSystem* pRecordingSystem = g_pGame->GetRecordingSystem(); if (!pRecordingSystem || (!pRecordingSystem->IsPlaybackQueued() && !pRecordingSystem->IsPlayingBack())) { CGameLobby *pGameLobby = g_pGame->GetGameLobby(); if (pGameLobby) { CryLog("[GameRules] Client trying to return to lobby"); pGameLobby->SvFinishedGame(frameTime); EnterPostGameState(ePGS_LeavingGame); } } #ifndef _RELEASE else if(g_pGameCVars->g_hud_postgame_debug && pRecordingSystem) { CryWatch("PostGameState - Waiting for highlight reel to end:"); CryWatch("IsPlaybackQueued: %s, IsPlayingBack: %s, IsPlayingHighlightsReel: %s", pRecordingSystem->IsPlaybackQueued() ? "True" : "False", pRecordingSystem->IsPlayingBack() ? "True" : "False", pRecordingSystem->IsPlayingHighlightsReel() ? "True" : "False"); } #endif break; } case ePGS_Top3: { if (m_timeInCurrentPostGameState > g_pGameCVars->g_gameRules_postGame_Top3Time) { EnterPostGameState(ePGS_Scoreboard); } break; } case ePGS_Scoreboard: { if(m_timeInCurrentPostGameState > g_pGameCVars->g_gameRules_postGame_ScoreboardTime) { if(!m_bHasShownHighlightReel && g_pGameCVars->kc_showHighlightsAtEndOfGame) { EnterPostGameState(ePGS_HighlightReel); } else { CGameLobby *pGameLobby = g_pGame->GetGameLobby(); if (pGameLobby) { CryLog("[GameRules] Client trying to return to lobby [No highlight reel]"); pGameLobby->SvFinishedGame(frameTime); } } } break; } } } } }