#ifndef BUDDY_H
#define BUDDY_H

/*#ifndef PLAYER_MELEE_H
#include "player_melee.h"
#endif*/

#include "../bot/bot.h"

// using these states we can tell why we cant do things
#define BSTATE_WEAPON_CANTMOVE		1 // cant shoot because current attack state
#define BSTATE_CANTSHOOT			2

class CBaseBuddyClass;
class CBaseBuddyWeapon;
class CBuddyTask;

struct buddy_swoop_s
{
	int iSwoopDir; // Current swoop direction
	bool bActive; // Is the buddy using swoop?
	float flStartTime;
	bool bChainSwoop;
	float flStartSwoopDelay;

	float GetSwoopTime(void) { return (flStartTime>0.0f) ? (gpGlobals->time - flStartTime) : 0.0f; };
};

class CBuddy;

class CBuddyMeleeClass
{
	CBuddy *m_pOwner;

public:
	float m_fLastPowerHitTime;
	bool m_bInitPowerHitAnim;
	char m_szPowerHitAnim[32];
	int m_iConsecutiveHits;
	CBasePlayer *m_pThrower;
	CBuddy *m_pBuddyThrower;
	float m_fLastRecoverTime;
	
	void SetOwner(CBuddy *pOwner) { m_pOwner = pOwner; };
	void Init(void);
	bool BlocksMelee(CBasePlayer *pPlayer);
	bool BlocksMelee(CBuddy *pBuddy);
	void SimpleMeleePowerhit( CBasePlayer *pOther, Vector vecDirection, int iDirection );
	void SimpleMeleePowerhit( CBuddy *pOther, Vector vecDirection, int iDirection );
	bool Powerhit( bool fPlayAnim, CBasePlayer *pOther, Vector vecDirection, int iDirection, float flDamage, float flMaxSpeed, float flMinSpeed, float flDeacceleration, float flMinRecoverTime );
	bool Powerhit( bool fPlayAnim, CBuddy *pOther, Vector vecDirection, int iDirection, float flDamage, float flMaxSpeed, float flMinSpeed, float flDeacceleration, float flMinRecoverTime );
	bool Powerhit( CBasePlayer *pOther, Vector vecDirection, int iDirection );
	bool Powerhit( CBuddy *pOther, Vector vecDirection, int iDirection );
	void SetPowerhitAnim( Vector vecDirection, int iDirection );
	void HandleHeadOn(CBasePlayer *pPlayer);
	void HandleHeadOn(CBuddy *pBuddy);
	bool CanMelee(CBasePlayer *pPlayer);
	bool CanMelee(CBuddy *pBuddy);
	CBasePlayer *GetNearestPlayerToMelee(CBasePlayer *pStruggle = NULL);
	CBuddy *GetNearestBuddyToMelee(CBuddy *pStruggle = NULL);
	float GetPowerRatio(CBasePlayer *pPlayer);
	float GetPowerRatio(CBuddy *pBuddy);
	void SetThrowAnim(Activity &Act, int &Anim);
};

class CBuddyToss
{
	CBuddy *m_pOwner;

public:
	Vector m_vTossDir;
	float m_fCurSpeed;	// Current Speed
	float m_fMinSpeed;	// Speed that we autorecover at
	float m_fDeacceleration; // Deacceleration rate
	float m_fMinRecoverTime;
	bool m_bFlyRecover;
	bool m_bTakeDmgOnCollision;
	float m_fLandRecoverStart;
	Vector m_vLandRecoverAngles;
	float m_fLayStart;
	Vector m_vWallStickNormal;
	float m_fStartWallStick;
	bool m_bOnGround;
	float m_fLastRecoverTime;
	THROW_STATUS m_eThrowStatus;

	bool Think(void);
	void SetOwner(CBuddy *pOwner) { m_pOwner = pOwner; };
	void Init(void);
	void SetTossAnim(char *szAnim, Activity &m_IdealActivity);
	Activity GetThrowActivity(void);
	void GetThrowAnimDirection(int null, int iDirection, char *pAnim);
	int GetThrowDirection(bool bUseUpDown);
	void StartToss( CBasePlayer *pThrower, bool fDmgOnCollision, Vector vecDirection, float flMaxSpeed, float flMinSpeed, float flDeacceleration, float flMinRecoverTime );
	void StartToss( CBuddy *pThrower, bool fDmgOnCollision, Vector vecDirection, float flMaxSpeed, float flMinSpeed, float flDeacceleration, float flMinRecoverTime );
	bool CheckForObsticales(void);
	bool Deaccelerate(void);
	bool FullRecover(void);
	bool SlowlyRecover(void);
	void HandleToss(void);
	void HandleRoll(void);
	void HandleWallStick(void);
	void HandleLay(void);
	void HandleLandRecover(void);
	void MakeCreater(void);
	bool InflictWallhitDmg(bool bObjectStick);
	void StartLandRecover(void);
	void StartLay(void);
	void StartWallStick(Vector vecOrigin, Vector vecNormal);
	void StartRoll(void);
	void EmitExplosionRocks( Vector vecSrc, Vector vecVelocity, float flSize, int iRandom, int iCount );
	void CheckCreater(void);
	void LandRecoverDash(void);
	void StopThrow(void);
};

