//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "c_basefourwheelvehicle.h"
#include "tf_movedata.h"
#include "ObjectControlPanel.h"
#include <vgui_controls/Label.h>
#include <vgui_controls/Button.h>
#include "vehicle_mortar_shared.h"
#include "vgui_rotation_slider.h"
#include <vgui/ISurface.h>
#include "vgui_BasePanel.h"
#include "ground_line.h"
#include "hud_minimap.h"
#include "vgui_bitmapimage.h"
#include "iusesmortarpanel.h"

// How long it waits after you've changed the mortar's yaw to draw using the server's value.
#define CLIENT_MORTAR_YAW_COUNTDOWN	0.5


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class C_VehicleMortar : public C_BaseTFFourWheelVehicle, public IUsesMortarPanel
{
	DECLARE_CLASS( C_VehicleMortar, C_BaseTFFourWheelVehicle );
public:
	DECLARE_CLIENTCLASS();

	C_VehicleMortar();

	virtual void ReceiveMessage( const char *msgname, int length, void *data );

	// Fire off a mortar.
	void FireMortar();

	virtual void ClientThink();

// C_BaseEntity overrides.
public:
	virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]);

// IUsesMortarPanel
public:
	// Get the data from this mortar needed by the panel
	virtual void	GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState );
	virtual void	SendYawCommand( void );
	virtual void	ForceClientYawCountdown( float flTime );
	virtual void	ClickFire( void );

public:
	// Mortar firing info.
	int m_iFiringState; // One of the MORTAR_ defines.
	bool m_bMortarReloading;
	float m_flPower;
	bool m_bAllowedToFire;
	
	// Parameters for the next shot.
	float m_flFiringPower;
	float m_flFiringAccuracy;

	float m_flMortarYaw;	// What direction the mortar is aimed in.
	float m_flMortarPitch;
	
	// This is what is used on the client to draw the ground line and orient the mortar.
	// It is usually copied right over from m_flClientMortarYaw (which comes from the server),
	// but this is also used when rotating the mortar so you can see the line move smoothly.
	float m_flClientMortarYaw;

	// This is set to about 1/4 seconds when you rotate the mortar line so you use the client's
	// (smooth, non-lagged) yaw changes instead of the server's.
	float m_flForceClientYawCountdown;

private:
	C_VehicleMortar( const C_VehicleMortar & );		// not defined, not accessible

};


IMPLEMENT_CLIENTCLASS_DT(C_VehicleMortar, DT_VehicleMortar, CVehicleMortar)
	RecvPropFloat( RECVINFO( m_flMortarYaw ) ),
	RecvPropFloat( RECVINFO( m_flMortarPitch ) ),
	RecvPropBool( RECVINFO( m_bAllowedToFire ) )
END_RECV_TABLE()


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------

C_VehicleMortar::C_VehicleMortar()
{
	m_iFiringState = MORTAR_IDLE;
	m_bMortarReloading = false;
	m_flPower = 0;
	
	m_flMortarYaw = 0;
	m_flClientMortarYaw = 0;
	m_flMortarPitch = 0;
	m_flForceClientYawCountdown = 0;
	m_bAllowedToFire = true;

	SetNextClientThink( CLIENT_THINK_ALWAYS );
}


