//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================//

#include "cbase.h"
#include "c_walker_strider.h"
#include "beamdraw.h"
#include "clienteffectprecachesystem.h"

extern ConVar vehicle_free_pitch, vehicle_free_roll;


CLIENTEFFECT_REGISTER_BEGIN( PrecacheWalkerStrider )
CLIENTEFFECT_MATERIAL( STRIDER_BEAM_MATERIAL )
CLIENTEFFECT_REGISTER_END()


IMPLEMENT_CLIENTCLASS_DT( C_WalkerStrider, DT_WalkerStrider, CWalkerStrider )
	RecvPropInt( RECVINFO( m_bCrouched ) )
END_RECV_TABLE()
LINK_ENTITY_TO_CLASS( walker_strider, C_WalkerStrider );


ConVar cl_brush_ropes( "cl_brush_ropes", "0" );


C_WalkerStrider::C_WalkerStrider()
{
	m_bCrouched = false;
}


C_WalkerStrider::~C_WalkerStrider()
{
	for ( int i=0; i < STRIDER_NUM_ROPES; i++ )
	{
		if ( m_hRopes[i].Get() )
			m_hRopes[i]->Release();
	}
}


float sideDist = 90;
float downDist = -400;
#include "studio.h"
bool C_WalkerStrider::GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld )
{
	//
	//
	// This is a TOTAL hack, but we don't have any nodes that work well at all for mounted guns.
	//
	//
	CStudioHdr *pStudioHdr = GetModelPtr( );
	if ( !pStudioHdr || iAttachment < 1 || iAttachment > pStudioHdr->GetNumAttachments() )
	{
		return false;
	}

	Vector vLocalPos( 0, 0, 0 );
	const mstudioattachment_t &pAttachment = pStudioHdr->pAttachment( iAttachment-1 );
	if ( stricmp( pAttachment.pszName(), "build_point_left_gun" ) == 0 )
	{
		vLocalPos.y = sideDist;
	}
	else if ( stricmp( pAttachment.pszName(), "build_point_right_gun" ) == 0 )
	{
		vLocalPos.y = -sideDist;
	}
	else if ( stricmp( pAttachment.pszName(), "ThirdPersonCameraOrigin" ) == 0 )
	{
	}
	else
	{
		// Ok, it's not one of our magical attachments. Use the regular attachment setup stuff.
		return BaseClass::GetAttachment( iAttachment, attachmentToWorld );
	}

	if ( m_bCrouched )
	{
		vLocalPos.z += downDist;
	}

	// Now build the output matrix.
	matrix3x4_t localMatrix;
	SetIdentityMatrix( localMatrix );
	PositionMatrix( vLocalPos, localMatrix );

	ConcatTransforms( EntityToWorldTransform(), localMatrix, attachmentToWorld );
	return true;
}


void C_WalkerStrider::ReceiveMessage( int classID, bf_read &msg )
{
	if ( classID != GetClientClass()->m_ClassID )
	{
		// message is for subclass
		BaseClass::ReceiveMessage( classID, msg );
		return;
	}

	Vector vHitPos;
	msg.ReadBitVec3Coord( vHitPos );

	CStriderBeamEffect eff;
	eff.m_vHitPos = vHitPos;
	eff.m_flStartTime = gpGlobals->curtime;
	m_BeamEffects.AddToTail( eff );
}


float flTestSlack = 280;
float flTestSlack2 = 380;

void C_WalkerStrider::OnDataChanged( DataUpdateType_t type )
{
	BaseClass::OnDataChanged( type );

	if ( type == DATA_UPDATE_CREATED )
	{
		if ( cl_brush_ropes.GetInt() )
		{
			// Create some ropes and hang them off certain attachments.
			int indices[7] = 
			{
				LookupAttachment( "kneeL" ),
				LookupAttachment( "kneeR" ),
				LookupAttachment( "kneeB" ),
				
				LookupAttachment( "MiniGun" ),
				LookupAttachment( "left foot" ),
				LookupAttachment( "right foot" ),
				LookupAttachment( "back foot" )
			};
			
			m_hRopes[0] = C_RopeKeyframe::Create( this, this, indices[0], indices[1] );
			m_hRopes[1] = C_RopeKeyframe::Create( this, this, indices[0], indices[2] );
			m_hRopes[2] = C_RopeKeyframe::Create( this, this, indices[1], indices[2] );

			for ( int i=0; i < 3; i++ )
			{
				if ( m_hRopes[i].Get() )
					m_hRopes[i]->SetSlack( flTestSlack );
			}


			m_hRopes[3] = C_RopeKeyframe::Create( this, this, indices[3], indices[4] );
			m_hRopes[4] = C_RopeKeyframe::Create( this, this, indices[3], indices[5] );
			m_hRopes[5] = C_RopeKeyframe::Create( this, this, indices[3], indices[6] );

			for ( i=3; i < 6; i++ )
			{
				if ( m_hRopes[i].Get() )
					m_hRopes[i]->SetSlack( flTestSlack2 );
			}
		}
	}
}


void C_WalkerStrider::ClientThink()
{
	// Retire beam effects.
	int iNext;
	for ( int i=m_BeamEffects.Head(); i != m_BeamEffects.InvalidIndex(); i=iNext )
	{
		iNext = m_BeamEffects.Next( i );
	
		if ( gpGlobals->curtime >= (m_BeamEffects[i].m_flStartTime + STRIDER_BEAM_LIFETIME) )
		{
			m_BeamEffects.Remove( i );
		}
	}
}


int C_WalkerStrider::DrawModel( int flags )
{
	BaseClass::DrawModel( flags );

	IMaterial *pMaterial = materials->FindMaterial( STRIDER_BEAM_MATERIAL, TEXTURE_GROUP_CLIENT_EFFECTS );

	Vector vGunPos;
	QAngle vAngles;
	BaseClass::GetAttachment( LookupAttachment( "BigGun" ), vGunPos, vAngles );

	// Draw our beam effects.
	FOR_EACH_LL( m_BeamEffects, i )
	{
		CStriderBeamEffect *pEff = &m_BeamEffects[i];

		float flAlpha = (gpGlobals->curtime - pEff->m_flStartTime) / STRIDER_BEAM_LIFETIME;
		flAlpha = 1.0 - clamp( flAlpha, 0, 1 );

		CBeamSegDraw segDraw;
		segDraw.Start( 2, pMaterial );

		CBeamSeg seg;
		seg.m_vColor.Init( 1, 0, 0 );
		seg.m_flWidth = STRIDER_BEAM_WIDTH;
		seg.m_flAlpha = flAlpha;

		seg.m_flTexCoord = 0;
		seg.m_vPos = vGunPos;
		segDraw.NextSeg( &seg );

		seg.m_flTexCoord = 1;
		seg.m_vPos = pEff->m_vHitPos;
		segDraw.NextSeg( &seg );
		
		segDraw.End();
	}

	return 1;
}