Русское сообщество по скриптингу

CS flags доработка плагина  [Выполнено]

Правила форума
1. Запрещено материться и оскорблять других участников форума.
2. Запрещен флуд, оффтоп, дабл постинг во всех разделах форума, кроме раздела "Болтовня".
3. Запрещено взламывать сайт/форум или наносить любой вред проекту.
4. Запрещено рекламировать другие ресурсы.
5. Запрещено создавать темы без информативного названия. Название темы должно отображать ее смысл.

В данном разделе форума разрешено создавать темы только с поиском исполнителя или заказчика.

Правила при создании новой темы:
1. При вставке кода плагина необходимо использовать тег [code=php].
2. Любые изображения должны быть загружены, как вложения к вашему сообщению.
3. При описании проблемы или запросе на помощь в редактировании плагина обязательно выкладывайте исходник sma плагина.

CS flags доработка плагина  [Выполнено]

Сообщение baisaganov » 06 авг 2017, 23:01

Мод: CSDM
Бюджет: оплата договорная
Техническое задание:
Нужно добавить функции:
1)Если флаг все такие отбили, появляется сообщение по центу экрана , о том что у Y появилась возможность отыграться
2)Если нет, сообщение по центу экрана команда X победила
3)Все флаги захвачены командой X, победа через :zz секунд
Код: Выделить всё
#include <amxmodx>
#include <amxmisc>
#include <fakemeta>

#define VERSION "1.194"

//#define USE_CUSTOM_SOUNDS

/* Activates loggers, commands for debugging */
//#define DEBUG_TOOLS

#if defined DEBUG_TOOLS
       /* debug results are stored in this file */
    #define DEBUG_FILE "csflags_debug.txt"
       /* automatically generates debug log */
    #define DEBUG_MODE
#endif

#define ADMIN_CSFLAGS ADMIN_ADMIN

// =================================================
// In the following pevs, 
// my intention was not to abuse from memory
// by creating an array for each required property.
// But storing values in entities like this can be a
// pain for documentation.

// uniqueid is meant to fast check if its
// a csflags entity in think and touch forwards;
#define pev_csf_uniqueid pev_groupinfo

// stores the id of player who's taken the flag
#define pev_csf_flagowner pev_iuser2

// stores the id of player who's touching the flag
#define pev_csf_flagtoucher pev_playerclass

// stores the delay for capturing this specific flag
#define pev_flagcapture_delay pev_fuser1


// the entity id of the flag controlled by this trigger
#define pev_csf_flagent pev_iuser3

// the array id of the flag controlled by this trigger
#define pev_csf_flagid pev_iuser4

// the flag status of a flag controlled by this trigger
#define pev_csf_flagstatus pev_body

// the type (size) of hitbox of this trigger
#define pev_csf_hitbox pev_team

// the entity id of the trigger that controls this flag
#define pev_csf_trigger pev_iuser1

// a special delay control for this entity to think
#define pev_think_delay pev_button

#define MAX_CSFLAGS 5 // hard limit
#define TEAMSNUM 2 // hard limit - designed for cs

#define ID_TEAM_CT 1
#define ID_TEAM_T 0
#define CLASSNAME_CSFLAG "_csf"
#define CLASSNAME_TRIGGER_FLAG "_ftrigger"
#define CSFLAG_TYPEID 11122
#define TRIGGERFLAG_TYPEID 11144

// random taskid
#define TASKID_SCORE_UPDATE 27328
#define TASKID_SYNC_SCORE 723
#define TASKID_RESTART_COUNTER 724
#define TASKID_MAPEND 2938
#define TASKID_RADIORANGE 33
#define TASKID_HIDERADIOICON 34
#define TASKID_RESTORE_MP 1298
#define TASKID_HUDREPEAT 989
#define TASKID_CAPTUREDELAY 1020

#define INTERVAL_SCORE_UPDATE 0.8
#define INTERVAL_SYNCH 0.5

#define GAMESTATE_STOPPED 1
#define GAMESTATE_STARTED (1 << 1)
#define GAMESTATE_WAIT (1 << 2)
#define GAMESTATE_FORCEDEND (1 << 3)
#define GAMESTATE_SHOWSCORE (1 << 4)
#define GAMESTATE_MATCHOVER (1 << 5)
#define GAMESTATE_HUDREPEAT (1 << 6)

#define MODEL_FLAGS "models/csflags/csflags.mdl"
#define FILE_DOMCFG "/csflags/%s.cfg"
#define SOUND_FLAGTAKEN "buttons/button9"
#define SOUND_OPPONENT_FLAGTAKEN "items/medshotno1"

#define CSFLAGS_ICON_NAME    "dmg_shock"
#define CSFLAGS_ICON_R         50
#define CSFLAGS_ICON_G         50
#define CSFLAGS_ICON_B         200

#define MAX_HITBOXES 3

#define HITBOX_ID_NORMAL 0
#define HITBOX_ID_LARGER 1
#define HITBOX_ID_LARGE 2

#define HITBOX_NORMAL {{-24.0, -24.0, -64.0}, {24.0, 24.0, 64.0}}
#define HITBOX_LARGER {{-60.0, -60.0, -80.0}, {60.0, 60.0, 80.0}}
#define HITBOX_LARGE {{-100.0, -100.0, -128.0}, {100.0, 100.0, 128.0}}

#define HITBOX_MAX 1
#define HITBOX_MIN 0

#if defined USE_CUSTOM_SOUNDS
/*
 * These are example sound files. 
 * if you choose USE_CUSTOM_SOUNDS, use your own sound files
 */
#define SOUND_MATCHWIN_CT "csflags/bouaxisscore.wav"
#define SOUND_MATCHWIN_T "csflags/boualliesscore.wav"
#define SOUND_WIN_CT "csflags/alliesscore.wav"
#define SOUND_WIN_T "csflags/axisscore.wav"

#else
#define SOUND_TEAMWIN "events/task_complete"

#define SOUND_OPPONENT_WIN "hassault/hw_spindown"
#define SOUND_MATCHWIN "ambience/goal_1"
#define SOUND_OPPONENT_MATCHWIN "ambience/xtal_down1"
#endif    //USE_CUSTOM_SOUNDS

#define HUD_LINE_MAXSIZE 32
#define HUD_FLAGS_STRING_MAXSIZE HUD_LINE_MAXSIZE * MAX_CSFLAGS

#define MSG_HEADER "[CSFLAGS]"

#define MSG_FLAGSTATE_NOTIFY_OP "^4[CSFLAGS] ^1 %s(%d) captured the ^4[%s]^1 flag for the %s^1."
#define MSG_FLAGSTATE_NOTIFY    "^4[CSFLAGS] ^3%s(%d)^1 captured the ^4[%s]^1 flag for the ^3%s^1."


#define MSG_COUNTER "CS Flags restarting in %d"
#define MSG_RESTARTED "CS Flags restarted!"
#define MSG_CONS_NOCFG "Could not start csflags because there's no cfg file or file contains no flags."
#define MSG_CONS_NOT_ENABLED "Could not start because CSFlags is not enabled."
#define MSG_TIME_OVER "Time is over. Waiting for a winner..."
#define MSG_CHANGEMAP_DELAY "CS Flags match is over, waiting for the next map."
#define HUD_TEAMWINNER "%s have won this match!"
#define HUD_TEAMWINS "%s win this flag round!"
#define HUD_BESTSCORE "^n^nBest scores in this match:"
#define TEAM_DESC_CT "CTs"
#define TEAM_DESC_T "Terrorists"

#define IFW_FLAGTAKEN "csf_flag_taken"
#define IFW_ROUNDWON "csf_round_won"
#define IFW_MATCHWON "csf_match_won"

#define MSG_RADIO_POINTSECURED "Control point is secure."

#define LANG_PLAYER_C -76

/******************************************************************************************
 * The following function/values were taken from
 * VEN's CTF plugin
 */
 // private data deaths offset
#define OFFSET_DEATHS_32BIT 444
#define OFFSET_DEATHS_64BIT 493
// deaths offset linux difference
#define OFFSET_DEATHS_LINUXDIFF 5 

// determination of actual offsets
#if !defined PROCESSOR_TYPE // is automatic 32/64bit processor detection?
    #if cellbits == 32 // is the size of a cell are 32 bits?
        // then considering processor as 32bit
        #define OFFSET_DEATHS OFFSET_DEATHS_32BIT
        //not used in this version //#define OFFSET_MONEY OFFSET_MONEY_32BIT
    #else // in other case considering the size of a cell as 64 bits
        // and then considering processor as 64bit
        #define OFFSET_DEATHS OFFSET_DEATHS_64BIT
        //not used in this version //#define OFFSET_MONEY OFFSET_MONEY_64BIT
    #endif
#else // processor type specified by PROCESSOR_TYPE define
    #if PROCESSOR_TYPE == 0 // 32bit processor defined
        #define OFFSET_DEATHS OFFSET_DEATHS_32BIT
        //not used in this version //#define OFFSET_MONEY OFFSET_MONEY_32BIT
    #else // considering that 64bit processor defined
        #define OFFSET_DEATHS OFFSET_DEATHS_64BIT
        //not used in this version //#define OFFSET_MONEY OFFSET_MONEY_64BIT
    #endif
#endif


// marco to retrieve user deaths
#define CS_GET_USER_DEATHS_(%1) get_pdata_int(%1, OFFSET_DEATHS, OFFSET_DEATHS_LINUXDIFF)
/******************************************************************************************
*/

/** Names of dom areas */
new g_PlaceNames[MAX_CSFLAGS][16]

/** State of flas, i.e. flag taken, etc */
new g_FlagState[MAX_CSFLAGS] = {-,...}

/** Score Counter for each player */
new Float:g_PlayerScore[33]

/** Score counter for each team */
new Float:g_TeamScore[TEAMSNUM]

/** Matches won by each team */
new g_TeamWins[TEAMSNUM]

/** Number of flags for the current map*/
new g_MapFlagsNum

/** Radio messages state */
new g_Radio[33]

/** mp time backup for swap */
new Float:g_OldMPTime

/** time to restart the match */
new Float:g_RestartTime

/** 
 * last team winner of a match
 * used to display info if a round restarts
 * when csflags match end info was being shown. 
 */
new g_LastWinner

new bool
:g_MatchLastWin

/** Stores pcvar for max points before a team win */
new g_cvarMaxPoints

/** Stores pcvar for csflags enabled */
new g_cvarDomEnabled

/** Stores pcvar for the delay before map ends */
new g_cvarMapEndTime

/** Stores pcvar for the number of csflags matches wins required for a map switch */
new g_cvarMaxWins

/** Stores pcvar that defines if a map switch should take place if csflags wins are tied */
new g_cvarTieMatch

/** Stores pcvar that defines if a match is won when all flags are taken by a team */
new g_cvarAllFlagsWin

/** Stores pcvar that switches radio messages */
new g_cvarUseRadio

/** Stores pcvar that defines if map objectives should be removed */
new g_cvarRemoveDefObjectives

/** Stores pcvar that defines how much frags are added to players of csflags winning team */ 
new g_cvarWinFrags

/** Stores pcvar that defines how much frags are added to a player that captures a flag */
new g_cvarCaptureFrags

/** Stores pcvar that defines how much time it takes for a player to capture a flag */
new g_cvarCaptureDelay

