//========= Copyright © 1996-2005, Sander Corporation, All rights reserved. ============//
//
// Purpose: TODO: Make a new class for the shared stuff of the basebuilding and component.
//
// $NoKeywords: $
//=============================================================================//

#ifndef CBASEBUILDING_H
#define CBASEBUILDING_H
#ifdef _WIN32
#pragma once
#endif

#include "hl2wars/rts_mouse_model.h"
#include "Sprite.h"
#include "ai_dynamiclink.h"

// All kind of destruction effects we support for buildings. Because we love blowing things up.
#define EF_PARTICLE			( 1 << 0 )		// 1, show the specified particle on event_killed
#define EF_JUNK				( 1 << 1 )		// 2, throw junk around
#define EF_CINEMATIC		( 1 << 2 )	    // 4, play the animation "explode" for a certain time before being removed
#define EF_SHAKE			( 1 << 3 )		// 8, Shake!
#define EF_EXPLOSION		( 1 << 4 )		// 16, Show the specified sprite by using explode
#define EF_SINK				( 1 << 5 )		// 32, MAke the building sink into the ground

enum Building_states_t
{
	BS_PRECONSTRUCTION = 0,
	BS_UNDERCONSTRUCTION,
	BS_CONSTRUCTED,
};

class CNavArea;
class CBuildingComponent;

// ##################################################################################
//	>> Bae Building Model implementation
//
// ##################################################################################
class CBaseBuildingModel : public CMouseRTSModel
{
public:
	DECLARE_CLASS( CBaseBuildingModel, CMouseRTSModel );

	DECLARE_SERVERCLASS();
	DECLARE_DATADESC();

	CBaseBuildingModel();
	~CBaseBuildingModel();
	void	UpdateOnRemove();

	virtual void Spawn( void );
	virtual void Precache();
	virtual void Activate();

	virtual void CreateSelectionHelper( const Vector &vecOrigin, const Vector &vecMins, const Vector &vecMaxs, CBaseEntity *pOwner );
	virtual void DestroySelectionHelper();

	// Only CBaseEntity implements these. CheckTransmit calls the virtual ShouldTransmit to see if the
	// entity wants to be sent. If so, it calls SetTransmit, which will mark any dependents for transmission too.
	virtual int				ShouldTransmit( const CCheckTransmitInfo *pInfo );

	Class_T 		Classify();

	virtual bool KeyValue( const char *szKeyName, const char *szValue );

	virtual void OnClickLeft( CBasePlayer *pActivator );
	virtual void OnClickRight( CBasePlayer *pActivator );
	virtual void OnClickLeftDouble( CBasePlayer *pActivator );
	virtual void OnClickRightDouble( CBasePlayer *pActivator );

	virtual int GetBrushType( void ) { return MOUSEBRUSH_BUILDING; }
	virtual int GetOwnerShip( void ) { return m_iOwnerShip; }

	// props don't think they are alive. Buildings are
	virtual bool IsAlive( void );

	int UpdateTransmitState()	// set transmit filter to transmit always
	{
		return SetTransmitState( FL_EDICT_FULLCHECK );
	}

	// ---------------------------------------------------
	// Base building functions ( construct, destroy, etc)
	// ---------------------------------------------------
	//virtual const impactdamagetable_t	&GetPhysicsImpactDamageTable( void );

	int					TakeHealth( float flHealth, int bitsDamageType );
	void				CauseDeath( const CTakeDamageInfo &info );
	void				SetHealth( int amt );


	// Don't override this for characters, override the per-life-state versions below
	virtual int				OnTakeDamage( const CTakeDamageInfo &info );

	// Override these to control how your character takes damage in different states
	virtual int				OnTakeDamage_Alive( const CTakeDamageInfo &info );
	virtual int				OnTakeDamage_Dying( const CTakeDamageInfo &info );
	virtual int				OnTakeDamage_Dead( const CTakeDamageInfo &info );

	// Character killed (only fired once)
	virtual void			Event_Killed( const CTakeDamageInfo &info );

	// some explosion types will use this
	virtual void			BreakThink(void);
	void					LinearMove( const Vector &vecDest, float flSpeed );

	// ---------------------------------------------------
	// Model building functions
	// ---------------------------------------------------
	void SetOwnership( int new_owner );
	void SetIconTarget( Vector icon_target );

	// ---------------------------------------------------
	// Construction functions
	// ---------------------------------------------------
	//void SetConstructed( bool constructed );
	void SetConstructTime( float time );
	void ConstructThink( void );

	void SetConstructionState( int state );

	// ---------------------------------------------------
	// Build/recruit functions
	// ---------------------------------------------------
	virtual bool AddToQueue( int ability, int ai_group ) { return false; }
	virtual bool RemoveFromQueue( int queue ) { return false; }
	virtual int CountQueue() { return 0; }
	virtual void OnSelectedRightClick( Vector position ) {}
	virtual int GetTypeAbility( int i ) { return 0; }

	virtual void BuildThink( void );

	// ---------------------------------------------------
	// Building component manage functions
	// ---------------------------------------------------
	virtual void CreateComponents( KeyValues *pComponents );
	virtual void AddComponent(CBuildingComponent *pComponent);	// this is for preplaced components in maps
	virtual void PrecacheComponents( KeyValues *pComponents );
	virtual void DestroyComponents( const CTakeDamageInfo &info );
	virtual void RemoveComponents();
	
	// ---------------------------------------------------
	// Node/nav mesh control. Buildings need to block nodes
	// ---------------------------------------------------
	bool DisableNodes( bool disable );
	bool UpdateNavAreas( bool block );

