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

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

#include "ai_basenpc_physicsflyer.h"
#include "Sprite.h"
#include "SpriteTrail.h"
#include "player_pickup.h"

// Start with the engine off and folded up.
#define SF_MANHACK_PACKED_UP			(1 << 16)
#define SF_MANHACK_NO_DAMAGE_EFFECTS	(1 << 17)
#define SF_MANHACK_USE_AIR_NODES		(1 << 18)
#define SF_MANHACK_CARRIED				(1 << 19)	// Being carried by a metrocop
#define SF_MANHACK_NO_DANGER_SOUNDS		(1 << 20)

enum
{
	MANHACK_EYE_STATE_IDLE,
	MANHACK_EYE_STATE_CHASE,
	MANHACK_EYE_STATE_CHARGE,
	MANHACK_EYE_STATE_STUNNED,
};

//-----------------------------------------------------------------------------
// Attachment points.
//-----------------------------------------------------------------------------
#define	MANHACK_GIB_HEALTH				30
#define	MANHACK_INACTIVE_HEALTH			25
#define	MANHACK_MAX_SPEED				500
#define MANHACK_BURST_SPEED				650
#define MANHACK_NPC_BURST_SPEED			800

//-----------------------------------------------------------------------------
// Movement parameters.
//-----------------------------------------------------------------------------
#define MANHACK_WAYPOINT_DISTANCE		25	// Distance from waypoint that counts as arrival.

class CSprite;
class SmokeTrail;
class CSoundPatch;

//-----------------------------------------------------------------------------
// Manhack 
//-----------------------------------------------------------------------------
class CNPC_Manhack : public CNPCBaseInteractive<CAI_BasePhysicsFlyingBot>, public CDefaultPlayerPickupVPhysics
{
DECLARE_CLASS( CNPC_Manhack, CNPCBaseInteractive<CAI_BasePhysicsFlyingBot> );
DECLARE_SERVERCLASS();

public:
	CNPC_Manhack();
	~CNPC_Manhack();

	Class_T			Classify(void);

	bool			CorpseGib( const CTakeDamageInfo &info );
	void			Event_Dying(void);
	void			Event_Killed( const CTakeDamageInfo &info );
	int				OnTakeDamage_Alive( const CTakeDamageInfo &info );
	int				OnTakeDamage_Dying( const CTakeDamageInfo &info );
	void			TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
	void			TranslateNavGoal( CBaseEntity *pEnemy, Vector &chasePosition );
	float			GetDefaultNavGoalTolerance();

	void			UpdateOnRemove( void );
	void			KillSprites( float flDelay );

	void			OnStateChange( NPC_STATE OldState, NPC_STATE NewState );

	virtual bool	CreateVPhysics( void );

	virtual void	DeathSound( const CTakeDamageInfo &info );
	virtual bool	ShouldGib( const CTakeDamageInfo &info );

	Activity		NPC_TranslateActivity( Activity baseAct );
	virtual int		TranslateSchedule( int scheduleType );
	int				MeleeAttack1Conditions ( float flDot, float flDist );
	void			HandleAnimEvent( animevent_t *pEvent );

	bool			OverrideMove(float flInterval);
	void			MoveToTarget(float flInterval, const Vector &MoveTarget);
	void			MoveExecute_Alive(float flInterval);
	void			MoveExecute_Dead(float flInterval);
	int				MoveCollisionMask(void);

	void			TurnHeadRandomly( float flInterval );

	void			CrashTouch( CBaseEntity *pOther );

	void			StartEngine( bool fStartSound );

	virtual Vector	BodyTarget( const Vector &posSrc, bool bNoisy = true ) { return WorldSpaceCenter(); }

	virtual float	GetHeadTurnRate( void ) { return 45.0f; } // Degrees per second

	void			CheckCollisions(float flInterval);
	virtual void	GatherEnemyConditions( CBaseEntity *pEnemy );
	void			PlayFlySound(void);
	virtual void	StopLoopingSounds(void);

	void			Precache(void);
	void			RunTask( const Task_t *pTask );
	void			Spawn(void);
	void			Activate();
	void			StartTask( const Task_t *pTask );

	void			BladesInit();
	void			SoundInit( void );
	void			StartEye( void );
	
	bool			HandleInteraction(int interactionType, void* data, CBaseCombatCharacter* sourceEnt);

	void			PostNPCInit( void );

	void			GatherConditions();
	void			PrescheduleThink( void );

	void			SpinBlades(float flInterval);

	void			Slice( CBaseEntity *pHitEntity, float flInterval, trace_t &tr );
	void			Bump( CBaseEntity *pHitEntity, float flInterval, trace_t &tr );
	void			Splash( const Vector &vecSplashPos );