/** Stores pcvar that defines if players should respawn after match is over */
new g_cvarMatchRespawn

/** Stores pcvar that defines if players should freeze when a match is won */
new g_cvarFreeze

new g_cvarVoteStartCommand

new bool
:g_VoteCmdExecuted = false

/** Stores the message id for score info */
new g_msgidScoreInfo

/** Stores the message id for icon display */
new g_msgidIcon

/** Stores the message id for the progress bar*/
new g_msgidProgress

/** Stores the message id for players 'say text' */
new g_msgidSayText

/** Stores the fakemeta touch forward registry */
new g_fwTouch

/** Stores the fakemeta think forward registry */
new g_fwThink

/** Stores the fakemeta player think foward registry */
new g_fwPThink


/** Stores the flag taken forward registry */
new g_ifw_FlagTaken

/** Stores the round won forward registry */
new g_ifw_RoundWon

/** Stores the match won forward registry */
new g_ifw_MatchWon

/** Stores the max players to avoid get_maxplayers calls */
new g_MaxPlayers

/** Stores the origin of triggers */
new Float:g_TriggerOrigin[MAX_CSFLAGS][3]

/** 
 *  Stores the size of triggers 
 *  current values are:
 *  HITBOX_NORMAL {{-24.0, -24.0, -64.0}, {24.0, 24.0, 64.0}}
 *  HITBOX_LARGER {{-60.0, -60.0, -80.0}, {60.0, 60.0, 80.0}}
 *  HITBOX_LARGE {{-100.0, -100.0, -128.0}, {100.0, 100.0, 128.0}}
 */
new Float:g_mmSize[3][2][3] = 
{
    HITBOX_NORMAL,
    HITBOX_LARGER,
    HITBOX_LARGE
}



/** Team name descriptions */ 
new g_Teams
[2][] = {"Terrorists", "CTs"}

/** Default notify sounds */
new g_NotifySound[2][] = {"csflags/t_notify.wav", "csflags/cs_notify.wav"}

/** 
 * Current plugin state thats defined by several flags: 
 * GAMESTATE_STOPPED - csflags has been stopped
 * GAMESTATE_STARTED - csflgas has started
 * GAMESTATE_WAIT - time is over, csflags is waiting for a winner.
 * GAMESTATE_FORCEDEND = csflags should end anyway
 * GAMESTATE_SHOWSCORE - csflags is showing score
 * GAMESTATE_MATCHOVER - csflags match is over
 * GAMESTATE_HUDREPEAT - hud info has been interrupted by a round restart and should be displayed again.
 */
public g_CSFlagsState




/** Flags if score hud string must be rebuilt */
new bool:g_UpdateScoresHud

/** Flags if flags hud string must be rebuilt */
new bool:g_UpdateFlagsHud

/** 
  * Stores last score integer for a team so script will detect
  * when score hud must be updated.
  */
new g_LastTeamScore[2] = {-1, ...}

/** Hud score messages are not translated for optimization */
new const g_ScoreHeaderFormat[2][] =
{
    "TTs : %d",
    "CTs : %d"
}

new bool:g_IsBot[33]
new bool:g_BotCapturing[33]

#if defined DEBUG_TOOLS

new const debugHeader[] =
{
    "[CSFlags_Debug]"
}
new const debugLine[] = 
{
    "----------------------------------"
}
new debugMsg[160]
new Tabs[16] = {'^t', ...}
new lastFlagState = -1
#if defined DEBUG_FILE
new pDebugFile

public status_debug
()
{
    server_print("stopped: %d^nstarted: %d^nwait: %d^nforced end: %d^nshow score: %d^nmatch over: %d^nhud repeat: %d^n",
                    g_CSFlagsState & GAMESTATE_STOPPED > 0,
                    g_CSFlagsState & GAMESTATE_STARTED > 0,
                    g_CSFlagsState & GAMESTATE_WAIT > 0, 
                    g_CSFlagsState 
& GAMESTATE_FORCEDEND > 0, 
                    g_CSFlagsState 
& GAMESTATE_SHOWSCORE > 0,
                    g_CSFlagsState & GAMESTATE_MATCHOVER > 0,
                    g_CSFlagsState & GAMESTATE_HUDREPEAT > 0)
}


#endif // DEBUG_FILE
#endif // DEBUG_TOOLS




/**
 * (amxmodx core forward.)
 * - Register all required events
 * - Registers all required cvars.
 * - Initializes messages ids
 * - Starts csflags match if :
 *    1) amx_csflags_enabled is set to 1;
 *    2) this maps has a config file for csflags.
 */
public plugin_init() 
{
    register_plugin("csflags", VERSION, "commonbullet")    
    register_event
("HLTV", "event_round_start", "a", "1=0", "2=0")
    register_logevent("event_game_commencing", 2, "1=Game_Commencing")
    register_concmd("amx_csflags_restart", "csflags_restart_cmd", ADMIN_CSFLAGS)
    register_concmd("amx_csflags_stop", "csflags_stop_cmd", ADMIN_CSFLAGS)

    #if defined DEBUG_TOOLS    
    register_concmd("amx_csflags_status", "status_debug", ADMIN_CSFLAGS)
    #endif // DEBUG_TOOLS
    
    register_dictionary
("csflags.txt")
    
    g_cvarMaxWins 
= register_cvar("amx_csflags_max_wins", "1")
    g_cvarMaxPoints = register_cvar("amx_csflags_max_points", "9999999")
    g_cvarDomEnabled = register_cvar("amx_csflags_enabled", "1")
    g_cvarMapEndTime = register_cvar("amx_csflags_mapendtime", "0.5")
    g_cvarTieMatch = register_cvar("amx_csflags_tiematch", "0")
    g_cvarAllFlagsWin = register_cvar("amx_csflags_allflags_win", "1")
    g_cvarUseRadio = register_cvar("amx_csflags_useradio", "0")
    g_cvarRemoveDefObjectives = register_cvar("amx_csflags_remove_map_obj", "1")
    g_cvarWinFrags = register_cvar("amx_csflags_winfrags", "0")
    g_cvarCaptureFrags = register_cvar("amx_csflags_capturefrags", "0")
    g_cvarCaptureDelay = register_cvar("amx_csflags_capturedelay", "3")
    g_cvarMatchRespawn = register_cvar("amx_csflags_respawn", "0")
    g_cvarFreeze = register_cvar("amx_csflags_freeze", "0")
    g_cvarVoteStartCommand = register_cvar("amx_csflags_vote_startcmd", "")

    g_msgidProgress = get_user_msgid("BarTime2")
    g_msgidScoreInfo = get_user_msgid("ScoreInfo")
    g_msgidIcon = get_user_msgid("StatusIcon")
    g_msgidSayText = get_user_msgid("SayText")
    
    g_MaxPlayers 
= get_maxplayers()
    
    if
(get_pcvar_num(g_cvarDomEnabled)) {
        if(load_config()) {
            csflags_init()
        }
    }
#if defined DEBUG_TOOLS
    register_concmd("csflags_trace_flags", "debug_flags")
    register_concmd("csflags_trace_gamestate", "debug_gamestate")
    
    new mapname
[32]
    new msg[128]
    
    get_mapname
(mapname, 31)
    
    open_debug_file
()
    formatex(msg, 127, "***^nStarting Debug Section^nMap: %s^n***", mapname)
    debug_print(0, msg)
    close_debug_file()    
#endif
}


/**
 * (amxmodx core forward)
 * - Precaches flags model
 * - Precaches sounds
 */
public plugin_precache() 
{
    precache_model(MODEL_FLAGS)
    precache_sound(g_NotifySound[0])
    precache_sound(g_NotifySound[1])
    
#if defined USE_CUSTOM_SOUNDS
    new prsounds[4][] = {
        SOUND_MATCHWIN_CT,
        SOUND_MATCHWIN_T,
        SOUND_WIN_CT,
        SOUND_WIN_T
    
}
    new cursound[72]
    for (new i = 0; i < 4; i++) {
        formatex(cursound, 71, "sound/%s", prsounds[i])
        if(file_exists(cursound))
            precache_sound(prsounds[i])
        else
            log_amx
("%L Cound't find sound file %s to precache.", "MSG_HEADER", id, cursound)
    }
#endif    //USE_CUSTOM_SOUNDS
}

/**
 *  This function is called at the very beginning of csflags match. It resets game state and
 *  initializes all required resources.
 *  - Sets the game state to GAMESTATE_STARTED
 *  - Removes the objetives if cvar has been properly set.
 *  - Register touch, think and player think forwards.
 *  - Register forwards to be used externally: flag taken, match won, round won.
 *  - Sets time interval to update scores hud.
 *  - Sets a hook mapend, it's 11.0, one second before map end counter.
 */
public csflags_init() 
{    
    g_CSFlagsState 
= 0
    g_CSFlagsState 
|= GAMESTATE_STARTED
    
    if
(get_pcvar_num(g_cvarRemoveDefObjectives))
        remove_default_objectives()
        
    g_UpdateScoresHud 
= true
    g_UpdateFlagsHud 
= true
    
    set_task
(INTERVAL_SCORE_UPDATE, "update_score", TASKID_SCORE_UPDATE, _, _, "b")
    
    g_fwTouch 
= register_forward(FM_Touch, "forward_touch")
    g_fwThink = register_forward(FM_Think, "flag_think")
    g_fwPThink = register_forward(FM_PlayerPreThink, "player_think")
    
    g_ifw_FlagTaken 
= CreateMultiForward(IFW_FLAGTAKEN, ET_IGNORE, FP_CELL)    // toucher
    g_ifw_MatchWon = CreateMultiForward(IFW_MATCHWON, ET_IGNORE, FP_CELL)    // team winner
    g_ifw_RoundWon = CreateMultiForward(IFW_ROUNDWON, ET_IGNORE, FP_CELL)    // team winner

    set_task(11.0, "set_mapend_mptimelimit", TASKID_MAPEND, _, _, "d", 1)
}

/**
 * Pauses a csflags match
 * @param pausescore If different from 0, it removes score hud.
 */
csflags_pause(pausescore = 0) 
{
    
    if
(pausescore)
        remove_task(TASKID_SCORE_UPDATE)
}

/**
 * Resets a csflags match by cleaning pevs stored in flags and triggers entities.
 * @param wins if different from 0, it resets also the team wins.
 * @param players if different from 0, it resets also the players score.
 **/
csflags_reset(wins = 0, players = 0) 
{
    new flag

#if defined DEBUG_MODE
    open_debug_file()
    print_stack(0, "csflags_reset")
    printvar_cell(0, "wins", wins)
    printvar_cell(0, "players", players)
    close_debug_file()
#endif    
    while((flag = engfunc(EngFunc_FindEntityByString, flag, "classname", CLASSNAME_CSFLAG))) {
        
        set_pev
(flag, pev_csf_flagstatus, 0)
        set_pev(flag, pev_csf_flagowner, 0)        
        
        if
(task_exists(TASKID_CAPTUREDELAY + flag))
            remove_task(TASKID_CAPTUREDELAY + flag)

        set_pev(flag, pev_csf_flagtoucher, 0)
    }
    
    g_TeamScore
[ID_TEAM_CT] = 0.0
    g_TeamScore
[ID_TEAM_T] = 0.0
    
    g_LastTeamScore
[ID_TEAM_CT] = -1
    g_LastTeamScore
[ID_TEAM_T] = -1
    
    if
(wins) {
        g_TeamWins[ID_TEAM_CT] = 0
        g_TeamWins
[ID_TEAM_T] = 0
    
}
    
    if
(players) {
        for(new i = 1; i < 33; i++)
            g_PlayerScore[i] = 0.0
    
}
    
    for
(new i = 0; i < MAX_CSFLAGS; i++)
        g_FlagState[i] = -1    
        
    
}