void C_VehicleMortar::ReceiveMessage( const char *msgname, int length, void *data )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_VehicleMortar::ClickFire()
{
	switch( m_iFiringState )
	{
	case MORTAR_IDLE:
		m_iFiringState = MORTAR_CHARGING_POWER;
		break;
	
	case MORTAR_CHARGING_POWER:
		m_flFiringPower = m_flPower;
		m_iFiringState = MORTAR_CHARGING_ACCURACY;
		break;
	
	case MORTAR_CHARGING_ACCURACY:
		m_flFiringAccuracy = m_flPower;
		m_iFiringState = MORTAR_IDLE;

		FireMortar();
		break;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_VehicleMortar::FireMortar()
{
	char cmd[512];
	Q_snprintf( cmd, sizeof( cmd ), "FireMortar %.2f %.2f", m_flFiringPower, m_flFiringAccuracy );
	SendClientCommand( cmd );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_VehicleMortar::SendYawCommand( void )
{
	char szbuf[48];
	Q_snprintf( szbuf, sizeof( szbuf ), "MortarYaw %0.2f\n", m_flClientMortarYaw );
	SendClientCommand( szbuf );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_VehicleMortar::ForceClientYawCountdown( float flTime )
{
	m_flForceClientYawCountdown = flTime;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_VehicleMortar::GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState )
{
	*flClientMortarYaw = m_flClientMortarYaw;
	*bAllowedToFire = m_bAllowedToFire;
	*flPower = m_flPower;
	*flFiringPower = m_flFiringPower;
	*flFiringAccuracy = m_flFiringAccuracy;
	*iFiringState = m_iFiringState;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_VehicleMortar::ClientThink()
{
	m_flForceClientYawCountdown -= gpGlobals->frametime;
	if ( m_flForceClientYawCountdown <= 0 )
	{
		m_flClientMortarYaw = m_flMortarYaw;
	}
}


void C_VehicleMortar::GetBoneControllers( float controllers[MAXSTUDIOBONECTRLS])
{
	BaseClass::GetBoneControllers( controllers);

	controllers[0] = anglemod( m_flClientMortarYaw ) / 360.0;
	controllers[1] = anglemod( m_flMortarPitch ) / 360.0;
}


//-----------------------------------------------------------------------------
// CMortarMinimapPanel
//-----------------------------------------------------------------------------
CMortarMinimapPanel::CMortarMinimapPanel( vgui::Panel *pParent, const char *pElementName )
	: CMinimapPanel( pElementName )
{
	SetParent( pParent );

	m_bMouseDown = false;
	m_bFireButtonDown = false;
	m_LastX = m_LastY = -1;
	
	m_nTextureId = vgui::surface()->CreateNewTextureID();
	vgui::surface()->DrawSetTextureFile( m_nTextureId, "hud/minimap/mortar_slider", true, false );

	m_nTextureId_CantFire = vgui::surface()->CreateNewTextureID();
	vgui::surface()->DrawSetTextureFile( m_nTextureId_CantFire, "hud/minimap/mortar_slider_cantfire", true, false );
}


CMortarMinimapPanel::~CMortarMinimapPanel()
{
}

void CMortarMinimapPanel::InitMortarMinimap( C_BaseEntity *pMortar )
{
	BaseClass::Init( NULL );

	m_hMortar = pMortar;
	
	m_MortarButtonUp.Init( GetVPanel(), "hud/minimap/icon_mortarbutton_up" );
	m_MortarButtonDown.Init( GetVPanel(), "hud/minimap/icon_mortarbutton_dn" );
	m_MortarButtonCantFire.Init( GetVPanel(), "hud/minimap/icon_mortarbutton_cantfire" );
	
	m_MortarDirectionImage.Init( GetVPanel(), "hud/minimap/icon_player_arrow" );
	m_MortarDirectionImage.SetColor( Color( 0, 255, 0, 255 ) );
}


C_BaseEntity *CMortarMinimapPanel::GetMortar() const
{
	return (C_BaseEntity*)m_hMortar;
}


void CMortarMinimapPanel::Paint()
{
	BaseClass::Paint();

	C_BaseEntity *pMortar = GetMortar();
	IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar );
	if ( pMortar && pMortarInterface )
	{
		float flClientMortarYaw, flPower, flFiringPower, flFiringAccuracy;
		int iFiringState;
		bool bAllowedToFire; 
		pMortarInterface->GetMortarData( &flClientMortarYaw, &bAllowedToFire, &flPower, &flFiringPower, &flFiringAccuracy, &iFiringState );

		float yaw = flClientMortarYaw + 90;
	
		float x, y;
		if ( WorldToMinimap( MINIMAP_CLAMP, pMortar->GetAbsOrigin(), x, y ) )
		{
			int size = 20;
			
			BitmapImage *pImage = &m_MortarButtonCantFire;
			if ( bAllowedToFire )
			{				
				if ( m_bFireButtonDown )
					pImage = &m_MortarButtonDown;
				else
					pImage = &m_MortarButtonUp;
			}

			pImage->DoPaint( x-size/2, y-size/2, size, size, yaw );

			size = 40;
			m_MortarDirectionImage.DoPaint( x-size/2, y-size/2, size, size, pMortar->GetAbsAngles()[YAW] + 90 );

		
			// Draw the power bar.
			float flAngle = pMortar->GetAbsAngles()[YAW] + flClientMortarYaw;
			Vector vForward( -sin( DEG2RAD( flAngle ) ), cos( DEG2RAD( flAngle ) ), 0 );
			Vector vRight( vForward.y, -vForward.x, 0 );

			Vector vStartPoint = pMortar->GetAbsOrigin();
			Vector vEndPoint = vStartPoint + vForward * MORTAR_RANGE_MAX_INITIAL;
			Vector vInaccuracy = vEndPoint + vRight * (MORTAR_RANGE_MAX_INITIAL * MORTAR_INACCURACY_MAX_INITIAL);
			
			Vector2D vStart2D, vEnd2D, vInaccuracy2D;
			WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, vStartPoint, vStart2D.x, vStart2D.y );
			WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, vEndPoint, vEnd2D.x, vEnd2D.y );
			WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, vInaccuracy, vInaccuracy2D.x, vInaccuracy2D.y );
			
			Vector2D vDir = vEnd2D - vStart2D;
			Vector2DNormalize( vDir );

			
			// These variables control the look.
			float flLength = (vEnd2D - vStart2D).Length();
			float flZeroT = 1.0f / 5;
			float flZero = flLength * flZeroT;
			
			float flFirePower = max( flPower, flFiringPower );

			float flStartFatness = 2;
			float flEndFatness = flStartFatness;
			
			float flScalePower = flFiringAccuracy;
			if ( iFiringState != MORTAR_IDLE )
				flScalePower = flPower;

			Vector2D vInaccuracyDir = vInaccuracy2D - vEnd2D;
			flEndFatness *= vInaccuracyDir.Length() * flScalePower * 0.4;
			flEndFatness = max( fabs( flEndFatness ), flStartFatness );
			
			Vector2D vPerp( vDir.y, -vDir.x );
			Vector2DNormalize( vPerp );
			
			Vector2D vStartPerp = vPerp * flStartFatness;
			Vector2D vEndPerp = vPerp * flEndFatness;

			
			// Draw the red-black power bars.
			vgui::ISurface *pSurface = vgui::surface();
			if ( bAllowedToFire )
				pSurface->DrawSetTexture( m_nTextureId );
			else
				pSurface->DrawSetTexture( m_nTextureId_CantFire );
			
			Vector2D vZeroPerp;
			Vector2DLerp( vStartPerp, vEndPerp, flZero / flLength, vZeroPerp );
						
			// Draw a black->red bar from zero to our current power.
			float flFirePowerDistance = RemapVal( flFirePower, 0, 1, flZero, flLength );
			Vector2D vPowerPerp;
			Vector2DLerp( vStartPerp, vEndPerp, RemapVal( flFirePowerDistance, flZero, flLength, flZeroT, 1 ), vPowerPerp );

			vgui::Vertex_t verts[4];
			verts[0].Init( vStart2D + vDir * flZero - vZeroPerp );
			verts[1].Init( verts[0].m_Position + vZeroPerp * 2 );

			verts[2].Init( vStart2D + vDir * flFirePowerDistance + vPowerPerp, Vector2D( flFirePower, 0 ) );
			verts[3] = verts[2];
			verts[3].m_Position -= vPowerPerp * 2;
			
			pSurface->DrawSetColor( 255, 255, 255, 255 );
			pSurface->DrawTexturedPolygon( 4, verts );


			// Draw the power slider.
			pSurface->DrawSetTexture( -1 );


			vgui::Vertex_t line[2];
			line[0].Init( vStart2D + vDir * flFirePowerDistance - vPowerPerp );
			line[1].Init( line[0].m_Position + vPowerPerp * 2 );
			pSurface->DrawTexturedLine( line[0], line[1] );



			// Draw a white outline.
			pSurface->DrawSetColor( 255, 255, 255, 255 );
			vgui::Vertex_t pts[4] =
			{
				vgui::Vertex_t( vStart2D - vStartPerp ),
				vgui::Vertex_t( vStart2D + vStartPerp ),
				vgui::Vertex_t( vEnd2D + vEndPerp ),
				vgui::Vertex_t( vEnd2D - vEndPerp )
			};
			pSurface->DrawTexturedPolyLine( pts, 4 );


			// Draw the zero line.
			line[0].Init( vStart2D + vDir * flZero - vZeroPerp );
			line[1].Init( line[0].m_Position + vZeroPerp * 2 );
			pSurface->DrawTexturedLine( line[0], line[1] );
		}
	}
}


void CMortarMinimapPanel::OnMousePressed( vgui::MouseCode code )
{
	BaseClass::OnMousePressed( code );

	if (code != vgui::MOUSE_LEFT)
		return;

	C_BaseEntity *pMortar = GetMortar();
	IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar );
	if ( !pMortar || !pMortarInterface )
		return;

	float flClientMortarYaw, flPower, flFiringPower, flFiringAccuracy;
	int iFiringState;
	bool bAllowedToFire; 
	pMortarInterface->GetMortarData( &flClientMortarYaw, &bAllowedToFire, &flPower, &flFiringPower, &flFiringAccuracy, &iFiringState );
	
	// See if they clicked the "fire" button.
	float x, y;
	if ( WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, pMortar->GetAbsOrigin(), x, y ) &&
		(Vector2D( x, y ) - Vector2D( m_LastX, m_LastY )).Length() <= 8 )
	{
		if ( bAllowedToFire )
		{
			// Treat it like they clicked the fire button.
			m_bFireButtonDown = true;
			pMortarInterface->ClickFire();
		}
	}
	else
	{
		pMortarInterface->ForceClientYawCountdown( 5000000 );
	}

	m_bMouseDown = true;
}