	// ---------------------------------------------------
	// anim
	// ---------------------------------------------------
	void AnimThink();
	void PropSetAnim( const char *szAnim );
	void FinishSetSequence( int nSequence );
	void PropSetSequence( int nSequence );

private:
	int					m_iGoalSequence;
	int					m_iTransitionDirection;

	// Random animations
	bool				m_bRandomAnimator;
	float				m_flNextRandAnim;
	float				m_flMinRandAnimTime;
	float				m_flMaxRandAnimTime;
	short				m_nPendingSequence;

private:
	void InputChangeOwnerShip( inputdata_t &inputdata );

//-- Navigation data
private:
	CHandle<CAI_DynamicLinkController> m_hLinkController;
	CUtlVector<unsigned int> m_utlBlockedNavList;

// -- Construction data
private:
	IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_iHealth );
	IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_iMaxHealth );

	//CNetworkVar( bool, m_bConstructed );
	CNetworkVar( int, m_iConstructionState );
	CNetworkVar( int, m_iConstructProgress );
	float m_fConstructTime;
	float m_fConstructFinished;

// -- selection helper data
private:
	bool m_bUseSelectionHelper;
	Vector m_vSelectionMin;
	Vector m_vSelectionMax;

// -- Animations
private:
	string_t			m_iszIdleAnim;

// -- Explosion/Destruction data
private:
	int m_nExplosionFlags;

	// EF_PARTICLE
	string_t m_iszExplosionParticle;
	
	// EF_EXPLOSION
	string_t m_iszFireballSprite;
	short m_sFireballSprite;
	int m_iMagnitude;
	int m_spriteScale;
	
	// EF_CINEMATIC
	float m_fCleanUpDuration;
	float m_fCleanUpTime;

	// EF_SHAKE
	float m_Amplitude;
	float m_Frequency;
	float m_Duration;
	float m_Radius;			// radius of 0 means all players

	// EF_SINK
	Vector m_vecFinalDest;
	float m_fSinkSpeed;

// -- sounds
private:
	string_t m_iszSoundSelected;
	string_t m_iszSoundDestroyed;

private:
	CUtlVector<CBuildingComponent *> m_ComponentsList;

// -- Build data
protected:
	CNetworkVar( int, m_iOwnerShip );	// which team owns this building?
	CNetworkVar( float, m_fViewDistance );

private:
	CNetworkVector( m_vOwnerShipIconTarget );
	string_t m_iszIcon;
	CNetworkString( m_iszNetIcon, MAX_PATH );

	EHANDLE m_hSprite;
	EHANDLE m_hSelectionHelper;
};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// CBuildingComponent
// Purpose: A way to add submodels that can receive clicks or damage and pass it
//			to the parent building
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class CBuildingComponent : public CMouseRTSModel
{
public:
	DECLARE_CLASS( CBuildingComponent, CMouseRTSModel );

	DECLARE_SERVERCLASS();
	DECLARE_DATADESC();

	CBuildingComponent();

	virtual void SetOuter( CBaseBuildingModel *pOuter )	{ m_hOuter = pOuter; }

	CBaseBuildingModel *		GetOuter() 			{ return m_hOuter.Get(); }
	const CBaseBuildingModel *	GetOuter() const 	{ return m_hOuter.Get(); }

	virtual void	Precache();
	virtual void	Spawn();
	Class_T 		Classify();

	// some explosion types will use this
	virtual void			Event_Killed( const CTakeDamageInfo &info );
	virtual void			BreakThink(void);
	void					LinearMove( const Vector &vecDest, float flSpeed );

	// we might be in break think. In that case we will remove ourself after a certain time
	bool					CanBeRemoved() { return m_bCanBeRemoved; }

	virtual bool KeyValue( const char *szKeyName, const char *szValue );

	// Don't override this for characters, override the per-life-state versions below
	virtual int				OnTakeDamage( const CTakeDamageInfo &info );

	virtual void OnClickLeft( CBasePlayer *pActivator );
	virtual void OnClickRight( CBasePlayer *pActivator );
	virtual void OnClickLeftDouble( CBasePlayer *pActivator );
	virtual void OnClickRightDouble( CBasePlayer *pActivator );

	// ---------------------------------------------------
	// anim
	// ---------------------------------------------------
	void AnimThink();
	void PropSetAnim( const char *szAnim );
	void FinishSetSequence( int nSequence );
	void PropSetSequence( int nSequence );

private:
	int					m_iGoalSequence;
	int					m_iTransitionDirection;

	// Random animations
	bool				m_bRandomAnimator;
	float				m_flNextRandAnim;
	float				m_flMinRandAnimTime;
	float				m_flMaxRandAnimTime;
	short				m_nPendingSequence;

	// -- Explosion/Destruction data
private:
	int m_nExplosionFlags;

	// EF_PARTICLE
	string_t m_iszExplosionParticle;
	
	// EF_EXPLOSION
	string_t m_iszFireballSprite;
	short m_sFireballSprite;
	int m_iMagnitude;
	int m_spriteScale;
	
	// EF_CINEMATIC
	float m_fCleanUpDuration;
	float m_fCleanUpTime;

	// EF_SHAKE
	float m_Amplitude;
	float m_Frequency;
	float m_Duration;
	float m_Radius;			// radius of 0 means all players

	// EF_SINK
	Vector m_vecFinalDest;
	float m_fSinkSpeed;

private:
	bool m_bCanBeRemoved;

private:
	CNetworkHandle( CBaseBuildingModel, m_hOuter );
};


#endif // CBASEBUILDING_H