/**
 *  Makes sure all forwards are properly registered, resets the score hud and removes
 *  GAME_STOPPED flag from csflags' status.
 */
csflags_restart() 
{
    
#if defined DEBUG_MODE
    open_debug_file()
    print_stack(0, "csflags_restart")
    close_debug_file()
#endif
    if(!g_fwTouch)
        g_fwTouch = register_forward(FM_Touch, "forward_touch")
    if(!g_fwThink)
        g_fwThink = register_forward(FM_Think, "flag_think")
    if(!g_fwPThink)
        g_fwPThink = register_forward(FM_Think, "player_think")
        
    if
(!g_ifw_FlagTaken)
        g_ifw_FlagTaken = CreateMultiForward(IFW_FLAGTAKEN, ET_IGNORE, FP_CELL)    // toucher
    if(!g_ifw_MatchWon)
        g_ifw_MatchWon = CreateMultiForward(IFW_MATCHWON, ET_IGNORE, FP_CELL)    // team winner
    if(!g_ifw_RoundWon)
        g_ifw_RoundWon = CreateMultiForward(IFW_ROUNDWON, ET_IGNORE, FP_CELL)    // team winner
    
    g_UpdateScoresHud 
= true
    g_UpdateFlagsHud 
= true
    g_LastTeamScore
[ID_TEAM_CT] = -
    g_LastTeamScore
[ID_TEAM_T] = -1
    
    g_MatchLastWin 
= false
    
    if
(!g_VoteCmdExecuted) {
        start_vote_cmd()
    }    
    
    if
(!task_exists(TASKID_SCORE_UPDATE))
        set_task(INTERVAL_SCORE_UPDATE, "update_score", TASKID_SCORE_UPDATE, _, _, "b")
    
    
    g_CSFlagsState 
&= ~GAMESTATE_STOPPED
    g_CSFlagsState 
|= GAMESTATE_STARTED
    
}

start_vote_cmd(Float:delay=6.0)
{
    new imminentWin
    new checkstr
[2]
    
    get_pcvar_string
(g_cvarVoteStartCommand, checkstr, 1)
    
    if
(checkstr[0]) {
        imminentWin = get_pcvar_flags(g_cvarMaxWins) - 1
        
        if
(imminentWin >= g_TeamWins[ID_TEAM_CT] || imminentWin >= g_TeamWins[ID_TEAM_T]) {
            g_VoteCmdExecuted = true
            set_task
(delay, "exec_vote_cmd", 2121)
        }
    }
}

public exec_vote_cmd()
{
    new voteCommand[64]
    
    get_pcvar_string
(g_cvarVoteStartCommand, voteCommand, 63)
    server_cmd(voteCommand)
}

/**
 *  This function is called by the command "amx_csflags_restart",
 *  forces game to reset, stop and start.
 */
public csflags_restart_cmd(id, level, cid) 
{
    if(!cmd_access(id, level, cid, 0))
        return PLUGIN_HANDLED
        
    if
(!get_pcvar_num(g_cvarDomEnabled))
        console_print(id, "%L", id, "MSG_CONS_NOT_ENABLED")
    
    csflags_reset
()
    csflags_stop(1)
    
    if
(load_config())
        csflags_init()
    else 
        console_print
(id, "%L", id, "MSG_CONS_NOCFG")
    
    return PLUGIN_HANDLED
}

/**
 *  This function is called by the command "amx_csflags_stop", and just stops
 *  the plugin.
 */
public csflags_stop_cmd(id, level, cid) 
{
    if(!cmd_access(id, level, cid, 0))
        return PLUGIN_HANDLED
    csflags_stop
(1)
    return PLUGIN_HANDLED
}

/**
 * Stops the plugin.
 * @param remove if different from 0, removes all csflags specific entities.
 */
csflags_stop(remove) 
{
#if defined DEBUG_MODE
    open_debug_file()
    print_stack(0, "csflags_restart_cmd")
    printvar_cell(0, "remove", remove)
    close_debug_file()
#endif

    if(g_CSFlagsState & GAMESTATE_STARTED) {
        if(task_exists(TASKID_SCORE_UPDATE))
            remove_task(TASKID_SCORE_UPDATE)
        if(remove) {
            remove_all_ents(CLASSNAME_CSFLAG)
            remove_all_ents(CLASSNAME_TRIGGER_FLAG)
            g_MapFlagsNum = 0
        
}
        g_CSFlagsState = GAMESTATE_STOPPED  | (g_CSFlagsState & GAMESTATE_SHOWSCORE)
        
        
/*
        unregister_forward(FM_Touch, g_fwTouch)
        unregister_forward(FM_Think, g_fwThink)
        g_fwThink = 0
        g_fwTouch = 0
        
        DestroyForward(g_ifw_FlagTaken)
        DestroyForward(g_ifw_MatchWon)
        DestroyForward(g_ifw_RoundWon)
        
        g_ifw_FlagTaken = 0
        g_ifw_MatchWon = 0
        g_ifw_RoundWon = 0 
        */
    }
}

/**
 *  Called to 'make' a team win a match.
 *  - Pauses the plugin.
 *  - Updates teams scores.
 *  - Cleans flags states
 *  - Makes sure to clean progress bars from users who were capturing flags.
 *  - Sets GAMESTATE_SCORE on.
 *  - Executes team won forward.
 *  
 *  @param team the team param is the actual team id - 1 so Ts = 0, CTs = 1
 */
team_win(team) 
{
    
    
/* if this state has already been set, means
     * something wrong is going on, so get off here
     */
    
    if
(g_CSFlagsState & GAMESTATE_SHOWSCORE)
        return PLUGIN_CONTINUE

    
/* makes it pause */
    csflags_pause(1)
    
    
/* this is used to check if csflags 
     * winning limit has been set in the cvar */
    new winlimit
    
    
/* used as an iterator for map flags */
    new flag
    
    
/* Adds a pont to the winner team */
    g_TeamWins[team]++
    

#if defined DEBUG_MODE
    debug_gamestate(0, "team_win(0-0)")
#endif    

    /* reset flags being captured, also resets
     * status bars from players who were capturing the flag
     */
    while((flag = engfunc(EngFunc_FindEntityByString, flag, "classname", CLASSNAME_CSFLAG))) {
        new toucher
        
        toucher 
= pev(flag, pev_csf_flagtoucher)
        if(toucher) {
            set_pev(flag, pev_csf_flagtoucher, 0)

            if(task_exists(TASKID_CAPTUREDELAY + flag))
                remove_task(TASKID_CAPTUREDELAY + flag)

            msg_csf_icon(toucher, false)
            msg_bar_progress(toucher, 100, true)
        }
    }
    
    
    
    
/* updates plugin status */
    g_CSFlagsState |= GAMESTATE_SHOWSCORE
    
    
    
/* executes "csf_round_won" forward */
    if(g_ifw_RoundWon) {
        new retval
        ExecuteForward
(g_ifw_RoundWon, retval, team + 1)
    }        
    
    
/* fetches current csflags winlimit value */
    winlimit = get_pcvar_num(g_cvarMaxWins)
    
    
/* Checks if the gamestate was set to wait.
     * Then a map_should_end call checks if map has max win limit
     * and if it as been reached.
     * If so csflags is stopped, lastwin is set to 1.
     */
    if(g_CSFlagsState & GAMESTATE_WAIT) {
        if(map_should_end()) {
            set_task(11.0, "restore_mptimelimit", TASKID_RESTORE_MP)
            csflags_stop(1)
            g_MatchLastWin = true
        
}
    }
    
    
/* 
     * The following code is run when plugin wasn't waiting for a winner
     * but the win limit has been reached by a team. In that case csflags
     * is stopped and lastwin variable is set to 1.
     */
    if(winlimit && !g_MatchLastWin) {
        if(g_TeamWins[team] >= winlimit && !(g_CSFlagsState & GAMESTATE_WAIT)) {
            force_end()
            csflags_stop(1)
            g_MatchLastWin = true
        
}
    }
    
    
/*
     * If it's the last win of the match
     * the csflags state should be updated, and the match
     * won forward executed.
     */
    if(g_MatchLastWin) {
        
        g_CSFlagsState 
|= GAMESTATE_MATCHOVER
        
        if
(g_ifw_MatchWon) {
            new retval
            ExecuteForward
(g_ifw_MatchWon, retval, team + 1)
        }        
    
}
    
    
/* this variable is only used in win_hud_repeat
     * Version 1.19 has correct a bug it would only
     * be reset in that function.
    */
    g_LastWinner = (team + 1)
    
    
/*
     * displayes the winning hud for the teams.
     */
    show_win_hud(team)


#if defined DEBUG_MODE
    open_debug_file()
    print_stack(0, "team_win")
    printvar_cell(0, "team", team)
    printvar_cell(0, "lastwin", g_MatchLastWin)
    printvar_cell(0, "winlimit", winlimit)
    printvar_cell(0, "g_TeamWins[team]", g_TeamWins[team])
    printvar_cell(0, "g_LastWinner", g_LastWinner)
    close_debug_file()
    
    debug_gamestate
(0, "team_win(0-1)")
    
#endif

    /* moves players to spawn if that's been set*/
    if(get_pcvar_num(g_cvarMatchRespawn))
        move_to_spawn()
    
    return PLUGIN_CONTINUE
}

/**
 * Prints those messages in players HUD channels when csflags match has
 * been partially or totally won.
 * @param team teamid - 1, so Ts = 0, CTs = 1.
 * @param lastwin used as a last win flag - last win messages are different.
 */
