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

csflags после рестарта на ножах  [Решено]

Все вопросы по работе и настройке AMXX и его плагинов.

Модератор: liFe iS GoOD

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

В данном разделе форума разрешено создавать темы, касающие только вопросов по AMX Mod X и его плагинам.

csflags после рестарта на ножах  [Решено]

Сообщение Don Corleone » 26 дек 2017, 19:01

Здравствуйте, подскажите как в плагине csflags, когда одна команда собрала все флажки, то идет рестарт N секунд и в этот время противника нельзя убить, а нужно сделать чтобы в этом момент только можно было на ножах сражаться

Код: Выделить всё
#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][] =
{
    
"Terrorists(%d) : %d",
    
"CTs(%d) : %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""3")
    
g_cvarMaxPoints register_cvar("amx_csflags_max_points""100")
    
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""1")
    
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(mapname31)
    
    
open_debug_file()
    
formatex(msg127"***^nStarting Debug Section^nMap: %s^n***"mapname)
    
debug_print(0msg)
    
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 
04i++) {
        
formatex(cursound71"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"idcursound)
    }
#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_FLAGTAKENET_IGNOREFP_CELL)    // toucher
    
g_ifw_MatchWon CreateMultiForward(IFW_MATCHWONET_IGNOREFP_CELL)    // team winner
    
g_ifw_RoundWon CreateMultiForward(IFW_ROUNDWONET_IGNOREFP_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 0players 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_FindEntityByStringflag"classname"CLASSNAME_CSFLAG))) {
        
        
set_pev(flagpev_csf_flagstatus0)
        
set_pev(flagpev_csf_flagowner0)        
        
        if(
task_exists(TASKID_CAPTUREDELAY flag))
            
remove_task(TASKID_CAPTUREDELAY flag)

        
set_pev(flagpev_csf_flagtoucher0)
    }
    
    
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 
133i++)
            
g_PlayerScore[i] = 0.0
    
}
    
    for(new 
0MAX_CSFLAGSi++)
        
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_FLAGTAKENET_IGNOREFP_CELL)    // toucher
    
if(!g_ifw_MatchWon)
        
g_ifw_MatchWon CreateMultiForward(IFW_MATCHWONET_IGNOREFP_CELL)    // team winner
    
if(!g_ifw_RoundWon)
        
g_ifw_RoundWon CreateMultiForward(IFW_ROUNDWONET_IGNOREFP_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_cvarVoteStartCommandcheckstr1)
    
    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_cvarVoteStartCommandvoteCommand63)
    
server_cmd(voteCommand)
}

/**
 *  This function is called by the command "amx_csflags_restart",
 *  forces game to reset, stop and start.
 */
