X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fteamplay.qc;h=ff9438e76d84b205679a05982d5b8bc1eb0b57f3;hp=cfd15f24807476ccdcede9326b98930f7733b13a;hb=1a18ff8e9f729e903015f5baa6605c92c92ea13d;hpb=eb13e9f317dc515b6b5a579010f2952e7261d82d diff --git a/qcsrc/server/teamplay.qc b/qcsrc/server/teamplay.qc index cfd15f248..ff9438e76 100644 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@ -181,7 +181,7 @@ bool Player_SetTeamIndex(entity player, int index) { // This is important when players join the game and one of their // color matches the team color while other doesn't. For example - // [BOT]Lion. + // [BOT]Lion: color 0 4. SetPlayerColors(player, new_team - 1); } return true; @@ -211,54 +211,100 @@ bool SetPlayerTeam(entity player, int team_index, int type) { return false; } - LogTeamchange(player.playerid, player.team, type); + LogTeamChange(player.playerid, player.team, type); if (team_index != old_team_index) { - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(player.team, - INFO_JOIN_PLAY_TEAM), player.netname); + PlayerScore_Clear(player); + if (team_index != -1) + { + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM( + player.team, INFO_JOIN_PLAY_TEAM), player.netname); + } + else + { + if (!CS(player).just_joined) + { + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, + player.netname); + } + } KillPlayerForTeamChange(player); + if (!IS_BOT_CLIENT(player)) + { + TeamBalance_AutoBalanceBots(); + } } - return true; -} - -bool MoveToTeam(entity client, int team_index, int type) -{ - //PrintToChatAll(sprintf("MoveToTeam: %s, %f", client.netname, team_index)); - int lockteams_backup = lockteams; // backup any team lock - lockteams = 0; // disable locked teams - PlayerScore_Clear(client); - if (!SetPlayerTeam(client, team_index, type)) + else if (team_index == -1) { - lockteams = lockteams_backup; // restore the team lock - return false; + if (!CS(player).just_joined && player.frags != FRAGS_SPECTATOR) + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, player.netname); } - lockteams = lockteams_backup; // restore the team lock return true; } -void KillPlayerForTeamChange(entity player) +void Player_SetTeamIndexChecked(entity player, int team_index) { - if (IS_DEAD(player)) + if (!teamplay) { return; } - if (MUTATOR_CALLHOOK(Player_ChangeTeamKill, player) == true) + if (!Team_IsValidIndex(team_index)) { return; } - Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, DMG_NOWEP, - player.origin, '0 0 0'); + if ((autocvar_g_campaign) || (autocvar_g_changeteam_banned && + CS(player).wasplayer)) + { + Send_Notification(NOTIF_ONE, player, MSG_INFO, + INFO_TEAMCHANGE_NOTALLOWED); + return; + } + entity balance = TeamBalance_CheckAllowedTeams(player); + if (team_index == 1 && !TeamBalance_IsTeamAllowedInternal(balance, 1)) + { + team_index = 4; + } + if (team_index == 4 && !TeamBalance_IsTeamAllowedInternal(balance, 4)) + { + team_index = 3; + } + if (team_index == 3 && !TeamBalance_IsTeamAllowedInternal(balance, 3)) + { + team_index = 2; + } + if (team_index == 2 && !TeamBalance_IsTeamAllowedInternal(balance, 2)) + { + team_index = 1; + } + // autocvar_g_balance_teams_prevent_imbalance only makes sense if autocvar_g_balance_teams is on, as it makes the team selection dialog pointless + if (autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance) + { + TeamBalance_GetTeamCounts(balance, player); + if ((Team_IndexToBit(team_index) & TeamBalance_FindBestTeams(balance, + player, false)) == 0) + { + Send_Notification(NOTIF_ONE, player, MSG_INFO, + INFO_TEAMCHANGE_LARGERTEAM); + TeamBalance_Destroy(balance); + return; + } + } + TeamBalance_Destroy(balance); + SetPlayerTeam(player, team_index, TEAM_CHANGE_MANUAL); } -void LogTeamchange(float player_id, float team_number, int type) +bool MoveToTeam(entity client, int team_index, int type) { - if(!autocvar_sv_eventlog) - return; - - if(player_id < 1) - return; - - GameLogEcho(strcat(":team:", ftos(player_id), ":", ftos(team_number), ":", ftos(type))); + //PrintToChatAll(sprintf("MoveToTeam: %s, %f", client.netname, team_index)); + int lockteams_backup = lockteams; // backup any team lock + lockteams = 0; // disable locked teams + if (!SetPlayerTeam(client, team_index, type)) + { + lockteams = lockteams_backup; // restore the team lock + return false; + } + lockteams = lockteams_backup; // restore the team lock + return true; } bool Player_HasRealForcedTeam(entity player) @@ -371,6 +417,42 @@ void Player_DetermineForcedTeam(entity player) } } +void TeamBalance_JoinBestTeam(entity player) +{ + //PrintToChatAll(sprintf("TeamBalance_JoinBestTeam: %s", player.netname)); + if (!teamplay) + { + return; + } + if (player.bot_forced_team) + { + return; + } + entity balance = TeamBalance_CheckAllowedTeams(player); + if (Player_HasRealForcedTeam(player)) + { + int forced_team_index = player.team_forced; + bool is_team_allowed = TeamBalance_IsTeamAllowedInternal(balance, + forced_team_index); + TeamBalance_Destroy(balance); + if (!is_team_allowed) + { + return; + } + if (!SetPlayerTeam(player, forced_team_index, TEAM_CHANGE_AUTO)) + { + return; + } + return; + } + int best_team_index = TeamBalance_FindBestTeam(balance, player, true); + TeamBalance_Destroy(balance); + if (!SetPlayerTeam(player, best_team_index, TEAM_CHANGE_AUTO)) + { + return; + } +} + entity TeamBalance_CheckAllowedTeams(entity for_whom) { entity balance = spawn(); @@ -382,8 +464,8 @@ entity TeamBalance_CheckAllowedTeams(entity for_whom) team_ent.m_num_bots = 0; } setthink(balance, TeamBalance_Destroy); - - int teams_mask = 0; + + int teams_mask = 0; string teament_name = string_null; bool mutator_returnvalue = MUTATOR_CALLHOOK(TeamBalance_CheckAllowedTeams, teams_mask, teament_name, for_whom); @@ -504,8 +586,8 @@ entity TeamBalance_CheckAllowedTeams(entity for_whom) TeamBalance_IsTeamAllowedInternal(balance, i)) { TeamBalance_BanTeamsExcept(balance, i); + break; } - break; } balance.m_team_balance_state = TEAM_BALANCE_TEAMS_CHECKED; return balance; @@ -750,51 +832,6 @@ int TeamBalance_FindBestTeams(entity balance, entity player, bool use_score) return team_bits; } -void TeamBalance_JoinBestTeam(entity this) -{ - //PrintToChatAll(sprintf("JoinBestTeam: %s", this.netname)); - if (!teamplay) - { - return; - } - if (this.bot_forced_team) - { - return; - } - entity balance = TeamBalance_CheckAllowedTeams(this); - if (Player_HasRealForcedTeam(this)) - { - int forced_team_index = this.team_forced; - bool is_team_allowed = TeamBalance_IsTeamAllowedInternal(balance, - forced_team_index); - TeamBalance_Destroy(balance); - if (!is_team_allowed) - { - return; - } - if (!SetPlayerTeam(this, forced_team_index, TEAM_CHANGE_AUTO)) - { - return; - } - if (!IS_BOT_CLIENT(this)) - { - TeamBalance_AutoBalanceBots(); - } - return; - } - int best_team_index = TeamBalance_FindBestTeam(balance, this, true); - TeamBalance_Destroy(balance); - PlayerScore_Clear(this); - if (!SetPlayerTeam(this, best_team_index, TEAM_CHANGE_AUTO)) - { - return; - } - if (!IS_BOT_CLIENT(this)) - { - TeamBalance_AutoBalanceBots(); - } -} - int TeamBalance_CompareTeams(entity balance, int team_index_a, int team_index_b, entity player, bool use_score) { @@ -828,18 +865,14 @@ int TeamBalance_CompareTeams(entity balance, int team_index_a, int team_index_b, void TeamBalance_AutoBalanceBots() { - if (!autocvar_g_balance_teams || - !autocvar_g_balance_teams_prevent_imbalance) - { - return; - } - //PrintToChatAll("TeamBalance_AutoBalanceBots"); + // checks disabled because we always want auto-balanced bots + //if (!(autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance)) + // return; + entity balance = TeamBalance_CheckAllowedTeams(NULL); TeamBalance_GetTeamCounts(balance, NULL); int smallest_team_index = 0; int smallest_team_player_count = 0; - int largest_team_index = 0; - int largest_team_player_count = 0; for (int i = 1; i <= NUM_TEAMS; ++i) { entity team_ = TeamBalance_GetTeamFromIndex(balance, i); @@ -847,53 +880,87 @@ void TeamBalance_AutoBalanceBots() { continue; } - int player_count = TeamBalanceTeam_GetNumberOfPlayers(team_); + int playercount = TeamBalanceTeam_GetNumberOfPlayers(team_); if (smallest_team_index == 0) { smallest_team_index = i; - smallest_team_player_count = player_count; + smallest_team_player_count = playercount; } - else if (player_count < smallest_team_player_count) + else if (playercount < smallest_team_player_count) { smallest_team_index = i; - smallest_team_player_count = player_count; + smallest_team_player_count = playercount; } - if (largest_team_index == 0) + } + //PrintToChatAll(sprintf("Smallest team: %f", smallest_team_index)); + //PrintToChatAll(sprintf("Smallest team players: %f", smallest_team_player_count)); + entity switchable_bot = NULL; + int teams = BITS(NUM_TEAMS); + while (teams != 0) + { + int largest_team_index = TeamBalance_GetLargestTeamIndex(balance, + teams); + if (smallest_team_index == largest_team_index) { - largest_team_index = i; - largest_team_player_count = player_count; + TeamBalance_Destroy(balance); + return; } - else if (player_count > largest_team_player_count) + entity largest_team = TeamBalance_GetTeamFromIndex(balance, + largest_team_index); + int largest_team_player_count = TeamBalanceTeam_GetNumberOfPlayers( + largest_team); + if (largest_team_player_count - smallest_team_player_count < 2) { - largest_team_index = i; - largest_team_player_count = player_count; + TeamBalance_Destroy(balance); + return; } + //PrintToChatAll(sprintf("Largest team: %f", largest_team_index)); + //PrintToChatAll(sprintf("Largest team players: %f", largest_team_player_count)); + switchable_bot = TeamBalance_GetPlayerForTeamSwitch(largest_team_index, + smallest_team_index, true); + if (switchable_bot != NULL) + { + break; + } + teams &= ~Team_IndexToBit(largest_team_index); } TeamBalance_Destroy(balance); - //PrintToChatAll(sprintf("Smallest team: %f", smallest_team_index)); - //PrintToChatAll(sprintf("Largest team: %f", largest_team_index)); - //PrintToChatAll(sprintf("Smallest team players: %f", smallest_team_player_count)); - //PrintToChatAll(sprintf("Largest team players: %f", largest_team_player_count)); - if (smallest_team_index == largest_team_index) - { - return; - } - if (largest_team_player_count - smallest_team_player_count < 2) + if (switchable_bot == NULL) { + //PrintToChatAll("No bot found after searching through all the teams"); return; } - entity lowest_bot = TeamBalance_GetPlayerForTeamSwitch(largest_team_index, - smallest_team_index, true); - if (lowest_bot == NULL) - { - //PrintToChatAll("No bot found"); - return; - } - if (!Player_SetTeamIndex(lowest_bot, smallest_team_index)) + SetPlayerTeam(switchable_bot, smallest_team_index, TEAM_CHANGE_AUTO); +} + +int TeamBalance_GetLargestTeamIndex(entity balance, int teams) +{ + int largest_team_index = 0; + int largest_team_player_count = 0; + for (int i = 1; i <= NUM_TEAMS; ++i) { - return; + if (!(Team_IndexToBit(i) & teams)) + { + continue; + } + entity team_ = TeamBalance_GetTeamFromIndex(balance, i); + if (!TeamBalanceTeam_IsAllowed(team_)) + { + continue; + } + int playercount = TeamBalanceTeam_GetNumberOfPlayers(team_); + if (largest_team_index == 0) + { + largest_team_index = i; + largest_team_player_count = playercount; + } + else if (playercount > largest_team_player_count) + { + largest_team_index = i; + largest_team_player_count = playercount; + } } - KillPlayerForTeamChange(lowest_bot); + return largest_team_index; } entity TeamBalance_GetPlayerForTeamSwitch(int source_team_index, @@ -935,6 +1002,33 @@ entity TeamBalance_GetPlayerForTeamSwitch(int source_team_index, return lowest_player; } +void LogTeamChange(float player_id, float team_number, int type) +{ + if (!autocvar_sv_eventlog) + { + return; + } + if (player_id < 1) + { + return; + } + GameLogEcho(sprintf(":team:%d:%d:%d", player_id, team_number, type)); +} + +void KillPlayerForTeamChange(entity player) +{ + if (IS_DEAD(player)) + { + return; + } + if (MUTATOR_CALLHOOK(Player_ChangeTeamKill, player) == true) + { + return; + } + Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, DMG_NOWEP, + player.origin, '0 0 0'); +} + bool TeamBalance_IsTeamAllowedInternal(entity balance, int index) { return balance.m_team_balance_team[index - 1].m_num_players != @@ -1023,99 +1117,24 @@ int TeamBalance_CompareTeamsInternal(entity team_a, entity team_b, return TEAMS_COMPARE_EQUAL; } -// Called when the player connects or when they change their color with "color" -// command. -void SV_ChangeTeam(entity this, float _color) +void SV_ChangeTeam(entity player, int new_color) { - //PrintToChatAll(sprintf("SV_ChangeTeam: %s, %f", this.netname, _color)); - - // in normal deathmatch we can just apply the color and we're done - if(!teamplay) - SetPlayerColors(this, _color); - - if(!IS_CLIENT(this)) - { - //PrintToChatAll("Not a client yet"); - // since this is an engine function, and gamecode doesn't have any calls earlier than this, do the connecting message here - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CONNECTING, this.netname); - return; - } - - if(!teamplay) - return; - - int source_color, destination_color; - int source_team_index, destination_team_index; - - source_color = this.clientcolors & 0x0F; - destination_color = _color & 0x0F; - - source_team_index = Team_TeamToIndex(source_color + 1); - destination_team_index = Team_TeamToIndex(destination_color + 1); - - if (destination_team_index == -1) - { - return; - } - - entity balance = TeamBalance_CheckAllowedTeams(this); - - if (destination_team_index == 1 && !TeamBalance_IsTeamAllowedInternal( - balance, 1)) - { - destination_team_index = 4; - } - if (destination_team_index == 4 && !TeamBalance_IsTeamAllowedInternal( - balance, 4)) - { - destination_team_index = 3; - } - if (destination_team_index == 3 && !TeamBalance_IsTeamAllowedInternal( - balance, 3)) + if (!teamplay) { - destination_team_index = 2; + SetPlayerColors(player, new_color); } - if (destination_team_index == 2 && !TeamBalance_IsTeamAllowedInternal( - balance, 2)) + // TODO: Should we really bother with this? + if(!IS_CLIENT(player)) { - destination_team_index = 1; - } - - // not changing teams - if (source_color == destination_color) - { - SetPlayerTeam(this, destination_team_index, TEAM_CHANGE_MANUAL); - TeamBalance_Destroy(balance); - TeamBalance_AutoBalanceBots(); // Hack + // since this is an engine function, and gamecode doesn't have any calls earlier than this, do the connecting message here + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CONNECTING, + player.netname); return; } - - if((autocvar_g_campaign) || (autocvar_g_changeteam_banned && CS(this).wasplayer)) { - Send_Notification(NOTIF_ONE, this, MSG_INFO, INFO_TEAMCHANGE_NOTALLOWED); - return; // changing teams is not allowed - } - - // autocvar_g_balance_teams_prevent_imbalance only makes sense if autocvar_g_balance_teams is on, as it makes the team selection dialog pointless - if (autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance) - { - TeamBalance_GetTeamCounts(balance, this); - if ((Team_IndexToBit(destination_team_index) & - TeamBalance_FindBestTeams(balance, this, false)) == 0) - { - Send_Notification(NOTIF_ONE, this, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM); - TeamBalance_Destroy(balance); - return; - } - } - TeamBalance_Destroy(balance); - if (IS_PLAYER(this) && source_team_index != destination_team_index) - { - // reduce frags during a team change - PlayerScore_Clear(this); - } - if (!SetPlayerTeam(this, destination_team_index, TEAM_CHANGE_MANUAL)) + if (!teamplay) { return; } - TeamBalance_AutoBalanceBots(); + Player_SetTeamIndexChecked(player, Team_TeamToIndex((new_color & 0x0F) + + 1)); }