AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Scripting (https://forums.alliedmods.net/forumdisplay.php?f=107)
-   -   Blocking a team change in TF2 (https://forums.alliedmods.net/showthread.php?t=183055)

x6herbius 04-16-2012 13:50

Blocking a team change in TF2
 
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 - 18:35:22: [TFBiohazard.smx] Client [X6] Herbius the Fuzzbutt is not disconnecting.
L 04/16/2012 - 18:35:22: [TFBiohazard.smx] Client [X6] Herbius the Fuzzbutt is leaving team Red.
L 04/16/2012 - 18:35:22: [TFBiohazard.smx] Client [X6] Herbius the Fuzzbutt is joining team Blue.
L 04/16/2012 - 18:35:22: [TFBiohazard.smx] Player count is still above the threshold.
L 04/16/2012 - 18:35:22: [TFBiohazard.smx] Player [X6] Herbius the Fuzzbutt leaving team Red.
L 04/16/2012 - 18:35:22: [TFBiohazard.smx] Player [X6] Herbius the Fuzzbutt joining team Blue.
L 04/16/2012 - 18:35: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?

napalm00 04-16-2012 14:47

Re: Blocking a team change in TF2
 
You have to either:
1)Hook "jointeam" and block team joining completely
2)Respawn the player (TF2_RespawnPlayer(client);) after you changed their team

x6herbius 04-16-2012 16:38

Re: Blocking a team change in TF2
 
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.

asherkin 04-16-2012 16:54

Re: Blocking a team change in TF2
 
Quote:

Originally Posted by x6herbius (Post 1690647)
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.

x6herbius 04-16-2012 17:39

Re: Blocking a team change in TF2
 
Quote:

Originally Posted by asherkin (Post 1690655)
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.

napalm00 04-17-2012 00:31

Re: Blocking a team change in TF2
 
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.

x6herbius 04-17-2012 02:30

Re: Blocking a team change in TF2
 
Quote:

Originally Posted by napalm00 (Post 1690856)
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.

napalm00 04-17-2012 08:14

Re: Blocking a team change in TF2
 
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.

x6herbius 04-17-2012 08:49

Re: Blocking a team change in TF2
 
Quote:

Originally Posted by napalm00 (Post 1690943)
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.

napalm00 04-17-2012 09:36

Re: Blocking a team change in TF2
 
I believe even doing it one frame after the event happened still works, glad I somewhat helped with my fail advice though :D


All times are GMT -4. The time now is 13:28.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.