//========= Copyright Valve Corporation, All rights reserved. ============//
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose: The TF Game rules object
//
// $Workfile:     $
// $Date:         $
// $NoKeywords: $
//=============================================================================

#ifndef TF_GAMERULES_H
#define TF_GAMERULES_H

#ifdef _WIN32
#pragma once
#endif


#include "teamplayroundbased_gamerules.h"
#include "convar.h"
#include "gamevars_shared.h"
#include "GameEventListener.h"
#include "tf_gamestats_shared.h"
#include "tf_match_description.h"

#ifdef CLIENT_DLL
#include "c_tf_player.h"
#else
#include "tf_player.h"
#endif

#ifdef CLIENT_DLL
	
	#define CTFGameRules C_TFGameRules
	#define CTFGameRulesProxy C_TFGameRulesProxy
	#define CBonusRoundLogic C_BonusRoundLogic
#else
	extern CUtlString s_strNextMvMPopFile;

	extern BOOL no_cease_fire_text;
	extern BOOL cease_fire;

	class CHealthKit;
	class CTrainingModeLogic;
	class CTFHolidayEntity;
	class CTFNavArea;
	class CTFBot;
	class CTFBotRoster;
	class CMedievalLogic;
	class CCPTimerLogic;
	class CPopulationManager;
	class CCompetitiveLogic;
#endif

class CBonusRoundLogic;
class CTeamTrainWatcher;
class CPhysicsProp;
class CObjectSentrygun;
class CGhost;
class CUpgrades;

extern ConVar	tf_spec_xray;
extern ConVar	tf_avoidteammates;
extern ConVar	tf_avoidteammates_pushaway;
extern ConVar	mp_tournament_blueteamname;
extern ConVar	mp_tournament_redteamname;
extern ConVar	tf_arena_force_class;
extern ConVar	tf_arena_change_limit;
extern ConVar	tf_ctf_bonus_time;
extern ConVar	tf_mvm_respec_enabled;
extern ConVar	tf_spawn_glows_duration;
#ifdef TF_RAID_MODE

class CRaidLogic;
class CBossBattleLogic;

extern ConVar tf_gamemode_raid;
extern ConVar tf_gamemode_creep_wave;
extern ConVar tf_gamemode_boss_battle;

#endif // TF_RAID_MODE

class CMannVsMachineLogic;
class CMannVsMachineUpgrades;

//extern ConVar tf_populator_health_multiplier;
//extern ConVar tf_populator_damage_multiplier;

const int kMVM_DefendersTeamSize = 6;
const int kLadder_TeamSize_6v6 = 6;
const int kLadder_TeamSize_9v9 = 9;
const int kLadder_TeamSize_12v12 = 12;

//#define TF_MVM_FCVAR_CHEAT 0 /* Cheats enabled */
#define TF_MVM_FCVAR_CHEAT FCVAR_CHEAT /* Cheats disabled */

extern bool TF_IsHolidayActive( /*EHoliday*/ int eHoliday );

//=============================================================================
// HPE_BEGIN
// [msmith] Used for the client to tell the server that we're whatching a movie or not
//			and weather or not we're ready to transition to the next map.
//=============================================================================
// Training mode cvars
extern ConVar	tf_training_client_message;
enum {
	TRAINING_CLIENT_MESSAGE_NONE = 0,
	TRAINING_CLIENT_MESSAGE_WATCHING_INTRO_MOVIE,
	TRAINING_CLIENT_MESSAGE_IN_SUMMARY_SCREEN,
	TRAINING_CLIENT_MESSAGE_NEXT_MAP,
	TRAINING_CLIENT_MESSAGE_REPLAY,
	TRAINING_CLIENT_MESSAGE_MAX,
};

// How many achievements we show in the summary screen.
#define MAX_SHOWN_ACHIEVEMENTS 6
//=============================================================================
// HPE_END
//=============================================================================


extern Vector g_TFClassViewVectors[];

#define NO_CLASS_LIMIT -1

enum {
	STOPWATCH_CAPTURE_TIME_NOT_SET = 0,
	STOPWATCH_RUNNING,
	STOPWATCH_OVERTIME,
};

class CTFGameRulesProxy : public CTeamplayRoundBasedRulesProxy, public CGameEventListener
{
public:
	DECLARE_CLASS( CTFGameRulesProxy, CTeamplayRoundBasedRulesProxy );
	DECLARE_NETWORKCLASS();

#ifdef GAME_DLL
	DECLARE_DATADESC();

	CTFGameRulesProxy();

	void	InputSetRedTeamRespawnWaveTime( inputdata_t &inputdata );
	void	InputSetBlueTeamRespawnWaveTime( inputdata_t &inputdata );
	void	InputAddRedTeamRespawnWaveTime( inputdata_t &inputdata );
	void	InputAddBlueTeamRespawnWaveTime( inputdata_t &inputdata );
	void	InputSetRedTeamGoalString( inputdata_t &inputdata );
	void	InputSetBlueTeamGoalString( inputdata_t &inputdata );
	void	InputSetRedTeamRole( inputdata_t &inputdata );
	void	InputSetBlueTeamRole( inputdata_t &inputdata );
	void	InputSetRequiredObserverTarget( inputdata_t &inputdata );
	void	InputAddRedTeamScore( inputdata_t &inputdata );
	void	InputAddBlueTeamScore( inputdata_t &inputdata );
	void	InputSetRedKothClockActive( inputdata_t &inputdata );
	void	InputSetBlueKothClockActive( inputdata_t &inputdata );
	void	InputSetCTFCaptureBonusTime( inputdata_t &inputdata );
	void	InputPlayVORed( inputdata_t &inputdata );
	void	InputPlayVOBlue( inputdata_t &inputdata );
	void	InputPlayVO( inputdata_t &inputdata );
	void	InputHandleMapEvent( inputdata_t &inputdata );
	void	InputSetCustomUpgradesFile( inputdata_t &inputdata );
	void	InputSetRoundRespawnFreezeEnabled( inputdata_t &inputdata );
	void	InputSetMapForcedTruceDuringBossFight( inputdata_t &inputdata );

	void	TeamPlayerCountChanged( CTFTeam *pTeam );
	void	PowerupTeamImbalance( int nTeam );
	void	StateEnterRoundRunning( void );
	void	StateEnterBetweenRounds( void );
	void	StateEnterPreRound( void );
	void	StateExitPreRound( void );
	void	MatchSummaryStart( void );
	void	TruceStart( void );
	void	TruceEnd( void );

	COutputEvent m_OnWonByTeam1;
	COutputEvent m_OnWonByTeam2;
	COutputInt m_Team1PlayersChanged;
	COutputInt m_Team2PlayersChanged;
	COutputEvent m_OnPowerupImbalanceTeam1;
	COutputEvent m_OnPowerupImbalanceTeam2;
	COutputEvent m_OnPowerupImbalanceMeasuresOver;
	COutputEvent m_OnStateEnterRoundRunning;
	COutputEvent m_OnStateEnterBetweenRounds;
	COutputEvent m_OnStateEnterPreRound;
	COutputEvent m_OnStateExitPreRound;
	COutputEvent m_OnMatchSummaryStart;
	COutputEvent m_OnTruceStart;
	COutputEvent m_OnTruceEnd;

	virtual void Activate();

private:

//=============================================================================
// HPE_BEGIN:
// [msmith]	hud type so the game type and hud type can be separate.  Used for
//			training missions.
//=============================================================================
	int		m_nHudType;
//=============================================================================
// HPE_END
//=============================================================================


	bool	m_bOvertimeAllowedForCTF;
#endif

public: // IGameEventListener Interface
	virtual void FireGameEvent( IGameEvent * event );
};

class CTFRadiusDamageInfo
{
	DECLARE_CLASS_NOBASE( CTFRadiusDamageInfo );
public:
	CTFRadiusDamageInfo( CTakeDamageInfo *pInfo, const Vector &vecSrcIn, float flRadiusIn, CBaseEntity *pIgnore = NULL, float flRJRadiusIn = 0, float flForceScaleIn = 1.0f )
	{
		dmgInfo = pInfo;
		vecSrc = vecSrcIn;
		flRadius = flRadiusIn;
		pEntityIgnore = pIgnore;
		flRJRadius = flRJRadiusIn;
		flFalloff = 0;
		m_flForceScale = flForceScaleIn;
		m_pEntityTarget = NULL;

		CalculateFalloff();
	}

	void CalculateFalloff( void );
	int ApplyToEntity( CBaseEntity *pEntity );

public:
	// Fill these in & call RadiusDamage()
	CTakeDamageInfo	*dmgInfo;
	Vector			vecSrc;
	float			flRadius;
	CBaseEntity		*pEntityIgnore;
	float			flRJRadius;	// Radius to use to calculate RJ, to maintain RJs when damage/radius changes on a RL
	float			m_flForceScale;
	CBaseEntity		*m_pEntityTarget;		// Target being direct hit if any
private:
	// These are used during the application of the RadiusDamage 
	float			flFalloff;
};

struct PlayerRoundScore_t
{
	int iPlayerIndex;	// player index
	int iRoundScore;	// how many points scored this round
	int	iTotalScore;	// total points scored across all rounds
};

struct PlayerArenaRoundScore_t
{
	int iPlayerIndex;	// player index
	int	iTotalDamage;	// damage done this round
	int iTotalHealing;	// healing done this round
	int iTimeAlive;		// time alive (in seconds)
	int iKillingBlows;	// killing blows this round
	int iScore;
};

