diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp index 9aefb8de4..eb2ecbf87 100644 --- a/src/game/client/components/hud.cpp +++ b/src/game/client/components/hud.cpp @@ -42,6 +42,8 @@ void CHud::RenderGameTimer() if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) Time = 0; } + else if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) + Time = m_pClient->m_Snap.m_pGameInfoObj->m_GameStateTimer/Client()->GameTickSpeed(); else Time = (Client()->GameTick()-m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick)/Client()->GameTickSpeed(); @@ -61,8 +63,7 @@ void CHud::RenderGameTimer() void CHud::RenderPauseTimer() { - if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED && - !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) + if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED) { char aBuf[256]; const char *pText = Localize("Game paused"); diff --git a/src/game/client/components/players.cpp b/src/game/client/components/players.cpp index bf270d8a9..449b60986 100644 --- a/src/game/client/components/players.cpp +++ b/src/game/client/components/players.cpp @@ -106,7 +106,8 @@ void CPlayers::RenderHook( // use preditect players if needed if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK) { - if(!m_pClient->m_Snap.m_pLocalCharacter || (m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) + if(!m_pClient->m_Snap.m_pLocalCharacter || + (m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_GAMEOVER))) { } else @@ -239,7 +240,8 @@ void CPlayers::RenderPlayer( // use preditect players if needed if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK) { - if(!m_pClient->m_Snap.m_pLocalCharacter || (m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) + if(!m_pClient->m_Snap.m_pLocalCharacter || + (m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_GAMEOVER))) { } else diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index c999e9571..8810ebb8e 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -359,7 +359,7 @@ void CGameClient::UpdatePositions() // local character position if(g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK) { - if(!m_Snap.m_pLocalCharacter || (m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) + if(!m_Snap.m_pLocalCharacter || (m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_GAMEOVER))) { // don't use predicted } diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index ce2208288..a5db54c09 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -983,7 +983,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) pPlayer->m_LastKill = Server()->Tick(); pPlayer->KillCharacter(WEAPON_SELF); } - else if (MsgID == NETMSGTYPE_CL_READYCHANGE && g_Config.m_SvPlayerReadyMode && !m_pController->IsGameOver()) + else if (MsgID == NETMSGTYPE_CL_READYCHANGE && g_Config.m_SvPlayerReadyMode) { if(pPlayer->m_LastReadyChange && pPlayer->m_LastReadyChange+Server()->TickSpeed()*1 > Server()->Tick()) return; @@ -1039,7 +1039,7 @@ void CGameContext::ConPause(IConsole::IResult *pResult, void *pUserData) if(pResult->NumArguments()) pSelf->m_pController->DoPause(clamp(pResult->GetInteger(0), -1, 1000)); else - pSelf->m_pController->DoPause(pSelf->m_pController->IsPaused() ? 0 : -1); + pSelf->m_pController->DoPause(pSelf->m_pController->GetGameState() == IGameController::GS_PAUSED ? 0 : IGameController::TIMER_INFINITE); } void CGameContext::ConChangeMap(IConsole::IResult *pResult, void *pUserData) @@ -1054,7 +1054,7 @@ void CGameContext::ConRestart(IConsole::IResult *pResult, void *pUserData) if(pResult->NumArguments()) pSelf->m_pController->DoWarmup(clamp(pResult->GetInteger(0), -1, 1000)); else - pSelf->m_pController->StartRound(); + pSelf->m_pController->DoRestart(); } void CGameContext::ConBroadcast(IConsole::IResult *pResult, void *pUserData) diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp index 55b00cbe8..13bfad800 100644 --- a/src/game/server/gamecontroller.cpp +++ b/src/game/server/gamecontroller.cpp @@ -20,14 +20,11 @@ IGameController::IGameController(CGameContext *pGameServer) m_UnbalancedTick = TBALANCE_OK; // game - m_GameOverTick = -1; - m_Paused = 0; - m_RoundCount = 0; + m_GameState = GS_GAME; + m_GameStateTimer = TIMER_INFINITE; m_RoundStartTick = Server()->Tick(); m_SuddenDeath = 0; - m_aTeamscore[TEAM_RED] = 0; - m_aTeamscore[TEAM_BLUE] = 0; - DoWarmup(g_Config.m_SvWarmup); + SetGameState(GS_WARMUP, g_Config.m_SvWarmup); // info m_GameFlags = 0; @@ -343,50 +340,6 @@ void IGameController::OnReset() } // game -void IGameController::DoPause(int Seconds) -{ - if(IsGameOver() || IsWarmup()) - return; - - if(Seconds != 0) - { - if(Seconds < 0) - { - m_Paused = -1; - SetPlayersReadyState(false); - } - else - m_Paused = Seconds*Server()->TickSpeed(); - - GameServer()->m_World.m_Paused = true; - } - else - { - m_Paused = 0; - SetPlayersReadyState(true); - GameServer()->m_World.m_Paused = false; - } -} - -void IGameController::DoWarmup(int Seconds) -{ - if(IsGameOver() || IsPaused()) - return; - - if(Seconds < 0 && g_Config.m_SvPlayerReadyMode) - { - m_Warmup = -1; - SetPlayersReadyState(false); - } - else if(Seconds > 0) - m_Warmup = Seconds*Server()->TickSpeed(); - else - { - m_Warmup = 0; - SetPlayersReadyState(true); - } - } - void IGameController::DoWincheck() { if(IsTeamplay()) @@ -434,39 +387,97 @@ void IGameController::DoWincheck() void IGameController::EndRound() { - if(IsWarmup() || IsPaused()) // game can't end when we are running warmup or pause - return; - - GameServer()->m_World.m_Paused = true; - m_GameOverTick = Server()->Tick(); - m_SuddenDeath = 0; + SetGameState(GS_GAMEOVER, 10); } void IGameController::ResetGame() { GameServer()->m_World.m_ResetRequested = true; + + SetGameState(GS_GAME); + m_RoundStartTick = Server()->Tick(); + m_SuddenDeath = 0; +} + +void IGameController::SetGameState(int GameState, int Seconds) +{ + switch(GameState) + { + case GS_WARMUP: + { + if(GetGameState() == GS_GAME || GetGameState() == GS_WARMUP) + { + if(Seconds < 0 && g_Config.m_SvPlayerReadyMode) + { + m_GameState = GS_WARMUP; + m_GameStateTimer = TIMER_INFINITE; + SetPlayersReadyState(false); + } + else if(Seconds > 0) + { + m_GameState = GS_WARMUP; + m_GameStateTimer = Seconds*Server()->TickSpeed(); + } + else + SetGameState(GS_GAME); + } + break; + } + case GS_GAME: + { + m_GameState = GS_GAME; + m_GameStateTimer = TIMER_INFINITE; + SetPlayersReadyState(true); + GameServer()->m_World.m_Paused = false; + } + break; + case GS_PAUSED: + { + if(GetGameState() == GS_GAME || GetGameState() == GS_PAUSED) + { + if(Seconds != 0) + { + if(Seconds < 0) + { + m_GameStateTimer = TIMER_INFINITE; + SetPlayersReadyState(false); + } + else + m_GameStateTimer = Seconds*Server()->TickSpeed(); + + m_GameState = GS_PAUSED; + GameServer()->m_World.m_Paused = true; + } + else + SetGameState(GS_GAME); + } + } + break; + case GS_GAMEOVER: + { + if(GetGameState() != GS_WARMUP && GetGameState() != GS_PAUSED) + { + m_GameState = GS_GAMEOVER; + m_GameStateTimer = Seconds*Server()->TickSpeed(); + m_SuddenDeath = 0; + GameServer()->m_World.m_Paused = true; + } + } + } } void IGameController::StartRound() { ResetGame(); - m_GameOverTick = -1; - m_Paused = 0; - m_RoundStartTick = Server()->Tick(); - m_SuddenDeath = 0; m_aTeamscore[TEAM_RED] = 0; m_aTeamscore[TEAM_BLUE] = 0; - m_Warmup = 0; - SetPlayersReadyState(true); if(m_UnbalancedTick == TBALANCE_CHECK) CheckTeamBalance(); if(m_UnbalancedTick > TBALANCE_OK) DoTeamBalance(); - GameServer()->m_World.m_Paused = false; - Server()->DemoRecorder_HandleAutoStart(); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "start round type='%s' teamplay='%d'", m_pGameType, m_GameFlags&GAMEFLAG_TEAMS); @@ -484,20 +495,22 @@ void IGameController::Snap(int SnappingClient) pGameInfoObj->m_GameStateFlags = 0; pGameInfoObj->m_GameStateTimer = 0; - if(IsGameOver()) + switch(GetGameState()) + { + case GS_WARMUP: + pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_WARMUP; + pGameInfoObj->m_GameStateTimer = m_GameStateTimer; + break; + case GS_PAUSED: + pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_PAUSED; + pGameInfoObj->m_GameStateTimer = m_GameStateTimer; + break; + case GS_GAMEOVER: pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_GAMEOVER; + pGameInfoObj->m_GameStateTimer = Server()->Tick()-m_RoundStartTick-10*Server()->TickSpeed()+m_GameStateTimer; + } if(m_SuddenDeath) pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_SUDDENDEATH; - if(IsWarmup()) - { - pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_WARMUP; - pGameInfoObj->m_GameStateTimer = m_Warmup; - } - if(IsPaused()) - { - pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_PAUSED; - pGameInfoObj->m_GameStateTimer |= m_Paused; - } pGameInfoObj->m_RoundStartTick = m_RoundStartTick; @@ -510,46 +523,37 @@ void IGameController::Snap(int SnappingClient) void IGameController::Tick() { - // do warmup - if(IsWarmup()) + // handle game states + if(GetGameState() != GS_GAME) { - if(m_Warmup > 0) - --m_Warmup; - else if(!g_Config.m_SvPlayerReadyMode || GetPlayersReadyState()) - m_Warmup = 0; + if(m_GameStateTimer > 0) + --m_GameStateTimer; - if(!IsWarmup()) - StartRound(); - } - - if(IsGameOver()) - { - // game over.. wait for restart - if(Server()->Tick() > m_GameOverTick+Server()->TickSpeed()*10) + switch(GetGameState()) { - CycleMap(); - StartRound(); - m_RoundCount++; + case GS_WARMUP: + if(m_GameStateTimer == 0 || (m_GameStateTimer == TIMER_INFINITE && (!g_Config.m_SvPlayerReadyMode || GetPlayersReadyState()))) + StartRound(); + break; + case GS_PAUSED: + if(m_GameStateTimer == 0 || (m_GameStateTimer == TIMER_INFINITE && g_Config.m_SvPlayerReadyMode && GetPlayersReadyState())) + SetGameState(GS_PAUSED, 0); + else + ++m_RoundStartTick; + break; + case GS_GAMEOVER: + if(m_GameStateTimer == 0) + { + CycleMap(); + StartRound(); + m_RoundCount++; + } } } // check if the game needs to be paused - if(!IsPaused() && g_Config.m_SvPlayerReadyMode && !GetPlayersReadyState()) - DoPause(-1); - - // do pause - if(IsPaused()) - { - if(m_Paused > 0) - --m_Paused; - else if(g_Config.m_SvPlayerReadyMode && GetPlayersReadyState()) - m_Paused = 0; - - if(!IsPaused()) - DoPause(0); - else - ++m_RoundStartTick; - } + if(GetGameState() != GS_PAUSED && g_Config.m_SvPlayerReadyMode && !GetPlayersReadyState()) + SetGameState(GS_PAUSED, TIMER_INFINITE); // do team-balancing if(IsTeamplay()) @@ -564,7 +568,7 @@ void IGameController::Tick() DoActivityCheck(); // win check - if(!IsGameOver() && !IsWarmup() && !IsPaused() && !GameServer()->m_World.m_ResetRequested) + if(GetGameState() == GS_GAME && !GameServer()->m_World.m_ResetRequested) DoWincheck(); } @@ -588,7 +592,7 @@ bool IGameController::IsFriendlyFire(int ClientID1, int ClientID2) const bool IGameController::IsPlayerReadyMode() const { - return g_Config.m_SvPlayerReadyMode != 0 && (m_Warmup == -1 || m_Paused == -1); + return g_Config.m_SvPlayerReadyMode != 0 && (m_GameStateTimer == TIMER_INFINITE && (GetGameState() == GS_WARMUP || GetGameState() == GS_PAUSED)); } const char *IGameController::GetTeamName(int Team) const @@ -697,12 +701,12 @@ void IGameController::CycleMap() // spawn bool IGameController::CanSpawn(int Team, vec2 *pOutPos) const { - CSpawnEval Eval; - // spectators can't spawn - if(Team == TEAM_SPECTATORS) + if(Team == TEAM_SPECTATORS || GameServer()->m_World.m_Paused || GameServer()->m_World.m_ResetRequested) return false; + CSpawnEval Eval; + if(IsTeamplay()) { Eval.m_FriendlyTeam = Team; @@ -847,7 +851,7 @@ void IGameController::DoTeamChange(CPlayer *pPlayer, int Team, bool DoChatMsg) GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); m_UnbalancedTick = TBALANCE_CHECK; - pPlayer->m_IsReadyToPlay = IsWarmup() || IsPaused() ? false : true; + pPlayer->m_IsReadyToPlay = GetGameState() != GS_WARMUP && GetGameState() != GS_PAUSED; OnPlayerInfoChange(pPlayer); } diff --git a/src/game/server/gamecontroller.h b/src/game/server/gamecontroller.h index 0344862d4..615f6b266 100644 --- a/src/game/server/gamecontroller.h +++ b/src/game/server/gamecontroller.h @@ -35,7 +35,11 @@ class IGameController void DoTeamBalance(); // game + int m_GameState; + int m_GameStateTimer; + virtual void DoWincheck(); + void SetGameState(int GameState, int Seconds=0); // map char m_aMapWish[128]; @@ -71,16 +75,14 @@ protected: IServer *Server() const { return m_pServer; } // game - int m_GameOverTick; - int m_Paused; int m_RoundCount; int m_RoundStartTick; int m_SuddenDeath; int m_aTeamscore[NUM_TEAMS]; - int m_Warmup; void EndRound(); void ResetGame(); + void StartRound(); // info int m_GameFlags; @@ -131,10 +133,19 @@ public: void OnReset(); // game - void DoPause(int Seconds); - void DoWarmup(int Seconds); + enum + { + GS_WARMUP, + GS_GAME, + GS_PAUSED, + GS_GAMEOVER, - void StartRound(); + TIMER_INFINITE = -1, + }; + + void DoPause(int Seconds) { SetGameState(GS_PAUSED, Seconds); } + void DoRestart() { StartRound(); } + void DoWarmup(int Seconds) { SetGameState(GS_WARMUP, Seconds); } // general virtual void Snap(int SnappingClient); @@ -142,12 +153,10 @@ public: // info bool IsFriendlyFire(int ClientID1, int ClientID2) const; - bool IsGameOver() const { return m_GameOverTick != -1; } - bool IsPaused() const { return m_Paused != 0; } bool IsPlayerReadyMode() const; bool IsTeamplay() const { return m_GameFlags&GAMEFLAG_TEAMS; } - bool IsWarmup() const { return m_Warmup != 0; } + int GetGameState() const { return m_GameState; } const char *GetGameType() const { return m_pGameType; } const char *GetTeamName(int Team) const; diff --git a/src/game/server/gameworld.cpp b/src/game/server/gameworld.cpp index 5240140c7..7fea4db08 100644 --- a/src/game/server/gameworld.cpp +++ b/src/game/server/gameworld.cpp @@ -174,7 +174,7 @@ void CGameWorld::Tick() pEnt = m_pNextTraverseEntity; } } - else + else if(GameServer()->m_pController->GetGameState() == IGameController::GS_PAUSED) { // update all objects for(int i = 0; i < NUM_ENTTYPES; i++) diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 713ad6a68..3405fc38b 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -24,7 +24,8 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, bool Dummy) m_LastActionTick = Server()->Tick(); m_TeamChangeTick = Server()->Tick(); m_Dummy = Dummy; - m_IsReadyToPlay = GameServer()->m_pController->IsWarmup() || GameServer()->m_pController->IsPaused() ? false : true; + m_IsReadyToPlay = GameServer()->m_pController->GetGameState() != IGameController::GS_WARMUP && + GameServer()->m_pController->GetGameState() != IGameController::GS_PAUSED; } CPlayer::~CPlayer() @@ -61,7 +62,13 @@ void CPlayer::Tick() } } - if(!GameServer()->m_World.m_Paused) + if(m_pCharacter && !m_pCharacter->IsAlive()) + { + delete m_pCharacter; + m_pCharacter = 0; + } + + if(GameServer()->m_pController->GetGameState() != IGameController::GS_PAUSED) { if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW) m_ViewPos -= vec2(clamp(m_ViewPos.x-m_LatestActivity.m_TargetX, -500.0f, 500.0f), clamp(m_ViewPos.y-m_LatestActivity.m_TargetY, -400.0f, 400.0f)); @@ -72,14 +79,7 @@ void CPlayer::Tick() if(m_pCharacter) { if(m_pCharacter->IsAlive()) - { m_ViewPos = m_pCharacter->m_Pos; - } - else - { - delete m_pCharacter; - m_pCharacter = 0; - } } else if(m_Spawning && m_RespawnTick <= Server()->Tick()) TryRespawn();