There is a setting in the UT.ini "bNoTeamChanges" but it is tied too closely together with other stuff so it doesn't work exactly as one would think it does. There also is no fix for this in the auto balance currently. In fact, these are the comments the author of ATB made in the code:
// DONE: If engine has bNoTeamChanges set, then players can't switch in Player Options. In that case, we should also disable !red and !blue!
// Actually it's not true - There is a bug in UT's implementation of bNoTeamChanges which means it doesn't work!
For anyone interested that doesn't feel like looking it up here is the uscript from TeamGamePlus where you can see how the setting is used:
function bool ChangeTeam(Pawn Other, int NewTeam)
{
local int i, Smallest, DesiredTeam;
local pawn APlayer, P;
local teaminfo SmallestTeam;
if ( bRatedGame && (Other.PlayerReplicationInfo.Team != 255) )
return false;
if ( Other.IsA('Spectator') )
{
Other.PlayerReplicationInfo.Team = 255;
if (LocalLog != None)
LocalLog.LogTeamChange(Other);
if (WorldLog != None)
WorldLog.LogTeamChange(Other);
return true;
}
// find smallest team
Smallest = 0;
for( i=1; i<MaxTeams; i++ )
if ( Teams[Smallest].Size > Teams[i].Size )
Smallest = i;
if ( (NewTeam == 255) || (NewTeam >= MaxTeams) )
NewTeam = Smallest;
if ( bPlayersBalanceTeams && (Level.NetMode != NM_Standalone) )
{
if ( Teams[NewTeam].Size > Teams[Smallest].Size )
NewTeam = Smallest;
if ( NumBots == 1 )
{
// join bot's team if sizes are equal, because he will leave
for ( P=Level.PawnList; P!=None; P=P.NextPawn )
if ( P.IsA('Bot') )
break;
if ( (P != None) && (P.PlayerReplicationInfo != None) && (P.PlayerReplicationInfo.Team != 255)
&& (Teams[P.PlayerReplicationInfo.Team].Size == Teams[Smallest].Size) )
NewTeam = P.PlayerReplicationInfo.Team;
}
}
if ( (Other.PlayerReplicationInfo.Team == NewTeam) && bNoTeamChanges )
return false;
if ( Other.IsA('TournamentPlayer') )
TournamentPlayer(Other).StartSpot = None;
if ( Other.PlayerReplicationInfo.Team != 255 )
{
ClearOrders(Other);
Teams[Other.PlayerReplicationInfo.Team].Size--;
}
if ( Teams[NewTeam].Size < MaxTeamSize )
{
AddToTeam(NewTeam, Other);
return true;
}
if ( Other.PlayerReplicationInfo.Team == 255 )
{
AddToTeam(Smallest, Other);
return true;
}
return false;
}
So, it works depending on whether the player is switching to the smallest (or red team if they are equal in size) and whether bPlayersBalanceTeams is set or not (ignoring another alternate path if there is only 1 bot in the game) π
But not to worry, a workaround for this is one of my top priorities. This has been a problem for way too long.