	float			ManhackMaxSpeed( void );
	virtual void	VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent );
	void			VPhysicsCollision( int index, gamevcollisionevent_t *pEvent );
	void			HitPhysicsObject( CBaseEntity *pOther );
	virtual void	ClampMotorForces( Vector &linear, AngularImpulse &angular );
	unsigned int	PhysicsSolidMaskForEntity( void ) const;

	// Create smoke trail!
	void CreateSmokeTrail();
	void DestroySmokeTrail();
		
	void Ignite( float flFlameLifetime, bool bNPCOnly, float flSize, bool bCalledByLevelDesigner ) { return; }

	void			InputDisableSwarm( inputdata_t &inputdata );
	void			InputUnpack( inputdata_t &inputdata );

	// 	CDefaultPlayerPickupVPhysics
	virtual void	OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason );
	virtual void	OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason );

	CBasePlayer *HasPhysicsAttacker( float dt );

	float GetMaxEnginePower();

	// INPCInteractive Functions
	virtual bool	CanInteractWith( CAI_BaseNPC *pUser ) { return false; } // Disabled for now (sjb)
	virtual	bool	HasBeenInteractedWith()	{ return m_bHackedByAlyx; }
	virtual void	NotifyInteraction( CAI_BaseNPC *pUser )
	{
		// Turn the sprites off and on again so their colors will change.
		KillSprites(0.0f);
		m_bHackedByAlyx = true; 
		StartEye();
	}

	virtual void	InputPowerdown( inputdata_t &inputdata )
	{
		m_iHealth = 0;
	}


	DEFINE_CUSTOM_AI;

	DECLARE_DATADESC();

private:

	bool IsInEffectiveTargetZone( CBaseEntity *pTarget );
	void MaintainGroundHeight( void );

	void StartBurst( const Vector &vecDirection );
	void StopBurst( bool bInterruptSchedule = false );

	void UpdatePanels( void );
	void SetEyeState( int state );

	void ShowHostile( bool hostile = true );

	bool IsFlyingActivity( Activity baseAct );

	// Computes the slice bounce velocity
	void ComputeSliceBounceVelocity( CBaseEntity *pHitEntity, trace_t &tr );

	// Take damage from being thrown by a physcannon 
	void TakeDamageFromPhyscannon( CBasePlayer *pPlayer );

	// Take damage from a vehicle: 
	void TakeDamageFromVehicle( int index, gamevcollisionevent_t *pEvent );

	// Take damage from physics impacts
	void TakeDamageFromPhysicsImpact( int index, gamevcollisionevent_t *pEvent );

	// Are we being held by the physcannon?
	bool IsHeldByPhyscannon( );

	void StartLoitering( const Vector &vecLoiterPosition );
	void StopLoitering() { m_vecLoiterPosition = vec3_invalid; m_fTimeNextLoiterPulse = gpGlobals->curtime; }
	bool IsLoitering() { return m_vecLoiterPosition != vec3_invalid; }
	void Loiter();

	//
	// Movement variables.
	//

	Vector			m_vForceVelocity;		// Someone forced me to move

	Vector			m_vTargetBanking;

	Vector			m_vForceMoveTarget;		// Will fly here
	float			m_fForceMoveTime;		// If time is less than this
	Vector			m_vSwarmMoveTarget;		// Will fly here
	float			m_fSwarmMoveTime;		// If time is less than this
	float			m_fEnginePowerScale;	// scale all thrust by this amount (usually 1.0!)

	float			m_flNextEngineSoundTime;
	float			m_flEngineStallTime;

	float			m_flNextBurstTime;
	float			m_flBurstDuration;
	Vector			m_vecBurstDirection;

	float			m_flWaterSuspendTime;
	int				m_nLastSpinSound;

	// physics influence
	CHandle<CBasePlayer>	m_hPhysicsAttacker;
	float					m_flLastPhysicsInfluenceTime;

	// Death
	float			m_fSparkTime;
	float			m_fSmokeTime;

	bool			m_bDirtyPitch; // indicates whether we want the sound pitch updated.(sjb)
	bool			m_bShowingHostile;

	bool			m_bBladesActive;
	bool			m_bIgnoreClipbrushes;

	float			m_flBladeSpeed;

	CSprite			*m_pEyeGlow;
	CSprite			*m_pLightGlow;
	
	CHandle<SmokeTrail>	m_hSmokeTrail;
	CHandle<CBaseEntity>	m_pPrevOwner;

	int				m_iPanel1;
	int				m_iPanel2;
	int				m_iPanel3;
	int				m_iPanel4;

	int				m_nLastWaterLevel;
	bool			m_bDoSwarmBehavior;
	bool			m_bGib;

	bool			m_bHeld;
	bool			m_bHackedByAlyx;
	Vector			m_vecLoiterPosition;
	float			m_fTimeNextLoiterPulse;

	float			m_flBumpSuppressTime;

	CNetworkVar( int,	m_nEnginePitch1 );
	CNetworkVar( int,	m_nEnginePitch2 );
	CNetworkVar( float,	m_flEnginePitch1Time );
	CNetworkVar( float,	m_flEnginePitch2Time );
};

#endif	//NPC_MANHACK_H