show_win_hud(team)
{
    /* used to store text messages */
    new message[256]
    
    
/* variables used in playes rank calculation */
    new Float:score[5]
    new bestplayer[5]
    new name[32]
    new Float:currentscore
    
    
/* well known prelude to get_players core function*/
    new players[32]
    new playersnum
    
    
/* shit names, here's a disambiguishing:
     * count - numbers of players in the rank, max 5 */
    new count
    
/* has nothing to do with ranking, is used for
     * formatting strings */
    new len
    
    if
(get_playersnum()) {        
        get_players
(players, playersnum)
        for(new i = 0; i < playersnum; i++) {            
            for
(new p = 0; p < 5; p++) {
                currentscore = g_PlayerScore[players[i]]
                if(currentscore == 0.0)
                    continue
                if
(currentscore > score[p]) {
                    for(new q = 4; q > p && q > 0; q--) {
                        score[q] = score[- 1]
                        bestplayer[q] = bestplayer[- 1]
                    }                
                    score
[p] = currentscore
                    bestplayer
[p] = players[i]
                    count++
                    break
                
}
            }
        }
        count = (count > 5) ? 5 : count
    
}
    
    
/* adds a message header */
    len = format(message, 100, "%s^n", MSG_HEADER)
    
    
/*
     * If it's the last win,the csflags winner is added the message
     */
     
    
/* 
     *   Is there an amxmodx problem when concatening language strings with LANG_PLAYER?
     *   - At least for me the first time it's shown in english (LANG_SERVER ??).
     *     I didn't see any bug reports related and I don't know if its a bug or something
     *     weird going on my test server. If someone complains about this behavior I'll
     *     have to make this a loop with players id - that seems to work.
    */
    if(g_MatchLastWin) {
        // the team variable may be changed regardless the round winner.
        team = (g_TeamWins[ID_TEAM_CT] > g_TeamWins[ID_TEAM_T]) ? ID_TEAM_CT : ID_TEAM_T
        len 
+= format(message[len], 255 - len, "%L" , LANG_PLAYER, "HUD_TEAMWINNER", g_Teams[team])
    }
    else
        len 
+= format(message[len], 255 - len, "%L", LANG_PLAYER, "HUD_TEAMWINS", g_Teams[team])
    
    
/* Adding the best scores */
    len += format(message[len], 255 - len, "%L^n", LANG_PLAYER, "HUD_BESTSCORE")
    
    for
(new i = 0; i < count; i++) {
        get_user_name(bestplayer[i], name, 31)
        len += format(message[len], 255 - len, "^n%s - %d", name, floatround(g_PlayerScore[bestplayer[i]]))        
    
}
    
    
/* send'em to the hud */
    set_hudmessage (255, 40, 20, 0.10, 0.30, 0, 0.1, 10.0, 0.0, 0.0, 3)
    show_hudmessage(0, message)
    
    
/* checks if it isn't a repeatition because
     * the hud had been interrupted by a round restart
     * - in that case it has already been run */
    if(!(g_CSFlagsState & GAMESTATE_HUDREPEAT)) {
        
        
/* round will restart as long as
         * it wasn't the last one
         */
        if(!g_MatchLastWin) {
            g_RestartTime = 10.0
            set_task
(1.0, "restart_counter", TASKID_RESTART_COUNTER, _, _, "b")
        }
        
            
#if !defined USE_CUSTOM_SOUNDS
        
        new t
        for
(new i = 0; i < playersnum; i++) {
            
            if
(!is_user_connected(players[i]))
                continue
                
            if
((= get_user_team(players[i]))) {
                
                if
((- 1) == team) {
                    if(g_MatchLastWin) client_cmd(players[i], "spk %s", SOUND_MATCHWIN)
                    else client_cmd(players[i], "spk %s", SOUND_TEAMWIN)
                }
                else if((- 1) == (team ^ 1)) {
                    if(g_MatchLastWin) client_cmd(players[i], "spk %s", SOUND_OPPONENT_MATCHWIN)
                    else client_cmd(players[i], "spk %s", SOUND_OPPONENT_WIN)
                }
            }
    
        
}
#else
        /**
         * This is not only custom songs, it behaves differently,
         * actually just like DOD there's a set of sound for each team:
         * 1) CTs win the match
         * 2) CTs win CSFlags in this map
         * 3) Ts win the match
         * 4) Ts win CSFlags in this map
         * So everybody hears one sound when the match is over,
         */
        switch(team) {
            case ID_TEAM_CT: {
                if(g_MatchLastWin) client_cmd(0, "spk %s", SOUND_MATCHWIN_CT)
                else client_cmd(0, "spk %s", SOUND_WIN_CT)        
            
}
            case ID_TEAM_T: {
                if(g_MatchLastWin) client_cmd(0, "spk %s", SOUND_MATCHWIN_T)
                else client_cmd(0, "spk %s", SOUND_WIN_T)
            }
            default: {}
        }
#endif //USE_CUSTOM_SOUNDS
    }
}

/**
 * The win hud messages can be abrutely interrupted if the round restarts.
 * This function has been designed to recover hud messages whenever it's
 * needed.
 */
public win_hud_repeat() 
{
#if defined DEBUG_MODE
    open_debug_file()
    print_stack(0, "win_hud_repeat")
    printvar_cell(0, "g_LastWinner", g_LastWinner)
    close_debug_file()
#endif

    /* last winner has been set in team_win function
       with the unique purpose to be recovered here. */
    if(g_LastWinner) {
        
        
/* repeat the hud message */
        show_win_hud(g_LastWinner)
        
        
/* resets the last winner */
        g_LastWinner = 0
        
        
/* removes hud repeat flag from game state */
        g_CSFlagsState &= ~GAMESTATE_HUDREPEAT

#if defined DEBUG_MODE
        lastFlagState = g_CSFlagsState
    
        open_debug_file
()
        print_stack(0, "win_hud_repeat(1,0)")
        printvar_cell(0, "lastwin", g_MatchLastWin)
        close_debug_file()
#endif
    }
}



/**
 * This counter function calls itself through a timer until it's
 * ready to restart the match.
 */
public restart_counter() 
{

#if defined DEBUG_MODE
    open_debug_file()
    print_stack(0, "restart_counter")
    printvar_float(0, "g_RestartTime", g_RestartTime)
    close_debug_file()
#endif

    /* not ready yet */
    if(g_RestartTime > 0.0) {
        client_print(0, print_center, "%L", LANG_PLAYER, "MSG_COUNTER", floatround(g_RestartTime))
        g_RestartTime -= 1.0
        return PLUGIN_CONTINUE
    
}
    
    
/* ready, restart it */
    remove_task(TASKID_RESTART_COUNTER)
    client_print(0, print_center, "%L", LANG_PLAYER, "MSG_RESTARTED")

#if defined DEBUG_MODE
    lastFlagState = g_CSFlagsState
    debug_gamestate
(0, "restart_counter-before")
#endif
    server_print("--- %d", g_CSFlagsState)
    g_CSFlagsState &= ~GAMESTATE_SHOWSCORE
    server_print
("--- %d", g_CSFlagsState)
    
#if defined DEBUG_MODE
    lastFlagState = g_CSFlagsState
    debug_gamestate
(0, "restart_counter-after")
#endif
    
    
/* restores players speed */
    for(new i = 1; i <= g_MaxPlayers; i++) {
        if(is_user_connected(i) && is_user_alive(i)) {
            engfunc(EngFunc_SetClientMaxspeed, i, 250.0)
            set_pev(i, pev_maxspeed, 250.0)
        }
    }
    
    g_LastWinner 
= 0 // 1.19 version - trying to fix array index out of bounds
    csflags_reset()
    csflags_restart()
    return PLUGIN_CONTINUE
}

/**
 *  forwarded in the log event it resets all
 *  csflags parameters.
 */
public event_game_commencing() 
{
    if(g_CSFlagsState & GAMESTATE_STARTED)
        csflags_reset(1, 1) 
}

/**
 *  Hooked from hltv event.
 *  - Checks if csflags was showing win scores when the round has been restarted; if so
 *    hud is displayed again.
 *  - Gets rid of hostages.
 */
public event_round_start() 
{
    /* is it showing scores? */
    if(g_CSFlagsState & GAMESTATE_SHOWSCORE ) {
        
        
/* set a hud messages being repeated in csflags status */
        g_CSFlagsState |= GAMESTATE_HUDREPEAT
        
        
/* in order to avoid bugs, sets a delay before hud is repeated*/
        set_task(0.2, "win_hud_repeat", TASKID_HUDREPEAT)
        
#if defined DEBUG_MODE
        print_comment(0, "event_round_start calls win_hut_repeat", 0, true)
        lastFlagState = g_CSFlagsState
#endif
        
    
}
    
    
/* if it's a rescue map, hostages are back - take them for a walk */
    if(get_pcvar_num(g_cvarRemoveDefObjectives) && (g_CSFlagsState & GAMESTATE_STARTED)) {
        if(engfunc(EngFunc_FindEntityByString, 32, "classname", "hostage_entity"))
            set_task(0.3, "take_for_a_walk", 2222)        
    
}
}


/**
 * While there should be a better way to
 * safely remove hostages, this is simple enough for this plugin.
 * This has been taken from an old BAILOPAN's CSDM version.
 */
public take_for_a_walk() 
{
    new hostage
    while
((hostage = engfunc(EngFunc_FindEntityByString, hostage, "classname", "hostage_entity"))) {
        new Float:origin[3] = {8191.0, 8191.0, 8191.0}
        engfunc(EngFunc_SetOrigin, hostage, origin)
    }
}

/**
 * Utilitary - removes all entities with a specific class name,
 * @param classname name of class of the entities to be removed. 
 */
remove_all_ents(const classname[]) 
{
    new flag
    while
((flag = engfunc(EngFunc_FindEntityByString, flag, "classname", classname)))
        engfunc(EngFunc_RemoveEntity, flag)
}

/**
 * Clears the radio for a user.
 * g_Radio global is used as a flag to avoid players to get spammed by radio messaged.
 */
public radio_clear(const id[1]) 
{
    g_Radio[id[0]] = 0
}

/**
 * Hides the radio icon for a player.
 */
public hide_radio_icon(const id[1]) 
{
    message_begin (MSG_ALL, 135)
    write_byte (0)
    write_byte (id[0])
    message_end ()
}

/**
 * This is called after the delay for capturing a flag has been consumed.
 * @param info a typical "set_task" target array with multiple params:
 *        0 -> the entity id of a flag
 *        1 -> then id of the toucher
 */
public flag_captured(const info[])
{
    new flag
    new toucher
    new flagid
    new team
    
    
/* gets the flag ent id */
    flag = info[0]
    
    
/* get the toucher id */
    toucher = info[1]
    
    
/* the id (index for plugin global arrays) is stored
       inside the flag, through the defined pev_csf_flagid */
    flagid = pev(flag, pev_csf_flagid)
    
    
/* the team of the "toucher" player */
    team = get_user_team(toucher)
    
    
/* if toucher's team is not CT or T, get off */
    if(team != 1 && team != 2)
        return
    
    if
(g_BotCapturing[toucher]) {
        g_BotCapturing[toucher] = false
        engfunc
(EngFunc_SetClientMaxspeed, toucher, 250.0)
        set_pev(toucher, pev_maxspeed, 250.0)
    }
    
    
/* sets the new owner of a flag */
    set_pev(flag, pev_csf_flagowner, toucher)
    
    
/* resets the flag toucher for that flag */
    set_pev(flag, pev_csf_flagtoucher, 0)
    
    
/* updates the team who's oweing that flag */
    set_pev(flag, pev_csf_flagstatus, team)
    
    
/* g_FlagsState global is used for faster score hud updating */
    g_FlagState[flagid] = team - 1                
    
    
/* clears icon for the toucher */
    msg_csf_icon(toucher, false)
    
    
/* clear the progress bar of the toucher */
    msg_bar_progress(toucher, 100, true)
    
    
/* if player frags for capturing flags cvar has been set, add it */
    if(get_pcvar_num(g_cvarCaptureFrags))
        add_user_frags(toucher, get_pcvar_num(g_cvarCaptureFrags), team)
    
    
/* sends chat and radio messages */
    notify_flag_taken(toucher, flagid)
    
    
/* flags list to be updated in next hud refresh */
    g_UpdateFlagsHud = true
    
    
/* should this match end if all flags has been taken (cvar setting)? */
    if(get_pcvar_num(g_cvarAllFlagsWin)) {
        new allflags = 1
        for
(new i = 1; i < g_MapFlagsNum; i++) {
            if(g_FlagState[i] != g_FlagState[-1]) {
                allflags = 0
                break
            
}
        }
        if(allflags) {
            new wf
            wf 
= get_pcvar_num(g_cvarWinFrags)
            if(wf)    add_user_frags(0, wf, team)                    
            team_win
(team - 1)
        }
    }
}