void CMortarMinimapPanel::OnCursorMoved( int x, int y )
{
	m_LastX = x;
	m_LastY = y;

	if ( !m_bMouseDown || m_bFireButtonDown )
		return;

	C_BaseEntity *pMortar = GetMortar();
	IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar );
	if ( !pMortar || !pMortarInterface )
		return;

	float flClientMortarYaw, flPower, flFiringPower, flFiringAccuracy;
	int iFiringState;
	bool bAllowedToFire; 
	pMortarInterface->GetMortarData( &flClientMortarYaw, &bAllowedToFire, &flPower, &flFiringPower, &flFiringAccuracy, &iFiringState );

	float mortarX, mortarY;
	if ( WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, pMortar->GetAbsOrigin(), mortarX, mortarY ) )
	{
		float flAngle = atan2( x - mortarX, mortarY - y );
		flClientMortarYaw = -anglemod( flAngle * 180.0f / M_PI + pMortar->GetAbsAngles()[YAW] );
	}
}


void CMortarMinimapPanel::OnMouseReleased( vgui::MouseCode code )
{
	BaseClass::OnMouseReleased( code );

	if ( code != vgui::MOUSE_LEFT )
		return;

	m_bMouseDown = false;
	
	if ( m_bFireButtonDown )
	{
		m_bFireButtonDown = false;
	}
	else
	{
		C_BaseEntity *pMortar = GetMortar();
		IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar );
		if ( pMortar && pMortarInterface )
		{
			pMortarInterface->SendYawCommand();
			pMortarInterface->ForceClientYawCountdown( CLIENT_MORTAR_YAW_COUNTDOWN );
		}
	}
}


