Kod:
#include <amxmodx>
#include <amxmisc>
#pragma semicolon 1
#pragma ctrlchar '\'
// Change this if you want to change the hardcoded ADMIN_LEVEL required for vc_ad_now.
const ADMIN_LEVEL = ADMIN_CFG;
// Below are the constants that will enable you to add new voicetools to the plugin.
// Add new voicetools here
enum VoiceTools
{ // vc_tool
Teamspeak2, // 0
Ventrilo, // 1
Mumble, // 2
Teamspeak3, // 3
RaidCall, // 4
};
// If you need more say commands you have to increase this number
const MAX_CMDS = 3;
/* This will hold the possible commands for the different Voicetools.
If one has less commands than the other you need to add an empty string for every missing to the other tool. -> ""
For new tools simply add your commands according to the syntax below (don't forget the new comma)
*/
new const SayCmd[ VoiceTools ][ MAX_CMDS ][ ] =
{
{ // Teamspeak 2
"ts2", "teamspeak", "teamspeak2"
},
{ // Ventrilo
"vent", "ventrilo", ""
},
{ // Mumble
"mumble", "murmur", ""
},
{ // Teamspeak 3
"ts3", "teamspeak", "teamspeak3"
},
{ // RaidCall
"raidcall", "rcall", ""
}
};
/* Instead of a precompiled syntax and a lot of ugly on-demand replacing the connect link will now
be built on-the-fly. The following enum marks the available options that can go into a link.
The BuildSequence array will define in what order the options will be put into the link when it
is built for the player.
The LinkBuild array specifies how each part of the link looks like for a specific voice plugin.
*/
enum _:LINK_OPTIONS
{
INVALID,
PROTOCOL,
SEPARATOR,
S_IP,
S_ID,
S_PORT,
S_NAME,
S_PW,
S_VERSION,
CHAN,
CHAN_PW,
PLAYER_NAME,
};
new const BuildSequence[ VoiceTools ][ LINK_OPTIONS ] =
{
{ // TS2
PROTOCOL, S_IP, S_PORT, SEPARATOR, CHAN, CHAN_PW, S_PW, PLAYER_NAME
},
{ // Ventrilo
PROTOCOL, S_IP, S_PORT, SEPARATOR, S_NAME, CHAN, CHAN_PW, S_PW
},
{ // Mumble
PROTOCOL, PLAYER_NAME, S_PW, S_IP, S_PORT, CHAN, SEPARATOR, S_VERSION, S_NAME
},
{ // TS3
PROTOCOL, S_IP, SEPARATOR, S_PORT, CHAN, CHAN_PW, S_PW, PLAYER_NAME
},
{ // RaidCall
PROTOCOL, SEPARATOR, S_ID
}
};
new const LinkBuild[ VoiceTools ][ LINK_OPTIONS ][ ] =
{
{ // TS2
"", "teamspeak://", "/", "%s", "", ":%s", "", "?password=%s", "", "?channel=%s", "?channelpassword=%s", "?nickname=%s"
},
{ // Ventrilo
"", "ventrilo://", "/", "%s", "", ":%s", "servername=%s&", "serverpassword=%s&", "", "channelname=%s&", "channelpassword=%s&", ""
},
{ // Mumble
"", "mumble://", "?", "@%s", "", ":%s", "title=%s&", ":%s", "version=%s&", "/%s", "", "%s"
},
{ // TS3
"", "ts3server://", "?", "%s", "", "port=%s&", "", "password=%s&", "", "channel=%s&", "channelpassword=%s&", "nickname=%s&"
},
{ // RaidCall
"", "raidcall://enterServer/", "?", "", "sid=%s", "", "", "", "", "", "", ""
}
};
// Simply add the name of the tools here, this is what will be displayed to users.
new const ToolName[ VoiceTools ][ ] =
{
"TeamSpeak 2",
"Ventrilo",
"Mumble",
"TeamSpeak 3",
"RaidCall"
};
//-------------------------------------------------------------------------------------------------------------
// Do not change anything below this line if you don't know exactly what you are doing!
//-------------------------------------------------------------------------------------------------------------
new const PLUGIN[] = "Voiceserver Connect";
new const VERSION[] = "1.1.015";
new const AUTHOR[] = "Nextra";
new p_Options[LINK_OPTIONS][4];
const TASK_AD = 89675;
new p_Enabled, p_VoiceTool, p_fwSlash, p_TeamEnabled,
p_AdEnabled, p_AdFreq, p_AdColor, p_BannedChars;
new g_iMaxPlayers, bool:g_iBannedNames, Trie:g_trieBanned;
enum MOD
{
INVALID,
CSTRIKE,
CZERO,
DOD
};
new const g_szMods[MOD][ ] =
{
"",
"cstrike",
"czero",
"dod"
};
new MOD:g_Mod;
new const HTML[ ] =
"<!DOCTYPE html PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\
<html><head>\
<meta http-equiv='content-type' content='text/html;charset=UTF-8'>\
<meta http-equiv='refresh' content=\"2; url=%s\">\
<title>%s</title>\
<style type='text/css'>\
body{background-color:#000000;color:#FFB000;}\
table{border:0px;width:100%%;height:100%%;}\
td{text-align:center;vertical-align:middle;}\
p{font-family:Verdana,Tahoma;font-size:20px;}\
</style></head><body>\
<table><tr><td>\
<p>%L</p>\
</td></tr></table>\
</body></html>";
// COLORCHAT.sma
enum Color
{
RED = 1, // Red
BLUE, // Blue
GREY, // Grey
YELLOW, // Yellow
GREEN, // Green
TEAM_COLOR, // Red, Grey, Blue
};
new g_msgid_TeamInfo, g_msgid_SayText;
new bool:IsConnected[33];
new const TeamName[ ][ ] =
{
"",
"TERRORIST",
"CT",
"SPECTATOR"
};
//-------------------------------------------
public plugin_init( )
{
register_plugin( PLUGIN, VERSION, AUTHOR );
register_cvar( "vc_version", VERSION, FCVAR_SERVER|FCVAR_SPONLY );
g_Mod = get_mod( );
if( g_Mod == INVALID )
set_fail_state( "[VC] This mod is not supported as it lacks essential features required for this plugin." );
register_dictionary( "voiceserver_connect.txt" );
register_clcmd( "say" , "clcmd_say", -1 );
register_clcmd( "say_team" , "clcmd_say", -1 );
register_clcmd( "voice_ad_now", "cmd_ad", ADMIN_LEVEL, "Display ads instantly." );
p_Enabled = register_cvar( "vc_enabled" , "1" ),
p_VoiceTool = register_cvar( "vc_tool" , "" ),
p_TeamEnabled = register_cvar( "vc_teamenabled" , "0" );
new szOptionName[LINK_OPTIONS][] =
{
"", "", "",
"serverip", "serverid", "serverport", "servername", "serverpw", "serverversion",
"channel", "channelpw",
""
};
new szTeamName[3][] =
{
"default", "team1", "team2"
};
new szVar[32];
for( new i = S_IP; i < PLAYER_NAME; ++i )
{
for( new iTeam = 0; iTeam <= 2; ++iTeam )
{
formatex( szVar, charsmax(szVar), "vc_%s_%s", szTeamName[iTeam], szOptionName[i] );
p_Options[i][iTeam] = register_cvar( szVar, "" );
}
p_Options[i][3] = p_Options[i][0];
}
p_BannedChars = register_cvar( "vc_bannedchars" , "" ),
p_fwSlash = register_cvar( "vc_fwslash" , "0" ),
p_AdEnabled = register_cvar( "vc_ads" , "1" ),
p_AdFreq = register_cvar( "vc_adfreq" , "120.0" );
if( g_Mod == CSTRIKE || g_Mod == CZERO )
{
p_AdColor = register_cvar( "vc_adcolor", "1" );
g_msgid_TeamInfo = get_user_msgid( "TeamInfo" ),
g_msgid_SayText = get_user_msgid( "SayText" );
}
g_iMaxPlayers = get_maxplayers( );
new szFile[256];
get_configsdir( szFile, charsmax(szFile) );
add( szFile, charsmax(szFile), "/voice_blacklist.txt" );
if( file_exists( szFile ) )
{
new szTmp[64], iErrors;
enum
{
FILE,
TRIE,
ERRORS
};
g_trieBanned = TrieCreate( );
new hFile = fopen( szFile, "rt" );
if( g_trieBanned == Invalid_Trie )
iErrors += (1<<TRIE);
if( !hFile )
iErrors += (1<<FILE);
if( !iErrors )
{
while( !feof( hFile ) )
{
fgets( hFile, szTmp, charsmax(szTmp) );
if( !szTmp[0] )
continue;
trim( szTmp );
strtolower( szTmp );
TrieSetCell( g_trieBanned, szTmp, g_iBannedNames++ );
}
fclose( hFile );
}
else
{
new const szErrors[ERRORS][ ] =
{
"Blacklist file was found but could not be opened.",
"Blacklist storage (trie) could not be created."
};
log_amx( "[VC] Name blacklist will not work. The following error(s) occured:" );
for( new i = FILE; i < ERRORS; i++ )
{
if( iErrors & (1<<i) )
log_amx( "[VC] %s", szErrors[i] );
}
if( hFile )
fclose( hFile );
}
}
}
public plugin_cfg( )
{
set_task( floatmin( get_pcvar_float( p_AdFreq ), 60.0 ), "advertise", TASK_AD );
}
public plugin_end( )
{
if( g_iBannedNames )
TrieDestroy( g_trieBanned );
}
public clcmd_say( id )
{
if( !get_pcvar_num( p_Enabled ) )
return PLUGIN_CONTINUE;
static szSaid[64], szCmdTmp[64];
read_args( szSaid, charsmax(szSaid) );
remove_quotes( szSaid );
if( !szSaid[0] )
return PLUGIN_CONTINUE;
new bool:bSlash;
if( szSaid[0] != '/' )
{
if( get_pcvar_num( p_fwSlash ) )
return PLUGIN_CONTINUE;
}
else
bSlash = true;
new VoiceTools:iVoiceTool = VoiceTools:get_pcvar_num( p_VoiceTool );
for( new i = 0; i < MAX_CMDS; ++i )
{
if( !SayCmd[iVoiceTool][i][0] )
continue;
formatex( szCmdTmp, charsmax(szCmdTmp), "%s%s", bSlash ? "/" : "", SayCmd[iVoiceTool][i] );
if( equali( szSaid, szCmdTmp ) )
{
motd_connect( id, iVoiceTool );
break;
}
}
return PLUGIN_CONTINUE;
}
bool:build_link( const id, const VoiceTools:iVoiceTool, const iTeam, szLink[], const iLen )
{
static szTmp[320], szVar[128], szEncodedVar[256], iReplacer;
szLink[0] = '\0';
for( new i = 0; i < LINK_OPTIONS; ++i )
{
iReplacer = BuildSequence[iVoiceTool][i];
switch( iReplacer )
{
case INVALID: continue;
case PROTOCOL, SEPARATOR:
{
strcat( szLink, LinkBuild[iVoiceTool][iReplacer], iLen );
continue;
}
case PLAYER_NAME: get_valid_name( id, szVar, charsmax(szVar) );
case S_IP, S_PORT, S_NAME, S_PW, S_VERSION:
{
if( !get_pcvar_num( p_TeamEnabled ) )
get_pcvar_string( p_Options[iReplacer][0], szVar, charsmax(szVar) );
else
{
get_pcvar_string( p_Options[iReplacer][iTeam], szVar, charsmax(szVar) );
if( !strlen( szVar ) )
get_pcvar_string( p_Options[iReplacer][0], szVar, charsmax(szVar) );
}
}
default:
{
if( !get_pcvar_num( p_TeamEnabled ) )
get_pcvar_string( p_Options[iReplacer][0], szVar, charsmax(szVar) );
else
get_pcvar_string( p_Options[iReplacer][iTeam], szVar, charsmax(szVar) );
}
}
if( !strlen( szVar ) )
continue;
else
StringURLEncode( szVar, szEncodedVar, charsmax(szEncodedVar) );
formatex( szTmp, charsmax(szTmp), LinkBuild[iVoiceTool][iReplacer], szEncodedVar );
strcat( szLink, szTmp, iLen );
}
return true;
}
bool:get_valid_name( const id, szName[], const iLen )
{
static szBannedChars[64], iBannedLen;
get_user_name( id, szName, iLen );
get_pcvar_string( p_BannedChars, szBannedChars, charsmax(szBannedChars) );
iBannedLen = strlen( szBannedChars );
for( new i = 0; i < iBannedLen; i++ )
{
replace_all( szName, iLen, szBannedChars[i], " " );
}
if( g_iBannedNames )
{
new iPos = strlen( szName ), szTmp[32];
copy( szTmp, charsmax(szTmp), szName );
strtolower( szTmp );
while( TrieKeyExists( g_trieBanned, szTmp ) )
{
szTmp[--iPos] = '\0';
if( !iPos )
{
if( g_Mod == CSTRIKE || g_Mod == CZERO )
{
ColorChat( id, Color:clamp( get_pcvar_num( p_AdColor ), 1, 6 ), "%L", id, "VC_NAME" );
}
else
{
client_print( id, print_chat, "%L", id, "VC_NAME" );
}
}
}
szName[iPos] = '\0';
}
}
motd_connect( const id, const VoiceTools:iVoiceTool )
{
static szBuffer[1440], szHeader[64];
formatex( szHeader, charsmax(szHeader), "%L", id, "VC_HEAD", ToolName[iVoiceTool] );
build_link( id, iVoiceTool, get_user_team( id ), szBuffer, charsmax(szBuffer) );
format( szBuffer, charsmax(szBuffer), HTML, szBuffer, szHeader, id, "VC_MOTD", ToolName[iVoiceTool] );
show_motd( id, szBuffer, szHeader );
}
public cmd_ad( id, level, cid )
{
if( cmd_access( id, level, cid, 1 ) )
{
remove_task( TASK_AD );
advertise( );
}
return PLUGIN_HANDLED;
}
public advertise( )
{
if( get_pcvar_num( p_AdEnabled ) && get_pcvar_num( p_Enabled ) )
{
new Color:iColor, VoiceTools:iVoiceTool = VoiceTools:get_pcvar_num( p_VoiceTool ),
bool:bFwSlash = ( get_pcvar_num( p_fwSlash ) ) ? true : false;
if( g_Mod == CSTRIKE || g_Mod == CZERO )
{
iColor = Color:clamp( get_pcvar_num( p_AdColor ), 1, 6 );
}
for( new id = 1; id <= g_iMaxPlayers; ++id )
{
if( !IsConnected[id] )
continue;
if( g_Mod == CSTRIKE || g_Mod == CZERO )
{
ColorChat( id, iColor, "%L", id, "VC_ADVE", ToolName[iVoiceTool], bFwSlash ? "/" : "", SayCmd[iVoiceTool][0] );
}
else
{
client_print( id, print_chat, "%L", id, "VC_ADVE", ToolName[iVoiceTool], bFwSlash ? "/" : "", SayCmd[iVoiceTool][0] );
}
}
}
set_task( get_pcvar_float( p_AdFreq ), "advertise", TASK_AD );
}
MOD:get_mod( )
{
new szMod[32];
get_modname( szMod, charsmax(szMod) );
for( new MOD:i = CSTRIKE; i < MOD; ++i )
{
if( equal( szMod, g_szMods[i] ) )
return i;
}
return INVALID;
}
stock StringURLEncode( const szInput[ ], szOutput[ ], const iLen ) // Exolent
{
static const HEXCHARS[ 16 ] = {
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46
};
new iPos, cChar, iFLen;
while( ( cChar = szInput[ iPos ] ) && iFLen < iLen )
{
if( cChar == 0x20 )
{
szOutput[ iFLen++ ] = cChar;
}
else if( !( 0x41 <= cChar <= 0x5A )
&& !( 0x61 <= cChar <= 0x7A )
&& !( 0x30 <= cChar <= 0x39 )
&& cChar != 0x2D
&& cChar != 0x2E
&& cChar != 0x5F )
{
if( ( iFLen + 3 ) > iLen )
{
break;
}
else if( cChar > 0xFF
|| cChar < 0x00 )
{
cChar = 0x2A;
}
szOutput[ iFLen++ ] = 0x25;
szOutput[ iFLen++ ] = HEXCHARS[ cChar >> 4 ];
szOutput[ iFLen++ ] = HEXCHARS[ cChar & 15 ];
}
else
{
szOutput[ iFLen++ ] = cChar;
}
iPos++;
}
szOutput[ iFLen ] = 0;
return iFLen;
}
// COLORCHAT.sma
public client_putinserver( id )
IsConnected[id] = true;
public client_disconnect( id )
IsConnected[id] = false;
public ColorChat( id, const Color:type, const msg[ ], any:...)
{
if( get_playersnum( ) < 1 )
return;
static message[256];
switch( type )
{
case YELLOW: // Yellow
{
message[0] = 0x01;
}
case GREEN: // Green
{
message[0] = 0x04;
}
default: // White, Red, Blue
{
message[0] = 0x03;
}
}
vformat( message[1], 251, msg, 4 );
// Make sure message is not longer than 192 character. Will crash the server.
message[192] = '\0';
new team, ColorChange, index, MSG_Type;
if( !id )
{
index = FindPlayer( );
MSG_Type = MSG_ALL;
}
else
{
MSG_Type = MSG_ONE;
index = id;
}
team = get_user_team( index );
ColorChange = ColorSelection( index, MSG_Type, type );
ShowColorMessage( index, MSG_Type, message );
if( ColorChange )
{
Team_Info( index, MSG_Type, TeamName[team] );
}
}
ShowColorMessage( const id, const type, const message[] )
{
message_begin( type, g_msgid_SayText, _, id );
write_byte( id );
write_string( message );
message_end( );
}
Team_Info( const id, const type, const team[] )
{
message_begin( type, g_msgid_TeamInfo, _, id );
write_byte( id );
write_string( team );
message_end( );
return 1;
}
ColorSelection( const index, const type, const Color:Type )
{
switch(Type)
{
case RED:
{
return Team_Info( index, type, TeamName[1] );
}
case BLUE:
{
return Team_Info( index, type, TeamName[2] );
}
case GREY:
{
return Team_Info( index, type, TeamName[0] );
}
}
return 0;
}
FindPlayer( )
{
new i = -1;
while( i <= g_iMaxPlayers )
{
if( IsConnected[++i] )
{
return i;
}
}
return -1;
}
//--------------------------------------------