/**
 * Player think forward. In this version it's only used
 * with a purpose: to prevent players from moving or attacking if
 * amx_csflags_freeze has been set to 1.
 * @param id entity id of a player.
 */
public player_think(id) 
{
    /* if csflags hasn't been started, ignore it */
    if(!(g_CSFlagsState & GAMESTATE_STARTED))
        return FMRES_IGNORED
    
    
/* if it's not displaying end of round score, ignore it */
    if(!(g_CSFlagsState & GAMESTATE_SHOWSCORE)) {
        if(g_BotCapturing[id]) {
            engfunc(EngFunc_SetClientMaxspeed, id, 0.1)
            set_pev(id, pev_maxspeed, 0.1)
        }
        return FMRES_IGNORED
    
}
    
    
    
/* if it's not the end of a match, ignore it */
    if(!(g_CSFlagsState & GAMESTATE_MATCHOVER)) {
        
        
/* if user isn't alive, get off */
        if(is_user_alive(id)) {
            
            
/* if freeze cvar is set, move on */
            if(get_pcvar_num(g_cvarFreeze)) {
                
                
/* makes players freeze */
                engfunc(EngFunc_SetClientMaxspeed, id, 0.1)
                set_pev(id, pev_maxspeed, 0.1)
            }
            
            
/* blocks attacks */
            set_pev(id, pev_button, (pev(id, pev_button) & ~IN_ATTACK) & ~IN_ATTACK2) 
        
}
    }
    
    return FMRES_IGNORED
}

/**
 * Forward to update flags.
 * @param flag the flag entity
 */
public flag_think(flag) 
{    
    
/* if game is showing scores or stopped, flags won't think */    
    if
(g_CSFlagsState & (GAMESTATE_SHOWSCORE | GAMESTATE_STOPPED)) {
        
#if defined DEBUG_MODE
        if(lastFlagState != g_CSFlagsState) {
            
            open_debug_file
()
            print_stack(0, "flag_think")
            printvar_cell(0, "g_CSFlagsState & GAMESTATE_SHOWSCORE", g_CSFlagsState & GAMESTATE_SHOWSCORE)
            printvar_cell(0, "g_CSFlagsState & GAMESTATE_STOPPED", g_CSFlagsState & GAMESTATE_STOPPED)
            close_debug_file()
            lastFlagState = g_CSFlagsState
        
}
#endif

        return FMRES_IGNORED
    
}
    
    
/* pev_csf_uniqueid is used to fast check if it's a flag */
    if(pev(flag, pev_csf_uniqueid) != CSFLAG_TYPEID)
        return FMRES_IGNORED
    
    
/* flags will delay to think with this artificial but efficient next think */
    if(pev(flag, pev_think_delay) < 4) {
        set_pev(flag, pev_think_delay, pev(flag, pev_think_delay) + 1)
        return FMRES_IGNORED
    
}
    
    
/* resets the delay counter */
    set_pev(flag, pev_think_delay, 0)
    
    
/* this is thinking, variables are static so cells are previously allocated */
    static classname[32]
    static team
    static owner
    static toucher    
    
    
/* now this actually checks if it is a csflag */
    pev(flag, pev_classname, classname, 31)
    if(!equal(classname, CLASSNAME_CSFLAG))
        return FMRES_IGNORED
        
    
/* this enables to stop csflags by setting this cvar. (why here?) */
    if(!get_pcvar_flags(g_cvarDomEnabled))
        csflags_stop(0)    
    
    
/* if there's a toucher, it should have been set in touch forward */
    toucher = pev(flag, pev_csf_flagtoucher)

    if(toucher) {
        /* if toucher has died or it's not touching that flag anymore */
        if(!is_user_alive(toucher) || !is_touching(toucher, flag)) {
            /* clears the capture delay for this flag */
            if(task_exists(TASKID_CAPTUREDELAY + flag)) {
                /* removes the task */
                remove_task(TASKID_CAPTUREDELAY + flag)
                /* resets the toucher*/
                set_pev(flag, pev_csf_flagtoucher, 0)
                /* resets icon */
                msg_csf_icon(toucher, false)
                /* resets progress bar */
                msg_bar_progress(toucher, 100, true)
                
                if
(g_BotCapturing[toucher]) {
                    engfunc(EngFunc_SetClientMaxspeed, toucher, 250.0)
                    set_pev(toucher, pev_maxspeed, 250.0)
                    g_BotCapturing[toucher] = false
                
}
                
            
}
        }
        
    
}
    /* gets the team who's owning that flag */
    team = pev(flag, pev_csf_flagstatus)
    
    
/* if it's owned by a team */
    if(team) {    
        
/* gets the player who has captured this flag */
        owner = pev(flag, pev_csf_flagowner)
        
        
/* adds a score to flag owner if he/she exists (that player may have disconnected) */
        if(owner)
            g_PlayerScore[owner] += 0.04
        
        
/* if team is ct or t (being checked to be more safe) */
        if(team == 1 || team == 2) {
            
            new curScore
            
            
/* adds a score for that team */
            g_TeamScore[team - 1] += 0.04
            
            
            
            curScore 
= floatround(g_TeamScore[team - 1])
            
            if
(g_LastTeamScore[team - 1] != curScore) {
                g_UpdateScoresHud = true
                g_LastTeamScore
[team -1] = curScore
            
}
            
            
/* if max points has been reached */
            if(curScore >= floatround(get_pcvar_float(g_cvarMaxPoints))) {
                /* if it isn't tied */
                if(curScore != floatround(g_TeamScore[(team - 1) ^ 1])) {
                    /* adds a frag to team as long as frags cvar has been set */
                    new wf
                    wf 
= get_pcvar_num(g_cvarWinFrags)
                    if(wf)    add_user_frags(0, wf, team)
                    /* set this team as the match winner */
                    team_win(team - 1)
                    
                
}
            }                
        
}
    }
    return FMRES_IGNORED
}


public client_connect(id)
{
    if(is_user_bot(id)) {
        g_IsBot[id] = true
    
}
}

/**
 * Amxmodx core forward
 * This is used to make sure that:
 * - score slot for player disconnected is reset
 * - if that player owns a flag it's reset (owner only, it continues up being captured to that player's team)
 * - removes a capture delay task
 * @param id Player id.
 */
public client_disconnect(id) 
{
    new flag
    
    
/* loops all existing csflags */
    while((flag = engfunc(EngFunc_FindEntityByString, flag, "classname", CLASSNAME_CSFLAG))) {
        
        
/* if this user is the one who captured that flag, it's cleaned */
        if(pev(flag, pev_csf_flagowner) == id)
            set_pev(flag, pev_csf_flagowner, 0)
        
        
/* if this user is touching this flag, remove tasks */
        if(pev(flag, pev_csf_flagtoucher) == id) {

            if(task_exists(TASKID_CAPTUREDELAY + flag))
                remove_task(TASKID_CAPTUREDELAY + flag)
            /* resets toucher */
            set_pev(flag, pev_csf_flagtoucher, 0)
        }
    }
    /* resets that player' score */
    g_PlayerScore[id] = 0.0
    
    if
(is_user_bot(id)) {
        g_IsBot[id] = false
        g_BotCapturing
[id] = false
    
}
}

/**
 * Check's if a player is touching a csflags. This is meant to be faster
 * than engine's FindEntitiesInSphere because it requires no loops - it takes
 * some advantages of those flags+triggers specificity.
 * @param playerid id of the player
 * @param flagent the csflag entity that's touching that flag.
 */
is_touching(playerid, flagent) 
{    
    
/* this is called inside think forwards,
       variables are static for best performance */
    static Float:pl_origin[3]
    static hitbox
    static flagid

    
/* gets the hitbox of that csflag */
    hitbox = pev(flagent, pev_csf_hitbox)
    
    
/* gets the origin of the testing player */
    pev(playerid, pev_origin, pl_origin)
    
    
/* gets that flag index (for global variables) */
    flagid = pev(flagent, pev_csf_flagid)
    
    
/* checks if a player is inside that box, a 17.0 margin is added */
    if( (pl_origin[0] + 17.0 >= (g_TriggerOrigin[flagid][0] + g_mmSize[hitbox][HITBOX_MIN][0]) &&
          pl_origin[0] - 17.0 <= (g_TriggerOrigin[flagid][0] + g_mmSize[hitbox][HITBOX_MAX][0])) &&
         (pl_origin[1] + 17.0 >= (g_TriggerOrigin[flagid][1] + g_mmSize[hitbox][HITBOX_MIN][1]) &&
          pl_origin[1] - 17.0 <= (g_TriggerOrigin[flagid][1] + g_mmSize[hitbox][HITBOX_MAX][1])) &&
         (pl_origin[2] + 17.0 >= (g_TriggerOrigin[flagid][2] + g_mmSize[hitbox][HITBOX_MIN][2]) &&
          pl_origin[2] - 17.0 <= (g_TriggerOrigin[flagid][2] + g_mmSize[hitbox][HITBOX_MAX][2])))
        return 1
    
    return 0
}

/**
 * Touch forward.
 * @param ent1 toucher
 * @param ent2 touched
 */
public forward_touch(ent2, ent1) 
{
    
    
/* static variables in this forwards for best performance */
    static toucher
    static classname
[32]
    static team
    static flag
    
    
/* checks entities consistency */
    if(!pev_valid(ent1) || !pev_valid(ent2))
        return FMRES_IGNORED
    
    
/* if this is a csflag trigger and the user is alive */
    if(pev(ent2, pev_csf_uniqueid) == TRIGGERFLAG_TYPEID && is_user_alive(ent1)) {
        
        
/* It's ignored in either cases:
           - math is over
           - score is being shown
           - plugin has been stopped
         */
        if(g_CSFlagsState & (GAMESTATE_SHOWSCORE | GAMESTATE_STOPPED | GAMESTATE_MATCHOVER))
            return FMRES_IGNORED        
        
        
/* the first filter (uniqueid) was meant to discard non flag messages more quickly,
         * now it's time to make sure this is actually a csflag trigger */
        pev(ent2, pev_classname, classname, 31)                
        if
(!equal(classname, CLASSNAME_TRIGGER_FLAG))
            return FMRES_IGNORED
        
        
/* checks if that player is in a valid team */
        team = get_user_team(ent1)
        if(team < 1 || team > 2)
            return FMRES_IGNORED
            
        
/* gets the flag entity from the touched csflag trigger entity */
        flag = pev(ent2, pev_csf_flagent)
        if(!pev_valid(flag))
            return FMRES_IGNORED
        
        
/* toucher stores the id of flag previous toucher */
        toucher = pev(flag, pev_csf_flagtoucher)
        
        
/* was that being touched by someone? */
        if(toucher) {
            /* is that toucher someone else from the opposed team ? */
            if(toucher != ent1 && get_user_team(toucher) != team) {
                /* resets flag ownwer */
                set_pev(flag, pev_csf_flagtoucher, 0)

                /* if there was a capture in progress, remove it */
                if(task_exists(TASKID_CAPTUREDELAY + flag)) {
                    remove_task(TASKID_CAPTUREDELAY + flag)
                    msg_bar_progress(toucher, 100, true)
                    msg_csf_icon(toucher, false)
                    if(g_BotCapturing[toucher]) {
                        engfunc(EngFunc_SetClientMaxspeed, ent1, 250.0)
                        set_pev(toucher, pev_maxspeed, 250.0)
                        g_BotCapturing[toucher] = false
                    
}
                    
                
}
            }
        }
        
        
/* it wasn't being touched */
        else if(pev(flag, pev_csf_flagstatus) != team) {
            
            
/* avoids progress bar flicking - that's probably because
             * dimensions covered by hitboxes differ's a bit from that
             * one checked in is_touching function.
             */
            if(!is_touching(ent1, flag))
                return FMRES_IGNORED
            
            
/* updates that flag toucher */
            set_pev(flag, pev_csf_flagtoucher, ent1)
            
            if
(g_IsBot[ent1]) {
                g_BotCapturing[ent1] = true
            
}
            
            
/* displays capturing icon */
            msg_csf_icon(ent1, true)
            
            
/* sets the delay for calling capture function */
            new info[2]
            info[0] = flag
            info
[1] = ent1
            if
(task_exists(TASKID_CAPTUREDELAY + flag))
                remove_task(TASKID_CAPTUREDELAY + flag)
            
            
/* displays the progress bar */
            msg_bar_progress(ent1, 0)
            
            set_task
(get_pcvar_float(g_cvarCaptureDelay),
                 "flag_captured", TASKID_CAPTUREDELAY + flag, info, 2)
        }
        
    
}
    return FMRES_IGNORED
}