class CBuddy : public CTalkMonster
{
public:
	float m_fMoveSpeed, m_fSideSpeed;
	int m_iMaxSpeed;
	float m_fSlowDown;
	EHANDLE m_pOwner;
	BOOL m_fControl;
	BOOL m_fCharging;
	float				m_flSlowDown;			//Slowdown compared to normal speed. needed for block, charge, powerup, etc
	bool m_bFlying;
	bool m_bSwat;
	bool m_bStrangled;
	bool m_bPowerUp;
	bool m_bChargingPrimary, m_bChargingSecondary;
	bool m_bTurbo;
	bool m_fBlockStruggleAttacker;
	bool m_fPowerStruggling;
	CBuddyTask *m_pCurrentTask;

	long m_lActionState;

	CPowerStruggle		*m_pPowerStruggle;		//the powerstruggle your participating in
	BOOL				m_fMelee;				// Melee in General
	PLAYER_ANIM	m_eAnimationTrigger;	//trigger for triggered animations
	float m_fIdleTime;			// how long the person was in "idle" for, to enable deep idle
	ANIM_FLAGS m_eAnimationFlags;		//flags for the animation
	char m_szModelName[64];
	Vector m_vIdealLookAngles;
	CBuddyAura *m_pAura;
	float m_fTurboTime;
	CBaseBuddyClass *m_pClass;
	float m_fKi, m_fDesiredKi;
	float m_fLastKi, m_fLastHealth;
	float m_fKiUpdateTime;
	float m_fShootDelay;
	Vector m_vVelocityDir;
	float m_fVelocityTime;
	float m_fVelocitySpeed;
	float m_fCheckNameDelay;
	char m_szBuddyName[32];
	CBaseBuddyWeapon *m_pCurrentWeapon;
	float m_fDeathTime;

	// Nav variabeles
	float m_fCheckUpDownTime;
	float m_fDontAvoidWallTime;
	float m_fLookDelay;
	float m_fAvoidFriendsDelay;

	/*
		depending on the order of death one of these may not be available
		these vars are used to ensure all players can be updated correctly
	*/
	int m_Owner_Ent_Index;
	int m_Buddy_Ent_Index;
	/* modified by harSens
	friend CBuddyMeleeClass;
	friend CBuddyToss;
	friend CBuddyAura;
	friend CBuddyTask;
	*/
	friend class CBuddyMeleeClass;
	friend class CBuddyToss;
	friend class CBuddyAura;
	friend class CBuddyTask;
public:
    int m_Activity; //What entity is doing (animation)
	bool m_bBecomeCandy;
	int	m_iPowerLevel;			//The powerlevel for the character
	int	m_iMaxPowerLevel;		//The max powerlevel for the character
	TLinkedList<CBaseBuddyWeapon *> m_WeaponList;
	Vector m_vecBlob[2]; // The Last positions where ki blast exploded

	// we are going to try to avoid hitting walls and generally looking like a stupid buddy but if we do get stuck
	// we can use our last origin and whether or not we should be moving to know if we are lost
	vec3_t	m_vlastOrigin; // this is our location during the last frame
	float   m_flostTime;   // this is the first time we realized we were lost

	// we do this so we dont turn turbo on when we get slightly furhter then our max distance from our owner
	int m_iShouldTurbo;		   // should we turn on our turbo?

	Vector m_vAimVec;

	float m_flBlobTime[2]; // The time the blobs were fired off
	char m_szAnimExtention[32];
	buddy_swoop_s m_Swoop;
	CBuddyMeleeClass m_Melee;
	CBuddyToss m_Toss;
	bool m_bBlock;
	bool m_bThrown;
	enemy_priority_s m_EnemyList[4];

	// this is the enemy we are currently fighting
	CBaseEntity *m_pCurrentEnemy;
	
	// this is our latest sensed enemy
	CBaseEntity *m_pScariestEnemy;

	EHANDLE m_pEnemy; // this is the enemy set our owner is currently looking at
    CBasePlayer *m_pBotEnemy;
    CBasePlayer *m_pLastEnemy;
	short m_sDangerLevel;
    int m_iDangerType;

	void Spawn( void );
	void Destroy(void);
    void Precache( void );
    int Classify ( void );
    
	void LookAndAim();
	
	// this will aim where are owner is looking
	void AimWithOwner();

