//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Entities for use in the Robot Destruction TF2 game mode.
//
//=========================================================================//
#ifndef LOGIC_ROBOT_DESTRUCTION_H
#define LOGIC_ROBOT_DESTRUCTION_H
#pragma once

#include "cbase.h"

#ifdef GAME_DLL
	#include "triggers.h"
	#include "tf_shareddefs.h"
	#include "GameEventListener.h"
	#include "entity_capture_flag.h"
#else
	#include "c_tf_player.h"
#endif


#include "tf_robot_destruction_robot.h"

#ifdef CLIENT_DLL
	#define CTFRobotDestructionLogic C_TFRobotDestructionLogic
	#define CTFRobotDestruction_RobotSpawn C_TFRobotDestruction_RobotSpawn
	#define CTFRobotDestruction_RobotGroup C_TFRobotDestruction_RobotGroup
#endif

#include "props_shared.h"

#define RD_POINTS_STOLEN_PER_TICK 2

//-----------------------------------------------------------------------------
class CTFRobotDestruction_RobotSpawn : public CBaseEntity
{
public:
	DECLARE_DATADESC();
	DECLARE_CLASS( CTFRobotDestruction_RobotSpawn, CBaseEntity )
	DECLARE_NETWORKCLASS();

	CTFRobotDestruction_RobotSpawn();

	virtual void Spawn() OVERRIDE;
	virtual void Activate() OVERRIDE;

#ifdef GAME_DLL
	virtual void Precache() OVERRIDE;
	virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const OVERRIDE;

	CTFRobotDestruction_Robot* GetRobot() const { return m_hRobot.Get(); }
	void OnRobotKilled();
	void ClearRobot();
	void SpawnRobot();
	void SetGroup( class CTFRobotDestruction_RobotGroup* pGroup ) { m_hGroup.Set( pGroup ); }
	// Inputs
	void InputSpawnRobot( inputdata_t &inputdata );
	
#endif
private:
	CHandle< CTFRobotDestruction_Robot > m_hRobot;
#ifdef GAME_DLL
	CHandle< class CTFRobotDestruction_RobotGroup > m_hGroup;
	RobotSpawnData_t m_spawnData;
	COutputEvent m_OnRobotKilled;
#endif
};

//-----------------------------------------------------------------------------
DECLARE_AUTO_LIST( IRobotDestructionGroupAutoList );
class CTFRobotDestruction_RobotGroup : public CBaseEntity, public IRobotDestructionGroupAutoList
{
	DECLARE_DATADESC();
	DECLARE_CLASS( CTFRobotDestruction_RobotGroup, CBaseEntity )
	DECLARE_NETWORKCLASS();
public:
	virtual ~CTFRobotDestruction_RobotGroup();
#ifdef GAME_DLL

	CTFRobotDestruction_RobotGroup();

	virtual int		UpdateTransmitState() OVERRIDE { return SetTransmitState( FL_EDICT_ALWAYS ); }
	virtual void	Spawn() OVERRIDE;
	virtual void	Activate() OVERRIDE;
	void	AddToGroup( CTFRobotDestruction_RobotSpawn * pSpawn );
	void	RemoveFromGroup( CTFRobotDestruction_RobotSpawn * pSpawn );
	void	UpdateState();
	void	RespawnRobots();
	int		GetNumAliveBots() const;
	float	GetTeamRespawnScale() const	{ return m_flTeamRespawnReductionScale; }

	// Respawn functions
	void StopRespawnTimer();
	void StartRespawnTimerIfNeeded( CTFRobotDestruction_RobotGroup *pMasterGroup );
	void RespawnCountdownFinish();

	void EnableUberForGroup();
	void DisableUberForGroup();

	void OnRobotAttacked();
	void OnRobotKilled();
	void OnRobotSpawned();
#else
	virtual void PostDataUpdate( DataUpdateType_t updateType ) OVERRIDE;
	virtual int GetTeamNumber( void ) const OVERRIDE { return m_iTeamNum; }
	virtual void SetDormant( bool bDormant ) OVERRIDE;
#endif
	const char *GetHUDIcon() const		{ return m_pszHudIcon; }
	int		GetGroupNumber() const		{ return m_nGroupNumber; }
	int		GetState() const			{ return m_nState; }
	float	GetRespawnStartTime() const	{ return m_flRespawnStartTime; }
	float	GetRespawnEndTime() const	{ return m_flRespawnEndTime; }
	float	GetLastAttackedTime() const	{ return m_flLastAttackedTime; }

private:

#ifdef GAME_DLL
	CUtlVector< CTFRobotDestruction_RobotSpawn* > m_vecSpawns;
	int m_nTeamNumber;
	IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_iTeamNum );
	float m_flRespawnTime;
	static float m_sflNextAllowedAttackAlertTime[ TF_TEAM_COUNT ];
	string_t m_iszHudIcon;
	float m_flTeamRespawnReductionScale;

	COutputEvent m_OnRobotsRespawn;
	COutputEvent m_OnAllRobotsDead;