/** 
 * Displays or hides the capturing icon
 * @param id player id
 * @param show flag to show or hide that icon.
 */
msg_csf_icon(id, bool:show = true) 
{
    message_begin(MSG_ONE, g_msgidIcon, {0, 0, 0}, id)
    write_byte((show ? 1 << 1: 0))
    write_string(CSFLAGS_ICON_NAME)
    if (show) {
        write_byte(CSFLAGS_ICON_R)
        write_byte(CSFLAGS_ICON_G)
        write_byte(CSFLAGS_ICON_B)
    }
    message_end()
}

/**
 * Shows or hides the capturing progress bar.
 * @param id player id
 * @param pos current position of the progress bar
 * @param kill flag to show or hide the progress bar
 */
msg_bar_progress(id, pos, bool:kill = false)
{
    
    message_begin
(MSG_ONE, g_msgidProgress, {0, 0, 0}, id)
    write_short(kill? 0 : get_pcvar_num(g_cvarCaptureDelay))
    write_short(pos)
    message_end()
}

/** 
 * Notifies to the team that a flag has been taken
 * This consistis in a radio and chat message.
 * @param toucher id of the person who's captured that flag
 * @param flagid id of the captured flag
 */
notify_flag_taken(toucher, flagid) 
{
    new name[32]
    new toucherteam
    new sid
[4]
    new team
    new id
[1]
    //new message[93]
    //new message_op[93]
    
    g_Radio
[toucher] = 1
    id
[0] = toucher
    
    
// avoid radio spam
    set_task(4.0, "radio_clear", TASKID_RADIORANGE, id, 1) 
    
    set_task
(1.5, "hide_radio_icon", TASKID_HIDERADIOICON, id, 1)
    
    toucherteam 
= get_user_team(toucher)
    get_user_name(toucher, name, 31)
    
    num_to_str
(toucher, sid, 3)
    //format(message, 92,  "%L", LANG_PLAYER, "MSG_FLAGSTATE_NOTIFY", name, floatround(g_PlayerScore[toucher]), g_PlaceNames[flagid], (toucherteam == 2) ? (TEAM_DESC_CT) : TEAM_DESC_T)//g_Teams[g_FlagState[flagid]])
    //format(message_op, 92, "%L", LANG_PLAYER, "MSG_FLAGSTATE_NOTIFY_OP", name, floatround(g_PlayerScore[toucher]), g_PlaceNames[flagid], (toucherteam == 2) ? (TEAM_DESC_CT) : TEAM_DESC_T)
    
    if
(g_ifw_FlagTaken) {
        new retval
        ExecuteForward
(g_ifw_FlagTaken, retval, toucher)
    }
    
    for
(new i = 1; i <= g_MaxPlayers; i++) {
        
        if
(!is_user_connected(i))
            continue
        
        team 
= get_user_team(i)
        
        if
(get_pcvar_num(g_cvarUseRadio) && (team == 1 || team == 2)) {
            if(team == toucherteam) {
                
                message_begin
(MSG_ONE_UNRELIABLE, 77, _,i)
                                    
                if 
(is_running("czero")) {                    
                    write_byte 
(5)
                    write_string (sid) 
                    write_string 
("#Game_radio_location")
                    write_string (name)
                    write_string (g_PlaceNames[flagid])                
                
}
                else {
                    write_byte (3)
                    write_string ("#Game_radio")
                    write_string (name)
                }
                
                write_string
(MSG_RADIO_POINTSECURED)
                message_end()
                
                message_begin 
(MSG_ONE, 135, _, i)
                write_byte (1)
                write_byte (toucher)
                message_end ()
                
                client_cmd
(i, "spk %s", SOUND_FLAGTAKEN)
                client_cmd(i, "spk %s", g_NotifySound[team - 1])
                //send_chat_msg(i, message)
                ml_client_print(i, "%L", LANG_PLAYER_C, "MSG_FLAGSTATE_NOTIFY", name, floatround(g_PlayerScore[toucher]), g_PlaceNames[flagid], (toucherteam == 2) ? (TEAM_DESC_CT) : TEAM_DESC_T)
            }
            
            else  
{
                if((team - 1) == ((toucherteam - 1) ^ 1))
                    client_cmd(i, "spk %s", SOUND_OPPONENT_FLAGTAKEN)
                ml_client_print(i, "%L", LANG_PLAYER_C, "MSG_FLAGSTATE_NOTIFY_OP", name, floatround(g_PlayerScore[toucher]), g_PlaceNames[flagid], (toucherteam == 2) ? (TEAM_DESC_CT) : TEAM_DESC_T)
            }            
            
        
}
        
    
}
}

// this is gungame_print by Avalanche
// with some tiny modifications.
// I only changed the function name
// because it's not gungame :P. Still
// all solution were provided by his code.
// and I couldn't have figured out anything
// better.
ml_client_print(id, msg[],any:...)
{
    new changeCount, num, i, j, argnum = numargs(), player
    static newMsg
[191], message[191], changed[8], players[32]

    if(id) {
        players[0] = id
        num 
= 1
    
}
    else get_players(players, num)

    for(= 0; i < num; i++) {
        
        player 
= players[i]
        changeCount = 0
        
        if
(!is_user_connected(player)) continue

        
// [Avalanche's comments] we have to change LANG_PLAYER into
        // a player-specific argument, because
        // ML doesn't work well with SayText
        for(= 2;< argnum;j++) {
            if(getarg(j) == LANG_PLAYER_C) {
                setarg(j,0,player);
                changed[changeCount++] = j
            
}
        }

        // [Avalanche's comments] do user formatting
        vformat(newMsg,190,msg,3);
        
        
// [Avalanche's comments] and now we have to change what we changed
        // back into LANG_PLAYER, so that the next
        // player will be able to have it in his language
        for(j=0;j<changeCount;j++) {
            setarg(changed[j],0,LANG_PLAYER_C);
        }

        // [Avalanche's comments] optimized color swapping
        replace_all(newMsg,190,"%n","^x03") // %n = team color
        replace_all(newMsg,190,"%g","^x04") // %g = green
        replace_all(newMsg,190,"%e","^x01") // %e = regular
        

        
// [Avalanche's comments] now do our formatting (I used two variables because sharing one caused glitches)
        formatex(message,190,"^x01%s",newMsg)

        message_begin(MSG_ONE, g_msgidSayText, _, player)
        write_byte(player)
        write_string(message)
        message_end()
    }
    
    return 1
}


/*send_chat_msg(id, msg[])
{    
    if(!is_user_connected(id))
        return
    message_begin(MSG_ONE, g_msgidSayText, {0,0,0}, id)
    write_byte(id)
    write_string(msg)
    message_end()    
}*/

move_to_spawn()
{
    new ctspawn
    new tspawn
    new spawn
    new players
[32]
    new playersnum
    new team
    new Float
:vec[3]
    new bool:restore
    
    restore 
= (get_pcvar_num(g_cvarMatchRespawn) == 2)    
    get_players
(players, playersnum)
    
    for
(new i = 0; i < playersnum; i++) {
        spawn = 0
        
        if
(players[i] && is_user_alive(players[i])) {
            team = get_user_team(players[i])
            switch(team) {
                case 1 : {
                    if(tspawn == -1)
                        continue
                    tspawn 
= engfunc(EngFunc_FindEntityByString, 
                             tspawn
,
                             "classname",
                             "info_player_deathmatch")
                    spawn = tspawn
                    if
(!tspawn)
                        tspawn = -1
                
}
                case 2 : {
                    if(ctspawn == -1)
                        continue
                    ctspawn 
= engfunc(EngFunc_FindEntityByString,
                              ctspawn,
                              "classname",
                              "info_player_start")
                    spawn = ctspawn
                    if
(!ctspawn)
                        ctspawn = -1
                
}                
            
}
            if(spawn) {
                
                pev
(spawn, pev_origin, vec)
                engfunc(EngFunc_SetOrigin, players[i], vec)
                set_pev(players[i], pev_fixangle, 1)
                pev(spawn, pev_angles, vec)
                set_pev(players[i], pev_angles, vec)
                
                if
(restore)
                    set_pev(players[i], pev_health, 100.0)
            }
        }
        
    
}    
    
}

