void IGameController::DoTeamBalance() { if(!IsTeamplay() || !g_Config.m_SvTeambalanceTime || absolute(m_aTeamSize[TEAM_RED]-m_aTeamSize[TEAM_BLUE]) < NUM_TEAMS) return; GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", "Balancing teams"); float aTeamScore[NUM_TEAMS] = {0}; float aPlayerScore[MAX_CLIENTS] = {0.0f}; // gather stats for(int i = 0; i < MAX_CLIENTS; i++) { if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) { aPlayerScore[i] = GameServer()->m_apPlayers[i]->m_Score*Server()->TickSpeed()*60.0f/ (Server()->Tick()-GameServer()->m_apPlayers[i]->m_ScoreStartTick); aTeamScore[GameServer()->m_apPlayers[i]->GetTeam()] += aPlayerScore[i]; } } int BiggerTeam = (m_aTeamSize[TEAM_RED] > m_aTeamSize[TEAM_BLUE]) ? TEAM_RED : TEAM_BLUE; int NumBalance = absolute(m_aTeamSize[TEAM_RED]-m_aTeamSize[TEAM_BLUE]) / NUM_TEAMS; // balance teams do { CPlayer *pPlayer = 0; float ScoreDiff = aTeamScore[BiggerTeam]; for(int i = 0; i < MAX_CLIENTS; i++) { if(!GameServer()->m_apPlayers[i] || !CanBeMovedOnBalance(i)) continue; // remember the player whom would cause lowest score-difference if(GameServer()->m_apPlayers[i]->GetTeam() == BiggerTeam && (!pPlayer || absolute((aTeamScore[BiggerTeam^1]+aPlayerScore[i]) - (aTeamScore[BiggerTeam]-aPlayerScore[i])) < ScoreDiff)) { pPlayer = GameServer()->m_apPlayers[i]; ScoreDiff = absolute((aTeamScore[BiggerTeam^1]+aPlayerScore[i]) - (aTeamScore[BiggerTeam]-aPlayerScore[i])); } } // move the player to the other team if(pPlayer) { int Temp = pPlayer->m_LastActionTick; DoTeamChange(pPlayer, BiggerTeam^1); pPlayer->m_LastActionTick = Temp; pPlayer->Respawn(); GameServer()->SendGameMsg(GAMEMSG_TEAM_BALANCE_VICTIM, pPlayer->GetTeam(), pPlayer->GetCID()); } } while(--NumBalance); m_UnbalancedTick = TBALANCE_OK; GameServer()->SendGameMsg(GAMEMSG_TEAM_BALANCE, -1); }
void IGameController::Tick() { // do warmup if(m_Warmup) { m_Warmup--; if(!m_Warmup) StartRound(); } if(m_GameOverTick != -1) { // game over.. wait for restart if(Server()->Tick() > m_GameOverTick+Server()->TickSpeed()*10) { CycleMap(); StartRound(); m_RoundCount++; } } // do team-balancing if (IsTeamplay() && m_UnbalancedTick != -1 && Server()->Tick() > m_UnbalancedTick+g_Config.m_SvTeambalanceTime*Server()->TickSpeed()*60) { GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", "Balancing teams"); int aT[2] = {0,0}; float aTScore[2] = {0,0}; float aPScore[MAX_CLIENTS] = {0.0f}; for(int i = 0; i < MAX_CLIENTS; i++) { if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) { aT[GameServer()->m_apPlayers[i]->GetTeam()]++; aPScore[i] = GameServer()->m_apPlayers[i]->m_Score*Server()->TickSpeed()*60.0f/ (Server()->Tick()-GameServer()->m_apPlayers[i]->m_ScoreStartTick); aTScore[GameServer()->m_apPlayers[i]->GetTeam()] += aPScore[i]; } } // are teams unbalanced? if(absolute(aT[0]-aT[1]) >= 2) { int M = (aT[0] > aT[1]) ? 0 : 1; int NumBalance = absolute(aT[0]-aT[1]) / 2; do { CPlayer *pP = 0; float PD = aTScore[M]; for(int i = 0; i < MAX_CLIENTS; i++) { if(!GameServer()->m_apPlayers[i] || !CanBeMovedOnBalance(i)) continue; // remember the player who would cause lowest score-difference if(GameServer()->m_apPlayers[i]->GetTeam() == M && (!pP || absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i])) < PD)) { pP = GameServer()->m_apPlayers[i]; PD = absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i])); } } // move the player to the other team int Temp = pP->m_LastActionTick; pP->SetTeam(M^1); pP->m_LastActionTick = Temp; pP->Respawn(); pP->m_ForceBalanced = true; } while (--NumBalance); m_ForceBalanced = true; } m_UnbalancedTick = -1; } // check for inactive players if(g_Config.m_SvInactiveKickTime > 0) { for(int i = 0; i < MAX_CLIENTS; ++i) { if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && !Server()->IsAuthed(i)) { if(Server()->Tick() > GameServer()->m_apPlayers[i]->m_LastActionTick+g_Config.m_SvInactiveKickTime*Server()->TickSpeed()*60) { switch(g_Config.m_SvInactiveKick) { case 0: { // move player to spectator GameServer()->m_apPlayers[i]->SetTeam(TEAM_SPECTATORS); } break; case 1: { // move player to spectator if the reserved slots aren't filled yet, kick him otherwise int Spectators = 0; for(int j = 0; j < MAX_CLIENTS; ++j) if(GameServer()->m_apPlayers[j] && GameServer()->m_apPlayers[j]->GetTeam() == TEAM_SPECTATORS) ++Spectators; if(Spectators >= g_Config.m_SvSpectatorSlots) Server()->Kick(i, "Kicked for inactivity"); else GameServer()->m_apPlayers[i]->SetTeam(TEAM_SPECTATORS); } break; case 2: { // kick the player Server()->Kick(i, "Kicked for inactivity"); } } } } } } // first condition is because player score gets reset pretty late. second is to not get two votes, if both sv_endvote_* are set. // third is to only cause the vote in the last round if (m_RoundStartTick != Server()->Tick() && *g_Config.m_SvMaprotation && !m_AutoVoteCaused && m_RoundCount >= g_Config.m_SvRoundsPerMap - 1) { if (g_Config.m_SvEndvoteTime > 0 && g_Config.m_SvTimelimit > 0 && g_Config.m_SvEndvoteTime < g_Config.m_SvTimelimit*60 && Server()->Tick() - m_RoundStartTick >= (g_Config.m_SvTimelimit*60 - g_Config.m_SvEndvoteTime) * Server()->TickSpeed()) { AutoVote(); //time } else if (g_Config.m_SvEndvoteScore > 0 && g_Config.m_SvScorelimit > 0 && g_Config.m_SvEndvoteScore < g_Config.m_SvScorelimit) { int Max = 0; if (m_GameFlags & GAMEFLAG_TEAMS) Max = m_aTeamscore[m_aTeamscore[TEAM_RED] > m_aTeamscore[TEAM_BLUE] ? TEAM_RED : TEAM_BLUE]; else for(int i = 0; i < MAX_CLIENTS; ++i) if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_Score > Max) Max = GameServer()->m_apPlayers[i]->m_Score; if (Max + g_Config.m_SvEndvoteScore >= g_Config.m_SvScorelimit) AutoVote(); //score } } }
void IGameController::Tick() { // do warmup if(m_Warmup) { m_Warmup--; if(!m_Warmup) StartRound(); } if(m_GameOverTick != -1) { // game over.. wait for restart if(Server()->Tick() > m_GameOverTick+Server()->TickSpeed()*10) { CycleMap(); StartRound(); m_RoundCount++; } } // game is Paused if(GameServer()->m_World.m_Paused) ++m_RoundStartTick; // do team-balancing if(IsTeamplay() && m_UnbalancedTick != -1 && Server()->Tick() > m_UnbalancedTick+g_Config.m_SvTeambalanceTime*Server()->TickSpeed()*60) { GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", "Balancing teams"); int aT[2] = {0,0}; float aTScore[2] = {0,0}; float aPScore[MAX_CLIENTS] = {0.0f}; for(int i = 0; i < MAX_CLIENTS; i++) { if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) { aT[GameServer()->m_apPlayers[i]->GetTeam()]++; aPScore[i] = GameServer()->m_apPlayers[i]->m_Score*Server()->TickSpeed()*60.0f/ (Server()->Tick()-GameServer()->m_apPlayers[i]->m_ScoreStartTick); aTScore[GameServer()->m_apPlayers[i]->GetTeam()] += aPScore[i]; } } // are teams unbalanced? if(absolute(aT[0]-aT[1]) >= 2) { int M = (aT[0] > aT[1]) ? 0 : 1; int NumBalance = absolute(aT[0]-aT[1]) / 2; do { CPlayer *pP = 0; float PD = aTScore[M]; for(int i = 0; i < MAX_CLIENTS; i++) { if(!GameServer()->m_apPlayers[i] || !CanBeMovedOnBalance(i)) continue; // remember the player who would cause lowest score-difference if(GameServer()->m_apPlayers[i]->GetTeam() == M && (!pP || absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i])) < PD)) { pP = GameServer()->m_apPlayers[i]; PD = absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i])); } } // move the player to the other team int Temp = pP->m_LastActionTick; pP->SetTeam(M^1); pP->m_LastActionTick = Temp; pP->Respawn(); pP->m_ForceBalanced = true; } while (--NumBalance); m_ForceBalanced = true; } m_UnbalancedTick = -1; } // check for inactive players if(g_Config.m_SvInactiveKickTime > 0) { // dont kick bots for(int i = 0; i < FIRST_BOT_ID; ++i) { #ifdef CONF_DEBUG if(g_Config.m_DbgDummies) { if(i >= MAX_CLIENTS-g_Config.m_DbgDummies) break; } #endif if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && !Server()->IsAuthed(i)) { if(Server()->Tick() > GameServer()->m_apPlayers[i]->m_LastActionTick+g_Config.m_SvInactiveKickTime*Server()->TickSpeed()*60) { switch(g_Config.m_SvInactiveKick) { case 0: { // move player to spectator GameServer()->m_apPlayers[i]->SetTeam(TEAM_SPECTATORS); } break; case 1: { // move player to spectator if the reserved slots aren't filled yet, kick him otherwise int Spectators = 0; for(int j = 0; j < FIRST_BOT_ID; ++j) if(GameServer()->m_apPlayers[j] && GameServer()->m_apPlayers[j]->GetTeam() == TEAM_SPECTATORS) ++Spectators; if(Spectators >= g_Config.m_SvSpectatorSlots) Server()->Kick(i, "Kicked for inactivity"); else GameServer()->m_apPlayers[i]->SetTeam(TEAM_SPECTATORS); } break; case 2: { // kick the player Server()->Kick(i, "Kicked for inactivity"); } } } } } } DoWincheck(); }
void IGameController::Tick() { // do warmup if(m_Warmup) { m_Warmup--; if(!m_Warmup) StartRound(); } if(m_GameOverTick != -1) { // game over.. wait for restart if(Server()->Tick() > m_GameOverTick+Server()->TickSpeed()*10) { CycleMap(); StartRound(); m_RoundCount++; } } // do team-balancing if (IsTeamplay() && m_UnbalancedTick != -1 && Server()->Tick() > m_UnbalancedTick+g_Config.m_SvTeambalanceTime*Server()->TickSpeed()*60) { dbg_msg("game", "Balancing teams"); int aT[2] = {0,0}; float aTScore[2] = {0,0}; float aPScore[MAX_CLIENTS] = {0.0f}; for(int i = 0; i < MAX_CLIENTS; i++) { if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != -1) { aT[GameServer()->m_apPlayers[i]->GetTeam()]++; aPScore[i] = GameServer()->m_apPlayers[i]->m_Score*Server()->TickSpeed()*60.0f/ (Server()->Tick()-GameServer()->m_apPlayers[i]->m_ScoreStartTick); aTScore[GameServer()->m_apPlayers[i]->GetTeam()] += aPScore[i]; } } // are teams unbalanced? if(absolute(aT[0]-aT[1]) >= 2) { int M = (aT[0] > aT[1]) ? 0 : 1; int NumBalance = absolute(aT[0]-aT[1]) / 2; do { CPlayer *pP = 0; int PD = aTScore[M]; for(int i = 0; i < MAX_CLIENTS; i++) { if(!GameServer()->m_apPlayers[i] || !CanBeMovedOnBalance(i)) continue; // remember the player who would cause lowest score-difference if(GameServer()->m_apPlayers[i]->GetTeam() == M && (!pP || absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i])) < PD)) { pP = GameServer()->m_apPlayers[i]; PD = absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i])); } } // move the player to the other team pP->SetTeam(M^1); pP->Respawn(); pP->m_ForceBalanced = true; } while (--NumBalance); m_ForceBalanced = true; } m_UnbalancedTick = -1; } // update browse info int Prog = -1; if(g_Config.m_SvTimelimit > 0) Prog = max(Prog, (Server()->Tick()-m_RoundStartTick) * 100 / (g_Config.m_SvTimelimit*Server()->TickSpeed()*60)); if(g_Config.m_SvScorelimit) { if(IsTeamplay()) { Prog = max(Prog, (m_aTeamscore[0]*100)/g_Config.m_SvScorelimit); Prog = max(Prog, (m_aTeamscore[1]*100)/g_Config.m_SvScorelimit); } else { for(int i = 0; i < MAX_CLIENTS; i++) { if(GameServer()->m_apPlayers[i]) Prog = max(Prog, (GameServer()->m_apPlayers[i]->m_Score*100)/g_Config.m_SvScorelimit); } } } if(m_Warmup) Prog = -1; Server()->SetBrowseInfo(m_pGameType, Prog); }