#else
	int m_iTeamNum;
#endif
	CNetworkString( m_pszHudIcon, MAX_PATH );
	CNetworkVar( int, m_nGroupNumber );
	CNetworkVar( int, m_nState );
	CNetworkVar( float, m_flRespawnStartTime );
	CNetworkVar( float, m_flRespawnEndTime );
	CNetworkVar( float, m_flLastAttackedTime );
};

struct RateLimitedSound_t
{
	RateLimitedSound_t( float flPause )
	{
		m_mapNextAllowedTime.SetLessFunc( DefLessFunc( const CBaseEntity* ) );
		m_flPause = flPause;
	}

	float m_flPause;
	CUtlMap< const CBaseEntity*, float > m_mapNextAllowedTime;
};

struct TeamSound_t
{
	const char *m_pszYourTeam;
	const char *m_pszTheirTeam;
};

//-----------------------------------------------------------------------------
class CTFRobotDestructionLogic : public CBaseEntity
#ifdef GAME_DLL
	, public CGameEventListener
#endif
{
	DECLARE_CLASS( CTFRobotDestructionLogic, CBaseEntity )
	DECLARE_NETWORKCLASS();
public:

	enum EType
	{
		TYPE_ROBOT_DESTRUCTION,
		TYPE_PLAYER_DESTRUCTION,
	};

	virtual EType GetType() const { return TYPE_ROBOT_DESTRUCTION; }

	CTFRobotDestructionLogic();
	virtual ~CTFRobotDestructionLogic();
	static CTFRobotDestructionLogic* GetRobotDestructionLogic();

	virtual void Spawn() OVERRIDE;
	virtual void Precache() OVERRIDE;

	float	GetRespawnScaleForTeam( int nTeam ) const;
	int		GetScore( int nTeam ) const;
	int		GetTargetScore( int nTeam ) const;
	int		GetMaxPoints() const { return m_nMaxPoints.Get(); }
	float	GetFinaleWinTime( int nTeam ) const;
	float	GetFinaleLength() const { return m_flFinaleLength; }
	void	PlaySoundInfoForScoreEvent( CTFPlayer* pPlayer, bool bPositive, int nNewScore, int nTeam, RDScoreMethod_t eMethod = SCORE_UNDEFINED );
	RDScoreMethod_t GetLastScoreMethod( int nTeam ) const { return (RDScoreMethod_t)m_eWinningMethod[ nTeam ]; }

#ifdef CLIENT_DLL

	virtual void OnDataChanged( DataUpdateType_t type ) OVERRIDE;
	virtual void ClientThink() OVERRIDE;
	const char* GetResFile() const { return STRING( m_szResFile ); }

#else
	DECLARE_DATADESC();

	virtual void Activate() OVERRIDE;
	virtual void FireGameEvent( IGameEvent * event ) OVERRIDE;

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

	CTFRobotDestruction_Robot * IterateRobots( CTFRobotDestruction_Robot * ) const;
	void	RobotCreated( CTFRobotDestruction_Robot *pRobot );
	void	RobotRemoved( CTFRobotDestruction_Robot *pRobot );
	void	RobotAttacked( CTFRobotDestruction_Robot *pRobot );
	float	GetScoringInterval() const { return m_flRobotScoreInterval; }
	void	ScorePoints( int nTeam, int nPoints, RDScoreMethod_t eMethod, CTFPlayer *pPlayer );
	void	AddRobotGroup( CTFRobotDestruction_RobotGroup* pGroup );
	void	ManageGameState();
	void	FlagCreated( int nTeam );
	void	FlagDestroyed( int nTeam );
	
	void	DBG_SetMaxPoints( int nNewMax ) { m_nMaxPoints.Set( nNewMax ); }
	void	InputRoundActivate( inputdata_t &inputdata );
	virtual int GetHealDistance( void ) { return 64; }
#endif

	virtual void SetCountdownEndTime( float flTime ){ m_flCountdownEndTime = flTime; }
	virtual float GetCountdownEndTime(){ return m_flCountdownEndTime; }
	virtual CTFPlayer *GetTeamLeader( int iTeam ) const { return NULL; }
	virtual string_t GetCountdownImage( void ) { return NULL_STRING; }
	virtual bool IsUsingCustomCountdownImage( void ) { return false; }

protected:


#ifdef GAME_DLL
	virtual void OnRedScoreChanged() {}
	virtual void OnBlueScoreChanged() {}
	void	ApproachTargetScoresThink();
	int		ApproachTeamTargetScore( int nTeam, int nApproachScore, int nCurrentScore );
	void	PlaySoundInPlayersEars( CTFPlayer* pPlayer, const EmitSound_t& params ) const;
	void	RedTeamWin();
	void	BlueTeamWin();
	virtual void	TeamWin( int nTeam );

	typedef CUtlMap< int, CTFRobotDestruction_RobotGroup* > RobotSpawnMap_t;
	CUtlVector< CTFRobotDestruction_Robot* > m_vecRobots;
	CUtlVector< CTFRobotDestruction_RobotGroup * > m_vecSpawnGroups;
	float m_flLoserRespawnBonusPerBot;
	float m_flRobotScoreInterval;
	float m_flNextRedRobotAttackedAlertTime;
	float m_flNextBlueRobotAttackedAlertTime;
	int m_nNumFlagsOut[ TF_TEAM_COUNT ];
	bool m_bEducateNewConnectors;
	string_t m_iszResFile;

	TeamSound_t m_AnnouncerProgressSound;
	CUtlMap< const char *, RateLimitedSound_t * > m_mapRateLimitedSounds;

	CUtlVector< CTFPlayer* > m_vecEducatedPlayers;

	// Outputs
	COutputEvent m_OnRedFinalePeriodEnd;
	COutputEvent m_OnBlueFinalePeriodEnd;
	COutputEvent m_OnBlueHitZeroPoints;
	COutputEvent m_OnRedHitZeroPoints;
	COutputEvent m_OnBlueHasPoints;
	COutputEvent m_OnRedHasPoints;
	COutputEvent m_OnBlueHitMaxPoints;
	COutputEvent m_OnRedHitMaxPoints;
	COutputEvent m_OnBlueLeaveMaxPoints;
	COutputEvent m_OnRedLeaveMaxPoints;

	COutputEvent m_OnRedFirstFlagStolen;
	COutputEvent m_OnRedFlagStolen;
	COutputEvent m_OnRedLastFlagReturned;
	COutputEvent m_OnBlueFirstFlagStolen;
	COutputEvent m_OnBlueFlagStolen;
	COutputEvent m_OnBlueLastFlagReturned;
#else
	float		m_flLastTickSoundTime;
#endif
	static CTFRobotDestructionLogic* m_sCTFRobotDestructionLogic;
	CNetworkVar( int, m_nMaxPoints );
	CNetworkVar( float, m_flFinaleLength );
	CNetworkVar( float, m_flBlueFinaleEndTime );
	CNetworkVar( float, m_flRedFinaleEndTime );
	CNetworkVar( int, m_nBlueScore );
	CNetworkVar( int, m_nRedScore );
	CNetworkVar( int, m_nBlueTargetPoints );
	CNetworkVar( int, m_nRedTargetPoints );
	CNetworkVar( float, m_flBlueTeamRespawnScale );
	CNetworkVar( float, m_flRedTeamRespawnScale );
	CNetworkString( m_szResFile, MAX_PATH );
	CNetworkArray( int, m_eWinningMethod, TF_TEAM_COUNT );
	CNetworkVar( float, m_flCountdownEndTime ); // used for player destruction countdown timers
};

#ifdef GAME_DLL
class CRobotDestructionVaultTrigger : public CBaseTrigger
{
	DECLARE_CLASS( CRobotDestructionVaultTrigger, CBaseTrigger );
	DECLARE_DATADESC();

public:
	CRobotDestructionVaultTrigger();
	virtual void Spawn() OVERRIDE;
	virtual void Precache() OVERRIDE;

	virtual bool PassesTriggerFilters( CBaseEntity *pOther ) OVERRIDE;
	virtual void StartTouch(CBaseEntity *pOther) OVERRIDE;
	virtual void EndTouch(CBaseEntity *pOther) OVERRIDE;

private:
	void StealPointsThink();
	int StealPoints( CTFPlayer *pPlayer );

	bool m_bIsStealing;
	COutputEvent m_OnPointsStolen;
	COutputEvent m_OnPointsStartStealing;
	COutputEvent m_OnPointsEndStealing;
};

#endif// GAME_DLL
#endif// LOGIC_ROBOT_DESTRUCTION_H