Monthly Target: $400 Donations: $221
 55% 

Blocking a team change in TF2


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
x6herbius
Senior Member
Join Date: May 2011
Location: West Sussex, UK
Old 04-16-2012 , 13:50   Blocking a team change in TF2
Reply With Quote #1

For the game mode I'm testing I'm attempting to restrict players changing teams in TF2. I've tried adding a command listener on "changeteam" but the command doesn't seem to be picked up. I've also tried hooking into the team change event, which has been a little more successful, but using ChangeClientTeam while in this event, even though it fires an event of its own, doesn't seem to actually change the team of the player.

As a demonstration, this is my player_team event hook:

PHP Code:
/*    Called when a player changes team.    */
public Event_TeamsChange(Handle:event, const String:name[], bool:dontBroadcast)
{
    if ( (
g_PluginState STATE_DISABLED == STATE_DISABLED) ||
            (
g_PluginState STATE_NOT_IN_ROUND == STATE_NOT_IN_ROUND) ) return;
    
    
// I've never liked team change hooks.
    
    // If the plugin is disabled or we're not in a round, ignore team changes.
    // If there are not enough players to begin a game, allow team changes but monitor team counts.
    // When the team counts go over the required threshold, end the round.
    
    // If instead all is clear, we first need to check the team the player is changing from.
    // If they're changing from a team which is not Red or Blue, force them to join Red.
    // If they are changing from Red or Blue, do the following:
        // If from Red, check target team. If team is blue, ensure they are marked as a zombie. If not blue, allow change.
        // If from Blue, check tartget team. If team is Red, ensure they are not marked as a zombie. If not Red, allow change.
    
    // After team change is complete, check team numbers. If either Red or Blue has <1 player, declare a win.
    // This means that players can leave Red or Blue to go spec or leave the game, at the expense of their team.
    
    // Using GetTeamClientCount in this hook reports the number of clients as it was BEFORE the change, even with HookMode_Post.
    // To get around this we need to build up what the teams will look like after the change.
    
    
new userid GetEventInt(event"userid");
    new 
client GetClientOfUserId(userid);
    new 
newTeam GetEventInt(event"team");
    new 
oldTeam GetEventInt(event"oldteam");
    new 
bool:disconnect GetEventBool(event"disconnect");
    
    new 
redTeam GetTeamClientCount(TEAM_RED);        // These will give us the team counts BEFORE the client has switched.
    
new blueTeam GetTeamClientCount(TEAM_BLUE);
    
    new 
cvDebug GetConVarInt(cv_Debug);
    
    if ( 
disconnect )             // If the team change happened because the client was disconnecting:
    
{
        if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Client %N is disconnecting."client);
        
                                
// Note that, if disconnect == true, the userid will point to the index 0.
                                // We fix this here.
        
client g_Disconnect;    // This is retrieved from player_disconnect, which is fired before player_team.
        
g_Disconnect 0;
        
                                
// If disconnected, this means the team he was on will lose a player and the other teams will stay the same.
        
switch (oldTeam)
        {
            case 
TEAM_RED:
            {
                if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Client %N is leaving team Red."client);
                
redTeam--;
            }
            
            case 
TEAM_BLUE:
            {
                if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Client %N is leaving team Blue."client);
                
blueTeam--;
            }
        }
    }
    else                        
// The client is not disconnecting.
    
{
        if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Client %N is not disconnecting."client);
        
                                
// Decrease the count for the team the client is leaving.
        
switch (oldTeam)
        {
            case 
TEAM_RED:
            {
                if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Client %N is leaving team Red."client);
                
redTeam--;
            }
            
            case 
TEAM_BLUE:
            {
                if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Client %N is leaving team Blue."client);
                
blueTeam--;
            }
        }
        
                                
// Increase the count for the team the client is joining.
        
switch (newTeam)
        {
            case 
TEAM_RED:
            {
                if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Client %N is joining team Red."client);
                
redTeam++;
            }
            
            case 
TEAM_BLUE:
            {
                if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Client %N is joining team Blue."client);
                
blueTeam++;
            }
        }
    }
    
    
// Team counts after the change are now held in redTeam and blueTeam.
    
new total redTeam blueTeam;
    
    
// If there were not enough players but we have just broken the threshold, end the round in a stalemate.
    
if ( g_PluginState STATE_FEW_PLAYERS == STATE_FEW_PLAYERS )
    {
        if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player count was below the threshold.");
        
        if ( 
total )
        {
            if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player count is now above the threshold!");
            
            
g_PluginState &= ~STATE_FEW_PLAYERS;    // Clear the FEW_PLAYERS flag.
            
RoundWinWithCleanup();
            
            return;
        }
        else
        {
            if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player count is still below the threshold.");
            
            return;
        }
    }
    
// If there were enough players but now there are not, win the round for the team which has the remaining player.
    
else if ( (g_PluginState STATE_FEW_PLAYERS != STATE_FEW_PLAYERS) && total <= )
    {
        if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player count is now below the threshold.");
        
        if        ( 
redTeam )        RoundWinWithCleanup(TEAM_RED);
        else if    ( 
blueTeam )    RoundWinWithCleanup(TEAM_BLUE);
        else                        
RoundWinWithCleanup();
        
        return;
    }
    
    if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player count is still above the threshold.");
    
    
// There are enough players to continue the game.
    // If a player is joining the game (ie. their old team is not Red or Blue), force them to join Red.
    
if ( oldTeam != TEAM_RED && oldTeam != TEAM_BLUE )
    {
        if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player %N joining from outside Red/Blue teams."client);
        
        if ( 
newTeam == TEAM_BLUE )
        {
            if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Blocking player %N from joining Blue."client);
            
            
ChangeClientTeam(clientTEAM_RED);
            return;
        }
        else
        {
            if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player %N not joining team Blue, ignoring."client);
            return;
        }
    }
    else if ( 
oldTeam == TEAM_RED )    // If Red->Blue, check whether the client is a zombie.
    
{
        if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player %N leaving team Red."client);
        
        if ( 
newTeam == TEAM_BLUE )
        {
            if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player %N joining team Blue."client);
            
            new 
dataIndex DataIndexForUserId(userid);
            if ( 
dataIndex == -)
            {
                if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player %N data index is -1, returning."client);
                return;
            }
            
            if ( !
g_Zombie[dataIndex] )    // If they are not a zombie, prohibit the change. #NOTE#: A better way to do this would be to block the command itself.
            
{
                if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Blocking non-zombie player %N from joining Blue."client);
                
                
ChangeClientTeam(clientTEAM_RED);
            }
        }
    }
    else if ( 
oldTeam == TEAM_BLUE )    // If Blue->Red, check whether the client is a zombie.
    
{
        if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player %N leaving team Blue."client);
        
        if ( 
newTeam == TEAM_RED )
        {
            if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player %N joining team Red."client);
            
            new 
dataIndex DataIndexForUserId(userid);
            if ( 
dataIndex == -)
            {
                if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Player %N data index is -1, returning."client);
                return;
            }
            
            if ( 
g_Zombie[dataIndex] )    // If they are a zombie, prohibit the change.
            
{
                if ( 
cvDebug DEBUG_TEAMCHANGE == DEBUG_TEAMCHANGE LogMessage("Blocking zombie player %N from joining Red."client);
                
                
ChangeClientTeam(clientTEAM_BLUE);
            }
        }
    }

And these are the log messages I get in the server console when I try and change from Red to Blue when there are 2 other players (bots) on the server (my switch to Blue should be blocked in this case):

L 04/16/2012 - 185:22: [TFBiohazard.smx] Client [X6] Herbius the Fuzzbutt is not disconnecting.
L 04/16/2012 - 185:22: [TFBiohazard.smx] Client [X6] Herbius the Fuzzbutt is leaving team Red.
L 04/16/2012 - 185:22: [TFBiohazard.smx] Client [X6] Herbius the Fuzzbutt is joining team Blue.
L 04/16/2012 - 185:22: [TFBiohazard.smx] Player count is still above the threshold.
L 04/16/2012 - 185:22: [TFBiohazard.smx] Player [X6] Herbius the Fuzzbutt leaving team Red.
L 04/16/2012 - 185:22: [TFBiohazard.smx] Player [X6] Herbius the Fuzzbutt joining team Blue.
L 04/16/2012 - 185:22: [TFBiohazard.smx] Blocking non-zombie player [X6] Herbius the Fuzzbutt from joining Blue.


Even though the plugin says it's blocking the change to Blue I still end up on the Blue team regardless, and I'm struggling to think of a better way to accomplish this. I also find it odd that GetTeamClientCount returns the number of clients on a team before the change, which might have something to do with the later team change not working (maybe this event is fired before the original "changeteam" command has gone through?).

Is there any way around this?
x6herbius is offline
Send a message via Skype™ to x6herbius
napalm00
Veteran Member
Join Date: Jun 2011
Location: Italy, sadly
Old 04-16-2012 , 14:47   Re: Blocking a team change in TF2
Reply With Quote #2

You have to either:
1)Hook "jointeam" and block team joining completely
2)Respawn the player (TF2_RespawnPlayer(client);) after you changed their team
__________________
napalm00 is offline
x6herbius
Senior Member
Join Date: May 2011
Location: West Sussex, UK
Old 04-16-2012 , 16:38   Re: Blocking a team change in TF2
Reply With Quote #3

