]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Added autospec feature
authorz411 <z411@omaera.org>
Sun, 28 May 2023 09:28:24 +0000 (05:28 -0400)
committerz411 <z411@omaera.org>
Sun, 28 May 2023 09:28:24 +0000 (05:28 -0400)
qcsrc/common/notifications/all.inc
qcsrc/server/client.qc
qcsrc/server/teamplay.qc
qcsrc/server/teamplay.qh
xonotic-server.cfg

index cbcf5aa059e21b7b0a700ed1dffb7e193e88b5f6..eb9884485864397e62525bb2ce1acee8380c3871 100644 (file)
@@ -422,9 +422,11 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
     MSG_INFO_NOTIF(QUIT_DISCONNECT,                         N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 disconnected"), "")
     MSG_INFO_NOTIF(QUIT_KICK_IDLING,                        N_CHATCON,  1, 1, "s1 f1", "",      "",             _("^BG%s^F3 was kicked after idling for %s seconds"), "")
     MSG_INFO_NOTIF(MOVETOSPEC_IDLING,                       N_CHATCON,  1, 1, "s1 f1", "",      "",             _("^BG%s^F3 was moved to^BG spectators^F3 after idling for %s seconds"), "")
+       MSG_INFO_NOTIF(MOVETOSPEC_REMOVE,                       N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 was moved to^BG spectators^F3 for balance reasons"), "")
     MSG_INFO_NOTIF(QUIT_KICK_SPECTATING,                    N_CONSOLE,  0, 0, "", "",           "",             _("^F2You were kicked from the server because you are a spectator and spectators aren't allowed at the moment."), "")
     MSG_INFO_NOTIF(QUIT_KICK_TEAMKILL,                      N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 was kicked for excessive teamkilling"), "")
     MSG_INFO_NOTIF(QUIT_SPECTATE,                           N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 is now^BG spectating"), "")
+       MSG_INFO_NOTIF(QUIT_QUEUE,                              N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 has left the queue"), "")
 
     MSG_INFO_NOTIF(RACE_ABANDONED,                          N_CONSOLE,  1, 0, "s1", "",                                                                     "",                         _("^BG%s^BG has abandoned the race"), "")
     MSG_INFO_NOTIF(RACE_FAIL_RANKED,                        N_CONSOLE,  1, 3, "s1 race_col f1ord race_col f3race_time race_diff", "s1 f3race_time",         "race_newfail",             _("^BG%s^BG couldn't break their %s%s^BG place record of %s%s %s"), "")
index da1daaf0af1b222ca53634ed1ed77ccef1988e7f..5e4c5eaa320b66427a3f920065a39e68e19e12d5 100644 (file)
@@ -1118,7 +1118,7 @@ void ClientConnect(entity this)
                GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? GameLog_ProcessIP(this.netaddress) : "bot"), ":", playername(this.netname, this.team, false)));
 
        CS(this).just_joined = true;  // stop spamming the eventlog with additional lines when the client connects
-       this.wants_join = false;
+       this.wants_join = 0;
 
        stuffcmd(this, clientstuff, "\n");
        stuffcmd(this, "cl_particles_reloadeffects\n"); // TODO do we still need this?
@@ -1265,6 +1265,9 @@ void ClientDisconnect(entity this)
 
        if (player_count == 0)
                localcmd("\nsv_hook_lastleave\n");
+
+       if (teamplay && autocvar_g_balance_teams_remove)
+               TeamBalance_RemoveExcessPlayers(NULL);
 }
 
 void ChatBubbleThink(entity this)
@@ -2006,9 +2009,7 @@ void Join(entity this)
        else
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_PLAY, this.netname);
        this.team_selected = false;
-
-       if(queued_join)
-               this.wants_join = 0;
+       this.wants_join = 0;
 }
 
 int GetPlayerLimit()
index 4afe7d1e4df85504cdfe00fc788835857a7becd0..ba3277ad52888d9101d99492d3d1be5b1baa3ccc 100644 (file)
@@ -236,7 +236,7 @@ bool Player_SetTeamIndex(entity player, int index)
 
 bool IsQueueNeeded(entity ignore)
 {
-       return (teamplay && TeamBalance_AreEqual(ignore));
+       return (teamplay && autocvar_g_balance_teams_queue && TeamBalance_AreEqual(ignore));
 }
 
 entity SpectatorWantsJoin(entity this)
@@ -276,7 +276,7 @@ bool SetPlayerTeam(entity player, int team_index, int type)
                        if (IsQueueNeeded(player) && !SpectatorWantsJoin(player))
                        {
                                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(player.team, INFO_JOIN_WANTS_TEAM), player.netname);
-                               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_JOIN_PREVENT_QUEUE);
+                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_JOIN_PREVENT_QUEUE);
                                player.wants_join = team_index; // Player queued to join
                        }
                        else
