]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/teamplay.qc
Update default video settings
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / teamplay.qc
index abc5df1d726a0e730e2c55402690112ad2cd9fc4..1cfdbf4a0538da331630210cdfbc92a4ef4333ec 100644 (file)
@@ -1,19 +1,19 @@
 #include "teamplay.qh"
 
-#include "client.qh"
-#include "race.qh"
-#include "scores.qh"
-#include "scores_rules.qh"
-
-#include "bot/api.qh"
-
-#include "command/vote.qh"
-
-#include <server/mutators/_mod.qh>
-
-#include "../common/deathtypes/all.qh"
+#include <common/deathtypes/all.qh>
 #include <common/gamemodes/_mod.qh>
-#include "../common/teams.qh"
+#include <common/teams.qh>
+#include <server/bot/api.qh>
+#include <server/bot/default/cvars.qh>
+#include <server/campaign.qh>
+#include <server/client.qh>
+#include <server/command/vote.qh>
+#include <server/damage.qh>
+#include <server/gamelog.qh>
+#include <server/mutators/_mod.qh>
+#include <server/race.qh>
+#include <server/scores.qh>
+#include <server/scores_rules.qh>
 
 /// \brief Describes a state of team balance entity.
 enum
@@ -28,8 +28,6 @@ enum
 /// \brief Indicates that the player is not allowed to join a team.
 const int TEAM_NOT_ALLOWED = -1;
 
-.float team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
-
 .int m_team_balance_state; ///< Holds the state of the team balance entity.
 .entity m_team_balance_team[NUM_TEAMS]; ///< ???
 
@@ -37,7 +35,7 @@ const int TEAM_NOT_ALLOWED = -1;
 .int m_num_players; ///< Number of players (both humans and bots) in a team.
 .int m_num_bots; ///< Number of bots in a team.
 .int m_num_players_alive; ///< Number of alive players in a team.
-.int m_num_control_points; ///< Number of control points owned by a team.
+.int m_num_owned_items; ///< Number of items owned by a team.
 
 string autocvar_g_forced_team_red;
 string autocvar_g_forced_team_blue;
@@ -46,11 +44,13 @@ string autocvar_g_forced_team_pink;
 
 entity g_team_entities[NUM_TEAMS]; ///< Holds global team entities.
 
-STATIC_INIT(g_team_entities)
+void Team_InitTeams()
 {
+       if (g_team_entities[0])
+               return;
        for (int i = 0; i < NUM_TEAMS; ++i)
        {
-               g_team_entities[i] = spawn();
+               g_team_entities[i] = new_pure(team_entity);
        }
 }
 
@@ -58,7 +58,7 @@ entity Team_GetTeamFromIndex(int index)
 {
        if (!Team_IsValidIndex(index))
        {
-               LOG_FATALF("Team_GetTeamFromIndex: Index is invalid: %f", index);
+               LOG_FATALF("Index is invalid: %f", index);
        }
        return g_team_entities[index - 1];
 }
@@ -67,7 +67,7 @@ entity Team_GetTeam(int team_num)
 {
        if (!Team_IsValidTeam(team_num))
        {
-               LOG_FATALF("Team_GetTeam: Value is invalid: %f", team_num);
+               LOG_FATALF("Value is invalid: %f", team_num);
        }
        return g_team_entities[Team_TeamToIndex(team_num) - 1];
 }
@@ -92,6 +92,21 @@ void Team_SetNumberOfAlivePlayers(entity team_ent, int number)
        team_ent.m_num_players_alive = number;
 }
 
+int Team_GetWinnerAliveTeam()
+{
+       int winner = 0;
+       for (int i = 0; i < NUM_TEAMS; ++i)
+       {
+               if (g_team_entities[i].m_num_players_alive > 0)
+               {
+                       if (winner)
+                               return 0;
+                       winner = Team_IndexToTeam(i + 1);
+               }
+       }
+       return (winner ? winner : -1);
+}
+
 int Team_GetNumberOfAliveTeams()
 {
        int result = 0;
@@ -105,22 +120,37 @@ int Team_GetNumberOfAliveTeams()
        return result;
 }
 