I've just tried the "jointeam" hook and while that does register as a command this time, using GetClientTeam from the command listener always returns the player's team as invalid, meaning I have no way of telling what team-restricting conditions I should be applying to them. The teams_change event happens after the command listener, so I can't get the team from there either. The RespawnPlayer method did nothing.
x6herbius is offline
Send a message via Skype™ to x6herbius
asherkin
Fennec Fox
Join Date: Aug 2009
Location: OnGameFrame()
Old 04-16-2012 , 16:54   Re: Blocking a team change in TF2
Reply With Quote #4

Quote:
Originally Posted by x6herbius View Post
I've just tried the "jointeam" hook and while that does register as a command this time, using GetClientTeam from the command listener always returns the player's team as invalid, meaning I have no way of telling what team-restricting conditions I should be applying to them.
Get the arguments of the command.
__________________
asherkin is online now
x6herbius
Senior Member
Join Date: May 2011
Location: West Sussex, UK
Old 04-16-2012 , 17:39   Re: Blocking a team change in TF2
Reply With Quote #5

Quote:
Originally Posted by asherkin View Post
Get the arguments of the command.
As far as I tested, the only arguments that came with the command were the team the player was switching to, not the one they were currently on.
x6herbius is offline
Send a message via Skype™ to x6herbius
napalm00
Veteran Member
Join Date: Jun 2011
Location: Italy, sadly
Old 04-17-2012 , 00:31   Re: Blocking a team change in TF2
Reply With Quote #6