#ifdef CLIENT_DLL
const char *GetMapType( const char *mapName );
const char *GetMapDisplayName( const char *mapName );
#else

class CKothLogic;

#endif

// Used to sort the players in the list by their bonus score
typedef CTFPlayer *BONUSPLAYERPTR;
class CBonusPlayerListLess
{
public:
	bool Less( const BONUSPLAYERPTR &src1, const BONUSPLAYERPTR &src2, void *pCtx )
	{
		if ( src1->m_Shared.GetItemFindBonus() > src2->m_Shared.GetItemFindBonus() )
			return true;
		return false;
	}
};

#define MAX_TEAMGOAL_STRING		256
#define MAX_TEAMNAME_STRING		6

class CTFGameRules : public CTeamplayRoundBasedRules
{
public:
	DECLARE_CLASS( CTFGameRules, CTeamplayRoundBasedRules );

	CTFGameRules();

	virtual void	LevelInitPostEntity( void );
	virtual float	GetRespawnTimeScalar( int iTeam );
	virtual float	GetRespawnWaveMaxLength( int iTeam, bool bScaleWithNumPlayers = true );

	// Damage Queries.
	virtual bool	Damage_IsTimeBased( int iDmgType );			// Damage types that are time-based.
	virtual bool	Damage_ShowOnHUD( int iDmgType );				// Damage types that have client HUD art.
	virtual bool	Damage_ShouldNotBleed( int iDmgType );			// Damage types that don't make the player bleed.
	// TEMP:
	virtual int		Damage_GetTimeBased( void );		
	virtual int		Damage_GetShowOnHud( void );
	virtual int		Damage_GetShouldNotBleed( void );

	int				GetFarthestOwnedControlPoint( int iTeam, bool bWithSpawnpoints );
	virtual bool	TeamMayCapturePoint( int iTeam, int iPointIndex );
	virtual bool	PlayerMayCapturePoint( CBasePlayer *pPlayer, int iPointIndex, char *pszReason = NULL, int iMaxReasonLength = 0 );
	virtual bool	PlayerMayBlockPoint( CBasePlayer *pPlayer, int iPointIndex, char *pszReason = NULL, int iMaxReasonLength = 0 );

	static int		CalcPlayerScore( RoundStats_t *pRoundStats, CTFPlayer *pPlayer );
	static int		CalcPlayerSupportScore( RoundStats_t *pRoundStats, int iPlayerIdx );

	bool			IsBirthday( void ) const;
	bool			IsBirthdayOrPyroVision( void ) const;
	virtual bool	IsHolidayActive( /*EHoliday*/ int eHoliday ) const;

	virtual const unsigned char *GetEncryptionKey( void ) { return GetTFEncryptionKey(); }

	int				GetClassLimit( int iClass );
	bool			CanPlayerChooseClass( CBasePlayer *pPlayer, int iClass );

	virtual bool	ShouldBalanceTeams( void );

	virtual int		GetBonusRoundTime( bool bGameOver = false ) OVERRIDE;

#ifdef GAME_DLL
public:
	virtual void	Precache( void );

	// Override this to prevent removal of game specific entities that need to persist
	virtual bool	RoundCleanupShouldIgnore( CBaseEntity *pEnt );
	virtual bool	ShouldCreateEntity( const char *pszClassName );
	virtual void	CleanUpMap( void );

	virtual void	FrameUpdatePostEntityThink();

	virtual void	RespawnPlayers( bool bForceRespawn, bool bTeam = false, int iTeam = TEAM_UNASSIGNED ) OVERRIDE;

	// Called when a new round is being initialized
	virtual void	SetupOnRoundStart( void );

	// Called when a new round is off and running
	virtual void	SetupOnRoundRunning( void );

	// Called before a new round is started (so the previous round can end)
	virtual void	PreviousRoundEnd( void );

	// Send the team scores down to the client
	virtual void	SendTeamScoresEvent( void ) { return; }

	// Send the end of round info displayed in the win panel
	virtual void	SendWinPanelInfo( bool bGameOver ) OVERRIDE;
	void			SendArenaWinPanelInfo( void );
	void			SendPVEWinPanelInfo( void );

	// Setup spawn points for the current round before it starts
	virtual void	SetupSpawnPointsForRound( void );

	// Called when a round has entered stalemate mode (timer has run out)
	virtual void	SetupOnStalemateStart( void );
	virtual void	SetupOnStalemateEnd( void );

	virtual void	RecalculateControlPointState( void );

	void			TeamPlayerCountChanged( CTFTeam *pTeam );
	void			PowerupTeamImbalance( int nTeam );
	int				GetAssignedHumanTeam( void );
	virtual void	HandleSwitchTeams( void );
	virtual void	HandleScrambleTeams( void );
	bool			CanChangeClassInStalemate( void );
	bool			CanChangeTeam( int iCurrentTeam ) const;

	virtual void	SetRoundOverlayDetails( void );	
	virtual void	ShowRoundInfoPanel( CTFPlayer *pPlayer = NULL ); // NULL pPlayer means show the panel to everyone

	virtual bool	TimerMayExpire( void );

	virtual void	Activate();

	virtual bool	AllowDamage( CBaseEntity *pVictim, const CTakeDamageInfo &info );

	void			SetTeamGoalString( int iTeam, const char *pszGoal );
//=============================================================================
// HPE_BEGIN:
// [msmith]	Added a HUD type separate from the game mode so we can do different
//			HUDs for the same mode.  This is used in training maps.
//=============================================================================
	void			SetHUDType( int nHudType );
//=============================================================================
// HPE_END
//=============================================================================

	// Speaking, vcds, voice commands.
	virtual void	InitCustomResponseRulesDicts();
	virtual void	ShutdownCustomResponseRulesDicts();

	virtual bool	HasPassedMinRespawnTime( CBasePlayer *pPlayer );
	virtual bool	ShouldRespawnQuickly( CBasePlayer *pPlayer );

	bool			ShouldScorePerRound( void );

	virtual bool	IsValveMap( void );

	virtual void	PlayTrainCaptureAlert( CTeamControlPoint *pPoint, bool bFinalPointInMap );

	void			SetRequiredObserverTarget( CBaseEntity *pEnt ){ m_hRequiredObserverTarget = pEnt; }
	void			SetObjectiveObserverTarget( CBaseEntity *pEnt ) { m_hObjectiveObserverTarget = pEnt; }
	EHANDLE			GetRequiredObserverTarget( void ){ return m_hRequiredObserverTarget.Get(); }
	EHANDLE			GetObjectiveObserverTarget( void ){ return m_hObjectiveObserverTarget.Get(); }

	virtual void	GetTaggedConVarList( KeyValues *pCvarTagList );

	virtual bool	PointsMayBeCaptured( void );
	virtual bool	PointsMayAlwaysBeBlocked(){ return ( GetGameType() == TF_GAMETYPE_ESCORT ); }

	virtual void	PlaySpecialCapSounds( int iCappingTeam, CTeamControlPoint *pPoint );

	virtual CTacticalMissionManager *TacticalMissionManagerFactory( void );

	virtual bool	ShouldSwitchTeams( void );
	virtual bool	ShouldScrambleTeams( void );

	virtual void	ClientCommandKeyValues( edict_t *pEntity, KeyValues *pKeyValues );

	bool            CanBotChangeClass( CBasePlayer* pPlayer );
	bool            CanBotChooseClass( CBasePlayer *pPlayer, int iClass );

	void SetCTFCaptureBonusTime( float flTime ){ m_flCTFCaptureBonusTime = flTime; }
	float GetCTFCaptureBonusTime( void )
	{ 
		float flRetVal = tf_ctf_bonus_time.GetFloat();
		if ( m_flCTFCaptureBonusTime >= 0.0f )
		{
			flRetVal = m_flCTFCaptureBonusTime;
		}

		return flRetVal; 
	}

	// populate vector with set of control points the player needs to capture
	virtual void CollectCapturePoints( CBasePlayer *player, CUtlVector< CTeamControlPoint * > *captureVector ) const;

	// populate vector with set of control points the player needs to defend from capture
	virtual void CollectDefendPoints( CBasePlayer *player, CUtlVector< CTeamControlPoint * > *defendVector ) const;

	CObjectSentrygun *FindSentryGunWithMostKills( int team = TEAM_ANY ) const;

	// Client connection/disconnection
	virtual bool ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen );

	virtual bool ShouldSkipAutoScramble( void )
	{ 
		return IsPVEModeActive();
	}

	bool			ShouldMakeChristmasAmmoPack( void );

	void			UpdatePeriodicEvent( CTFPlayer *pPlayer, eEconPeriodicScoreEvents eEvent, uint32 nCount );

	void			HandleMapEvent( inputdata_t &inputdata );

	void			SetCustomUpgradesFile( inputdata_t &inputdata );

	virtual bool	ShouldWaitToStartRecording( void );

	void			SetGravityMultiplier( float flValue ){ m_flGravityMultiplier.Set( flValue ); }

	bool			CanFlagBeCaptured( CBaseEntity *pOther );
	bool			PowerupModeFlagStandoffActive( void );

	void			TeleportPlayersToTargetEntities( int iTeam, const char *pszEntTargetName, CUtlVector< CTFPlayer * > *pTeleportedPlayers );

	virtual void LoadMapCycleFileIntoVector ( const char *pszMapCycleFile, CUtlVector<char *> &mapList ) OVERRIDE;

	void			OnWorkshopMapUpdated( PublishedFileId_t nWorkshopID );

	void			RecalculateTruce( void );

	void			SetMapForcedTruceDuringBossFight( bool bState ){ m_bMapForcedTruceDuringBossFight = bState; }
	bool			IsMapForcedTruceDuringBossFight( void ){ return m_bMapForcedTruceDuringBossFight; }