-int Team_GetNumberOfControlPoints(entity team_ent)
+int Team_GetWinnerTeam_WithOwnedItems(int min_control_points)
+{
+       int winner = 0;
+       for (int i = 0; i < NUM_TEAMS; ++i)
+       {
+               if (g_team_entities[i].m_num_owned_items >= min_control_points)
+               {
+                       if (winner)
+                               return 0;
+                       winner = Team_IndexToTeam(i + 1);
+               }
+       }
+       return (winner ? winner : -1);
+}
+
+int Team_GetNumberOfOwnedItems(entity team_ent)
 {
-       return team_ent.m_num_control_points;
+       return team_ent.m_num_owned_items;
 }
 
-void Team_SetNumberOfControlPoints(entity team_ent, int number)
+void Team_SetNumberOfOwnedItems(entity team_ent, int number)
 {
-       team_ent.m_num_control_points = number;
+       team_ent.m_num_owned_items = number;
 }
 
-int Team_GetNumberOfTeamsWithControlPoints()
+int Team_GetNumberOfTeamsWithOwnedItems()
 {
        int result = 0;
        for (int i = 0; i < NUM_TEAMS; ++i)
        {
-               if (g_team_entities[i].m_num_control_points > 0)
+               if (g_team_entities[i].m_num_owned_items > 0)
                {
                        ++result;
                }
@@ -130,7 +160,7 @@ int Team_GetNumberOfTeamsWithControlPoints()
 
 void setcolor(entity this, int clr)
 {
-#if 0
+#if 1
        this.clientcolors = clr;
        this.team = (clr & 15) + 1;
 #else
@@ -181,7 +211,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;
@@ -207,37 +237,38 @@ bool Player_SetTeamIndex(entity player, int index)
 bool SetPlayerTeam(entity player, int team_index, int type)
 {
        int old_team_index = Entity_GetTeamIndex(player);
+
        if (!Player_SetTeamIndex(player, team_index))
-       {
                return false;
-       }
+
        LogTeamChange(player.playerid, player.team, type);
+
        if (team_index != old_team_index)
        {
-               PlayerScore_Clear(player);
+               KillPlayerForTeamChange(player);
+               PlayerScore_Clear(player); // works only in game modes without teams
+
+               if (!IS_BOT_CLIENT(player))
+                       TeamBalance_AutoBalanceBots();
+
                if (team_index != -1)
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(player.team, INFO_JOIN_PLAY_TEAM), player.netname);
+       }
+
+       if (team_index == -1)
+       {
+               if (autocvar_sv_maxidle_playertospectator > 0 && CS(player).idlekick_lasttimeleft)
                {
-                       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);
-                       }
-                       else
-                       {
-                               CS(player).just_joined = false;
-                       }
+                       // this done here so it happens even when manually speccing during the countdown
+                       Kill_Notification(NOTIF_ONE_ONLY, player, MSG_CENTER, CPID_IDLING);
+                       CS(player).idlekick_lasttimeleft = 0;
                }
-               KillPlayerForTeamChange(player);
-               if (!IS_BOT_CLIENT(player))
+               else if (!CS(player).just_joined && player.frags != FRAGS_SPECTATOR)
                {
-                       TeamBalance_AutoBalanceBots();
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, player.netname);
                }
        }
+
        return true;
 }
 
@@ -330,7 +361,7 @@ void Player_SetForcedTeamIndex(entity player, int team_index)
                {
                        if (!Team_IsValidIndex(team_index))
                        {
-                               LOG_FATAL("Player_SetForcedTeamIndex: Invalid team index.");
+                               LOG_FATAL("Invalid team index.");
                        }
                        else
                        {
@@ -463,8 +494,9 @@ entity TeamBalance_CheckAllowedTeams(entity for_whom)
                team_ent.m_num_bots = 0;
        }
        setthink(balance, TeamBalance_Destroy);
-       
-       int teams_mask = 0;     
+       balance.nextthink = time;
+
+       int teams_mask = 0;
        string teament_name = string_null;
        bool mutator_returnvalue = MUTATOR_CALLHOOK(TeamBalance_CheckAllowedTeams,
                teams_mask, teament_name, for_whom);
@@ -495,8 +527,7 @@ entity TeamBalance_CheckAllowedTeams(entity for_whom)
        }
 
        // TODO: Balance quantity of bots across > 2 teams when bot_vs_human is set (and remove next line)
