#include < amxmodx >
#include < amxmisc >
#include < engine >
#include < cstrike >
#include < hamsandwich >
#define OppositeTeam(%1) CsTeams:( ( ( _:%1 ) % 2 ) + 1 )
/*CsTeams:OppositeTeam( CsTeams:iTeam )
{
return CsTeams:( ( ( _:iTeam ) % 2 ) + 1 );
}*/
#define MAX_PLAYERS 32
new const g_szSpawnClassnames[ CsTeams ][ ] =
{
"",
"info_player_deathmatch",
"info_player_start",
""
};
new const g_szFakeSpawnClassnames[ CsTeams ][ ] =
{
"",
"removed_t_spawn",
"removed_ct_spawn",
""
};
enum _:RemoveMethods
{
Remove_Kick,
Remove_Spec,
Remove_Transfer
};
const g_iDefaultMethod = Remove_Spec;
new const g_szRemoveMethods[ RemoveMethods ][ ] =
{
"kick",
"spec",
"transfer"
};
new Trie:g_tMethodNameToIndex;
new Float:g_fJoinTime[ MAX_PLAYERS + 1 ];
new pCvar_RemoveMethod;
new bool:g_bFreezeTime = false;
public plugin_init( )
{
register_plugin( "Team Limiter", "0.0.3", "Exolent" );
register_concmd( "team_limits", "CmdSetTeamLimits", ADMIN_RCON, "<terrorist limit> <ct limit> -- * for map default" );
register_event( "HLTV", "EventNewRound", "a", "1=0", "2=0" );
register_logevent( "EventRoundStart", 2, "1=Round_Start" );
pCvar_RemoveMethod = register_cvar( "tl_remove", g_szRemoveMethods[ g_iDefaultMethod ] );
g_tMethodNameToIndex = TrieCreate( );
for( new iMethod = 0; iMethod < RemoveMethods; iMethod++ )
{
TrieSetCell( g_tMethodNameToIndex, g_szRemoveMethods[ iMethod ], iMethod );
}
}
public plugin_end( )
{
TrieDestroy( g_tMethodNameToIndex );
}
public client_putinserver( iPlayer )
{
g_fJoinTime[ iPlayer ] = get_gametime( );
}
public CmdSetTeamLimits( iAdmin, iLevel, iCID )
{
if( !cmd_access( iAdmin, iLevel, iCID, 3 ) )
{
return PLUGIN_HANDLED;
}
new szT[ 3 ], szCT[ 3 ];
read_argv( 1, szT, charsmax( szT ) );
read_argv( 2, szCT, charsmax( szCT ) );
new iNewLimit[ CsTeams ];
iNewLimit[ CS_TEAM_T ] = is_str_num( szT ) ? str_to_num( szT ) : -1;
iNewLimit[ CS_TEAM_CT ] = is_str_num( szCT ) ? str_to_num( szCT ) : -1;
if( iNewLimit[ CS_TEAM_T ] < 0 && iNewLimit[ CS_TEAM_CT ] < 0 )
{
console_print( iAdmin, "Setting both limits to < 0 doesn't change the team limit of either team." );
return PLUGIN_HANDLED;
}
new iRemoveMethod = GetRemoveMethod( );
new iAllPlayers[ MAX_PLAYERS ], iAllNum;
get_players( iAllPlayers, iAllNum );
new iPlayers[ CsTeams ][ MAX_PLAYERS ], iNum[ CsTeams ];
new iPlayer, CsTeams:iTeam;
for( new i = 0; i < iAllNum; i++ )
{
iPlayer = iAllPlayers[ i ];
iTeam = cs_get_user_team( iPlayer );
iPlayers[ iTeam ][ iNum[ iTeam ]++ ] = iPlayer;
}
new iTransferPlayers[ CsTeams ][ MAX_PLAYERS ], iTransferNum[ CsTeams ];
new bool:bSame = true;
new iCurLimit;
new iFakeCount;
new iDiff;
new iEntity;
for( new CsTeams:iTeam = CS_TEAM_T; iTeam <= CS_TEAM_CT; iTeam++ )
{
iCurLimit = 0;
iEntity = 0;
while( ( iEntity = find_ent_by_class( iEntity, g_szSpawnClassnames[ iTeam ] ) ) )
{
iCurLimit++;
}
if( iNewLimit[ iTeam ] < 0 )
{
// there is no limit, so check if fake ones exist so the maximum spawns are available
iFakeCount = 0;
iEntity = 0;
while( ( iEntity = find_ent_by_class( iEntity, g_szFakeSpawnClassnames[ iTeam ] ) ) )
{
iFakeCount++;
}
// set to real spawns + fake spawns (even if no fake ones exist, it will still skip)
iNewLimit[ iTeam ] = iCurLimit + iFakeCount;
}
iDiff = iCurLimit - iNewLimit[ iTeam ];
if( !iDiff )
{
continue;
}
bSame = false;
if( iDiff > 0 )
{
// current > new = deleting
iCurLimit = iDiff;
while( iDiff > 0 )
{
iEntity = find_ent_by_class( -1, g_szSpawnClassnames[ iTeam ] );
if( !is_valid_ent( iEntity ) )
{
iNewLimit[ iTeam ] += iDiff;
console_print( iAdmin, "There were not enough %sT spawn points to remove. Only removed %i of %i.",\
iTeam == CS_TEAM_T ? "" : "C", ( iCurLimit - iDiff ), iCurLimit );
break;
}
entity_set_string( iEntity, EV_SZ_classname, g_szFakeSpawnClassnames[ iTeam ] );
iDiff--;
}
iDiff = iNum[ iTeam ] - iNewLimit[ iTeam ];
if( iDiff > 0 )
{
// more players than spawn points
if( iNum[ iTeam ] > 1 )
{
// sort from earliest joining to latest
SortCustom1D( iPlayers[ iTeam ], iNum[ iTeam ], "SortByJoinTime" );
}
// last players in array are the last players who joined
while( iDiff > 0 )
{
iPlayer = iPlayers[ iTeam ][ iNum[ iTeam ] - iDiff ];
switch( iRemoveMethod )
{
case Remove_Kick:
{
message_begin( MSG_ONE, SVC_DISCONNECT, _, iPlayer );
write_string( "Sorry, your spawn point was removed." );
message_end( );
}
case Remove_Spec:
{
TransferPlayer( iPlayer, CS_TEAM_SPECTATOR );
}
case Remove_Transfer:
{
iTransferPlayers[ iTeam ][ iTransferNum[ iTeam ]++ ] = iPlayer;
}
}
iDiff--;
}
}
}
else
{
// current < new = adding
iDiff *= -1;
iCurLimit = iDiff;
while( iDiff > 0 )
{
iEntity = find_ent_by_class( -1, g_szFakeSpawnClassnames[ iTeam ] );
if( !is_valid_ent( iEntity ) )
{
iNewLimit[ iTeam ] -= iDiff;
console_print( iAdmin, "There were not enough %sT spawn points to restore. Only restored %i of %i.",\
iTeam == CS_TEAM_T ? "" : "C", ( iCurLimit - iDiff ), iCurLimit );
break;
}
entity_set_string( iEntity, EV_SZ_classname, g_szSpawnClassnames[ iTeam ] );
iDiff--;
}
}
}
if( bSame )
{
console_print( iAdmin, "The teams are already limited to this amount." );
}
else
{
if( iRemoveMethod == Remove_Transfer )
{
// find how many both need to transfer so they don't just trade places
new iSame = min( iTransferNum[ CS_TEAM_T ], iTransferNum[ CS_TEAM_CT ] );
new i;
new CsTeams:iOppositeTeam;
new iAvailable;
for( new CsTeams:iTeam = CS_TEAM_T; iTeam <= CS_TEAM_CT; iTeam++ )
{
SortCustom1D( iTransferPlayers[ iTeam ], iTransferNum[ iTeam ], "SortByJoinTime" );
// transfer last joined players who can't fit on a team to spectator
for( i = 0; i < iSame; i++ )
{
TransferPlayer( iTransferPlayers[ iTeam ][ iTransferNum[ iTeam ] - i - 1 ], CS_TEAM_SPECTATOR );
}
// find how many players need to be transferred
iDiff = iTransferNum[ iTeam ] - iSame;
// get opposite team to transfer to
iOppositeTeam = OppositeTeam( iTeam );
// find how many slots are available for players
iAvailable = iNewLimit[ iOppositeTeam ] - iNum[ iOppositeTeam ];
// available < needed = move extra players to spectator
while( i < iTransferNum[ iTeam ] )
{
TransferPlayer( iTransferPlayers[ iTeam ][ iTransferNum[ iTeam ] - i - 1 ], ( iAvailable < iDiff ) ? CS_TEAM_SPECTATOR : iOppositeTeam );
iDiff--;
i++;
}
}
}
console_print( iAdmin, "The teams have been limited to T:%i, CT:%i", iNewLimit[ CS_TEAM_T ], iNewLimit[ CS_TEAM_CT ] );
new szName[ 32 ];
get_user_name( iAdmin, szName, charsmax( szName ) );
new szSteamID[ 35 ];
get_user_authid( iAdmin, szSteamID, charsmax( szSteamID ) );
show_activity( iAdmin, szName, "limited the teams to T:%i, CT:%i", iNewLimit[ CS_TEAM_T ], iNewLimit[ CS_TEAM_CT ] );
log_amx( "%s<%s> limited the teams to T:%i, CT:%i", szName, szSteamID, iNewLimit[ CS_TEAM_T ], iNewLimit[ CS_TEAM_CT ] );
}
return PLUGIN_HANDLED;
}
public EventNewRound( )
{
g_bFreezeTime = true;
}
public EventRoundStart( )
{
g_bFreezeTime = false;
}
public SortByJoinTime( iIndex1, iIndex2, iPlayers[ ], iData[ ], iDataSize )
{
return ( ( g_fJoinTime[ iPlayers[ iIndex1 ] ] - g_fJoinTime[ iPlayers[ iIndex2 ] ] ) < 0.0 ) ? -1 : 1;
}
GetRemoveMethod( )
{
new szMethod[ 32 ];
get_pcvar_string( pCvar_RemoveMethod, szMethod, charsmax( szMethod ) );
strtolower( szMethod );
new iMethod;
if( TrieGetCell( g_tMethodNameToIndex, szMethod, iMethod ) )
{
return iMethod;
}
if( is_str_num( szMethod ) )
{
iMethod = str_to_num( szMethod );
if( 0 <= iMethod < RemoveMethods )
{
return iMethod;
}
}
static szInvalidMessage[ 128 ];
new iLen = formatex( szInvalidMessage, charsmax( szInvalidMessage ), "Invalid remove method '%s'. Valid Methods: [", szMethod );
for( iMethod = 0; iMethod < RemoveMethods; iMethod++ )
{
iLen += formatex( szInvalidMessage[ iLen ], charsmax( szInvalidMessage ) - iLen, "'%s', ", g_szRemoveMethods[ iMethod ] );
}
// remove the last ", " from the end
iLen -= 2;
copy( szInvalidMessage[ iLen ], charsmax( szInvalidMessage ) - iLen, "]" );
log_amx( "%s", szInvalidMessage );
set_pcvar_string( pCvar_RemoveMethod, g_szRemoveMethods[ g_iDefaultMethod ] );
return g_iDefaultMethod;
}
TransferPlayer( iPlayer, CsTeams:iTeam )
{
static const szTeamNames[ CsTeams ][ ] =
{
"Spectator",
"Terrorist",
"Counter-Terrorist",
"Spectator"
};
client_print( iPlayer, print_chat, "* Sorry, your spawn point was removed, so you are now a %s.", szTeamNames[ iTeam ] );
cs_set_user_team( iPlayer, iTeam );
if( is_user_alive( iPlayer ) )
{
// if switched teams during freezetime, revive player
if( ( CS_TEAM_T <= iTeam <= CS_TEAM_CT ) && g_bFreezeTime )
{
ExecuteHamB( Ham_CS_RoundRespawn, iPlayer );
}
else
{
user_silentkill( iPlayer );
}
}
}
/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1033\\ f0\\ fs16 \n\\ par }
*/