protected:
	virtual void LoadMapCycleFile( void ) OVERRIDE;
	void TrackWorkshopMapsInMapCycle( void );

	virtual const char* GetStalemateSong( int nTeam ) OVERRIDE;
	virtual const char* WinSongName( int nTeam ) OVERRIDE;
	virtual const char* LoseSongName( int nTeam ) OVERRIDE;

	virtual void	InitTeams( void );

	virtual void	RoundRespawn( void );
	virtual void	RespawnTeam( int iTeam );

	virtual void	InternalHandleTeamWin( int iWinningTeam );
	
	static int		PlayerRoundScoreSortFunc( const PlayerRoundScore_t *pRoundScore1, const PlayerRoundScore_t *pRoundScore2 );
	static int		PlayerArenaRoundScoreSortFunc( const PlayerArenaRoundScore_t *pRoundScore1, const PlayerArenaRoundScore_t *pRoundScore2 );

	virtual void FillOutTeamplayRoundWinEvent( IGameEvent *event );

	virtual bool CanChangelevelBecauseOfTimeLimit( void );
	virtual bool CanGoToStalemate( void );

	virtual void RestoreActiveTimer( void );

	void BroadcastDrawLine( CTFPlayer *pTFPlayer, KeyValues *pKeyValues );

#endif // GAME_DLL

public:
	// Bonus round handling
#ifdef GAME_DLL
	virtual bool	ShouldGoToBonusRound( void );
	virtual void	SetupOnBonusStart( void );
	virtual void	SetupOnBonusEnd( void );
	virtual void	BonusStateThink( void );
	void			BonusStateAbort( void );
	void			SetBonusItem( itemid_t iItemID );

	// Between rounds handling
	virtual void	BetweenRounds_Start( void );
	virtual void	BetweenRounds_End( void );
	virtual void	BetweenRounds_Think( void );
	virtual void	PreRound_Start( void ) OVERRIDE;
	virtual void	PreRound_End( void ) OVERRIDE;
#endif

public:
	// Return the value of this player towards capturing a point
	virtual int		GetCaptureValueForPlayer( CBasePlayer *pPlayer );

	// Collision and Damage rules.
	virtual bool	ShouldCollide( int collisionGroup0, int collisionGroup1 );
	
	int GetTimeLeft( void );

	// Get the view vectors for this mod.
	virtual const CViewVectors *GetViewVectors() const;

	virtual void FireGameEvent( IGameEvent *event );

	virtual const char *GetGameTypeName( void );
	virtual int GetGameType( void ){ return m_nGameType; }

	virtual void ClientSpawned( edict_t * pPlayer );

	virtual void OnFileReceived( const char * fileName, unsigned int transferID );

	virtual bool FlagsMayBeCapped( void );

	void	RunPlayerConditionThink ( void );

	const char *GetTeamGoalString( int iTeam );

	int		GetStopWatchState( void ) { return m_nStopWatchState; }
	
	// Game Modes
	virtual bool IsInArenaMode( void ) const OVERRIDE;
	virtual bool IsInKothMode( void ) const OVERRIDE { return m_bPlayingKoth; }
	bool IsInMedievalMode( void ) const { return m_bPlayingMedieval; }
	bool IsHolidayMap( int nHoliday ) const { return m_nMapHolidayType == nHoliday; }
	
#ifdef TF_RAID_MODE
	bool IsRaidMode( void ) const;
	bool IsBossBattleMode( void ) const;
#endif // TF_RAID_MODE

#ifdef TF_CREEP_MODE
bool IsCreepWaveMode( void ) const;
#endif

	bool IsMannVsMachineMode( void ) const { return m_bPlayingMannVsMachine; }

	void SetMannVsMachineAlarmStatus( bool bStatus ){ m_bMannVsMachineAlarmStatus.Set( bStatus ); }
	bool GetMannVsMachineAlarmStatus( void ){ return m_bMannVsMachineAlarmStatus; }
	
	bool IsQuickBuildTime( void );

	bool GameModeUsesUpgrades( void );
	bool GameModeUsesCurrency( void ) { return IsMannVsMachineMode() || IsBountyMode(); }
	bool GameModeUsesMiniBosses( void ) { return IsMannVsMachineMode() || IsBountyMode(); }

	bool IsPasstimeMode() const { return m_nGameType == TF_GAMETYPE_PASSTIME; }

#ifdef STAGING_ONLY
	bool GameModeUsesExperience( void ) { return IsBountyMode(); }
#endif // STAGING_ONLY
	bool IsMannVsMachineRespecEnabled( void ) { return IsMannVsMachineMode() && tf_mvm_respec_enabled.GetBool(); }
	bool CanPlayerUseRespec( CTFPlayer *pTFPlayer );
	bool IsPowerupMode( void ) { return m_bPowerupMode; }
	void SetPowerupMode( bool bValue );

#ifdef GAME_DLL
	// Managed competitive matches should go through the End/StopCompetitiveMatch path
	void EndManagedMvMMatch( bool bKickPlayersToParties );
#endif

	// Competitive games
	bool IsCompetitiveMode( void ) const;			// means we're using competitive/casual matchmaking
	bool IsMatchTypeCasual( void ) const;
	bool IsMatchTypeCompetitive( void ) const;
	// Are we showing the match-start-countdown doors right now
	bool BInMatchStartCountdown() const;
#ifdef GAME_DLL
	void SyncMatchSettings();
	// ! Check return
	bool StartManagedMatch();
	void SetCompetitiveMode( bool bValue );
#endif
	void StartCompetitiveMatch( void );
	void StopCompetitiveMatch( CMsgGC_Match_Result_Status nCode );
	void EndCompetitiveMatch( void );
	void ManageCompetitiveMode( void );
	bool ReportMatchResultsToGC( CMsgGC_Match_Result_Status nCode );
	bool MatchmakingShouldUseStopwatchMode();

	EMatchGroup GetCurrentMatchGroup() const;
	bool IsManagedMatchEnded() const;

	bool UsePlayerReadyStatusMode( void );
	bool PlayerReadyStatus_HaveMinPlayersToEnable( void );
#ifdef GAME_DLL
	bool PlayerReadyStatus_ArePlayersOnTeamReady( int iTeam );
	bool PlayerReadyStatus_ShouldStartCountdown( void );
	void PlayerReadyStatus_ResetState( void );
	void PlayerReadyStatus_UpdatePlayerState( CTFPlayer *pTFPlayer, bool bState );
#endif // GAME_DLL

	bool IsDefaultGameMode( void );		// The absence of arena, mvm, tournament mode, etc

	// Upgrades
	int	GetCostForUpgrade( CMannVsMachineUpgrades *pUpgrade, int iItemSlot, int nClass, CTFPlayer *pPurchaser = NULL );
	bool CanUpgradeWithAttrib( CTFPlayer *pPlayer, int iWeaponSlot, attrib_definition_index_t iAttribIndex, CMannVsMachineUpgrades *pUpgrade );
	int GetUpgradeTier( int iUpgrade );
	bool IsUpgradeTierEnabled( CTFPlayer *pTFPlayer, int iItemSlot, int iUpgrade );
	bool IsPVEModeActive( void ) const;						// return true if we are playing a PvE mode
	bool IsPVEModeControlled( CBaseEntity *who ) const;		// return true for PvE opponents (ie: enemy bot team)
	const char*		GetCustomUpgradesFile() { return m_pszCustomUpgradesFile.Get(); }

//=============================================================================
// HPE_BEGIN:
// [msmith]	Training Status. And HUD type.
//=============================================================================
	bool IsInTraining( void ){ return m_bIsInTraining; }
	bool AllowTrainingAchievements() { return m_bAllowTrainingAchievements; }
	void SetAllowTrainingAchievements( bool bAllow) { m_bAllowTrainingAchievements = bAllow; }
	bool IsWaitingForTrainingContinue() { return m_bIsWaitingForTrainingContinue; }
	void SetIsWaitingForTrainingContinue( bool bWaiting ) { m_bIsWaitingForTrainingContinue = bWaiting; }
	int GetHUDType( void ){ return m_nHudType; }
//=============================================================================
// HPE_END
//=============================================================================
	bool IsTrainingHUDVisible( void ) { return IsInTraining() && m_bIsTrainingHUDVisible; }
	void SetTrainingHUDVisible( bool bVisible ) { m_bIsTrainingHUDVisible.Set( bVisible ); }

	virtual bool	IsInItemTestingMode( void ) { return m_bIsInItemTestingMode; }
	void			SetInItemTestingMode( bool bInTesting ) { m_bIsInItemTestingMode.Set( bInTesting ); }
	int				ItemTesting_GetBotAnim( void ) { return m_iItemTesting_BotAnim; }
	float			ItemTesting_GetBotAnimSpeed( void );
	bool			ItemTesting_GetBotForceFire( void ) { return m_bItemTesting_BotForceFire; }
	bool			ItemTesting_GetBotTurntable( void ) { return m_bItemTesting_BotTurntable; }
	bool			ItemTesting_GetBotViewScan( void ) { return m_bItemTesting_BotViewScan; }
	void			ItemTesting_SetupFromKV( KeyValues *pKV );
	
	bool IsPlayingHybrid_CTF_CP( void ) const { return m_bPlayingHybrid_CTF_CP; }
	bool IsPlayingSpecialDeliveryMode( void ) const { return m_bPlayingSpecialDeliveryMode; }
	bool IsPlayingRobotDestructionMode( void ) const { return m_bPlayingRobotDestructionMode; }

	virtual bool AllowThirdPersonCamera( void ) { return ( IsInMedievalMode() || ShowMatchSummary() ); }

	// Bonus rounds
	CBonusRoundLogic *GetBonusLogic( void ) { return m_hBonusLogic.Get(); }
	void		BuildBonusPlayerList( void );

	CTeamRoundTimer *GetRedKothRoundTimer( void ) { return m_hRedKothTimer.Get(); }
	CTeamRoundTimer *GetBlueKothRoundTimer( void ) { return m_hBlueKothTimer.Get(); }

	int		GetStatsMinimumPlayers( void );
	int		GetStatsMinimumPlayedTime( void );

	// BountyMode