-       if (AvailableTeams() == 2)
-       if (autocvar_bot_vs_human && for_whom)
+       if (autocvar_bot_vs_human && AVAILABLE_TEAMS == 2 && for_whom)
        {
                if (autocvar_bot_vs_human > 0)
                {
@@ -585,8 +616,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;
@@ -609,12 +640,11 @@ int TeamBalance_GetAllowedTeams(entity balance)
 {
        if (balance == NULL)
        {
-               LOG_FATAL("TeamBalance_GetAllowedTeams: Team balance entity is NULL.");
+               LOG_FATAL("Team balance entity is NULL.");
        }
        if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
        {
-               LOG_FATAL("TeamBalance_GetAllowedTeams: "
-                       "Team balance entity is not initialized.");
+               LOG_FATAL("Team balance entity is not initialized.");
        }
        int result = 0;
        for (int i = 1; i <= NUM_TEAMS; ++i)
@@ -631,16 +661,15 @@ bool TeamBalance_IsTeamAllowed(entity balance, int index)
 {
        if (balance == NULL)
        {
-               LOG_FATAL("TeamBalance_IsTeamAllowed: Team balance entity is NULL.");
+               LOG_FATAL("Team balance entity is NULL.");
        }
        if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
        {
-               LOG_FATAL("TeamBalance_IsTeamAllowed: "
-                       "Team balance entity is not initialized.");
+               LOG_FATAL("Team balance entity is not initialized.");
        }
        if (!Team_IsValidIndex(index))
        {
-               LOG_FATALF("TeamBalance_IsTeamAllowed: Team index is invalid: %f",
+               LOG_FATALF("Team index is invalid: %f",
                        index);
        }
        return TeamBalance_IsTeamAllowedInternal(balance, index);
@@ -650,12 +679,11 @@ void TeamBalance_GetTeamCounts(entity balance, entity ignore)
 {
        if (balance == NULL)
        {
-               LOG_FATAL("TeamBalance_GetTeamCounts: Team balance entity is NULL.");
+               LOG_FATAL("Team balance entity is NULL.");
        }
        if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
        {
-               LOG_FATAL("TeamBalance_GetTeamCounts: "
-                       "Team balance entity is not initialized.");
+               LOG_FATAL("Team balance entity is not initialized.");
        }
        if (MUTATOR_CALLHOOK(TeamBalance_GetTeamCounts) == true)
        {
@@ -682,7 +710,7 @@ void TeamBalance_GetTeamCounts(entity balance, entity ignore)
                        }
                        int team_num;
                        // TODO: Reconsider when the player is truly on the team.
-                       if (IS_CLIENT(it) || (it.caplayer))
+                       if (IS_CLIENT(it) || INGAME(it))
                        {
                                team_num = it.team;
                        }
@@ -732,18 +760,15 @@ int TeamBalance_GetNumberOfPlayers(entity balance, int index)
 {
        if (balance == NULL)
        {
-               LOG_FATAL("TeamBalance_GetNumberOfPlayers: "
-                       "Team balance entity is NULL.");
+               LOG_FATAL("Team balance entity is NULL.");
        }
        if (balance.m_team_balance_state != TEAM_BALANCE_TEAM_COUNTS_FILLED)
        {
-               LOG_FATAL("TeamBalance_GetNumberOfPlayers: "
-                       "TeamBalance_GetTeamCounts has not been called.");
+               LOG_FATAL("TeamBalance_GetTeamCounts has not been called.");
        }
        if (!Team_IsValidIndex(index))
        {
-               LOG_FATALF("TeamBalance_GetNumberOfPlayers: Team index is invalid: %f",
-                       index);
+               LOG_FATALF("Team index is invalid: %f", index);
        }
        return balance.m_team_balance_team[index - 1].m_num_players;
 }
@@ -752,12 +777,11 @@ int TeamBalance_FindBestTeam(entity balance, entity player, bool ignore_player)
 {
        if (balance == NULL)
        {
-               LOG_FATAL("TeamBalance_FindBestTeam: Team balance entity is NULL.");
+               LOG_FATAL("Team balance entity is NULL.");
        }
        if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
        {
-               LOG_FATAL("TeamBalance_FindBestTeam: "
-                       "Team balance entity is not initialized.");
+               LOG_FATAL("Team balance entity is not initialized.");
        }
        // count how many players are in each team
        if (ignore_player)
@@ -771,8 +795,7 @@ int TeamBalance_FindBestTeam(entity balance, entity player, bool ignore_player)
        int team_bits = TeamBalance_FindBestTeams(balance, player, true);
        if (team_bits == 0)
        {
-               LOG_FATALF("TeamBalance_FindBestTeam: No teams available for %s\n",
-                       MapInfo_Type_ToString(MapInfo_CurrentGametype()));
+               LOG_FATALF("No teams available for %s\n", GetGametype());
        }
        RandomSelection_Init();
        for (int i = 1; i <= NUM_TEAMS; ++i)
@@ -789,12 +812,11 @@ int TeamBalance_FindBestTeams(entity balance, entity player, bool use_score)
 {
        if (balance == NULL)
        {
-               LOG_FATAL("TeamBalance_FindBestTeams: Team balance entity is NULL.");
+               LOG_FATAL("Team balance entity is NULL.");
        }
        if (balance.m_team_balance_state != TEAM_BALANCE_TEAM_COUNTS_FILLED)
        {
-               LOG_FATAL("TeamBalance_FindBestTeams: "
-                       "TeamBalance_GetTeamCounts has not been called.");
+               LOG_FATAL("TeamBalance_GetTeamCounts has not been called.");
        }
        if (MUTATOR_CALLHOOK(TeamBalance_FindBestTeams, player) == true)
        {
@@ -836,21 +858,20 @@ int TeamBalance_CompareTeams(entity balance, int team_index_a, int team_index_b,
 {
        if (balance == NULL)
        {
-               LOG_FATAL("TeamBalance_CompareTeams: Team balance entity is NULL.");
+               LOG_FATAL("Team balance entity is NULL.");
        }
        if (balance.m_team_balance_state != TEAM_BALANCE_TEAM_COUNTS_FILLED)
        {
-               LOG_FATAL("TeamBalance_CompareTeams: "
-                       "TeamBalance_GetTeamCounts has not been called.");
+               LOG_FATAL("TeamBalance_GetTeamCounts has not been called.");
        }
        if (!Team_IsValidIndex(team_index_a))
        {
-               LOG_FATALF("TeamBalance_CompareTeams: team_index_a is invalid: %f",
+               LOG_FATALF("team_index_a is invalid: %f",
                        team_index_a);
        }
        if (!Team_IsValidIndex(team_index_b))
        {
-               LOG_FATALF("TeamBalance_CompareTeams: team_index_b is invalid: %f",
+               LOG_FATALF("team_index_b is invalid: %f",
                        team_index_b);
        }
        if (team_index_a == team_index_b)
@@ -864,12 +885,10 @@ 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;
@@ -881,16 +900,16 @@ 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;
                }
        }
        //PrintToChatAll(sprintf("Smallest team: %f", smallest_team_index));
@@ -949,16 +968,16 @@ int TeamBalance_GetLargestTeamIndex(entity balance, int teams)
                {
                        continue;
                }
-               int player_count = TeamBalanceTeam_GetNumberOfPlayers(team_);
+               int playercount = TeamBalanceTeam_GetNumberOfPlayers(team_);
                if (largest_team_index == 0)
                {
                        largest_team_index = i;
-                       largest_team_player_count = player_count;
+                       largest_team_player_count = playercount;
                }
-               else if (player_count > largest_team_player_count)
+               else if (playercount > largest_team_player_count)
                {
                        largest_team_index = i;
-                       largest_team_player_count = player_count;
+                       largest_team_player_count = playercount;
                }
        }
        return largest_team_index;
@@ -1013,7 +1032,7 @@ void LogTeamChange(float player_id, float team_number, int type)
        {
                return;
        }
-       GameLogEcho(sprintf(":team:%f:%f:%f", player_id, team_number, type));
+       GameLogEcho(sprintf(":team:%d:%d:%d", player_id, team_number, type));
 }
 
 void KillPlayerForTeamChange(entity player)
@@ -1051,7 +1070,7 @@ entity TeamBalance_GetTeamFromIndex(entity balance, int index)
 {
        if (!Team_IsValidIndex(index))
        {
-               LOG_FATALF("TeamBalance_GetTeamFromIndex: Index is invalid: %f", index);
+               LOG_FATALF("Index is invalid: %f", index);
        }
        return balance.m_team_balance_team[index - 1];
 }
@@ -1124,18 +1143,13 @@ void SV_ChangeTeam(entity player, int new_color)
        {
                SetPlayerColors(player, new_color);
        }
-       // TODO: Should we really bother with this?
        if(!IS_CLIENT(player))
        {
-               // 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 (!teamplay)
        {
                return;
        }
-       Player_SetTeamIndexChecked(player, Team_TeamToIndex((new_color & 0x0F) +
-               1));
+       Player_SetTeamIndexChecked(player, Team_TeamToIndex((new_color & 0x0F) + 1));
 }