Код за потвърждение: Избери целия код
/*
* Modified by Safety1st
* 2/1/2014
*
* Original topic: https://forums.alliedmods.net/showthread.php?t=186460
*
* Changes are:
* - huge performance optimization thanks to ConnorMcLeod's idea
* - proper knife attacks handling
* - fixed 'Run time error 4: index out of bounds' error
* - revized redisplaying menu algorithm, now it also could be easily closed to continue playing
* - corrected colorchat function
* - other optimizations
*/
#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#define SERVER_TAG " DM VOTE "
#define USE_MENU_FIX // should be commented for AMXX 1.8.3
#define MAX_PLAYERS 32
enum _:TASKS
{
TASK_VOTE_INIT = 1445,
TASK_VOTE_TIME,
TASK_VOTE_COUNTDOWN
}
enum _:MODES
{
NORMAL = 0,
HEAD
}
new g_iMaxPlayers, g_iVoteTime, g_iVoteCountdown = 7
new cvar_votetime, cvar_blockknife_dmg, cvar_voteinit_time
#define NO_MENU -1
#define MENU_CLOSE 2
new g_vote[MODES], g_menu_id[ MAX_PLAYERS + 1 ] = { NO_MENU, NO_MENU, ... }
// macro; %1 - variable being modified, %2 - player index
#define CheckFlag(%1,%2) ( %1 & ( 1 << (%2-1) ) )
#define AddFlag(%1,%2) ( %1 |= ( 1 << (%2-1) ) )
new giHasVoted, giHasCloseOption
new const sound_countdown[ ][ ] = {
"misc/one.wav",
"misc/two.wav",
"misc/three.wav",
"misc/four.wav",
"misc/five.wav"
}
// temporary holds info
new szBuffer[MODES][64]
new iSum, iNormal, iHead
const m_iMenu = 205 // cbaseplayer offset
new gMsgSayText
public plugin_precache() {
for( new i = 0; i < sizeof sound_countdown; i++ )
precache_sound( sound_countdown[i] )
}
public plugin_init() {
register_plugin( "DeathMatch Mod's Vote", "1.6", "Neeeeeeeeeel.- / Safety1st" )
register_dictionary( "dm_vote.txt" )
cvar_votetime = register_cvar( "dm_vote_time", "15" )
cvar_blockknife_dmg = register_cvar( "dm_block_knife_dmg", "0" )
cvar_voteinit_time = register_cvar( "dm_voteinit_time", "40" )
g_iMaxPlayers = get_maxplayers()
gMsgSayText = get_user_msgid("SayText")
}
public plugin_cfg() {
set_task( get_pcvar_float( cvar_voteinit_time ), "show_vote", TASK_VOTE_INIT )
}
public client_disconnect(id) {
g_menu_id[id] = NO_MENU
}
public show_vote()
{
if( g_iVoteCountdown == 7 )
{
g_iVoteCountdown--
set_task( 1.0, "show_vote", TASK_VOTE_COUNTDOWN, _, _, "b" )
return
}
else if( g_iVoteCountdown )
{
set_hudmessage( 85, 255, 0, -1.0, 0.09, 1, 6.0, 1.0 )
if( g_iVoteCountdown != 1 )
{
for( new i = 1; i <= g_iMaxPlayers; i++ )
{
if( is_user_connected( i ) )
show_hudmessage( i, "%L", i, "VOTE_STARTS_IN", g_iVoteCountdown - 1 )
}
PlaySound( g_iVoteCountdown - 2 )
g_iVoteCountdown--
return
}
else
{
for( new i = 1; i <= g_iMaxPlayers; i++ )
{
if( is_user_connected( i ) )
show_hudmessage( i, "%L", i, "VOTE_STARTING" )
}
}
}
remove_task( TASK_VOTE_COUNTDOWN )
g_iVoteTime = get_pcvar_num( cvar_votetime )
set_task( 1.0, "time_vote", TASK_VOTE_TIME, _, _, "b" )
for( new i = 1; i <= g_iMaxPlayers; i++ )
{
if( is_user_connected( i ) )
prepare_menu_vote( i )
}
return
}
public time_vote()
{
if( !g_iVoteTime ) {
remove_task( TASK_VOTE_TIME )
finish_vote()
return
}
set_hudmessage( 85, 255, 0, -1.0, 0.09, 1, 6.0, 1.0 )
for( new i = 1; i <= g_iMaxPlayers; i++ )
{
if( is_user_connected( i ) )
show_hudmessage( i, "%L", i, "VOTE_FINISHS_IN", g_iVoteTime )
}
g_iVoteTime--
}
public finish_vote() {
// hide menu
show_menu( 0, 0, "^n", .time = 1 )
new result = g_vote[ HEAD ] == g_vote[ NORMAL ] ? 0 : 1
if( result )
calculate_votes()
for( new i = 1; i <= g_iMaxPlayers; i++ )
{
if( is_user_connected( i ) )
{
if( !result )
ChatColor( i, "!g[%s] %L", SERVER_TAG, i, "VOTE_NOWINNER" )
else
{
ChatColor( i, "!g[%s] %L", SERVER_TAG, i, "VOTE_FINISH", iHead, iNormal )
ChatColor( i, "!g[%s] %L", SERVER_TAG, i, "VOTE_RESULT", g_vote [ HEAD ] > g_vote[ NORMAL ] ? "Only Headshot mode" : "Normal mode" )
}
}
}
if( g_vote[ HEAD ] > g_vote[ NORMAL ] )
RegisterHam( Ham_TraceAttack, "player", "fw_TraceAttack" ) // we will block all damage except headshots and knife
set_cvar_num( "sv_restart", 3 )
}
public PlaySound( sound )
client_cmd( 0, "spk ^"%s^"", sound_countdown[ sound ] )
public prepare_menu_vote(id) {
formatex( szBuffer[NORMAL], 63, "%L", id, "VOTE_MENU_TITLE" )
new Menu = menu_create( szBuffer[NORMAL], "menu_vote" ) // menu ids start from 0
new iCallback = menu_makecallback( "CallbackMenu" )
menu_additem( Menu, "", .callback = iCallback )
menu_additem( Menu, "", .callback = iCallback )
formatex( szBuffer[NORMAL], 63, "%L", id, "VOTE_MENU_EXIT" )
menu_additem( Menu, szBuffer[NORMAL] )
menu_setprop( Menu, MPROP_EXIT, MEXIT_NEVER )
show_menu_vote( id, Menu )
g_menu_id[id] = Menu
}
public CallbackMenu( id, menu, item ) {
if( CheckFlag( giHasVoted, id ) )
return ITEM_DISABLED
return ITEM_IGNORE
}
show_menu_vote( id, menu ) {
formatex( szBuffer[NORMAL], 63, "Normal mode \r[\y%d%%\r]", iSum ? iNormal : 0 )
formatex( szBuffer[HEAD], 63, "Only Headshot \r[\y%d%%\r]", iSum ? iHead : 0 )
menu_item_setname( menu, NORMAL, szBuffer[NORMAL] )
menu_item_setname( menu, HEAD, szBuffer[HEAD] )
if( CheckFlag( giHasVoted, id ) && !CheckFlag( giHasCloseOption, id ) ) {
formatex( szBuffer[NORMAL], 63, "%L", id, "VOTE_MENU_CLOSE" )
menu_item_setname( menu, MENU_CLOSE, szBuffer[NORMAL] )
AddFlag( giHasCloseOption, id )
}
#if defined USE_MENU_FIX
/* Fix for AMXX menus, more info here:
https://bugs.alliedmods.net/show_bug.cgi?id=4778
https://forums.alliedmods.net/showthread.php?t=230887 */
set_pdata_int( id, m_iMenu, 0 )
#endif
menu_display( id, menu )
}
public menu_vote( id, menu, item ) {
if( item == MENU_EXIT )
return PLUGIN_HANDLED
/* do you see that? Even if a menu hasn't 'exit' option it is called anyway when menu is redisplayed for player.
who made this crap called 'new menus'?! */
if( item == MENU_CLOSE ) {
// destroy the menu and don't disturb player anymore
menu_destroy(menu)
g_menu_id[id] = NO_MENU
return PLUGIN_HANDLED
}
AddFlag( giHasVoted, id );
g_vote[item]++
new uName[ 33 ]
get_user_name( id, uName, charsmax( uName ) )
ChatColor( 0, "!g[%s] %L", SERVER_TAG, id, "VOTE_HAS_CHOOSEN", uName, !item ? "Normal" : "OnlyHead" )
new iMenuId
calculate_votes()
for( new i = 1; i <= g_iMaxPlayers; i++ ) {
iMenuId = g_menu_id[i]
if( iMenuId != NO_MENU )
show_menu_vote( i, iMenuId )
}
return PLUGIN_HANDLED
}
calculate_votes() {
iSum = g_vote[ NORMAL ] + g_vote[ HEAD ]
if( iSum ) {
iNormal = g_vote[ NORMAL ] * 100 / iSum
iHead = 100 - iNormal
}
}
public fw_TraceAttack( victim, attacker, Float:damage, Float:direction[3], trace, damageBits ) {
if( get_user_weapon( attacker ) == CSW_KNIFE ) {
if( get_pcvar_num( cvar_blockknife_dmg ) )
return HAM_SUPERCEDE
}
else if( victim != attacker && ( 1 <= attacker <= g_iMaxPlayers ) && get_tr2( trace, TR_iHitgroup ) != HIT_HEAD ) {
set_tr2( trace, TR_flFraction, 1.0 ) // didn't hit anything
return HAM_SUPERCEDE
}
return HAM_IGNORED
}
ChatColor( const id, const input[ ], any:... ) {
new count = 1, players[32], player
static msg[191]
vformat( msg, 190, input, 3 )
replace_all( msg, 190, "!g", "^4" )
replace_all( msg, 190, "!y", "^1" )
replace_all( msg, 190, "!team", "^3" )
replace_all( msg, 190, "!team2", "^0" )
if( id ) {
if( !is_user_connected(id) )
return
players[0] = id
}
else
get_players(players, count, "ch")
for( new i = 0; i < count; i++ ) {
player = players[i]
message_begin(MSG_ONE_UNRELIABLE, gMsgSayText, _, player)
write_byte(player)
write_string(msg)
message_end()
}
}