#ifdef STAGING_ONLY
	bool IsBountyMode( void ) { return m_bBountyModeEnabled && !IsMannVsMachineMode() && !IsInTraining(); }
#else
	bool IsBountyMode( void ) { return false; }
#endif

	float GetGravityMultiplier(  void ){ return m_flGravityMultiplier; }

	virtual bool IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer );

	void SetPlayersInHell( bool bState ){ m_bHelltowerPlayersInHell.Set( bState ); } // used for Halloween 2013 state of the game (players in the underworld fighting)
	bool ArePlayersInHell( void ) const { return m_bHelltowerPlayersInHell; }
	void SpawnPlayerInHell( CTFPlayer *pPlayer, const char *pszSpawnPointName );
	
	// Halloween 2013 
	void PlayHelltowerAnnouncerVO( int iRedLine, int iBlueLine );

	void SetUsingSpells( bool bState )
	{ 
		m_bIsUsingSpells.Set( bState ); 
	}

	bool IsUsingSpells( void ) const;
	bool IsUsingGrapplingHook( void ) const;

	bool IsTruceActive( void ) const; 

	bool MapHasMatchSummaryStage( void ){ return m_bMapHasMatchSummaryStage; }
	bool PlayersAreOnMatchSummaryStage( void ){ return m_bPlayersAreOnMatchSummaryStage; }

	bool ShowMatchSummary( void ){ return m_bShowMatchSummary; }

	bool HaveStopWatchWinner( void ) { return m_bStopWatchWinner; }

	int GetGameTeamForGCTeam( TF_GC_TEAM nGCTeam );
	TF_GC_TEAM GetGCTeamForGameTeam( int nGameTeam );

	enum ENextMapVotingState
	{
		NEXT_MAP_VOTE_STATE_NONE,
		NEXT_MAP_VOTE_STATE_WAITING_FOR_USERS_TO_VOTE,
		NEXT_MAP_VOTE_STATE_MAP_CHOSEN_PAUSE,
	};

	enum EUserNextMapVote
	{
		USER_NEXT_MAP_VOTE_MAP_0 = 0,
		USER_NEXT_MAP_VOTE_MAP_1,
		USER_NEXT_MAP_VOTE_MAP_2,
		USER_NEXT_MAP_VOTE_UNDECIDED,

		NUM_VOTE_STATES
	};

	EUserNextMapVote GetWinningVote( int (&nVotes)[ EUserNextMapVote::NUM_VOTE_STATES ] ) const;
	EUserNextMapVote PlayerNextMapVoteState( int nIndex ) const { return m_ePlayerWantsRematch.Get( nIndex ); }
	ENextMapVotingState GetCurrentNextMapVotingState() const { return m_eRematchState; }
	MapDefIndex_t GetNextMapVoteOption( int nIndex ) const { return m_nNextMapVoteOptions.Get( nIndex ); }
	
#ifdef GAME_DLL
	void UpdateNextMapVoteOptionsFromLobby();
	void KickPlayersNewMatchIDRequestFailed();

	void CheckAndSetPartyLeader( CTFPlayer *pTFPlayer, int iTeam );
#endif // GAME_DLL

#ifdef STAGING_ONLY
#ifdef GAME_DLL
	void SetBountyMode( bool bValue );
#endif // GAME_DLL

#endif // STAGING_ONLY

#ifdef CLIENT_DLL

	DECLARE_CLIENTCLASS_NOBASE(); // This makes data tables able to access our private vars.

	virtual ~CTFGameRules();

	virtual void	OnDataChanged( DataUpdateType_t updateType );
	virtual void	HandleOvertimeBegin();

	bool			ShouldShowTeamGoal( void );

	const char *GetVideoFileForMap( bool bWithExtension = true );

	const char *FormatVideoName( const char *videoName, bool bWithExtension = true );

	void			SetUpVisionFilterKeyValues( void );

	bool			UseSillyGibs( void );

	virtual bool	AllowMapParticleEffect( const char *pszParticleEffect );

	virtual bool	AllowWeatherParticles( void );

	virtual bool AllowMapVisionFilterShaders( void );
	virtual const char* TranslateEffectForVisionFilter( const char *pchEffectType, const char *pchEffectName );

	virtual void	ModifySentChat( char *pBuf, int iBufSize );

	virtual void	GetTeamGlowColor( int nTeam, float &r, float &g, float &b );

	virtual bool ShouldConfirmOnDisconnect();

	bool ShouldShowPreRoundDoors() const;
	bool RecievedBaseline() const { return m_bRecievedBaseline; }

#else

	DECLARE_SERVERCLASS_NOBASE(); // This makes data tables able to access our private vars.
	
	virtual ~CTFGameRules();

	virtual void LevelShutdown();
	virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args );
	virtual void Think();

	void PeriodicHalloweenUpdate();

	virtual bool SwitchToNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon );

	bool CheckWinLimit( bool bAllowEnd = true, int nAddValueWhenChecking = 0 ) OVERRIDE;
	bool SetCtfWinningTeam();
	bool SetPasstimeWinningTeam();
	bool CheckCapsPerRound();
	virtual void CheckRespawnWaves();
	virtual void PlayWinSong( int team ) OVERRIDE;

//=============================================================================
// HPE_BEGIN:
// [msmith]	Used in training to load the next training map in sequence.
//=============================================================================
	void LoadNextTrainingMap();
//=============================================================================
// HPE_END
//=============================================================================

	virtual void SetWinningTeam( int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false, bool bFinal = false ) OVERRIDE;
	virtual void SetStalemate( int iReason, bool bForceMapReset = true, bool bSwitchTeams = false );

	void CheckTauntAchievement( CTFPlayer *pAchiever, int nGibs, int *pTauntCamAchievements );

	virtual bool FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker, const CTakeDamageInfo &info );

	// Spawing rules.
	CBaseEntity *GetPlayerSpawnSpot( CBasePlayer *pPlayer );
	bool IsSpawnPointValid( CBaseEntity *pSpot, CBasePlayer *pPlayer, bool bIgnorePlayers, PlayerTeamSpawnMode_t nSpawndMode = PlayerTeamSpawnMode_Normal );

	virtual int ItemShouldRespawn( CItem *pItem );
	virtual float FlItemRespawnTime( CItem *pItem );
	virtual Vector VecItemRespawnSpot( CItem *pItem );
	virtual QAngle VecItemRespawnAngles( CItem *pItem );

	virtual const char *GetChatFormat( bool bTeamOnly, CBasePlayer *pPlayer );
	void ClientSettingsChanged( CBasePlayer *pPlayer );
	void ChangePlayerName( CTFPlayer *pPlayer, const char *pszNewName );

	virtual VoiceCommandMenuItem_t *VoiceCommand( CBaseMultiplayerPlayer *pPlayer, int iMenu, int iItem ); 

	float GetPreMatchEndTime() const;	// Returns the time at which the prematch will be over.
	void GoToIntermission( void );

	virtual int GetAutoAimMode()	{ return AUTOAIM_NONE; }
	void SetSetup( bool bSetup );
	void ManageStopwatchTimer( bool bInSetup );
	virtual void HandleTeamScoreModify( int iTeam, int iScore);

	bool CanHaveAmmo( CBaseCombatCharacter *pPlayer, int iAmmoIndex );

	virtual const char *GetGameDescription( void ){ return "Team Fortress"; }

	virtual void Status( void (*print) (PRINTF_FORMAT_STRING const char *fmt, ...) );

	// Sets up g_pPlayerResource.
	virtual void CreateStandardEntities();

	virtual void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info );
	virtual void PlayerKilledCheckAchievements( CTFPlayer *pAttacker, CTFPlayer *pVictim );
	virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info );
	virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info, const char* eventName );
	virtual CBasePlayer *GetDeathScorer( CBaseEntity *pKiller, CBaseEntity *pInflictor, CBaseEntity *pVictim );

	void CalcDominationAndRevenge( CTFPlayer *pAttacker, CBaseEntity *pWeapon, CTFPlayer *pVictim, bool bIsAssist, int *piDeathFlags );

	const char *GetKillingWeaponName( const CTakeDamageInfo &info, CTFPlayer *pVictim, int *iWeaponID );
	CBasePlayer *GetAssister( CBasePlayer *pVictim, CBasePlayer *pScorer, CBaseEntity *pInflictor );
	CTFPlayer *GetRecentDamager( CTFPlayer *pVictim, int iDamager, float flMaxElapsed );

	virtual void ClientDisconnected( edict_t *pClient );

	virtual void  RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore );
	void	RadiusDamage( CTFRadiusDamageInfo &info );

	bool ApplyOnDamageModifyRules( CTakeDamageInfo &info, CBaseEntity *pVictimBaseEntity, bool bAllowDamage );

	struct DamageModifyExtras_t
	{
		bool bIgniting;
		bool bSelfBlastDmg;
		bool bSendPreFeignDamage;
		bool bPlayDamageReductionSound;
	};
	float ApplyOnDamageAliveModifyRules( const CTakeDamageInfo &info, CBaseEntity *pVictimBaseEntity, DamageModifyExtras_t& outParams );

	virtual float FlPlayerFallDamage( CBasePlayer *pPlayer );

	virtual bool  FlPlayerFallDeathDoesScreenFade( CBasePlayer *pl ) { return false; }

	virtual bool UseSuicidePenalty() { return false; }

	int		GetPreviousRoundWinners( void ) { return m_iPreviousRoundWinners; }

	void	SendHudNotification( IRecipientFilter &filter, HudNotification_t iType, bool bForceShow = false  );
	void	SendHudNotification( IRecipientFilter &filter, const char *pszText, const char *pszIcon, int iTeam = TEAM_UNASSIGNED );
	void	StopWatchModeThink( void );

	virtual		void RestartTournament( void );

	bool	TFVoiceManager( CBasePlayer *pListener, CBasePlayer *pTalker );

	void	OnNavMeshLoad( void );
	void	OnDispenserBuilt( CBaseEntity *dispenser );
	void	OnDispenserDestroyed( CBaseEntity *dispenser );
	void	OnPlayerSpawned( CTFPlayer *pPlayer );
	void	OnCoachJoining( uint32 unCoachAccountID, uint32 unStudentAccountID );
	void 	OnRemoveCoach( uint32 unCoachAccountID );

	//Arena
	void		AddPlayerToQueue( CTFPlayer *pPlayer );
	void		AddPlayerToQueueHead( CTFPlayer *pPlayer );
	void		RemovePlayerFromQueue( CTFPlayer *pPlayer );
	virtual bool BHavePlayers( void ) OVERRIDE;

	void		Arena_RunTeamLogic( void );
	void		Arena_ResetLosersScore( bool bResetAll );
	void		Arena_PrepareNewPlayerQueue( bool bResetAll );
	int			Arena_PlayersNeededForMatch( void );
	void		Arena_CleanupPlayerQueue( void );
	void		Arena_ClientDisconnect( const char *playername );
	void		Arena_SendPlayerNotifications( void );
	void		Arena_NotifyTeamSizeChange( void );
	float		GetRoundStart( void ) { return m_flRoundStartTime; }

	// Voting
	void		ManageServerSideVoteCreation( void );