//-----------------------------------------------------------------------------
// Control screen 
//-----------------------------------------------------------------------------
class CVehicleMortarControlPanel : public CObjectControlPanel
{
	DECLARE_CLASS( CVehicleMortarControlPanel, CObjectControlPanel );

public:
	
	CVehicleMortarControlPanel( vgui::Panel *parent, const char *panelName );
	virtual ~CVehicleMortarControlPanel();
	
	virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
	virtual void OnCommand( const char *command );
	C_VehicleMortar* GetMortar() const;


protected:

	virtual vgui::Panel* TickCurrentPanel();


private:

	void OnTickMainPanel();
	void OnTickDeployPanel( float flDeployTime );
	void OnTickGunnerPanel();

	void GetInRam( void );

	void StartDeploying();
	void StopDismantling();
	bool IsDeploying() const;
	bool IsUndeploying() const;
	bool IsDeployed() const;

private:
	vgui::Label		*m_pDriverLabel;
	vgui::Label		*m_pPassengerLabel;
	vgui::Button	*m_pOccupyButton;
	vgui::Button	*m_pCancelDeployButton;
	
	vgui::Label *m_pDeployMessageLabel; // says "Deployed in" or "Undeployed in"
	vgui::Label *m_pDeployTimeLabel; // says "N seconds"
	