    void SetActivity(int activity);                                 
    int  GetActivity() { return m_Activity; }
    void SetCollisionBox(void);
	void PreThink( void );
    void EXPORT BuddyThink(void);
	void EXPORT DeathThink( void );
    int BloodColor() { return BLOOD_COLOR_RED; }
	CBaseEntity *GetEnemy(void);
	void ShootEnemy(CBasePlayer *pBuddyOwner);
	bool AttackThink(CBasePlayer *pBuddyOwner);
	bool DefendOwner(CBasePlayer *pBuddyOwner);
	void WeaponIdle(void);
	void SetMoveSpeed(float flSpeed) { m_fMoveSpeed = flSpeed; };
	void MoveBuddy(float flInterval);
	void StartFly(void);
	void StopFly(void);
	int GetLowerBodyAnimation(void);
	int GetUpperBodyAnimation(int &iFrame);
	int PlayFullBodyAnimation(CBasePlayer* pBuddyOwner);
	float GetMaxSpeed(void);
	bool CanPlayForwardWalk(void);
	void SetAnimation(PLAYER_ANIM playerAnim);
	void PlayAnimation(CBasePlayer *pBuddyOwner);
	void RemoveAnimationTriggers(void);
	void AimAt(Vector vOrigin);
	void AimToIdeal(void);
	int GetAuraDirection(void);
	void StartTurbo(void);
	void StopTurbo(void);
	void DeathSound( void );
	void PainSound( void );
	void EmitClassSound(const char *sound);
	void Teleport(void);
	void StartPowerUp(void);
	void StopPowerUp(void);
	bool CanPowerUp(void);
	Vector GetMoveDirection(void);
	Vector GetVelocity(void);
	bool UseKi(float flKi);
	BOOL UseOwnerKi(int amount);
	int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
	void WaitToBecomeCandy(CBasePlayer *Attacker);
	void ReleaseCandy(void);
	bool BecomeCandy(const char *candy, CBaseEntity *attacker);
	void IncreaseStrength(CBasePlayer *pVictim, int damage);
	void IncreaseStrength(CBuddy *pVictim, int damage);
	virtual BOOL IsAlive( void ) { return ((pev->deadflag != DEAD_DEAD) && (pev->health > 0) && (m_IdealMonsterState != MONSTERSTATE_DEAD)); }
	void ShootBigKiBlast(void);
	void ShootSmallKiBlast(void);
	int GetPowerLevel( void ) {	return (m_bTurbo ? 2 : 1) * m_iPowerLevel; };
	bool HasWeapon(const char *szName);
	CBaseBuddyWeapon *GetWeapon(const char *szName);
	bool CanSwoop(void);
	void StartSwoop(int iDirection);
	void StopSwoop(void);
	void SwoopThink(void);
	void SetSwoopAnim( char *pAnim, Activity &IdealActivity );
	Vector GetSwoopDirection(void);
	bool CanTakeDamage(CBaseEntity *pEntity);
	virtual Vector GetGunPosition( void );
	void ApplyVelocity(Vector v_velocitydir, float flSpeed, float flDuration);
	void VelocityThink(void);
	void ResetVelocity(void);
	void CheckName(void);
	char *GetCurrentWeaponName(void);
	void SetCurrentWeapon(CBaseBuddyWeapon *pWeapon);
	void Die(CBaseEntity *pKiller, CBaseEntity *pInflictor);

	// Nav functions
	void HomeThroughMap(void);
	void CheckFOV(void);
	void CheckSkybox(void);
	void CheckUpDown(void);
	void TurnAtWall(Vector *vecPlaneNormal);
	void TurnAround(void);
	void AvoidNearFriends(void);

	bool IsBusy(void);
	void FollowOwner(void);

	bool CanMove(CBasePlayer* pBuddyOwner);
	bool CanDefend(CBasePlayer* pBuddyOwner);
	bool CanAttack(CBasePlayer* pBuddyOwner);

	bool Follow(); // FIXME:: this function just does direct line following, it should do avoidance following

	// aim functions
	void SetIdealAngles(Vector v_ideal) { m_vAimVec = v_ideal; };
	void AimToVec(const Vector &v_vec)	{ SetIdealAngles(GetAimAngles(v_vec)); };
	void AimToVecFromPevOrigin(const Vector &v_vec, const Vector &v_loc) { SetIdealAngles(v_vec-v_loc); };
	Vector GetAimAngles(Vector v_vec) { return UTIL_VecToAngles(v_vec-pev->origin); };

	void SendUpdateMsg();
/*
	void BuddySense();
	void SenseSurroundingAttacks(danger_info_s &DangerInfo);
	void SenseSurroundingPlayers(danger_info_s &DangerInfo);
	void SenseSurroundingSounds(danger_info_s &DangerInfo);
	void SenseHit(danger_info_s &DangerInfo);
*/

	EAttackType ClassifyAttack(const char *szAttackName);


};


#endif