#ifdef TF_RAID_MODE
	// Raid game mode
	CRaidLogic	*GetRaidLogic( void ) const		{ return m_hRaidLogic.Get(); }
#endif // TF_RAID_MODE

	// Currency awarding
	int		CalculateCurrencyAmount_CustomPack( int nAmount );											// If we should drop a custom currency pack, and how much money to put in - 0 means don't drop
	int		CalculateCurrencyAmount_ByType( CurrencyRewards_t nType );									// How much to give players for specific items and events, i.e. cash collection bonus, small packs
	int		DistributeCurrencyAmount( int nAmount, CTFPlayer *pTFPlayer = NULL, bool bShared = true, bool bCountAsDropped = false, bool bIsBonus = false );	// Distributes nAmount to a specific player or team

	virtual bool StopWatchShouldBeTimedWin( void ) OVERRIDE;

public:
	void SetPlayerNextMapVote( int nIndex, EUserNextMapVote eState ) { m_ePlayerWantsRematch.Set( nIndex, eState ); }

	CTrainingModeLogic *GetTrainingModeLogic() { return m_hTrainingModeLogic; }
	CTFHolidayEntity *GetHolidayLogic() const { return m_hHolidayLogic; }

	void	HandleCTFCaptureBonus( int nTeam );
	bool	TournamentModeCanEndWithTimelimit( void ){ return ( GetStopWatchTimer() == NULL ); }

	CTeamRoundTimer *GetKothTeamTimer( int iTeam )
	{
		if ( IsInKothMode() == false )
			return NULL;

		if ( iTeam == TF_TEAM_RED )
		{
			return m_hRedKothTimer.Get();
		}
		else if ( iTeam == TF_TEAM_BLUE )
		{
			return m_hBlueKothTimer.Get();
		}

		return NULL;
	}

	void SetKothTeamTimer( int iTeam, CTeamRoundTimer *pTimer )
	{
		if ( iTeam == TF_TEAM_RED )
		{
			m_hRedKothTimer.Set( pTimer );
		}
		else if ( iTeam == TF_TEAM_BLUE )
		{
			m_hBlueKothTimer.Set( pTimer );
		}
	}

	void SetOvertimeAllowedForCTF( bool bAllowed ){ m_bOvertimeAllowedForCTF = bAllowed; }
	bool GetOvertimeAllowedForCTF( void ){ return m_bOvertimeAllowedForCTF; }

	const CUtlVector< CHandle< CBaseEntity > > &GetHealthEntityVector( void );		// return vector of health entities 
	const CUtlVector< CHandle< CBaseEntity > > &GetAmmoEntityVector( void );		// return vector of ammo entities 

	CHandle< CTeamTrainWatcher > GetPayloadToPush( int pushingTeam ) const;			// return the train watcher for the Payload cart the given team needs to push to win, or NULL if none currently exists
	CHandle< CTeamTrainWatcher > GetPayloadToBlock( int blockingTeam ) const;		// return the train watcher for the Payload cart the given team needs to block from advancing, or NULL if none currently exists

	virtual void ProcessVerboseLogOutput( void );

	void PushAllPlayersAway( const Vector& vFromThisPoint, float flRange, float flForce, int nTeam, CUtlVector< CTFPlayer* > *pPushedPlayers = NULL );

	bool ShouldDropSpellPickup();
	void DropSpellPickup( const Vector& vPosition, int nTier = 0 ) const;
	
	bool ShouldDropBonusDuck( void );
	bool ShouldDropBonusDuckFromPlayer( CTFPlayer *pScorer, CTFPlayer *pVictim );
	void DropBonusDuck( const Vector& vPosition, CTFPlayer *pScorer = NULL, CTFPlayer *pAssistor = NULL, CTFPlayer *pVictim = NULL, bool bCrit = false, bool bObjective = false ) const;

	void DropHalloweenSoulPackToTeam( int nAmount, const Vector& vecPosition, int nTeamNumber, int nSourceTeam );
	void DropHalloweenSoulPack( int nAmount, const Vector& vecSource, CBaseEntity *pTarget, int nSourceTeam );

#ifdef STAGING_ONLY
	void MatchSummaryTest( void );
#endif // STAGING_ONLY
	void MatchSummaryStart( void );
	void MatchSummaryEnd( void );

	int GetTeamAssignmentOverride( CTFPlayer *pTFPlayer, int iDesiredTeam, bool bAutoBalance = false );
private:

	void ChooseNextMapVoteOptions();

	int DefaultFOV( void ) { return 75; }
	int GetDuckSkinForClass( int nTeam, int nClass ) const;
	void MatchSummaryTeleport();

	void StopWatchShouldBeTimedWin_Calculate( void );
	
#endif // GAME_DLL

private:

	void ComputeHealthAndAmmoVectors( void );		// compute internal vectors of health and ammo locations
	bool m_areHealthAndAmmoVectorsReady;


#ifdef GAME_DLL

	
	void CheckHelltowerCartAchievement( int iTeam );

	Vector2D	m_vecPlayerPositions[MAX_PLAYERS];

	CUtlVector<CHandle<CHealthKit> > m_hDisabledHealthKits;	


	char	m_szMostRecentCappers[MAX_PLAYERS+1];	// list of players who made most recent capture.  Stored as string so it can be passed in events.
	int		m_iNumCaps[TF_TEAM_COUNT];				// # of captures ever by each team during a round

	int SetCurrentRoundStateBitString();
	void SetMiniRoundBitMask( int iMask );
	int m_iPrevRoundState;	// bit string representing the state of the points at the start of the previous miniround
	int m_iCurrentRoundState;
	int m_iCurrentMiniRoundMask;

	CHandle<CTeamRoundTimer>	m_hStopWatchTimer;
	

	CTeamRoundTimer* GetStopWatchTimer( void ) { return (CTeamRoundTimer*)m_hStopWatchTimer.Get(); }

	EHANDLE m_hRequiredObserverTarget;
	EHANDLE m_hObjectiveObserverTarget;

	CHandle<CTFGameRulesProxy> m_hGamerulesProxy;

	//Arena
	bool IsFirstBloodAllowed( void );
	EHANDLE m_hArenaEntity;
	CUtlVector<CHandle<CTFPlayer> > m_hArenaPlayerQueue;	
	int		m_iPreviousTeamSize;
	bool	m_bArenaFirstBlood;

	float	m_flSendNotificationTime;

	// Tournament
	CHandle< CCompetitiveLogic > m_hCompetitiveLogicEntity;
	
	CHandle<CTrainingModeLogic> m_hTrainingModeLogic;
	CHandle<CTFHolidayEntity> m_hHolidayLogic;

	bool	m_bOvertimeAllowedForCTF;

	// for bot rosters
	CHandle<CTFBotRoster> m_hBlueBotRoster;
	CHandle<CTFBotRoster> m_hRedBotRoster;

	// coaching
	typedef CUtlMap<uint32, uint32> tCoachToStudentMap;
	tCoachToStudentMap m_mapCoachToStudentMap;

	// Automatic vote called near the end of a map
	bool	m_bVoteCalled;
	bool	m_bServerVoteOnReset;
	float	m_flVoteCheckThrottle;

	CUtlVector< CHandle< CCPTimerLogic > > m_CPTimerEnts;
	float	m_flCapInProgressBuffer;

	float	m_flMatchSummaryTeleportTime;