	vgui::EditablePanel	*m_pDeployPanel;
	vgui::EditablePanel	*m_pGunnerPanel;

	CMortarMinimapPanel *m_pMinimapPanel;
	
	vgui::Label *m_pReloadingLabel;
};


DECLARE_VGUI_SCREEN_FACTORY( CVehicleMortarControlPanel, "vehicle_mortar_control_panel" );


//-----------------------------------------------------------------------------
// Constructor: 
//-----------------------------------------------------------------------------
CVehicleMortarControlPanel::CVehicleMortarControlPanel( vgui::Panel *parent, const char *panelName )
	: BaseClass( parent, "CVehicleMortarControlPanel" ) 
{
	m_pDeployPanel = new CCommandChainingPanel( this, "DeployPanel" );
	m_pDeployPanel->SetZPos( -1 );

	m_pGunnerPanel = new CCommandChainingPanel( this, "GunnerPanel" );
	m_pGunnerPanel->SetZPos( -1 );

	m_pMinimapPanel = new CMortarMinimapPanel( m_pGunnerPanel, "MinimapPanel" );
	m_pMinimapPanel->SetZPos( 10 );
	m_pMinimapPanel->Init( NULL );
}


CVehicleMortarControlPanel::~CVehicleMortarControlPanel()
{
	delete m_pMinimapPanel;
}


//-----------------------------------------------------------------------------
// Initialization 
//-----------------------------------------------------------------------------
bool CVehicleMortarControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
{
	m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" );
	m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" );
	m_pOccupyButton = new vgui::Button( this, "OccupyButton", "Occupy" );
	
	m_pDeployMessageLabel = new vgui::Label( m_pDeployPanel, "DeployMessage", "" );
	m_pDeployTimeLabel = new vgui::Label( m_pDeployPanel, "DeployTime", "" );
	m_pCancelDeployButton = new vgui::Button( m_pDeployPanel, "CancelDeployButton", "" );

	m_pReloadingLabel = new vgui::Label( m_pGunnerPanel, "ReloadingLabel", "" );

	// Make sure all named panels are created up above because BaseClass::Init initializes them
	// all from their keyvalues.
	if ( !BaseClass::Init( pKeyValues, pInitData ) )
		return false;

	// Init subpanels.
	int x, y, w, h;
	GetBounds( x, y, w, h );

	m_pMinimapPanel->LevelInit( engine->GetLevelName() );
	m_pMinimapPanel->SetVisible( true );
	m_pMinimapPanel->InitMortarMinimap( GetMortar() );
	
	m_pDeployPanel->SetBounds( x, y, w, h );
	m_pDeployPanel->SetVisible( false );

	m_pGunnerPanel->SetBounds( x, y, w, h );
	m_pGunnerPanel->SetVisible( false );

	m_pReloadingLabel->SetVisible( false );
	return true;
}


//-----------------------------------------------------------------------------
// Frame-based update
//-----------------------------------------------------------------------------