public update_score() 
{    
    
    static headerCT
[25]
    static headerT[25]
    
    static flagsTakenT
[HUD_FLAGS_STRING_MAXSIZE]
    static flagsTakenCT[HUD_FLAGS_STRING_MAXSIZE]
    
    
    static scoreCT
[25 + HUD_FLAGS_STRING_MAXSIZE]
    static scoreT[25 + HUD_FLAGS_STRING_MAXSIZE]
    
    new ind
    
    
// updates scores
    if(g_UpdateScoresHud) {
        formatex(headerT, 30, g_ScoreHeaderFormat[ID_TEAM_T], g_TeamWins[ID_TEAM_T], floatround(g_TeamScore[ID_TEAM_T]))
        formatex(headerCT, 30, g_ScoreHeaderFormat[ID_TEAM_CT], g_TeamWins[ID_TEAM_CT], floatround(g_TeamScore[ID_TEAM_CT]))
    }
    
    
// updates flags list
    if(g_UpdateFlagsHud) {
        
        new flagsTakenCTLen
        new flagsTakenTLen
        flagsTakenT
[0] = 0
        flagsTakenCT
[0] = 0
        
        for
(ind = 0; ind < MAX_CSFLAGS; ind++) {
            
            if
(g_FlagState[ind] == 1) {
                flagsTakenCTLen += format(flagsTakenCT[flagsTakenCTLen], 
                                HUD_FLAGS_STRING_MAXSIZE 
- flagsTakenCTLen,
                                "^n%s", g_PlaceNames[ind])
            } 
            else if
(g_FlagState[ind] == 0) {
                flagsTakenTLen += format(flagsTakenT[flagsTakenTLen], 
                               HUD_FLAGS_STRING_MAXSIZE 
- flagsTakenTLen,
                               "^n%s", g_PlaceNames[ind])
            }
            
        
}
    }
    
    
// only reformat if there was an update
    if(g_UpdateFlagsHud || g_UpdateScoresHud) {
        formatex(scoreCT, 24 + HUD_FLAGS_STRING_MAXSIZE, "%s%s", headerCT, flagsTakenCT)
        formatex(scoreT, 24 + HUD_FLAGS_STRING_MAXSIZE, "%s%s", headerT, flagsTakenT)
    }
    
    
// clean updates
    g_UpdateFlagsHud = false
    g_UpdateScoresHud 
= false
    
    
// send hud messages
    for(ind = 1; ind <= g_MaxPlayers; ind++) {
        if(is_user_connected(ind)) {
            if(is_user_alive(ind)) {    
                set_hudmessage
(255, 0, 0, 0.3, 0.0, 0, 6.0, INTERVAL_SCORE_UPDATE, 0.1, 0.2, 3)
                show_hudmessage(ind, scoreT)
                set_hudmessage(ind, 0, 255, 0.6, 0.0, 0, 6.0, INTERVAL_SCORE_UPDATE, 0.1, 0.2, 4)
                show_hudmessage(ind, scoreCT)
            }
            else {
                set_hudmessage(255, 0, 0, 0.3, 0.17, 0, 6.0, INTERVAL_SCORE_UPDATE, 0.1, 0.2, 3)
                show_hudmessage(ind, scoreT)
                set_hudmessage(ind, 0, 255, 0.6, 0.17, 0, 6.0, INTERVAL_SCORE_UPDATE, 0.1, 0.2, 4)
                show_hudmessage(ind, scoreCT)
            }
        }            
    
}
}

remove_default_objectives() 
{
    new objectives[6][] = {
        "func_bomb_target",
        "info_bomb_target",
        "info_hostage_rescue",
        "func_hostage_rescue",
        "func_vip_safetyzone",
        "func_escapezone"
    }
    for(new i = 0; i < 6; i++)
        remove_all_ents(objectives[i])
}
        
add_user_frags
(id, value, team)
{
    /*
     * Taken from VEN's CTF,
     * modified to fit this plugin
     */
    
    new Float
:frags
    new players
[32]
    new playersnum
    static const fnTeamFilter
[3][] = { "", "TERRORIST", "CT" }
    
    if
(id) {
        playersnum = 1
        players
[0] = id
    
}
    else {
        if(team > 0 && team < 2)
            get_players(players, playersnum, "e",  fnTeamFilter[team])
        
        
/*new tstr[16]
        if(team == (ID_TEAM_T + 1))
            formatex(tstr, 15, "TERRORIST")
        else if(team == (ID_TEAM_CT + 1))
            formatex(tstr, 15, "CT")
        get_players(players, playersnum, "e",  tstr)*/
    }    
    
    for
(new i = 0; i < playersnum; i++) {
        pev(players[i], pev_frags, frags)
        frags += value
        set_pev
(players[i], pev_frags, frags)
        
        message_begin
(MSG_ALL, g_msgidScoreInfo)
        write_byte(players[i])
        write_short(floatround(frags))
        write_short(CS_GET_USER_DEATHS_(players[i]))
        write_short(0)
        write_short(team)
        message_end()
    }    
    
}
        
load_config
() 
{
    new file[72]
    
    if
(get_configfile(file, 71)) {
        new numbers[5][6]
        new Float:origin[3]
        new Float:angle[3]
        new line[96]        
        new arg1
[16]
        new arg2[80]
        new hitbox
        new count        
        new flag
        new trigger
        new filepointer
        
        filepointer 
= fopen(file, "r")
        
        while
(fgets(filepointer, line, 95) && count < MAX_CSFLAGS) {
            if(!strlen(line) || line[0] == ';')
                continue
            parse
(line, arg1, 15, arg2, 79)
            
            if
(!strlen(arg2))
                continue
                
            if
(strlen(arg1))
                copy(g_PlaceNames[count], 15, arg1)
            else
                formatex
(g_PlaceNames[count], 15, "Flag[%d]", count)
            
            parse    
(arg2, 
                numbers
[0], 5,
                numbers[1], 5,
                numbers[2], 5,
                numbers[3], 5,
                numbers[4], 5)
                
            origin
[0] = str_to_float(numbers[0])
            origin[1] = str_to_float(numbers[1])
            origin[2] = str_to_float(numbers[2])
            angle[1] = str_to_float(numbers[3])
            hitbox = str_to_num(numbers[4])
            engfunc(EngFunc_MakeVectors, angle)
            
            flag 
= engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "cycler_sprite"))
            
            if
(pev_valid(flag)) {
                engfunc(EngFunc_SetOrigin, flag, origin)                
                set_pev
(flag, pev_model, MODEL_FLAGS)
                set_pev(flag, pev_framerate, 1.0)
                dllfunc(DLLFunc_Spawn, flag)                
                set_pev
(flag, pev_classname, CLASSNAME_CSFLAG)
                set_pev(flag, pev_angles, angle)
                set_pev(flag, pev_csf_uniqueid, CSFLAG_TYPEID)            
                set_pev
(flag, pev_csf_flagid, count)
                set_pev(flag, pev_csf_hitbox, hitbox)
                
                trigger 
= engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "trigger_multiple"))
                
                if
(pev_valid(trigger)) {
                    origin[2] += 48.0
                    engfunc
(EngFunc_SetOrigin, trigger, origin)                    
                    dllfunc
(DLLFunc_Spawn, trigger)
                    engfunc(EngFunc_SetSize, trigger, g_mmSize[hitbox][HITBOX_MIN], g_mmSize[hitbox][HITBOX_MAX])
                    set_pev(trigger, pev_csf_uniqueid, TRIGGERFLAG_TYPEID)
                    set_pev(trigger, pev_classname, CLASSNAME_TRIGGER_FLAG)
                    set_pev(trigger, pev_csf_flagent, flag)
                    set_pev(trigger, pev_csf_flagid, count)
                    set_pev(flag, pev_csf_trigger, trigger)
                    
                    
                    g_TriggerOrigin
[count][0] = origin[0]
                    g_TriggerOrigin[count][1] = origin[1]
                    g_TriggerOrigin[count][2] = origin[2]                    
                
}
                else {
                    fclose(filepointer)
                    return 0
                
}
                if(count < MAX_CSFLAGS)
                    count++
            }
            else {
                fclose(filepointer)
                return 0
            
}
            flag = 0
            trigger 
= 0            
        
}
        fclose(filepointer)
        
        if
(count) {
            g_MapFlagsNum = count
            return 1
        
}
        else
            return 0
    
}
    return 0
}

get_configfile(file[], len) 
{
    new map[36]
    
    get_mapname
(map, 35)
    get_configsdir(file, len)
    format(file[strlen(file)], len - strlen(file), FILE_DOMCFG, map)
    
    return file_exists
(file)
}

// map time functions


/**
 * This is called when a csflags match is over, it's meant
 * to shorten the map left time to an acceptable time - to
 * do the voting maps or whatever. This delay is defined in
 * "amx_csflags_mapendtime" cvar.
 */
public force_end() 
{

#if defined DEBUG_MODE
    open_debug_file()
    print_stack(0, "server_changelevel")
#endif

    new Float:mplimit    // stores the current mp_timelimit
    mplimit = get_cvar_float("mp_timelimit")
    
    
// I don't remember why the number of players was relevant
    // it make some sense anyway.
    if (get_playersnum() && mplimit != 0.0) {

        new Float:newlimit
        
        
// calculates the new limit
        newlimit = mplimit - float(get_timeleft() / 60) + get_pcvar_float(g_cvarMapEndTime)
        
        
// flags game state so mp_timelimit can be recovered before the
        // level changes
        g_CSFlagsState |= GAMESTATE_FORCEDEND
        
        
// stores the old mp_timelimit into the global 
        g_OldMPTime = mplimit
        
        
// attempts to launch a voting system
        // (if it's been defined)
        start_vote_cmd(0.0)
        
        
// sets the new mp_time limit
        server_cmd("mp_timelimit %f", newlimit)        
        client_print
(0,print_chat,"%s %s", MSG_HEADER, "%L", LANG_PLAYER, "MSG_CHANGEMAP_DELAY")

#if defined DEBUG_MODE
        printvar_float(0, "mplimit", mplimit)
        printvar_float(0, "newlimit", newlimit)
        close_debug_file()
#endif

    }
}

/**
 * Change level forward
 */
public server_changelevel(map[]) 
{
    
#if defined DEBUG_MODE
    open_debug_file()
    print_stack(0, "server_changelevel")
#endif
    
    
// checks if one of these situations is true so an previously saved mp_timelimit must be restored:
    // 1) the match was over, it's been given some delay but now it's time to go
    // 2) there wasn't a winner, now it came up
    if((g_CSFlagsState & GAMESTATE_FORCEDEND || g_CSFlagsState & GAMESTATE_WAIT) && g_OldMPTime) {
        
        if 
(get_cvar_num("mp_timelimit") == get_pcvar_num(g_cvarMapEndTime)) {
            // restores the original value
            server_cmd("mp_timelimit %d", g_OldMPTime)

#if defined DEBUG_MODE
        print_comment(0, "setting mp_timelimit to g_OldMPTime", 1)
#endif
             
            
        
}
    }
#if defined DEBUG_MODE
    close_debug_file()
#endif
}

/**
 *  Checks if game end should be delayed because csflags match isn't over.
 *  This is called when it's missing 11 seconds to change level process.
 *  The amxmodx count down starts at 10, so that's why it's 11. 
 */