#ifdef TF_RAID_MODE
	CHandle< CRaidLogic >		m_hRaidLogic;
	CHandle< CBossBattleLogic > m_hBossBattleLogic;
#endif // TF_RAID_MODE
	
	int		m_nCurrencyAccumulator;
	int		m_iCurrencyPool;

	float	m_flCheckPlayersConnectingTime;

	CountdownTimer m_helltowerTimer;		// used for Halloween 2013 Announcer VO in plr_hightower_event
	CountdownTimer m_doomsdaySetupTimer;	// used for Halloween 2014 Announcer Setup VO in sd_doomsday_event
	CountdownTimer m_doomsdayTicketsTimer;	// Used on sd_doomsday_event to nag players about picking up the tickets

	float m_flNextStrangeEventProcessTime;

	bool m_bMapForcedTruceDuringBossFight;
	float m_flNextHalloweenGiftUpdateTime;
#else

	KeyValues *m_pkvVisionFilterTranslations;
	KeyValues *m_pkvVisionFilterShadersMapWhitelist;

	bool	m_bSillyGibs;

#endif

	CNetworkVar( ETFGameType, m_nGameType ); // Type of game this map is (CTF, CP)
	CNetworkVar( int, m_nStopWatchState );
	CNetworkString( m_pszTeamGoalStringRed, MAX_TEAMGOAL_STRING );
	CNetworkString( m_pszTeamGoalStringBlue, MAX_TEAMGOAL_STRING );
	CNetworkVar( float, m_flCapturePointEnableTime );
	CNetworkVar( int, m_iGlobalAttributeCacheVersion );

//=============================================================================
// HPE_BEGIN:
// [msmith]	Training and HUD status.
//=============================================================================
	CNetworkVar( int, m_nHudType ); // Used by map authors to override the default HUD clients are showing
	CNetworkVar( bool, m_bIsInTraining );
	CNetworkVar( bool, m_bAllowTrainingAchievements );
	CNetworkVar( bool, m_bIsWaitingForTrainingContinue );
//=============================================================================
// HPE_END
//=============================================================================
	CNetworkVar( bool, m_bIsTrainingHUDVisible );

	CNetworkVar( bool, m_bIsInItemTestingMode );
	int		m_iItemTesting_BotAnim;
	float	m_flItemTesting_BotAnimSpeed;
	bool	m_bItemTesting_BotForceFire;
	bool	m_bItemTesting_BotTurntable;
	bool	m_bItemTesting_BotViewScan;

	CNetworkVar( CHandle<CBonusRoundLogic>, m_hBonusLogic );

	CNetworkVar( bool, m_bPlayingKoth );
	CNetworkVar( bool, m_bPowerupMode );
	CNetworkVar( bool, m_bPlayingRobotDestructionMode );
	CNetworkVar( bool, m_bPlayingMedieval );
	CNetworkVar( bool, m_bPlayingHybrid_CTF_CP );
	CNetworkVar( bool, m_bPlayingSpecialDeliveryMode );

	CNetworkVar( bool, m_bPlayingMannVsMachine );
	CNetworkVar( bool, m_bMannVsMachineAlarmStatus );
	CNetworkVar( bool, m_bHaveMinPlayersToEnableReady );

	CNetworkVar( bool, m_bBountyModeEnabled );
	CNetworkVar( bool, m_bCompetitiveMode );
	CNetworkVar( float, m_flGravityMultiplier );
	CNetworkVar( int, m_nMatchGroupType );
	CNetworkVar( bool, m_bMatchEnded );

	// This is used to check if players are in hell. The name doesn't make sense because we thought this would only be used for Halloween 2013
	// cannot change the name because it's network var which will break demo
	CNetworkVar( bool, 	m_bHelltowerPlayersInHell );

	CNetworkVar( bool, m_bIsUsingSpells );

	CNetworkVar( bool, m_bTruceActive );
	CNetworkVar( bool, m_bTeamsSwitched );

#ifdef GAME_DLL
	float	m_flNextFlagAlarm;
	float	m_flNextFlagAlert;

	float	m_flSafeToLeaveTimer;

	CBaseEntity *m_pUpgrades;
#endif

	CNetworkVar( CHandle<CTeamRoundTimer>, m_hRedKothTimer );
	CNetworkVar( CHandle<CTeamRoundTimer>, m_hBlueKothTimer );

	CNetworkVar( int, m_nMapHolidayType ); // Used by map authors to indicate this is a holiday map

	CNetworkString( m_pszCustomUpgradesFile, MAX_PATH );

	CNetworkVar( bool, m_bShowMatchSummary );
	CNetworkVar( bool, m_bMapHasMatchSummaryStage );
	CNetworkVar( bool, m_bPlayersAreOnMatchSummaryStage );
	CNetworkVar( bool, m_bStopWatchWinner );
	// This is called m_ePlayerWantsRematch because we initially had rematches, but now we
	// let players vote on the next map instead.  Can't rename this variable, so we're just
	// going to use with the wrong name
	CNetworkArray( EUserNextMapVote, m_ePlayerWantsRematch, MAX_PLAYERS + 1 );
	CNetworkVar( ENextMapVotingState, m_eRematchState );
	CNetworkArray( MapDefIndex_t, m_nNextMapVoteOptions, 3 );

	float		m_flCTFCaptureBonusTime;
public:

	bool m_bControlSpawnsPerTeam[ MAX_TEAMS ][ MAX_CONTROL_POINTS ];
	int	 m_iPreviousRoundWinners;

	float	GetCapturePointTime( void ) { return m_flCapturePointEnableTime; }

	virtual bool ShouldDrawHeadLabels()
	{ 
		if ( IsInTournamentMode() )
			return false;

		return BaseClass::ShouldDrawHeadLabels();
	}

	enum HalloweenScenarioType
	{
		HALLOWEEN_SCENARIO_NONE = 0,
		HALLOWEEN_SCENARIO_MANN_MANOR,
		HALLOWEEN_SCENARIO_VIADUCT,
		HALLOWEEN_SCENARIO_LAKESIDE,
		HALLOWEEN_SCENARIO_HIGHTOWER,
		HALLOWEEN_SCENARIO_DOOMSDAY,
	};
	HalloweenScenarioType GetHalloweenScenario( void ) const;
	bool IsHalloweenScenario( HalloweenScenarioType scenario ) const;

	bool CanInitiateDuels( void );

#ifdef GAME_DLL

	// Used on sd_doomsday_event to nag players about picking up the tickets
	void StartDoomsdayTicketsTimer( void ) { m_doomsdayTicketsTimer.Start( RandomInt( 30, 60 ) ); }
	void StopDoomsdayTicketsTimer( void ) { m_doomsdayTicketsTimer.Invalidate(); }
	bool DoomsdayTicketTimerElapsed( void ) const { return m_doomsdayTicketsTimer.HasStarted() && m_doomsdayTicketsTimer.IsElapsed(); }

	int GetBossCount() const { return m_activeBosses.Count(); }

	CBaseCombatCharacter *GetActiveBoss( int iBoss = 0 )
	{
		if ( iBoss < 0 || iBoss >= m_activeBosses.Count() )
			return NULL;

		return m_activeBosses[iBoss];
	}

	void AddActiveBoss( CBaseCombatCharacter *boss )
	{
		// don't add the same boss
		if ( m_activeBosses.Find( boss ) != m_activeBosses.InvalidIndex() )
			return;

		m_activeBosses.AddToTail( boss );
	}

	void RemoveActiveBoss( CBaseCombatCharacter *boss )
	{
		m_activeBosses.FindAndRemove( boss );
	}

	CBaseEntity *GetIT( void ) const			// who is the boss chasing
	{
		return m_itHandle;
	}

	void SetIT( CBaseEntity *who );
	void SetBirthdayPlayer( CBaseEntity *pEntity );

	void SetHalloweenEffectStatus( int effect, float duration )		// Update the current Halloween effect on the HUD
	{
		m_nHalloweenEffect = effect;
		m_fHalloweenEffectStartTime = gpGlobals->curtime;
		m_fHalloweenEffectDuration = duration;
	}


	// remove all projectiles in the world
	void RemoveAllProjectiles();

	// remove all buildings in the world
	void RemoveAllBuildings( bool bExplodeBuildings = false );

	// remove all sentry's ammo
	void RemoveAllSentriesAmmo();

	// remove all projectiles and objects
	void RemoveAllProjectilesAndBuildings( bool bExplodeBuildings = false );