vgui::Panel* CVehicleMortarControlPanel::TickCurrentPanel()
{
	C_VehicleMortar *pMortar = GetMortar();
	if ( !pMortar )
		return BaseClass::TickCurrentPanel();

	if ( IsUndeploying() )
	{
		OnTickDeployPanel( pMortar->GetDeployFinishTime() );
		return m_pDeployPanel;
	}
	else if ( IsDeploying() )
	{
		OnTickDeployPanel( pMortar->GetDeployFinishTime() );
		return m_pDeployPanel;
	}
	else if ( IsDeployed() )
	{
		OnTickGunnerPanel();
		return m_pGunnerPanel;
	}
	else
	{
		OnTickMainPanel();
		return BaseClass::TickCurrentPanel();
	}
}


C_VehicleMortar* CVehicleMortarControlPanel::GetMortar() const
{
	return dynamic_cast< C_VehicleMortar* >( GetOwningObject() );
}


void CVehicleMortarControlPanel::OnTickMainPanel()
{
	C_BaseObject *pObj = GetOwningObject();
	if (!pObj)
		return;

	ShowOwnerLabel( true );
	ShowHealthLabel( true );

	Assert( dynamic_cast<C_VehicleMortar*>(pObj) );
	C_VehicleMortar *pRam = static_cast<C_VehicleMortar*>(pObj);

	char buf[256];
	// Update the currently manned player label
	if ( pRam->GetDriverPlayer() )
	{
		Q_snprintf( buf, 256, "Driven by %s", pRam->GetDriverPlayer()->GetPlayerName() );
		m_pDriverLabel->SetText( buf );
		m_pDriverLabel->SetVisible( true );
	}
	else
	{
		m_pDriverLabel->SetVisible( false );
	}

	int nPassengerCount = pRam->GetPassengerCount();
	int nMaxPassengerCount = pRam->GetMaxPassengerCount();

	Q_snprintf( buf, 256, "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 );
	m_pPassengerLabel->SetText( buf );

	// Update the get in button
	if ( pRam->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) ) 
	{
		m_pOccupyButton->SetEnabled( false );
		return;
	}

	if ( pRam->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() )
	{
		if (nPassengerCount == nMaxPassengerCount)
		{
			// Owners can boot other players to get in
			C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pRam->GetPassenger( VEHICLE_DRIVER ));
			Q_snprintf( buf, 256, "Get In (Ejecting %s)", pPlayer->GetPlayerName() );
			m_pDriverLabel->SetText( buf );
			m_pOccupyButton->SetEnabled( true );
		}
		else
		{
			m_pOccupyButton->SetText( "Get In" );
			m_pOccupyButton->SetEnabled( true );
		}
	}
	else
	{
		m_pOccupyButton->SetText( "Get In" );
		m_pOccupyButton->SetEnabled( pRam->GetPassengerCount() < pRam->GetMaxPassengerCount() );
	}
}


void CVehicleMortarControlPanel::OnTickDeployPanel( float flDeployTime )
{
	ShowDismantleButton( false );

	// Update the countdown.
	int nSec = (int)(flDeployTime - gpGlobals->curtime + 0.5f);
	if (nSec < 0)
		nSec = 0;

	char buf[256];
	int nLen = Q_snprintf( buf, 256, "%d second", nSec );
	if (nSec != 1)
	{
		buf[nLen] = 's';
		++nLen;
		buf[nLen] = 0;
	}

	m_pDeployTimeLabel->SetText( buf );
}