public set_mapend_mptimelimit() 
{    
#if defined DEBUG_MODE
    open_debug_file()
    print_stack(0, "set_mapend_mplimit")
#endif
    
    
// confusing part; if statement was nested like that so
    // I could still have debug messages
    //
    // here's the first "if" description in the order statements are placed:
    // 1) csflags must have been started --> ok
    // 2) any of these case are true: 
    //    a) level being forced to end because of csflags match is over
    //    b) csflags match over
    //    c) csflags match is delaying the map time because it's waiting for a winner
    // 3) there are players (why am I checking this?)
    // 4) OldMPTime must not be set, added in 1.93
    // 5) the server has a level time limit --> would this function get called if not?
    // 6) what? why would that be disabled now?
    if( (g_CSFlagsState & GAMESTATE_STARTED) &&
        !(g_CSFlagsState & (GAMESTATE_FORCEDEND | GAMESTATE_MATCHOVER | GAMESTATE_WAIT)) &&
         get_playersnum() &&
         g_OldMPTime == 0.0 &&
         get_cvar_float("mp_timelimit") != 0.0 &&
         get_pcvar_num(g_cvarDomEnabled)) {        
         
        
// it doesn't allow tied matches
        if(!get_pcvar_num(g_cvarTieMatch)) {            
            
            
// checks csflags match isn't over
            if(!map_should_end()) {
                
                
// flags it to wait
                g_CSFlagsState |= GAMESTATE_WAIT
                
                
// stores the current mp_timelimit
                g_OldMPTime = get_cvar_float("mp_timelimit")
                
                
// set time limit to infinite
                server_cmd("mp_timelimit 0")
                
                
// removing this task
                remove_task(TASKID_MAPEND) // <-- added in 1.93
                
                
// attempts to launch a voting system
                // (if it's been defined)
                start_vote_cmd(0.0)

#if defined DEBUG_MODE
                print_comment(0, "waiting for a winner", 1)
                print_comment(0, "mp_timelimit = 0, gamestate |= GAMESTATE_WAIT", 1)
                printvar_float(0, "g_OldMPTime", g_OldMPTime)
#endif

                client_print(0, print_chat, "%L %L", LANG_PLAYER, "MSG_HEADER", LANG_PLAYER, "MSG_TIME_OVER")
            
            
}

#if defined DEBUG_MODE
            else
                print_comment
(0, "map_should_end returned 1, won't mess with time")
#endif
        }

#if defined DEBUG_MODE
        else
            print_comment
(0, "Tie match enabled, won't mess with time", 1) 
#endif

    }

#if defined DEBUG_MODE
    else {
        print_comment(0, "At least one of these statements failed:", 1)
        printvar_cell(0, "g_CSFlagsState & GAMESTATE_STARTED", g_CSFlagsState & GAMESTATE_STARTED)
        printvar_cell(0, "!(g_CSFlagsState & GAMESTATE_FORCEDEND", !(g_CSFlagsState & GAMESTATE_FORCEDEND))
        printvar_cell(0, "!(g_CSFlagsState & GAMESTATE_MATCHOVER)", !(g_CSFlagsState & GAMESTATE_MATCHOVER))
        printvar_cell(0, "!(g_CSFlagsState & GAMESTATE_WAIT)", !(g_CSFlagsState & GAMESTATE_WAIT))
        printvar_cell(0, "get_playersnum()", get_playersnum())
        printvar_cell(0, "get_cvar_float(^"mp_timelimit^") != 0.0", get_cvar_float("mp_timelimit") != 0.0)
        printvar_cell(0, "get_playersnum()", get_playersnum())
        printvar_cell(0, "get_pcvar_num(g_cvarDomEnabled)", get_pcvar_num(g_cvarDomEnabled))
        
    
}
    close_debug_file()
#endif
}

/**
 * Analyzes if there's a reason a map should end or not.
 * This functions doesn't consider the tie match configuration
 * in cvar for making the assertion.
 * @return 0 for negative, 1 for affirmative.
 */
map_should_end() 
{
    new maxwins = get_pcvar_num(g_cvarMaxWins)
    
    new tscore 
= g_TeamWins[ID_TEAM_T]
    new ctscore = g_TeamWins[ID_TEAM_CT]
    
    
// 1) max wins must be a relevant condition (cvar)
    // 2) max wins must have been reached
    // 3) match must not be tied
    if((maxwins) ? (maxwins > ctscore && maxwins > tscore) || tscore == ctscore : tscore == ctscore)
        return 0
        
    return 1
}

public restore_mptimelimit() 
{
#if defined DEBUG_MODE
    open_debug_file()
    print_stack(0, "restore_mplimit")
    printvar_float(0, "g_OldMPTime", g_OldMPTime)
    printvar_cell(0, "get_cvar_num(^"mp_timelimit^")", get_cvar_num("mp_timelimit"))
    close_debug_file()
#endif

    g_CSFlagsState = GAMESTATE_STOPPED    
    if 
(get_cvar_num("mp_timelimit") == 0)
        server_cmd("mp_timelimit %f", g_OldMPTime)
}


// ---------------------------------------------------------------------------------------
// Debug tools

#if defined DEBUG_TOOLS

#define DEBUG_LINE 160

#define PRINT_MSG1(%1,%2,%3) format(debugMsg, 127, %2, %3); debug_print(%1, debugMsg)
#define PRINT_MSG2(%1,%2,%3,%4) format(debugMsg, 127, %2, %3, %4); debug_print(%1, debugMsg)
#define PRINT_MSG3(%1,%2,%3,%4,%5) format(debugMsg, 127, %2, %3, %4, %5); debug_print(%1, debugMsg)



public debug_gamestate(id, stack[])
{
    open_debug_file()
    
    if
(stack[0]) 
        print_stack
(id, stack)
    else
        print_stack
(id)
    
    print_debug_cmd
(id, "Game State tracing")
    
    PRINT_MSG1
(id, "GAMESTATE_STARTED: %d", g_CSFlagsState & GAMESTATE_STARTED ? 1 : 0)
    PRINT_MSG1(id, "GAMESTATE_FORCEDEND: %d", g_CSFlagsState & GAMESTATE_FORCEDEND ? 1 : 0)
    PRINT_MSG1(id, "GAMESTATE_HUDREPEAT: %d", g_CSFlagsState & GAMESTATE_HUDREPEAT ? 1 : 0)
    PRINT_MSG1(id, "GAMESTATE_MATCHOVER: %d", g_CSFlagsState & GAMESTATE_MATCHOVER ? 1 : 0)
    PRINT_MSG1(id, "GAMESTATE_SHOWSCORE: %d", g_CSFlagsState & GAMESTATE_SHOWSCORE ? 1 : 0)
    PRINT_MSG1(id, "GAMESTATE_STOPPED: %d", g_CSFlagsState & GAMESTATE_STOPPED ? 1 : 0)
    PRINT_MSG1(id, "GAMESTATE_WAIT: %d", g_CSFlagsState & GAMESTATE_WAIT ? 1 : 0)
    
    close_debug_file
()
}


open_debug_file()
{
#if defined DEBUG_FILE
    if(!pDebugFile)
        pDebugFile = fopen(DEBUG_FILE, "a+")
#endif
}
close_debug_file() {
#if defined DEBUG_FILE
    if(pDebugFile) {
        fclose(pDebugFile)
        pDebugFile = 0
    
}
#endif
}
    

public debug_flags
(id, stack[])
{
    new flag
    new trigger
    new Float
:vector[3]
    new count
    
    open_debug_file
()
    
    if
(!stack[0]) 
        print_stack
(id, stack)
    else
        print_stack
(id)
    
    print_debug_cmd
(id, "Flags Tracing")
    
    while
((flag = engfunc(EngFunc_FindEntityByString, flag, "classname", CLASSNAME_CSFLAG))) {
        
        PRINT_MSG2
(id, "***^nflagent: %d, flagid: %d", flag, pev(flag, pev_csf_flagid))
        PRINT_MSG1(id, "Flag name: %s", g_PlaceNames[pev(flag, pev_csf_flagid)])
        
        pev
(flag, pev_origin, vector)
        PRINT_MSG3(id, "Origin: %f %f %f", vector[0], vector[1], vector[2])
        
        pev
(flag, pev_angles, vector)
        PRINT_MSG3(id, "Angles: %f %f %f", vector[0], vector[1], vector[2])
        
        PRINT_MSG1
(id, "Hitbox: %d", pev(flag, pev_csf_hitbox))
        PRINT_MSG1(id, "Owner: %d", pev(flag, pev_csf_flagowner))
        PRINT_MSG1(id, "Toucher: %d", pev(flag, pev_csf_flagtoucher))
        PRINT_MSG1(id, "Status: %d", pev(flag, pev_csf_flagstatus))
        PRINT_MSG1(id, "typeid: %d", pev(flag, pev_csf_uniqueid))    
        
        trigger 
= pev(flag, pev_csf_trigger)
        PRINT_MSG1(id, "Flag trigger:", trigger)
        
        if
(pev_valid(trigger)) {
            pev(trigger, pev_origin, vector)
            PRINT_MSG3(id, "^tOrigin: %f %f %f", vector[0], vector[1], vector[2])
            
            pev
(trigger, pev_maxs, vector)
            PRINT_MSG3(id, "^tMaxs(size): %f %f %f", vector[0], vector[1], vector[2])
            
            pev
(trigger, pev_mins, vector)
            PRINT_MSG3(id, "^tMins(size): %f %f %f", vector[0], vector[1], vector[2])            
            
            PRINT_MSG1
(id, "^tflagid(ref): %d", pev(trigger, pev_csf_flagid))
            PRINT_MSG1(id, "^tflagent(ref): %d", pev(trigger, pev_csf_flagent))
            PRINT_MSG1(id, "^ttypeid: %d", pev(trigger, pev_csf_uniqueid))            
        
}
        else
            debug_print
(id, "^t[invalid trigger entity]")
        
        count
++
        
    
}
    
    PRINT_MSG1
(id, "--- Found %d flags", count)
    
    close_debug_file
()
}

debug_print(id, const msg[])
{
    if(id)
        console_print(id, msg)
    else
        server_print
(msg)
    
#if defined DEBUG_FILE
    if(pDebugFile) {
        fputs(pDebugFile, msg)
        fputs(pDebugFile, "^n")
    }
#endif // DEBUG_FILE
}

print_debug_cmd(id, cmd[])
{
    PRINT_MSG3(id, "%s^n%s CMD: %s", debugLine, debugHeader, cmd)
}

print_stack(id, stack[] = "Unknown", bool:opendfile = false)
{
    if(opendfile)
        open_debug_file()
    
    PRINT_MSG2
(id, "^n%s Stack on %s", debugHeader, stack)
    
    if
(opendfile)
        close_debug_file()
}

stock printvar_cell(id, const varname[], value)
{
    PRINT_MSG2(id, "^t[cell] %s = %d", varname, value)
}

stock printvar_float(id, const varname[], Float:value)
{
    PRINT_MSG2(id, "^t[float] %s = %f", varname, value)
}

stock printvar_string(id, const varname[], const value[])
{
    PRINT_MSG2(id, "^t[string] %s = %s", varname, value)
}

stock printvar_cell_array(id, const varname[], const array[], length)
{
    PRINT_MSG1(id, "^t[array] %s", varname)
    for(new i; i < length; i++)
        PRINT_MSG2(id, "^t^t[%d] = %d", array[i])  
}

stock printvar_float_array(id, const varname[], const Float:array[], length)
{
    PRINT_MSG1(id, "^t[array] %s", varname)
    for(new i; i < length; i++)
        PRINT_MSG2(id, "^t^t[%d] = %f", array[i])  
}

stock printvar_string_array(id, const varname[], const array[][], length)
{
    PRINT_MSG1(id, "^t[array] %s", varname)
    for(new i; i < length; i++)
        PRINT_MSG2(id, "^t^t[%d] = %s", array[i])  
}

stock print_comment(id, const comment[], tabnum = 0, bool:opendfile = false)
{
    new fmt[180]
    
    new len
    
    
// why am I doing this?
    if(tabnum >= 16)
        tabnum = 15
    
    len 
= format(fmt, tabnum, Tabs)
    len += format(fmt, 179, "** %s", comment)
    
    if
(opendfile)
        open_debug_file()
    
    debug_print
(id, fmt)
    
    if
(opendfile)
        close_debug_file()
}

#endif // DEBUG_TOOLS

Связь Вы должны зарегистрироваться, чтобы видеть ссылки.
Аватара пользователя
baisaganov
 
Сообщения: 10
Зарегистрирован: 21 июн 2017, 22:46
Благодарил (а): 1 раз.
Поблагодарили: 0 раз.
Языки программирования: Pawn
SourcePawn
C++
Php
Ruby
Python
C#

Вернуться в Поиск исполнителей / заказчиков

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6

cron