//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Medic's resupply beacon
//
// $NoKeywords: $
//=============================================================================//

#include "cbase.h"
#include "tf_obj.h"
#include "tf_player.h"
#include "tf_team.h"
#include "techtree.h"
#include "tf_shield.h"
#include "VGuiScreen.h"

//-----------------------------------------------------------------------------
// Shield wall defines
//-----------------------------------------------------------------------------

#define SHIELDWALL_MINS				Vector(-20, -20, 0)
#define SHIELDWALL_MAXS				Vector( 20,  20, 100)

#define SHIELD_WALL_PITCH -10.0f


ConVar	obj_shieldwall_health( "obj_shieldwall_health","200", FCVAR_NONE, "Shield wall health" );


//-----------------------------------------------------------------------------
// Shield wall object that's built by the player
//-----------------------------------------------------------------------------
class CObjectShieldWallBase : public CBaseObject
{
DECLARE_CLASS( CObjectShieldWallBase, CBaseObject );

public:
	CObjectShieldWallBase();

	virtual void	UpdateOnRemove( void );

	virtual void	Spawn();

	virtual void	PowerupStart( int iPowerup, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier );
	virtual	void	PowerupEnd( int iPowerup );

	// Team change
	virtual void	ChangeTeam( int nTeamNumber ) OVERRIDE;

public:
	CNetworkHandle( CShield, m_hDeployedShield );
};

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CObjectShieldWallBase::CObjectShieldWallBase()
{
	m_hDeployedShield.Set(0);
	AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CObjectShieldWallBase::UpdateOnRemove( void )
{
	if ( m_hDeployedShield.Get() )
	{
		UTIL_Remove( m_hDeployedShield );
		m_hDeployedShield.Set( NULL );
	}

	// Chain at end to mimic destructor unwind order
	BaseClass::UpdateOnRemove();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CObjectShieldWallBase::Spawn()
{
	m_takedamage = DAMAGE_YES;

	SetType( OBJ_SHIELDWALL );

	BaseClass::Spawn();
}

//-----------------------------------------------------------------------------
// Purpose: Powerup has just started
//-----------------------------------------------------------------------------
void CObjectShieldWallBase::PowerupStart( int iPowerup, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier )
{
	switch( iPowerup )
	{
	case POWERUP_BOOST:
		// Increase our shield's energy
		if ( m_hDeployedShield )
		{
			m_hDeployedShield->SetPower( m_hDeployedShield->GetPower() + (flAmount * 3) );
		}
		break;

	case POWERUP_EMP:
		if (m_hDeployedShield)
		{
			m_hDeployedShield->SetEMPed(true);
		}
		break;

	default:
		break;
	}

	BaseClass::PowerupStart( iPowerup, flAmount, pAttacker, pDamageModifier );
}

//-----------------------------------------------------------------------------
// Purpose: Powerup has just started
//-----------------------------------------------------------------------------
void CObjectShieldWallBase::PowerupEnd( int iPowerup )
{
	switch ( iPowerup )
	{
	case POWERUP_EMP:
		if (m_hDeployedShield)
		{
			m_hDeployedShield->SetEMPed(false);
		}
		break;

	default:
		break;
	}

	BaseClass::PowerupEnd( iPowerup );
}


//-----------------------------------------------------------------------------
// Team change
//-----------------------------------------------------------------------------
void CObjectShieldWallBase::ChangeTeam( int nTeamNumber )
{
	BaseClass::ChangeTeam( nTeamNumber );
	if ( m_hDeployedShield )
	{
		m_hDeployedShield->ChangeTeam( nTeamNumber );
	}
}


//-----------------------------------------------------------------------------
// Shield wall object that's built by the player
//-----------------------------------------------------------------------------
class CObjectShieldWall : public CObjectShieldWallBase
{
DECLARE_CLASS( CObjectShieldWall, CObjectShieldWallBase );

public:
	DECLARE_SERVERCLASS();

					CObjectShieldWall();

	virtual void	Spawn();
	virtual void	Precache();
	virtual void	GetControlPanelInfo( int nPanelIndex, const char *&pPanelName );
	virtual void	ObjectMoved( );
	virtual void	FinishedBuilding( void );
};

IMPLEMENT_SERVERCLASS_ST(CObjectShieldWall, DT_ObjectShieldWall)
	SendPropEHandle(SENDINFO(m_hDeployedShield)),
END_SEND_TABLE();

LINK_ENTITY_TO_CLASS(obj_shieldwall, CObjectShieldWall);
PRECACHE_REGISTER(obj_shieldwall);

CObjectShieldWall::CObjectShieldWall()
{
	UseClientSideAnimation();
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CObjectShieldWall::Spawn()
{
	SetModel( "models/objects/obj_shieldwall.mdl" );
	SetSolid( SOLID_BBOX );
	UTIL_SetSize(this, SHIELDWALL_MINS, SHIELDWALL_MAXS);
	m_iHealth = obj_shieldwall_health.GetInt();
	m_hDeployedShield = NULL;

	SetType( OBJ_SHIELDWALL );

	BaseClass::Spawn();
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CObjectShieldWall::Precache()
{
	PrecacheModel( "models/objects/obj_shieldwall.mdl" );
	PrecacheVGuiScreen( "screen_obj_shieldwall" );
}


//-----------------------------------------------------------------------------
// Purpose: Gets info about the control panels
//-----------------------------------------------------------------------------
void CObjectShieldWall::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
{
	pPanelName = "screen_obj_shieldwall";
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CObjectShieldWall::FinishedBuilding( void )
{
	BaseClass::FinishedBuilding();

	int nAttachmentIndex = LookupAttachment( "projectionpoint" );

	m_hDeployedShield = CreateMobileShield( this );
	m_hDeployedShield->SetAlwaysOrient( false );
	m_hDeployedShield->SetAttachmentIndex( nAttachmentIndex );
	m_hDeployedShield->SetAngularSpringConstant( 20 );
	ObjectMoved();
}


//-----------------------------------------------------------------------------
// Called when the builder rotates this object...
//-----------------------------------------------------------------------------
void CObjectShieldWall::ObjectMoved( )
{
	if (m_hDeployedShield)
	{
		VMatrix matangles;
		VMatrix matoffset;
		VMatrix matfinal;

		// This represents how much to pitch the shield up from the attachment point
		QAngle angleOffset( SHIELD_WALL_PITCH, 0, 0 );

		// Get the location and angles of the attachment point
		// Attachment point position is the origin of the shield
		QAngle angles;

		// Rotate the angles of the attachment point by the angle offset
		MatrixFromAngles( GetAbsAngles(), matangles );
		MatrixFromAngles( angleOffset, matoffset );
		MatrixMultiply( matangles, matoffset, matfinal );
		MatrixToAngles( matfinal, angles );
		m_hDeployedShield->SetCenterAngles( angles );

		m_hDeployedShield->ShieldMoved();
	}
	BaseClass::ObjectMoved();
}