@@ -292,14 +292,17 @@ bool SetPlayerTeam(entity player, int team_index, int type)
                        Kill_Notification(NOTIF_ONE_ONLY, player, MSG_CENTER, CPID_IDLING);
                        CS(player).idlekick_lasttimeleft = 0;
                }
-               else if (player.wants_join)
+               else if (player.wants_join > 0)
                {
+                       LOG_INFOF("Triggered by %s (%d)", player.netname, player.wants_join);
                        player.wants_join = 0;
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, player.netname);
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_QUEUE, player.netname);
                }
                else if (!CS(player).just_joined && player.frags != FRAGS_SPECTATOR)
                {
                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, player.netname);
+                       if(autocvar_g_balance_teams_remove)
+                               TeamBalance_RemoveExcessPlayers(player);
                }
        }
 
@@ -700,10 +703,10 @@ bool TeamBalance_AreEqual(entity ignore)
        int total;
        int prev_total = 0;
 
-       for(int i = 0; i < AVAILABLE_TEAMS; i++)
+       for(int i = 1; i <= AVAILABLE_TEAMS; i++)
        {
-               total = TeamBalance_GetTeamFromIndex(balance, i+1).m_num_players;
-               if(i > 0 && total != prev_total)
+               total = TeamBalance_GetTeamFromIndex(balance, i).m_num_players;
+               if(i > 1 && total != prev_total)
                {
                        TeamBalance_Destroy(balance);
                        return false;
@@ -714,6 +717,49 @@ bool TeamBalance_AreEqual(entity ignore)
        return true;
 }
 
+void TeamBalance_RemoveExcessPlayers(entity ignore)
+{
+       entity balance = TeamBalance_CheckAllowedTeams(ignore);
+       TeamBalance_GetTeamCounts(balance, ignore);
+
+       int min = 0;
+
+       for(int i = 1; i <= AVAILABLE_TEAMS; i++)
+       {
+               int cur = TeamBalance_GetTeamFromIndex(balance, i).m_num_players;
+               if(cur < min)
+                       min = cur;
+       }
+
+       for(int tmi = 1; tmi <= AVAILABLE_TEAMS; tmi++)
+       {
+               int cur = TeamBalance_GetTeamFromIndex(balance, tmi).m_num_players;
+               if(cur > 0 && cur > min)
+               {
+                       // Get newest player
+                       int latest_join = 0;
+                       entity latest_join_pl = NULL;
+
+                       FOREACH_CLIENT(IS_CLIENT(it) || INGAME(it), {
+                               if(it.team == Team_IndexToTeam(tmi) && CS(it).startplaytime > latest_join)
+                               {
+                                       latest_join = CS(it).startplaytime;
+                                       latest_join_pl = it;
+                               }
+                       });
+
+                       // Force player to spectate
+                       if(latest_join_pl)
+                       {
+                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MOVETOSPEC_REMOVE, latest_join_pl.netname);
+                               PutObserverInServer(latest_join_pl, true, true);
+                       }
+               }
+       }
+
+       TeamBalance_Destroy(balance);
+}
+
 bool TeamBalance_IsTeamAllowed(entity balance, int index)
 {
        if (balance == NULL)
index f50808ff436501815190e8bd8eb3d14f87fac2fb..08423dc082b21993e0207fab7dcb752ccebe97f4 100644 (file)
@@ -7,6 +7,8 @@ bool autocvar_teamplay_lockonrestart;
 
 bool autocvar_g_balance_teams;
 bool autocvar_g_balance_teams_prevent_imbalance;
+bool autocvar_g_balance_teams_queue;
+bool autocvar_g_balance_teams_remove;
 
 string autocvar_g_forced_team_otherwise;
 
@@ -187,6 +189,7 @@ void TeamBalance_Destroy(entity balance);
 int TeamBalance_GetAllowedTeams(entity balance);
 
 bool TeamBalance_AreEqual(entity ignore);
+void TeamBalance_RemoveExcessPlayers(entity ignore);
 
 /// \brief Returns whether the team change to the specified team is allowed.
 /// \param[in] balance Team balance entity.
index 03404ebf4555482d04ad7fe4047a7a248f02eb41..0cc7674dd64f2d0fd6f86e50c8b33bffc469909f 100644 (file)
@@ -277,6 +277,8 @@ set g_teamdamage_resetspeed 20      "for teamplay_mode 4: how fast player's team
 
 set g_balance_teams 1 "automatically balance out players entering instead of asking them for their preferred team"
 set g_balance_teams_prevent_imbalance 1 "prevent players from changing to larger teams"
+set g_balance_teams_queue 1 "queue players before joining"
+set g_balance_teams_remove 1 "remove excess players from teams"
 set g_changeteam_banned 0 "not allowed to change team"
 
 set sv_teamnagger 1 "enable a nag message when the teams are unbalanced"