void CVehicleMortarControlPanel::OnTickGunnerPanel()
{
	C_VehicleMortar *pMortar = GetMortar();
	if ( !pMortar )
		return;

	ShowOwnerLabel( false );
	ShowHealthLabel( false );

	m_pMinimapPanel->Repaint();

	// If it's reloading, tell the player
	m_pReloadingLabel->SetVisible( pMortar->m_bMortarReloading );
	if ( pMortar->m_bMortarReloading )
	{
		return;
	}

	float flAccuracySpeed = (1.0 / MORTAR_CHARGE_ACCURACY_RATE);

	// Handle power charging
	switch( pMortar->m_iFiringState )
	{
	case MORTAR_IDLE:
		pMortar->m_flPower = 0;
		break;

	case MORTAR_CHARGING_POWER:
		pMortar->m_flPower = min( pMortar->m_flPower + ( (1.0 / MORTAR_CHARGE_POWER_RATE) * gpGlobals->frametime), 1 );
		pMortar->m_flFiringPower = 0;
		pMortar->m_flFiringAccuracy = 0;
		if ( pMortar->m_flPower >= 1.0 )
		{
			// Hit Max, start going down
			pMortar->m_flFiringPower = pMortar->m_flPower;
			pMortar->m_iFiringState = MORTAR_CHARGING_ACCURACY;
		}
		break;

	case MORTAR_CHARGING_ACCURACY:
		// Calculate accuracy speed
		if ( pMortar->m_flFiringPower > 0.5 )
		{
			// Shots over halfway suffer an increased speed to the accuracy power, making accurate shots harder
			float flAdjustedPower = (pMortar->m_flFiringPower - 0.5) * 3.0;
			flAccuracySpeed += (pMortar->m_flFiringPower * flAdjustedPower);
		}

		pMortar->m_flPower = max( pMortar->m_flPower - ( flAccuracySpeed * gpGlobals->frametime), -0.25f);
		if ( pMortar->m_flPower <= -0.25 )
		{
			// Hit Min, fire mortar
			pMortar->m_flFiringAccuracy = pMortar->m_flPower;
			pMortar->m_iFiringState = MORTAR_IDLE;

			pMortar->FireMortar();
		}
		break;
	
	default:
		break;
	}
}


//-----------------------------------------------------------------------------
// Purpose: Handle clicking on the Occupy button
//-----------------------------------------------------------------------------
void CVehicleMortarControlPanel::GetInRam( void )
{
	SendToServerObject( "toggle_use" );
}

//-----------------------------------------------------------------------------
// Starts/stops deploying
//-----------------------------------------------------------------------------

bool CVehicleMortarControlPanel::IsDeploying() const
{
	C_VehicleMortar *pMortar = GetMortar();
	if ( !pMortar )
		return false;

	return !IsDeployed() && pMortar->GetDeployFinishTime() > 0.0f;
}

bool CVehicleMortarControlPanel::IsUndeploying() const
{
	C_VehicleMortar *pMortar = GetMortar();
	if ( !pMortar )
		return false;

	return IsDeployed() && pMortar->GetDeployFinishTime() > 0.0f;
}

bool CVehicleMortarControlPanel::IsDeployed() const
{
	C_VehicleMortar *pMortar = GetMortar();
	if ( pMortar )
		return pMortar->GetVehicleModeDeploy() == VEHICLE_MODE_DEPLOYED;
	else
		return false;
}

//-----------------------------------------------------------------------------
// Button click handlers
//-----------------------------------------------------------------------------
void CVehicleMortarControlPanel::OnCommand( const char *command )
{
	C_VehicleMortar *pMortar = GetMortar();
	if ( !pMortar )
		return;

	if (!Q_strnicmp(command, "Occupy", 7))
	{
		GetInRam();
		return;
	}
	else if ( !Q_stricmp( command, "Deploy" ) )
	{
		m_pDeployMessageLabel->SetText( "Deployed in" );
		m_pCancelDeployButton->SetVisible( true );

		SendToServerObject( "Deploy" );	// Tell the server.
	}
	else if ( !Q_stricmp( command, "CancelDeploy" ) )
	{
		SendToServerObject( command );
	}
	else if ( !Q_stricmp( command, "Undeploy" ) )
	{
		m_pDeployMessageLabel->SetText( "Undeployed in" );
		m_pCancelDeployButton->SetVisible( false );

		SendToServerObject( "Undeploy" );	// Tell the server.
	}
	else if ( !Q_stricmp( command, "FireMortar" ) )
	{
		pMortar->ClickFire();
	}

	BaseClass::OnCommand(command);
}

