DM Vote Mod

admin646

Новичок
Сообщения
1,023
Решения
59
Реакции
98
Как-то видел на одном сервере плагин с голосованием за режим в Deathmatch Моде.

Так вот нашел что-то похожее но в плагине происходит рестарт. И только после рестарта срабатывает плагин.

Можете пожалуйста помочь. Как сделать так чтобы плагин срабатывал сразу после окончания голосования и без всяких рестартов?


Код:
/*
*    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
*
*    version 1.65
*    {
*        wopox1337:
*        - add support ReAPI,
*        - add support bots for amxx 1.8.3,
*        - add more custom info about HUDMessage's
*    }
*/

// Use ReAPI for correctly work with bots
// #define USE_REAPI

// Use DHUD or HUD informer
#define USE_DHUD

#include <amxmodx>
#include <fakemeta>

#if !defined USE_REAPI
    #include <hamsandwich>
#else
    #include <reapi>
#endif

#define SERVER_TAG " DM VOTE " // Tag in chat
//#define USE_MENU_FIX    // should be commented for AMXX 1.8.3


#if AMXX_VERSION_NUM < 183
    #define MAX_PLAYERS 32
    
    #if defined USE_DHUD
        #include <dhudmessage>
    #endif
#endif

const STATUSICON_SHOW = 1

enum _:TASKS
{
    TASK_VOTE_INIT = 1445,
    TASK_VOTE_TIME,
    TASK_VOTE_COUNTDOWN
}

enum _:MODES
{
    NORMAL = 0,
    HEAD
}

enum {
    // Settings color for HeadShot sprite
    iColor_R = 139,
    iColor_G = 0,
    iColor_B = 250
}

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 g_iMsgIdStatusIcon

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.65", "Neeeeeeeeeel.- / Safety1st" )
    
    register_dictionary( "dm_vote.txt" )
    
    cvar_votetime = register_cvar( "dm_vote_time", "10" )
    cvar_blockknife_dmg = register_cvar( "dm_block_knife_dmg", "1" )
    cvar_voteinit_time = register_cvar( "dm_voteinit_time", "30" )

    g_iMaxPlayers = get_maxplayers()
    gMsgSayText = get_user_msgid("SayText")
    g_iMsgIdStatusIcon = get_user_msgid("StatusIcon")
}

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
}

#if defined USE_DHUD
    #define set_hudmessage set_dhudmessage
    #define show_hudmessage show_dhudmessage
#endif

public show_vote()
{
    if( g_iVoteCountdown == 7 )
    {
        g_iVoteCountdown--
        set_task( 1.0, "show_vote", TASK_VOTE_COUNTDOWN, _, _, "b" )
        return
    }
    
    else if( g_iVoteCountdown )
    {
        // Custom your HUD Message as you want
        // Add info: https://goldsrc.ru/amxxapi/amxmodx/set_hudmessage
        set_hudmessage(
            .red = 85,
            .green = 255,
            .blue = 0,
            .x = -1.0,
            .y = 0.09,
            .effects = 1,
            .fxtime = 6.0,
            .holdtime = 0.8,
            .fadeintime = 0.1,
            .fadeouttime = 0.2
            )
        
        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
    }
    
    // Custom your HUD Message as you want
    // Add info: https://goldsrc.ru/amxxapi/amxmodx/set_hudmessage
    set_hudmessage(
        .red = 85,
        .green = 255,
        .blue = 0,
        .x = -1.0,
        .y = 0.09,
        .effects = 1,
        .fxtime = 6.0,
        .holdtime = 0.8
        )
    
    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 ] ){
            // we will block all damage except headshots and knife
            
            
        #if !defined USE_REAPI
            #if AMXX_VERSION_NUM < 183
                RegisterHam( Ham_TraceAttack, "player", "CBasePlayer_TraceAttack", .Post = false)
            #else
                RegisterHam( Ham_TraceAttack, "player", "CBasePlayer_TraceAttack", .Post = false, .specialbot = true)
            #endif
            RegisterHamPlayer( Ham_Spawn, "CBasePlayer_Spawn", .Post = true )
        #else
            RegisterHookChain( RG_CBasePlayer_TraceAttack, "CBasePlayer_TraceAttack", .post = false);
            RegisterHookChain( RG_CBasePlayer_Spawn, "CBasePlayer_Spawn", .post = true);
        #endif
    }
    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 CBasePlayer_TraceAttack( victim, attacker, Float:damage, Float:direction[3], trace, damageBits ) {
    if( get_user_weapon( attacker ) == CSW_KNIFE ) {
        if( get_pcvar_num( cvar_blockknife_dmg ) )
        {
            #if !defined USE_REAPI
            return HAM_SUPERCEDE
            #else
            return HC_SUPERCEDE
            #endif
        }
    }
    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
            #if !defined USE_REAPI
            return HAM_SUPERCEDE
            #else
            return HC_SUPERCEDE
            #endif
    }
    #if !defined USE_REAPI
    return HAM_IGNORED
    #else
    return HC_CONTINUE
    #endif   
}


public CBasePlayer_Spawn(id) {
    if( !is_user_alive(id) )
        return

    SendStatusIcon(id)
}

stock SendStatusIcon(id)
{
    message_begin(MSG_ONE_UNRELIABLE, g_iMsgIdStatusIcon, .player = id)
    write_byte(STATUSICON_SHOW) // status: 0 - off, 1 - on, 2 - flash
    write_string("d_headshot") // sprite name in hud.txt
    write_byte(iColor_R)
    write_byte(iColor_G)
    write_byte(iColor_B)
    message_end()
}

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()
    }
}
Сообщение автоматически объединено:

И да. После того как выбрали режим. Допустим Headshot Only . То в название сервера добавляется HS ONLY
 
Последнее редактирование:
Сверху
Назад