#endif // GAME_DLL

	void ClearHalloweenEffectStatus( void )							// Clear the current Halloween effect and hide the HUD display
	{
		m_nHalloweenEffect = -1;
		m_fHalloweenEffectStartTime = -1.0f;
		m_fHalloweenEffectDuration = -1.0f;
	}

	bool IsIT( CBaseEntity *who ) const
	{
		return ( who && who == m_itHandle.Get() );
	}

	CBaseEntity *GetBirthdayPlayer( void ) const
	{
		return m_hBirthdayPlayer.Get();
	}

	bool IsHalloweenEffectStatusActive( void ) const
	{
		return m_nHalloweenEffect >= 0;
	}

	int GetHalloweenEffectStatus( void ) const
	{
		return m_nHalloweenEffect;
	}

	float GetHalloweenEffectTimeLeft( void ) const
	{
		float expireTime = m_fHalloweenEffectStartTime + m_fHalloweenEffectDuration;

		return expireTime - gpGlobals->curtime;
	}

	float GetHalloweenEffectDuration( void ) const
	{
		return m_fHalloweenEffectDuration;
	}

	int GetGlobalAttributeCacheVersion( void ) const
	{
		return m_iGlobalAttributeCacheVersion;
	}

	void FlushAllAttributeCaches( void )
	{
		m_iGlobalAttributeCacheVersion++;
	}

private:	
#ifdef CLIENT_DLL
	bool m_bRecievedBaseline;
#endif


	CountdownTimer m_botCountTimer;

	CUtlVector< CHandle< CBaseEntity > > m_ammoVector;			// vector of active ammo entities
	bool m_isAmmoVectorReady;									// for lazy evaluation

	CUtlVector< CHandle< CBaseEntity > > m_healthVector;		// vector of active health entities
	bool m_isHealthVectorReady;									// for lazy evaluation

	bool m_bUseMatchHUD;
	bool m_bUsePreRoundDoors;
#ifdef GAME_DLL
	mutable CHandle< CTeamTrainWatcher > m_redPayloadToPush;
	mutable CHandle< CTeamTrainWatcher > m_bluePayloadToPush;
	mutable CHandle< CTeamTrainWatcher > m_redPayloadToBlock;
	mutable CHandle< CTeamTrainWatcher > m_bluePayloadToBlock;

	bool m_hasSpawnedToy;
	void SpawnHalloweenBoss( void );
	CountdownTimer m_halloweenBossTimer;
	CUtlVector< CHandle< CBaseCombatCharacter > > m_activeBosses;
	bool m_bHasSpawnedSoccerBall[TF_TEAM_COUNT];

	CountdownTimer m_ghostTimer;

	void SpawnZombieMob( void );
	CountdownTimer m_zombieMobTimer;
	int m_zombiesLeftToSpawn;
	Vector m_zombieSpawnSpot;

public:
	void BeginHaunting( int nDesiredCount, float flMinDuration, float flMaxDuration );

	void StartHalloweenBossTimer( float flTime, float flVariation = 0.f )
	{
		m_halloweenBossTimer.Start( RandomFloat( flTime - flVariation, flTime + flVariation ) );
	}

	// Recent player stuff
	void PlayerHistory_AddPlayer( CTFPlayer *pTFPlayer );
	PlayerHistoryInfo_t *PlayerHistory_GetPlayerInfo( CTFPlayer *pTFPlayer );
	int PlayerHistory_GetTimeSinceLastSeen( CTFPlayer *pTFPlayer );

	CUtlVector< Vector > *GetHalloweenSpawnLocations() { return &m_halloweenGiftSpawnLocations; }

	bool BAttemptMapVoteRollingMatch();

	bool BIsManagedMatchEndImminent( void );

private:
	CUtlVector< CHandle< CGhost > > m_ghostVector;
	CUtlVector< PlayerHistoryInfo_t > m_vecPlayerHistory;

	struct TeleportLocation_t
	{
		Vector m_vecPosition;
		QAngle m_qAngles;
	};
	CUtlMap< string_t, CUtlVector< TeleportLocation_t >* > m_mapTeleportLocations;

	// Keep track of kills made with powerups
	int		m_nPowerupKillsRedTeam;
	int		m_nPowerupKillsBlueTeam;
	float	m_flTimeToRunImbalanceMeasures;
	float	m_flTimeToStopImbalanceMeasures;
	bool	m_bPowerupImbalanceMeasuresRunning;

	bool	m_bMapCycleNeedsUpdate;

	CUtlVector< Vector > m_halloweenGiftSpawnLocations;		// vector of valid gift spawn locations from the map
	float	m_flCompModeRespawnPlayersAtMatchStart;

#endif // GAME_DLL

	// LEGACY BOSS CODE. Keeping this to not break demo
	CNetworkVar( int, m_nBossHealth );
	CNetworkVar( int, m_nMaxBossHealth );
	CNetworkVar( float, m_fBossNormalizedTravelDistance );

	CNetworkHandle( CBaseEntity, m_itHandle );	// entindex of current IT entity (0 = no it)
	CNetworkHandle( CBaseEntity, m_hBirthdayPlayer );	// entindex of current birthday player (0 = none)

	CNetworkVar( int, m_nHalloweenEffect );
	CNetworkVar( float, m_fHalloweenEffectStartTime );
	CNetworkVar( float, m_fHalloweenEffectDuration );
	CNetworkVar( HalloweenScenarioType, m_halloweenScenario );

// MvM Helpers
#ifdef GAME_DLL
public:
	void SetNextMvMPopfile ( const char * next );
	const char * GetNextMvMPopfile ();

	virtual void BalanceTeams( bool bRequireSwitcheesToBeDead );
#endif
};

//-----------------------------------------------------------------------------
// Gets us at the team fortress game rules
//-----------------------------------------------------------------------------

inline CTFGameRules* TFGameRules()
{
	return static_cast<CTFGameRules*>(g_pGameRules);
}

inline float CTFGameRules::ItemTesting_GetBotAnimSpeed( void ) 
{ 
	static const ConVar *pHostTimescale = NULL;

	if ( !pHostTimescale )
	{
		pHostTimescale = cvar->FindVar( "host_timescale" );
	}

	if ( pHostTimescale )
		return (m_flItemTesting_BotAnimSpeed * pHostTimescale->GetFloat());
	return m_flItemTesting_BotAnimSpeed;
}

#ifdef TF_RAID_MODE

inline bool CTFGameRules::IsRaidMode( void ) const
{
#ifdef GAME_DLL
	return m_hRaidLogic != NULL; 
#else
	return tf_gamemode_raid.GetBool();
#endif
}



inline bool CTFGameRules::IsBossBattleMode( void ) const
{
	return tf_gamemode_boss_battle.GetBool();
}

#endif // TF_RAID_MODE

#ifdef TF_CREEP_MODE

inline bool CTFGameRules::IsCreepWaveMode( void ) const
{
	return tf_gamemode_creep_wave.GetBool();
}

#endif


inline bool CTFGameRules::IsHalloweenScenario( HalloweenScenarioType scenario ) const
{
	return m_halloweenScenario == scenario;
}


#ifdef GAME_DLL
bool EntityPlacementTest( CBaseEntity *pMainEnt, const Vector &vOrigin, Vector &outPos, bool bDropToGround );

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CArenaLogic : public CPointEntity
{
	DECLARE_CLASS( CArenaLogic, CPointEntity );
public:
	DECLARE_DATADESC();

	virtual int UpdateTransmitState()
	{
		return SetTransmitState( FL_EDICT_ALWAYS );
	}

	virtual void ArenaLogicThink( void );
	virtual void Spawn( void );

	COutputEvent	m_OnArenaRoundStart;
	float			m_flTimeToEnableCapPoint;
	COutputEvent	m_OnCapEnabled;
	bool			m_bFiredOutput;
};

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CCompetitiveLogic : public CPointEntity
{
	DECLARE_CLASS( CCompetitiveLogic, CPointEntity );
public:
	DECLARE_DATADESC();

	void OnSpawnRoomDoorsShouldLock( void );
	void OnSpawnRoomDoorsShouldUnlock( void );

	COutputEvent	m_OnSpawnRoomDoorsShouldLock;
	COutputEvent	m_OnSpawnRoomDoorsShouldUnlock;
};

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CLogicMannPower : public CPointEntity
{
	DECLARE_CLASS( CLogicMannPower, CPointEntity );
public:
	DECLARE_DATADESC();
};

//-----------------------------------------------------------------------------
// Purpose: New training stuff
//-----------------------------------------------------------------------------
class CTrainingModeLogic : public CPointEntity
{
	DECLARE_CLASS( CTrainingModeLogic, CPointEntity );
public:
	DECLARE_DATADESC();

	void SetupOnRoundStart( void );
	void SetTrainingMsg( const char *msg );
	void SetTrainingObjective( const char *msg );
	void OnPlayerSpawned( CTFPlayer *pPlayer );
	void OnPlayerDied( CTFPlayer *pPlayer, CBaseEntity *pKiller );
	void OnBotDied( CTFPlayer *pPlayer, CBaseEntity *pKiller );
	void OnPlayerSwitchedWeapons( CTFPlayer *pPlayer );
	void OnPlayerWantsToContinue();
	void OnPlayerBuiltBuilding( CTFPlayer *pPlayer, CBaseObject *pBaseObject );
	void OnPlayerUpgradedBuilding( CTFPlayer *pPlayer, CBaseObject *pBaseObject );
	void OnPlayerDetonateBuilding( CTFPlayer *pPlayer, CBaseObject *pBaseObject );
	void UpdateHUDObjective();
	const char* GetNextMap();
	const char* GetTrainingEndText();
	int GetDesiredClass() const;