public csflags_restart_cmd(idlevelcid
{
    if(!
cmd_access(idlevelcid0))
        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(idlevelcid
{
    if(!
cmd_access(idlevelcid0))
        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_FindEntityByStringflag"classname"CLASSNAME_CSFLAG))) {
        new 
toucher
        
        toucher 
pev(flagpev_csf_flagtoucher)
        if(
toucher) {
            
set_pev(flagpev_csf_flagtoucher0)

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

            
msg_csf_icon(toucherfalse)
            
msg_bar_progress(toucher100true)
        }
    }
    
    
    
    
/* updates plugin status */
    
g_CSFlagsState |= GAMESTATE_SHOWSCORE
    
    
    
/* executes "csf_round_won" forward */
    
if(g_ifw_RoundWon) {
        new 
retval
        ExecuteForward
(g_ifw_RoundWonretvalteam 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_MatchWonretvalteam 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(playersplayersnum)
        for(new 
0playersnumi++) {            
            for(new 
05p++) {
                
currentscore g_PlayerScore[players[i]]
                if(
currentscore == 0.0)
                    continue
                if(
currentscore score[p]) {
                    for(new 
4&& 0q--) {
                        
score[q] = score[1]
                        
bestplayer[q] = bestplayer[1]
                    }                
                    
score[p] = currentscore
                    bestplayer
[p] = players[i]
                    
count++
                    break
                }
            }
        }
        
count = (count 5) ? count
    
}
    
    
/* adds a message header */
    
len format(message100"%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 
0counti++) {
        
get_user_name(bestplayer[i], name31)
        
len += format(message[len], 255 len"^n%s - %d"namefloatround(g_PlayerScore[bestplayer[i]]))        
    }
    
    
/* send'em to the hud */
    
set_hudmessage (25540200.100.3000.110.00.00.03)
    
show_hudmessage(0message)
    
    
/* 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 35.0
            set_task
(1.0"restart_counter"TASKID_RESTART_COUNTER__"b")
        }
        
            
#if !defined USE_CUSTOM_SOUNDS
        
        
new t
        
for(new 0playersnumi++) {
            
            if(!
is_user_connected(players[i]))
                continue
                
            if((
get_user_team(players[i]))) {
                
                if((
1) == team) {
                    if(
g_MatchLastWinclient_cmd(players[i], "spk %s"SOUND_MATCHWIN)
                    else 
client_cmd(players[i], "spk %s"SOUND_TEAMWIN)
                }
                else if((
1) == (team 1)) {
                    if(
g_MatchLastWinclient_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_MatchLastWinclient_cmd(0"spk %s"SOUND_MATCHWIN_CT)
                else 
client_cmd(0"spk %s"SOUND_WIN_CT)        
            }
            case 
ID_TEAM_T: {
                if(
g_MatchLastWinclient_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(0print_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(0print_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 1<= g_MaxPlayersi++) {
        if(
is_user_connected(i) && is_user_alive(i)) {
            
engfunc(EngFunc_SetClientMaxspeedi250.0)
            
set_pev(ipev_maxspeed250.0)
        }
    }
    
    
g_LastWinner // 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(11
}

/**
 *  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"0true)
        
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_FindEntityByString32"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_FindEntityByStringhostage"classname""hostage_entity"))) {
        new 
Float:origin[3] = {8191.08191.08191.0}
        
engfunc(EngFunc_SetOriginhostageorigin)
    }
}

/**
 * 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_FindEntityByStringflag"classname"classname)))
        
engfunc(EngFunc_RemoveEntityflag)
}

/**
 * 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_ALL135)
    
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(flagpev_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 != && team != 2)
        return
    
    if(
g_BotCapturing[toucher]) {
        
g_BotCapturing[toucher] = false
        engfunc
(EngFunc_SetClientMaxspeedtoucher250.0)
        
set_pev(toucherpev_maxspeed250.0)
    }
    
    
/* sets the new owner of a flag */
    
set_pev(flagpev_csf_flagownertoucher)
    
    
/* resets the flag toucher for that flag */
    
set_pev(flagpev_csf_flagtoucher0)
    
    
/* updates the team who's oweing that flag */
    
set_pev(flagpev_csf_flagstatusteam)
    
    
/* g_FlagsState global is used for faster score hud updating */
    
g_FlagState[flagid] = team 1                
    
    
/* clears icon for the toucher */
    
msg_csf_icon(toucherfalse)
    
    
/* clear the progress bar of the toucher */
    
msg_bar_progress(toucher100true)
    
    
/* if player frags for capturing flags cvar has been set, add it */
    
if(get_pcvar_num(g_cvarCaptureFrags))
        
add_user_frags(toucherget_pcvar_num(g_cvarCaptureFrags), team)
    
    
/* sends chat and radio messages */
    
notify_flag_taken(toucherflagid)
    
    
/* 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 1g_MapFlagsNumi++) {
            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(0wfteam)                    
            
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_SetClientMaxspeedid0.1)
            
set_pev(idpev_maxspeed0.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_SetClientMaxspeedid0.1)
                
set_pev(idpev_maxspeed0.1)
            }
            
            
/* blocks attacks */
            
set_pev(idpev_button, (pev(idpev_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
    
}
    
    if(!
pev_valid(flag))
        return 
FMRES_IGNORED
    
    
/* pev_csf_uniqueid is used to fast check if it's a flag */
    
if(pev(flagpev_csf_uniqueid) != CSFLAG_TYPEID)
        return 
FMRES_IGNORED
    
    
/* flags will delay to think with this artificial but efficient next think */
    
if(pev(flagpev_think_delay) < 4) {
        
set_pev(flagpev_think_delaypev(flagpev_think_delay) + 1)
        return 
FMRES_IGNORED
    
}
    
    
/* resets the delay counter */
    
set_pev(flagpev_think_delay0)
    
    
/* 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(flagpev_classnameclassname31)
    if(!
equal(classnameCLASSNAME_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(flagpev_csf_flagtoucher)

    if(
toucher) {
        
/* if toucher has died or it's not touching that flag anymore */
        
if(!is_user_alive(toucher) || !is_touching(toucherflag)) {
            
/* 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(flagpev_csf_flagtoucher0)
                
/* resets icon */
                
msg_csf_icon(toucherfalse)
                
/* resets progress bar */
                
msg_bar_progress(toucher100true)
            }
        }
        
    }
    
/* gets the team who's owning that flag */
    
team pev(flagpev_csf_flagstatus)
    
    
/* if it's owned by a team */
    
if(team) {    
        
/* gets the player who has captured this flag */
        
owner pev(flagpev_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 == || 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(0wfteam)
                    
/* 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_FindEntityByStringflag"classname"CLASSNAME_CSFLAG))) {
        
        
/* if this user is the one who captured that flag, it's cleaned */
        
if(pev(flagpev_csf_flagowner) == id)
            
set_pev(flagpev_csf_flagowner0)
        
        
/* if this user is touching this flag, remove tasks */
        
if(pev(flagpev_csf_flagtoucher) == id) {

            if(
task_exists(TASKID_CAPTUREDELAY flag))
                
remove_task(TASKID_CAPTUREDELAY flag)
            
/* resets toucher */
            
set_pev(flagpev_csf_flagtoucher0)
        }
    }
    
/* 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(playeridflagent
{    
    
/* 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(flagentpev_csf_hitbox)
    
    
/* gets the origin of the testing player */
    
pev(playeridpev_originpl_origin)
    
    
/* gets that flag index (for global variables) */
    
flagid pev(flagentpev_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(ent2ent1
{
    
    
/* 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(ent2pev_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(ent2pev_classnameclassname31)                
        if(!
equal(classnameCLASSNAME_TRIGGER_FLAG))
            return 
FMRES_IGNORED
        
        
/* checks if that player is in a valid team */
        
team get_user_team(ent1)
        if(
team || team 2)
            return 
FMRES_IGNORED
            
        
/* gets the flag entity from the touched csflag trigger entity */
        
flag pev(ent2pev_csf_flagent)
        if(!
pev_valid(flag))
            return 
FMRES_IGNORED
        
        
/* toucher stores the id of flag previous toucher */
        
toucher pev(flagpev_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(flagpev_csf_flagtoucher0)

                
/* if there was a capture in progress, remove it */
                
if(task_exists(TASKID_CAPTUREDELAY flag)) {
                    
remove_task(TASKID_CAPTUREDELAY flag)
                    
msg_bar_progress(toucher100true)
                    
msg_csf_icon(toucherfalse)
                    if(
g_BotCapturing[toucher]) {
                        
engfunc(EngFunc_SetClientMaxspeedent1250.0)
                        
set_pev(toucherpev_maxspeed250.0)
                        
g_BotCapturing[toucher] = false
                    
}
                    
                }
            }
        }
        
        
/* it wasn't being touched */
        
else if(pev(flagpev_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(ent1flag))
                return 
FMRES_IGNORED
            
            
/* updates that flag toucher */
            
set_pev(flagpev_csf_flagtoucherent1)
            
            if(
g_IsBot[ent1]) {
                
g_BotCapturing[ent1] = true
            
}
            
            
/* displays capturing icon */
            
msg_csf_icon(ent1true)
            
            
/* 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(ent10)
            
            
set_task(get_pcvar_float(g_cvarCaptureDelay),
                 
"flag_captured"TASKID_CAPTUREDELAY flaginfo2)
        }
        
    }
    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(idbool:show true
{
    
message_begin(MSG_ONEg_msgidIcon, {000}, id)
    
write_byte((show << 10))
    
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(idposbool:kill false)
{    
    
message_begin(MSG_ONEg_msgidProgress, {000}, id)
    
write_short(killget_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(toucherflagid
{
    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_RADIORANGEid1
    
    
set_task(1.5"hide_radio_icon"TASKID_HIDERADIOICONid1)
    
    
toucherteam get_user_team(toucher)
    
get_user_name(touchername31)
    
    
num_to_str(touchersid3)
    
//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_FlagTakenretvaltoucher)
    }
    
    for(new 
1<= g_MaxPlayersi++) {
        
        if(!
is_user_connected(i))
            continue
        
        
team get_user_team(i)
        
        if(
get_pcvar_num(g_cvarUseRadio) && (team == || team == 2)) {
            if(
team == toucherteam) {
                
                
message_begin(MSG_ONE_UNRELIABLE77_,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_ONE135_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"namefloatround(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"namefloatround(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(idmsg[],any:...)
{
    new 
changeCountnumijargnum numargs(), player
    
static newMsg[191], message[191], changed[8], players[32]

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

    for(
0numi++) {
        
        
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_ONEg_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(playersplayersnum)
    
    for(new 
0playersnumi++) {
        
spawn 0
        
        
if(players[i] && is_user_alive(players[i])) {
            
team get_user_team(players[i])
            switch(
team) {
                case 
: {
                    if(
tspawn == -1)
                        continue
                    
tspawn engfunc(EngFunc_FindEntityByString
                             
tspawn,
                             
"classname",
                             
"info_player_deathmatch")
                    
spawn tspawn
                    
if(!tspawn)
                        
tspawn = -1
                
}
                case 
: {
                    if(
ctspawn == -1)
                        continue
                    
ctspawn engfunc(EngFunc_FindEntityByString,
                              
ctspawn,
                              
"classname",
                              
"info_player_start")
                    
spawn ctspawn
                    
if(!ctspawn)
                        
ctspawn = -1
                
}                
            }
            if(
spawn) {
                
                
pev(spawnpev_originvec)
                
engfunc(EngFunc_SetOriginplayers[i], vec)
                
set_pev(players[i], pev_fixangle1)
                
pev(spawnpev_anglesvec)
                
set_pev(players[i], pev_anglesvec)
                
                if(
restore)
                    
set_pev(players[i], pev_health100.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(headerT30g_ScoreHeaderFormat[ID_TEAM_T], g_TeamWins[ID_TEAM_T], floatround(g_TeamScore[ID_TEAM_T]))
        
formatex(headerCT30g_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 0ind MAX_CSFLAGSind++) {
            
            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(scoreCT24 HUD_FLAGS_STRING_MAXSIZE"%s%s"headerCTflagsTakenCT)
        
formatex(scoreT24 HUD_FLAGS_STRING_MAXSIZE"%s%s"headerTflagsTakenT)
    }
    
    
// clean updates
    
g_UpdateFlagsHud false
    g_UpdateScoresHud 
false
    
    
// send hud messages
    
for(ind 1ind <= g_MaxPlayersind++) {
        if(
is_user_connected(ind)) {
            if(
is_user_alive(ind)) {    
                
set_hudmessage(255000.30.006.0INTERVAL_SCORE_UPDATE0.10.23)
                
show_hudmessage(indscoreT)
                
set_hudmessage(ind02550.60.006.0INTERVAL_SCORE_UPDATE0.10.24)
                
show_hudmessage(indscoreCT)
            }
            else {
                
set_hudmessage(255000.30.1706.0INTERVAL_SCORE_UPDATE0.10.23)
                
show_hudmessage(indscoreT)
                
set_hudmessage(ind02550.60.1706.0INTERVAL_SCORE_UPDATE0.10.24)
                
show_hudmessage(indscoreCT)
            }
        }            
    }
}

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 
06i++)
        
remove_all_ents(objectives[i])
}
        
add_user_frags(idvalueteam)
{
    
/*
     * 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 && team 2)
            
get_players(playersplayersnum"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 
0playersnumi++) {
        
pev(players[i], pev_fragsfrags)
        
frags += value
        set_pev
(players[i], pev_fragsfrags)
        
        
message_begin(MSG_ALLg_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(file71)) {
        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(filepointerline95) && count MAX_CSFLAGS) {
            if(!
strlen(line) || line[0] == ';')
                continue
            
parse(linearg115arg279)
            
            if(!
strlen(arg2))
                continue
                
            if(
strlen(arg1))
                
copy(g_PlaceNames[count], 15arg1)
            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_MakeVectorsangle)
            
            
flag engfunc(EngFunc_CreateNamedEntityengfunc(EngFunc_AllocString"cycler_sprite"))
            
            if(
pev_valid(flag)) {
                
engfunc(EngFunc_SetOriginflagorigin)                
                
set_pev(flagpev_modelMODEL_FLAGS)
                
set_pev(flagpev_framerate1.0)
                
dllfunc(DLLFunc_Spawnflag)                
                
set_pev(flagpev_classnameCLASSNAME_CSFLAG)
                
set_pev(flagpev_anglesangle)
                
set_pev(flagpev_csf_uniqueidCSFLAG_TYPEID)            
                
set_pev(flagpev_csf_flagidcount)
                
set_pev(flagpev_csf_hitboxhitbox)
                
                
trigger engfunc(EngFunc_CreateNamedEntityengfunc(EngFunc_AllocString"trigger_multiple"))
                
                if(
pev_valid(trigger)) {
                    
origin[2] += 48.0
                    engfunc
(EngFunc_SetOrigintriggerorigin)                    
                    
dllfunc(DLLFunc_Spawntrigger)
                    
engfunc(EngFunc_SetSizetriggerg_mmSize[hitbox][HITBOX_MIN], g_mmSize[hitbox][HITBOX_MAX])
                    
set_pev(triggerpev_csf_uniqueidTRIGGERFLAG_TYPEID)
                    
set_pev(triggerpev_classnameCLASSNAME_TRIGGER_FLAG)
                    
set_pev(triggerpev_csf_flagentflag)
                    
set_pev(triggerpev_csf_flagidcount)
                    
set_pev(flagpev_csf_triggertrigger)
                    
                    
                    
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(map35)
    
get_configsdir(filelen)
    
format(file[strlen(file)], len strlen(file), FILE_DOMCFGmap)
    
    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(0print_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(idstack[])
{
    
open_debug_file()
    
    if(
stack[0]) 
        
print_stack(idstack)
    else
        
print_stack(id)
    
    
print_debug_cmd(id"Game State tracing")
    
    
PRINT_MSG1(id"GAMESTATE_STARTED: %d"g_CSFlagsState GAMESTATE_STARTED 0)
    
PRINT_MSG1(id"GAMESTATE_FORCEDEND: %d"g_CSFlagsState GAMESTATE_FORCEDEND 0)
    
PRINT_MSG1(id"GAMESTATE_HUDREPEAT: %d"g_CSFlagsState GAMESTATE_HUDREPEAT 0)
    
PRINT_MSG1(id"GAMESTATE_MATCHOVER: %d"g_CSFlagsState GAMESTATE_MATCHOVER 0)
    
PRINT_MSG1(id"GAMESTATE_SHOWSCORE: %d"g_CSFlagsState GAMESTATE_SHOWSCORE 0)
    
PRINT_MSG1(id"GAMESTATE_STOPPED: %d"g_CSFlagsState GAMESTATE_STOPPED 0)
    
PRINT_MSG1(id"GAMESTATE_WAIT: %d"g_CSFlagsState GAMESTATE_WAIT 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(idstack[])
{
    new 
flag
    
new trigger
    
new Float:vector[3]
    new 
count
    
    open_debug_file
()
    
    if(!
stack[0]) 
        
print_stack(idstack)
    else
        
print_stack(id)
    
    
print_debug_cmd(id"Flags Tracing")
    
    while((
flag engfunc(EngFunc_FindEntityByStringflag"classname"CLASSNAME_CSFLAG))) {
        
        
PRINT_MSG2(id"***^nflagent: %d, flagid: %d"flagpev(flagpev_csf_flagid))
        
PRINT_MSG1(id"Flag name: %s"g_PlaceNames[pev(flagpev_csf_flagid)])
        
        
pev(flagpev_originvector)
        
PRINT_MSG3(id"Origin: %f %f %f"vector[0], vector[1], vector[2])
        
        
pev(flagpev_anglesvector)
        
PRINT_MSG3(id"Angles: %f %f %f"vector[0], vector[1], vector[2])
        
        
PRINT_MSG1(id"Hitbox: %d"pev(flagpev_csf_hitbox))
        
PRINT_MSG1(id"Owner: %d"pev(flagpev_csf_flagowner))
        
PRINT_MSG1(id"Toucher: %d"pev(flagpev_csf_flagtoucher))
        
PRINT_MSG1(id"Status: %d"pev(flagpev_csf_flagstatus))
        
PRINT_MSG1(id"typeid: %d"pev(flagpev_csf_uniqueid))    
        
        
trigger pev(flagpev_csf_trigger)
        
PRINT_MSG1(id"Flag trigger:"trigger)
        
        if(
pev_valid(trigger)) {
            
pev(triggerpev_originvector)
            
PRINT_MSG3(id"^tOrigin: %f %f %f"vector[0], vector[1], vector[2])
            
            
pev(triggerpev_maxsvector)
            
PRINT_MSG3(id"^tMaxs(size): %f %f %f"vector[0], vector[1], vector[2])
            
            
pev(triggerpev_minsvector)
            
PRINT_MSG3(id"^tMins(size): %f %f %f"vector[0], vector[1], vector[2])            
            
            
PRINT_MSG1(id"^tflagid(ref): %d"pev(triggerpev_csf_flagid))
            
PRINT_MSG1(id"^tflagent(ref): %d"pev(triggerpev_csf_flagent))
            
PRINT_MSG1(id"^ttypeid: %d"pev(triggerpev_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(idmsg)
    else
        
server_print(msg)
    
#if defined DEBUG_FILE
    
if(pDebugFile) {
        
fputs(pDebugFilemsg)
        
fputs(pDebugFile"^n")
    }
#endif // DEBUG_FILE
}

print_debug_cmd(idcmd[])
{
    
PRINT_MSG3(id"%s^n%s CMD: %s"debugLinedebugHeadercmd)
}

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

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

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

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

stock printvar_cell_array(id, const varname[], const array[], length)
{
    
PRINT_MSG1(id"^t[array] %s"varname)
    for(new 
ilengthi++)
        
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 
ilengthi++)
        
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 
ilengthi++)
        
PRINT_MSG2(id"^t^t[%d] = %s", array[i])  
}

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

#endif // DEBUG_TOOLS
 
Аватара пользователя
Don Corleone
 
Сообщения: 79
Зарегистрирован: 23 окт 2016, 16:13
Благодарил (а): 5 раз.
Поблагодарили: 0 раз.
Опыт программирования: Около 3 месяцев
Языки программирования: Pawn
SourcePawn
C++
Php
Ruby
Python
C#

Re: csflags после рестарта на ножах

Сообщение TheTenderMan » 26 дек 2017, 19:13

В коде копаться не хочу, а так подскажу, что реализовать можно с помощью функций:
Код: Выделить всё
strip_user_weapon(id) //Забирает все оружие включая нож у игрока с указанным id
give_item(id, "weapon_knife") //Выдать оружие НОЖ игроку с указанным id

В это время противника нельзя убить
Возможно есть часть кода где выдается godmode, или логическая переменная отвечающая за это.
Аватара пользователя
TheTenderMan
 
Сообщения: 2
Зарегистрирован: 13 сен 2017, 20:41
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
Языки программирования: Pawn
Php


Вернуться в Вопросы по AMXX и его плагинам

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

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