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

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


#include "baseentity.h"

#include "positionwatcher.h"

class CRopeKeyframe : public CBaseEntity, public IPositionWatcher
{
	DECLARE_CLASS( CRopeKeyframe, CBaseEntity );
public:
	DECLARE_SERVERCLASS();
	DECLARE_DATADESC();

					CRopeKeyframe();
	virtual			~CRopeKeyframe();

	// Create a rope and attach it to two entities.
	// Attachment points on the entities are optional.
	static CRopeKeyframe* Create(
		CBaseEntity *pStartEnt,
		CBaseEntity *pEndEnt,
		int iStartAttachment=0,
		int iEndAttachment=0,
		int ropeWidth = 2,
		const char *pMaterialName = "cable/cable.vmt",		// Note: whoever creates the rope must
															// use PrecacheModel for whatever material
															// it specifies here.
		int numSegments = 5
		);

	static CRopeKeyframe* CreateWithSecondPointDetached(
		CBaseEntity *pStartEnt,
		int iStartAttachment = 0,	// must be 0 if you don't want to use a specific model attachment.
		int ropeLength = 20,
		int ropeWidth = 2,
		const char *pMaterialName = "cable/cable.vmt",		// Note: whoever creates the rope
															// use PrecacheModel for whatever material
															// it specifies here.
		int numSegments = 5,
		bool bInitialHang = false
		);

	bool		SetupHangDistance( float flHangDist );
	void		ActivateStartDirectionConstraints( bool bEnable );
	void		ActivateEndDirectionConstraints( bool bEnable );

	
	// Shakes all ropes near vCenter. The higher flMagnitude is, the larger the shake will be.
	static void ShakeRopes( const Vector &vCenter, float flRadius, float flMagnitude );


// CBaseEntity overrides.
public:
	
	// don't cross transitions
	virtual int		ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
	virtual void	Activate();
	virtual void	Precache();
	virtual int		OnTakeDamage( const CTakeDamageInfo &info );
	virtual bool	KeyValue( const char *szKeyName, const char *szValue );

	void			PropagateForce(CBaseEntity *pActivator, CBaseEntity *pCaller, CBaseEntity *pFirstLink, float x, float y, float z);

	// Once-off length recalculation
	void			RecalculateLength( void );

	// Kill myself when I next come to rest
	void			DieAtNextRest( void );

	virtual int		UpdateTransmitState(void);
	virtual void	SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
	virtual void	SetParent( CBaseEntity *pParentEntity, int iAttachment );

// Input functions.
public:

	void InputSetScrollSpeed( inputdata_t &inputdata );
	void InputSetForce( inputdata_t &inputdata );
	void InputBreak( inputdata_t &inputdata );

public:

	bool			Break( void );
	void			DetachPoint( int iPoint );
	
	void			EndpointsChanged();

	// By default, ropes don't collide with the world. Call this to enable it.
	void			EnableCollision();

	// Toggle wind.
	void			EnableWind( bool bEnable );

	// Unless this is called during initialization, the caller should have done
	// PrecacheModel on whatever material they specify in here.
	void			SetMaterial( const char *pName );

	CBaseEntity*	GetEndPoint() { return m_hEndPoint.Get(); }
	int				GetEndAttachment() { return m_iStartAttachment; };

	void			SetStartPoint( CBaseEntity *pStartPoint, int attachment = 0 );
	void			SetEndPoint( CBaseEntity *pEndPoint, int attachment = 0 );

	// See ROPE_PLAYER_WPN_ATTACH for info.
	void			EnablePlayerWeaponAttach( bool bAttach );


	// IPositionWatcher
	virtual void NotifyPositionChanged( CBaseEntity *pEntity );

private:

	void			SetAttachmentPoint( CBaseHandle &hOutEnt, short &iOutAttachment, CBaseEntity *pEnt, int iAttachment );

	// This is normally called by Activate but if you create the rope at runtime,
	// you must call it after you have setup its variables.
	void			Init();

	// These work just like the client-side versions.
	bool			GetEndPointPos2( CBaseEntity *pEnt, int iAttachment, Vector &v );
	bool			GetEndPointPos( int iPt, Vector &v );

	void			UpdateBBox( bool bForceRelink );


public:

	CNetworkVar( int, m_RopeFlags );		// Combination of ROPE_ defines in rope_shared.h
	
	string_t	m_iNextLinkName;
	CNetworkVar( int, m_Slack );
	CNetworkVar( float, m_Width );
	CNetworkVar( float, m_TextureScale );
	CNetworkVar( int, m_nSegments );		// Number of segments.
	CNetworkVar( bool, m_bConstrainBetweenEndpoints );

	string_t m_strRopeMaterialModel;
	CNetworkVar( int, m_iRopeMaterialModelIndex );	// Index of sprite model with the rope's material.
	
	// Number of subdivisions in between segments.
	CNetworkVar( int, m_Subdiv );
	
	//EHANDLE		m_hNextLink;
	
	CNetworkVar( int, m_RopeLength );	// Rope length at startup, used to calculate tension.

	CNetworkVar( int, m_fLockedPoints );

	bool		m_bCreatedFromMapFile; // set to false when creating at runtime

	CNetworkVar( float, m_flScrollSpeed );

private:
	// Used to detect changes.
	bool		m_bStartPointValid;
	bool		m_bEndPointValid;
	
	CNetworkHandle( CBaseEntity, m_hStartPoint );		// StartPoint/EndPoint are entities
	CNetworkHandle( CBaseEntity, m_hEndPoint );
	CNetworkVar( short, m_iStartAttachment );	// StartAttachment/EndAttachment are attachment points.
	CNetworkVar( short, m_iEndAttachment );
};


#endif // ROPE_H