	// Inputs
	void InputForcePlayerSpawnAsClassOutput( inputdata_t &inputdata );
	void InputKickAllBots( inputdata_t &inputdata );
	void InputShowTrainingMsg( inputdata_t &inputdata );
	void InputShowTrainingObjective( inputdata_t &inputdata );
	void InputShowTrainingHUD( inputdata_t &inputdata );
	void InputHideTrainingHUD( inputdata_t &inputdata );
	void InputEndTraining( inputdata_t &inputdata );
	void InputPlaySoundOnPlayer( inputdata_t &inputdata );
	void InputWaitForTimerOrKeypress( inputdata_t &inputdata );
	void InputSetNextMap( inputdata_t &inputdata );
	void InputForcePlayerSwapToWeapon( inputdata_t &inputdata );

protected:
	enum
	{
		kMaxLengthObjectiveText = 128,
	};

	// outputs based on the class the player spawned as
	COutputEvent m_outputOnPlayerSpawnAsScout;
	COutputEvent m_outputOnPlayerSpawnAsSniper;
	COutputEvent m_outputOnPlayerSpawnAsSoldier;
	COutputEvent m_outputOnPlayerSpawnAsDemoman;
	COutputEvent m_outputOnPlayerSpawnAsMedic;
	COutputEvent m_outputOnPlayerSpawnAsHeavy;
	COutputEvent m_outputOnPlayerSpawnAsPyro;
	COutputEvent m_outputOnPlayerSpawnAsSpy;
	COutputEvent m_outputOnPlayerSpawnAsEngineer;
	// outputs based on the weapon the player swapped to
	COutputEvent m_outputOnPlayerSwappedToWeaponSlotPrimary;
	COutputEvent m_outputOnPlayerSwappedToWeaponSlotSecondary;
	COutputEvent m_outputOnPlayerSwappedToWeaponSlotMelee;
	COutputEvent m_outputOnPlayerSwappedToWeaponSlotBuilding;
	COutputEvent m_outputOnPlayerSwappedToWeaponSlotPDA;
	// outputs based on if the player built inside a suggested area
	COutputEvent m_outputOnPlayerBuiltOutsideSuggestedArea;
	// player detonated their own building
	COutputEvent m_outputOnPlayerDetonateBuilding;
	// other outputs
	COutputEvent m_outputOnPlayerDied;
	COutputEvent m_outputOnBotDied;

	CHandle<CBaseEntity> m_waitingForKeypressTimer;
	string_t m_nextMapName;
	char m_objText[kMaxLengthObjectiveText];
	string_t m_endTrainingText;
};

class CMultipleEscort : public CPointEntity
{
	DECLARE_CLASS( CMultipleEscort, CPointEntity );
public:

	virtual int UpdateTransmitState()
	{
		return SetTransmitState( FL_EDICT_ALWAYS );
	}
};

class CMedievalLogic : public CPointEntity
{
	DECLARE_CLASS( CMedievalLogic, CPointEntity );
public:

	virtual int UpdateTransmitState()
	{
		return SetTransmitState( FL_EDICT_ALWAYS );
	}
};

class CHybridMap_CTF_CP : public CPointEntity
{
	DECLARE_CLASS( CHybridMap_CTF_CP, CPointEntity );
public:

	virtual int UpdateTransmitState()
	{
		return SetTransmitState( FL_EDICT_ALWAYS );
	}
};

class CTFHolidayEntity : public CPointEntity, public CGameEventListener
{
	DECLARE_CLASS( CTFHolidayEntity, CPointEntity );
public:
	DECLARE_DATADESC();

	CTFHolidayEntity()
	{ 
		m_nHolidayType = kHoliday_None;
		m_nTauntInHell = 0;
		m_nAllowHaunting = 0;
		ListenForGameEvent( "player_turned_to_ghost" );
		ListenForGameEvent( "player_disconnect" );
		ListenForGameEvent( "player_team" );
	}
	~CTFHolidayEntity()
	{
	}

	virtual int UpdateTransmitState()
	{
		return SetTransmitState( FL_EDICT_ALWAYS );
	}
	int GetHolidayType( void ){ return m_nHolidayType; }
	bool ShouldTauntInHell( void ){ return ( m_nTauntInHell > 0 ); }
	bool ShouldAllowHaunting( void ){ return ( m_nAllowHaunting > 0 ); }

	void InputHalloweenSetUsingSpells( inputdata_t &inputdata );
	void InputHalloweenTeleportToHell( inputdata_t &inputdata );

	virtual void FireGameEvent( IGameEvent *event );

	void ResetWinner() { m_nWinningTeam = TF_TEAM_COUNT; }
	int GetWinningTeam() const { return m_nWinningTeam; }
private:

	void HalloweenTeleportToHellDanceThink( void );
	void Teleport();

	CUtlVector< CHandle<CTFPlayer> > m_vecDancers;
	int m_nWinningTeam;

	int m_nHolidayType;
	int m_nTauntInHell;
	int m_nAllowHaunting;
};

class CKothLogic : public CPointEntity
{
	DECLARE_CLASS( CKothLogic, CPointEntity );
public:
	DECLARE_DATADESC();

	CKothLogic()
	{ 
		m_nTimerInitialLength = 180; // seconds
		m_nTimeToUnlockPoint = 30; // seconds

		m_hRedTimer = NULL;
		m_hBlueTimer = NULL;
	}
	virtual int UpdateTransmitState()
	{
		return SetTransmitState( FL_EDICT_ALWAYS );
	}

	int GetInitialTimerLength( void ){ return m_nTimerInitialLength; }
	int GetTimerToUnlockPoint( void ){ return m_nTimeToUnlockPoint; }

	void InputRoundSpawn( inputdata_t &inputdata );
	void InputRoundActivate( inputdata_t &inputdata );
	void InputSetRedTimer( inputdata_t &inputdata );
	void InputSetBlueTimer( inputdata_t &inputdata );
	void InputAddRedTimer( inputdata_t &inputdata );
	void InputAddBlueTimer( inputdata_t &inputdata );

private:
	int m_nTimerInitialLength;
	int m_nTimeToUnlockPoint;

	CHandle< CTeamRoundTimer > m_hRedTimer;
	CHandle< CTeamRoundTimer > m_hBlueTimer;
};

#define CP_TIMER_THINK "CCPTimerLogicThink"
class CCPTimerLogic : public CPointEntity
{
	DECLARE_CLASS( CCPTimerLogic, CPointEntity );
public:
	DECLARE_DATADESC();

	CCPTimerLogic()
	{ 
		m_nTimerLength = 60; // seconds
		m_iszControlPointName = NULL_STRING;
		m_hControlPoint = NULL;
		m_bFire15SecRemain = m_bFire10SecRemain = m_bFire5SecRemain = true;
	
		SetContextThink( &CCPTimerLogic::Think, gpGlobals->curtime + 0.15, CP_TIMER_THINK );
	}
	virtual int UpdateTransmitState()
	{
		return SetTransmitState( FL_EDICT_ALWAYS );
	}

	void InputRoundSpawn( inputdata_t &inputdata );
	void Think( void );
	bool TimerMayExpire( void );

private:
	int m_nTimerLength;
	string_t m_iszControlPointName;
	CHandle<CTeamControlPoint> m_hControlPoint;
	CountdownTimer m_pointTimer;

	bool m_bFire15SecRemain;
	bool m_bFire10SecRemain;
	bool m_bFire5SecRemain;

	COutputEvent m_onCountdownStart;
	COutputEvent m_onCountdown15SecRemain;
	COutputEvent m_onCountdown10SecRemain;
	COutputEvent m_onCountdown5SecRemain;
	COutputEvent m_onCountdownEnd;
};
#endif

class CBonusRoundLogic : public CBaseEntity
{
	DECLARE_CLASS( CBonusRoundLogic, CBaseEntity );
public:
	DECLARE_NETWORKCLASS();

#ifdef GAME_DLL
	bool		InitBonusRound( void );
	void		SetBonusItem( itemid_t iItemID );
	virtual int UpdateTransmitState()
	{
		return SetTransmitState( FL_EDICT_ALWAYS );
	}
#endif

	void		BuildBonusPlayerList( void );
	int			GetNumBonusPlayers( void ) { return m_aBonusPlayerList.Count(); }
	CTFPlayer	*GetBonusPlayer( int i ) { Assert ( i < m_aBonusPlayerList.Count() ); return m_aBonusPlayerList[i]; }
	CTFPlayer	*GetBonusWinner( void ) { return m_hBonusWinner.Get(); }
	void		SetBonusStateAborted( bool bAborted ) { m_bAbortedBonusRound = bAborted; }
	bool		BonusStateAborted( void ) { return m_bAbortedBonusRound; }
	int			GetPlayerBonusRoll( int iPlayer ) { return (iPlayer < m_aBonusPlayerRoll.Count()) ? m_aBonusPlayerRoll[iPlayer] : 0; }
	CEconItemView	*GetBonusItem( void ) { return &m_Item; }

private:
	CUtlSortVector< BONUSPLAYERPTR, CBonusPlayerListLess >	m_aBonusPlayerList;
	CUtlVector<int>			m_aBonusPlayerRoll;
	CNetworkVar( CHandle<CTFPlayer>, m_hBonusWinner );
	CNetworkVar( bool,		m_bAbortedBonusRound );
	itemid_t			m_iBonusItemID;
	CNetworkVarEmbedded( CEconItemView,	m_Item );
};

#ifdef GAME_DLL
class CSingleUserReliableRecipientFilter : public CRecipientFilter
{
public:
	CSingleUserReliableRecipientFilter( CBasePlayer *player )
	{
		AddRecipient( player );
		MakeReliable();
	}
};
#endif

#endif // TF_GAMERULES_H