Try with
PHP Code:
SetEntProp(clientProp_Send"m_lifeState"2);
ChangeClientTeam(clientteam);
SetEntProp(clientProp_Send"m_lifeState"0);
TF2_RespawnPlayer(client); 
in the player_team event.
__________________

Last edited by napalm00; 04-17-2012 at 00:42.
napalm00 is offline
x6herbius
Senior Member
Join Date: May 2011
Location: West Sussex, UK
Old 04-17-2012 , 02:30   Re: Blocking a team change in TF2
Reply With Quote #7

Quote:
Originally Posted by napalm00 View Post
Try with
PHP Code:
SetEntProp(clientProp_Send"m_lifeState"2);
ChangeClientTeam(clientteam);
SetEntProp(clientProp_Send"m_lifeState"0);
TF2_RespawnPlayer(client); 
in the player_team event.
Nope, still nothing.
x6herbius is offline
Send a message via Skype™ to x6herbius
napalm00
Veteran Member
Join Date: Jun 2011
Location: Italy, sadly
Old 04-17-2012 , 08:14   Re: Blocking a team change in TF2
Reply With Quote #8

I am not completely sure about this, but try delaying the above code by using a timer. A time of 100msecs (0.1 seconds) should be enough.
__________________
napalm00 is offline
x6herbius
Senior Member
Join Date: May 2011
Location: West Sussex, UK
Old 04-17-2012 , 08:49   Re: Blocking a team change in TF2
Reply With Quote #9

Quote:
Originally Posted by napalm00 View Post
I am not completely sure about this, but try delaying the above code by using a timer. A time of 100msecs (0.1 seconds) should be enough.
I had wondered about that, but I was keen on achieving everything with as little asynchronism as possible because there's potential for miscalculations to be made on the player numbers within that 0.1 second period.

As it happens, it looks as though the "jointeam" listener may be enough, as I'm saving some data about players in global variables and I think I can check them in the listener instead of the client's team. Thanks for all the help.
x6herbius is offline
Send a message via Skype™ to x6herbius
napalm00
Veteran Member
Join Date: Jun 2011
Location: Italy, sadly
Old 04-17-2012 , 09:36   Re: Blocking a team change in TF2
Reply With Quote #10

I believe even doing it one frame after the event happened still works, glad I somewhat helped with my fail advice though
__________________
napalm00 is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 15:20.


Powered by vBulletin®
Copyright ©2000 - 2015, vBulletin Solutions, Inc.
Theme made by Freecode