#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "weapons.h"
#include "talkmonster.h"
#include "player.h"
#include "../bot/bot_util.h"
#include "buddy_aura.h"
#include "buddy.h"
#include "buddy_weapons.h"
#include <string.h>

extern cvar_t nomeleehittime;
extern unsigned short m_usMeleeSounds;

void CBuddyMeleeClass::Init()
{
	m_fLastPowerHitTime = 0.0f;
	m_bInitPowerHitAnim = false;
	m_szPowerHitAnim[0] = 0;
	m_pBuddyThrower = NULL;
	m_pThrower = NULL;
	m_iConsecutiveHits = 0;
	m_fLastRecoverTime = 0.0f;
}

CBasePlayer *CBuddyMeleeClass::GetNearestPlayerToMelee(CBasePlayer *pStruggle)
{
	CBaseEntity *pEntity = NULL;
	CBaseEntity *pCEntity = NULL;		// Closest entity
	Vector		vecLOS;
	float flMaxDot = VIEW_FIELD_NARROW;	// FOV for advanced melee is LARGER than simple melee
	float flDot;
	float flLength;
	float flMaxDist = MELEE_RADIUS+1;	// Closest distance for pCEntity

	// Search for player in sphere
	while ((pEntity = UTIL_FindEntityInSphere( pEntity, m_pOwner->pev->origin, MELEE_RADIUS )) != NULL)
	{
		flLength = (pEntity->pev->origin - m_pOwner->pev->origin).Length();

		if(flLength < flMaxDist && pEntity != (CBaseEntity*)this && pEntity->IsPlayer() && pEntity->IsAlive() && !((CBasePlayer*)pEntity)->m_Melee.InAdvMeleeBattle())
		{
			if (!CanMelee((CBasePlayer *)pEntity))
				continue;

			// Set up dotproduct
			vecLOS = pEntity->pev->origin - m_pOwner->pev->origin;
			vecLOS = vecLOS.Normalize();

			flDot = DotProduct (vecLOS, m_pOwner->GetSwoopDirection());

			// Hes in our prepunching view, save entity
			if (flDot > flMaxDot )
			{	pCEntity = pEntity;
				flMaxDist = flLength;

				if(pStruggle && (pEntity == pStruggle))
				{	return (CBasePlayer*)pEntity;
				}
			}
		}
	}

	return (CBasePlayer*)pCEntity;
}

CBuddy *CBuddyMeleeClass::GetNearestBuddyToMelee(CBuddy *pStruggle)
{
	CBaseEntity *pEntity = NULL;
	CBaseEntity *pCEntity = NULL;		// Closest entity
	Vector		vecLOS;
	float flMaxDot = VIEW_FIELD_NARROW;	// FOV for advanced melee is LARGER than simple melee
	float flDot;
	float flLength;
	float flMaxDist = MELEE_RADIUS+1;	// Closest distance for pCEntity

	// Search for buddy in sphere
	while ((pEntity = UTIL_FindEntityInSphere( pEntity, m_pOwner->pev->origin, MELEE_RADIUS )) != NULL)
	{
		flLength = (pEntity->pev->origin - m_pOwner->pev->origin).Length();

		if((flLength < flMaxDist) && (pEntity != (CBaseEntity*)this) && pEntity->IsAlive() &&
		   FStrEq(STRING(pEntity->pev->classname), "player_buddy"))
		{
			if (!CanMelee((CBuddy *)pEntity))
				continue;

			// Set up dotproduct
			vecLOS = pEntity->pev->origin - m_pOwner->pev->origin;
			vecLOS = vecLOS.Normalize();

			flDot = DotProduct (vecLOS, m_pOwner->GetSwoopDirection());

			// Hes in our prepunching view, save entity
			if (flDot > flMaxDot )
			{	pCEntity = pEntity;
				flMaxDist = flLength;

				if(pStruggle && (pEntity == pStruggle))
				{	return (CBuddy*)pEntity;
				}
			}
		}
	}

	return (CBuddy*)pCEntity;
}


bool CBuddyMeleeClass::CanMelee(CBasePlayer *pPlayer)
{	if(pPlayer->m_Melee.m_eThrowStatus == THROW_LAY || pPlayer->m_Melee.m_eThrowStatus == THROW_RECOVER ||
	   pPlayer->m_Melee.m_eThrowStatus == THROW_WALLSTICK || pPlayer->m_Melee.m_eThrowStatus == THROW_LANDRECOVER)
	{	return false;
	}

	// Can we attack?
	if(pPlayer->m_fStrangled || pPlayer->m_fPowerStruggling || pPlayer->m_fBlockStruggling || pPlayer->m_fBlockStruggleAttacker || pPlayer->m_fBecomeCandy ||
		pPlayer->m_fAscending ||	pPlayer->m_fShield || pPlayer->m_fSpawnInvulnerable || !pPlayer->IsAlive() || pPlayer->m_Melee.InAdvMeleeBattle() ||
		pPlayer->m_Melee.m_flLastRecoverTime > gpGlobals->time - nomeleehittime.value)
	{	return false;
	}

	// Can the player take dmg?
	if(!m_pOwner->CanTakeDamage(pPlayer))
	{	return false;
	}

	return true;
}

bool CBuddyMeleeClass::CanMelee(CBuddy *pBuddy)
{
	if(pBuddy->m_Toss.m_eThrowStatus == THROW_LAY || pBuddy->m_Toss.m_eThrowStatus == THROW_RECOVER ||
	   pBuddy->m_Toss.m_eThrowStatus == THROW_WALLSTICK || pBuddy->m_Toss.m_eThrowStatus == THROW_LANDRECOVER)
	{	return false;
	}

	// Can we attack?
	if(/*pBuddy->m_fPowerStruggling || pBuddy->m_fBlockStruggling || pBuddy->m_fBlockStruggleAttacker || */pBuddy->m_bBecomeCandy ||/*
	   pBuddy->m_fAscending ||	pPlayer->m_fShield || pPlayer->m_fSpawnInvulnerable || !pBuddy->IsAlive() || pBuddy->m_Melee.InAdvMeleeBattle() ||*/
	   pBuddy->m_Melee.m_fLastRecoverTime > gpGlobals->time - nomeleehittime.value)
	{
		return false;
	}

	if (pBuddy == m_pOwner)
		return false;

	// Can the player take dmg?
	if(!m_pOwner->CanTakeDamage(pBuddy))
	{	return false;
	}

	return true;
}

void CBuddyMeleeClass::HandleHeadOn(CBasePlayer *pPlayer)
{
	float flOtherSwoopTime = pPlayer->m_Swoop.GetSwoopTime();
	Vector vecSwoop = m_pOwner->GetSwoopDirection();

	// Disable Swoop
	m_pOwner->StopSwoop();
	pPlayer->StopSwoop();

	CBaseEntity *pWinner;
	CBaseEntity *pLooser;

	// Set winner/looser
	if((m_pOwner->m_Swoop.GetSwoopTime() > flOtherSwoopTime) && m_pOwner->UseKi(BLOW_KICK_KI_COST))
	{	pWinner = m_pOwner;
		pLooser = pPlayer;
	}
	else if(pPlayer->UseKi(BLOW_KICK_KI_COST))
	{	pWinner = pPlayer;
		pLooser = m_pOwner;
		vecSwoop = -vecSwoop;
	}
	// Both players have no KI
	else
	{	
		m_pOwner->m_Toss.StartToss( pPlayer, FALSE, -vecSwoop, 700, 400, 200, 1 );
		pPlayer->m_Melee.StartToss( m_pOwner, FALSE, vecSwoop, 700, 400, 200, 1 );
		return;
	}

	CBuddy *pBuddyWinner = NULL, *pBuddyLooser = NULL;
	CBasePlayer *pPlayerWinner = NULL, *pPlayerLooser = NULL;

	if (pWinner->IsPlayer())
		pPlayerWinner = (CBasePlayer *)pWinner;
	else
		pBuddyWinner = (CBuddy *)pWinner;

	if (pLooser->IsPlayer())
		pPlayerLooser = (CBasePlayer *)pLooser;
	else
		pBuddyLooser = (CBuddy *)pLooser;

	// Knock players back
	if(simplemelee.value)
	{
		if (pPlayerWinner)
		{
			if (pPlayerLooser)
				pPlayerWinner->m_Melee.Powerhit( FALSE, pPlayerLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 1400, 800, 450, 1.5 );
			else
				pPlayerWinner->m_Melee.Powerhit( FALSE, pBuddyLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 1400, 800, 450, 1.5 );
		}
		else
		{
			if (pPlayerLooser)
				Powerhit( FALSE, pPlayerLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 1400, 800, 450, 1.5 );
			else
				Powerhit( FALSE, pBuddyLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 1400, 800, 450, 1.5 );
		}
	}
	else
	{
		if (pPlayerWinner)
		{
			if (pPlayerLooser)
				pPlayerWinner->m_Melee.Powerhit( FALSE, pPlayerLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 900, 500, 300, 1.5 );
			else
				pPlayerWinner->m_Melee.Powerhit( FALSE, pBuddyLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 900, 500, 300, 1.5 );
		}
		else
		{
			if (pPlayerLooser)
				Powerhit( FALSE, pPlayerLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 900, 500, 300, 1.5 );
			else
				Powerhit( FALSE, pBuddyLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 900, 500, 300, 1.5 );
		}

		if (pPlayerLooser && pPlayerLooser->IsAlive())
		{
			if (pPlayerWinner)
				pPlayerLooser->m_Melee.Powerhit( FALSE, pPlayerWinner, -vecSwoop, FRONT, POWERHIT_DAMAGE*0.65, 900, 500, 300, 1.5 );
			else
				pPlayerLooser->m_Melee.Powerhit( FALSE, pBuddyWinner, -vecSwoop, FRONT, POWERHIT_DAMAGE*0.65, 900, 500, 300, 1.5 );
		}
		else if (pBuddyLooser && pBuddyLooser->IsAlive())
		{
			if (pPlayerWinner)
				Powerhit( FALSE, pPlayerWinner, -vecSwoop, FRONT, POWERHIT_DAMAGE*0.65, 900, 500, 300, 1.5 );
			else
				Powerhit( FALSE, pBuddyWinner, -vecSwoop, FRONT, POWERHIT_DAMAGE*0.65, 900, 500, 300, 1.5 );
		}
	}

	// Struggle text
	pPlayer->m_Melee.MeleeText( MELEETXT_HEADON, 0 );
	pPlayer->m_Melee.MeleeText( MELEETXT_KNOCKBACK, 0 );
}

void CBuddyMeleeClass::HandleHeadOn(CBuddy *pBuddy)
{
	float flOtherSwoopTime = pBuddy->m_Swoop.GetSwoopTime();
	Vector vecSwoop = m_pOwner->GetSwoopDirection();

	// Disable Swoop
	m_pOwner->StopSwoop();
	pBuddy->StopSwoop();

	CBuddy *pWinner;
	CBuddy *pLooser;

	// Set winner/looser
	if((m_pOwner->m_Swoop.GetSwoopTime() > flOtherSwoopTime) && m_pOwner->UseKi(BLOW_KICK_KI_COST))
	{	pWinner = m_pOwner;
		pLooser = pBuddy;
	}
	else if(pBuddy->UseKi(BLOW_KICK_KI_COST))
	{	pWinner = pBuddy;
		pLooser = m_pOwner;
		vecSwoop = -vecSwoop;
	}
	// Both players have no KI
	else
	{	
		m_pOwner->m_Toss.StartToss( pBuddy, FALSE, -vecSwoop, 700, 400, 200, 1 );
		pBuddy->m_Toss.StartToss( m_pOwner, FALSE, vecSwoop, 700, 400, 200, 1 );
		return;
	}

	// Knock players back
	if(simplemelee.value)
	{
		pWinner->m_Melee.Powerhit(FALSE, pLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 1400, 800, 450, 1.5 );
/*
		if (pPlayerWinner)
		{
			if (pPlayerLooser)
				pPlayerWinner->m_Melee.Powerhit( FALSE, pPlayerLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 1400, 800, 450, 1.5 );
			else
				pPlayerWinner->m_Melee.Powerhit( FALSE, pBuddyLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 1400, 800, 450, 1.5 );
		}
		else if (pMeleeWeap)
		{
			if (pPlayerLooser)
				pMeleeWeap->Powerhit( FALSE, pPlayerLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 1400, 800, 450, 1.5 );
			else
				pMeleeWeap->Powerhit( FALSE, pBuddyLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 1400, 800, 450, 1.5 );
		}*/
	}
	else
	{
		pWinner->m_Melee.Powerhit(FALSE, pLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 900, 500, 300, 1.5 );
		pLooser->m_Melee.Powerhit(FALSE, pWinner, -vecSwoop, FRONT, POWERHIT_DAMAGE*0.65, 900, 500, 300, 1.5 );

		/*
		if (pPlayerWinner)
		{
			if (pPlayerLooser)
				pPlayerWinner->m_Melee.Powerhit( FALSE, pPlayerLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 900, 500, 300, 1.5 );
			else
				pPlayerWinner->m_Melee.Powerhit( FALSE, pBuddyLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 900, 500, 300, 1.5 );
		}
		else if (pMeleeWeap)
		{
			if (pPlayerLooser)
				pMeleeWeap->Powerhit( FALSE, pPlayerLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 900, 500, 300, 1.5 );
			else
				pMeleeWeap->Powerhit( FALSE, pBuddyLooser, vecSwoop, FRONT, POWERHIT_DAMAGE*1.1, 900, 500, 300, 1.5 );
		}

		if (pPlayerLooser && pPlayerLooser->IsAlive())
		{
			if (pPlayerWinner)
				pPlayerLooser->m_Melee.Powerhit( FALSE, pPlayerWinner, -vecSwoop, FRONT, POWERHIT_DAMAGE*0.65, 900, 500, 300, 1.5 );
			else
				pPlayerLooser->m_Melee.Powerhit( FALSE, pBuddyWinner, -vecSwoop, FRONT, POWERHIT_DAMAGE*0.65, 900, 500, 300, 1.5 );
		}
		else if (pBuddyLooser && pMeleeWeap && pBuddyLooser->IsAlive())
		{
			if (pPlayerWinner)
				pMeleeWeap->Powerhit( FALSE, pPlayerWinner, -vecSwoop, FRONT, POWERHIT_DAMAGE*0.65, 900, 500, 300, 1.5 );
			else
				pMeleeWeap->Powerhit( FALSE, pBuddyWinner, -vecSwoop, FRONT, POWERHIT_DAMAGE*0.65, 900, 500, 300, 1.5 );
		}*/
	}
}

void CBuddyMeleeClass::SimpleMeleePowerhit( CBasePlayer *pOther, Vector vecDirection, int iDirection )
{
	// If you're on the ground, force upwards direction
	if(FBitSet(m_pOwner->pev->flags, FL_ONGROUND))
	{	vecDirection = Vector(0,0,1);
		iDirection = UP;
	}

	//Powerhit( pOther, vecDirection, iDirection, (pOther->m_Melee.m_fThrown ? BLOW_KICK_DAMAGE * 1.5 : BLOW_KICK_DAMAGE),
	//		 1600, 500, 400, 1.75 );
	Powerhit( true, pOther, vecDirection, iDirection, BLOW_KICK_DAMAGE, 1600, 500, 400, 1.75 );
}

void CBuddyMeleeClass::SimpleMeleePowerhit( CBuddy *pOther, Vector vecDirection, int iDirection )
{
	// If you're on the ground, force upwards direction
	if(FBitSet(m_pOwner->pev->flags, FL_ONGROUND))
	{	vecDirection = Vector(0,0,1);
		iDirection = UP;
	}

	//Powerhit( pOther, vecDirection, iDirection, (pOther->m_Melee.m_fThrown ? BLOW_KICK_DAMAGE * 1.5 : BLOW_KICK_DAMAGE),
	//		 1600, 500, 400, 1.75 );
	Powerhit( true, pOther, vecDirection, iDirection, BLOW_KICK_DAMAGE, 1600, 500, 400, 1.75 );
}

bool CBuddyMeleeClass::Powerhit(bool fPlayAnim, CBasePlayer *pOther, Vector vecDirection,
							   int iDirection, float flDamage, float flMaxSpeed, float flMinSpeed,
							   float flDeacceleration, float flMinRecoverTime)
{
	if(!m_pOwner)
		return false;

	if (!CanMelee(pOther))
		return false;

	bool fBlock = false;

	/*
	// Get weapon pointer
	CBasePlayerWeapon *pWeapon = NULL;
	if(m_pAttacker->m_pActiveItem)
	{	pWeapon = (CBasePlayerWeapon*)m_pAttacker->m_pActiveItem;
	}
	// We're attacking too soon
	if(pWeapon && pWeapon->m_iId == WEAPON_MELEE && pWeapon->m_flNextSecondaryAttack > gpGlobals->time)
	{	return false;
	}*/

	
	// Damage + Anim
	if(iDirection != FRONT)
		pOther->TakeDamage(m_pOwner->pev, m_pOwner->pev, ((int)(flDamage * GetPowerRatio(pOther)) * 1.4), DMG_KICK);
	else
		pOther->TakeDamage(m_pOwner->pev, m_pOwner->pev, ((int)(flDamage * GetPowerRatio(pOther))), DMG_KICK);

	// Emit Shockwave
	MESSAGE_BEGIN( MSG_PVS, gmsgMeleeFX, m_pOwner->pev->origin);
		WRITE_BYTE (MELEE_SIMPLE);
		WRITE_BYTE ( m_pOwner->entindex() );
	MESSAGE_END();

	// Emit Sound
	PLAYBACK_EVENT_FULL( FEV_GLOBAL, /*GetSoundEdict()*/ m_pOwner->edict(), m_usMeleeSounds, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, (float)CHAN_WEAPON, /*(float)MELEESOUND_SHOCKWAVE*/1.0f, 0, 0, 0, 0 );

	if(fPlayAnim)
		SetPowerhitAnim( vecDirection, iDirection );

	if(pOther->IsAlive())
	{	// Toss
		if(BlocksMelee(pOther) ? !pOther->UseKi(BLOCK_BLOW_KI_COST) : true )
		{	pOther->m_Melee.StartToss( m_pOwner, true, vecDirection, flMaxSpeed, flMinSpeed, flDeacceleration, flMinRecoverTime );
		}
		else
		{	fBlock = true;/*
			if(pOther->m_pActiveItem)
			{	CBasePlayerWeapon *pWeapon = (CBasePlayerWeapon*)pOther->m_pActiveItem;
				pWeapon->m_flNextPrimaryAttack = pWeapon->m_flNextSecondaryAttack = gpGlobals->time + 0.8;
			}*/
		}
	}
	// Player is dead, push back his velocity a little
	else
	{	pOther->pev->velocity = vecDirection * flMaxSpeed;
	}
/*
	// Weapon delay
	if(pWeapon)
	{	if(fBlock)
			pWeapon->m_flNextPrimaryAttack = pWeapon->m_flNextSecondaryAttack = gpGlobals->time + 1.0;
		else
			pWeapon->m_flNextPrimaryAttack = pWeapon->m_flNextSecondaryAttack = gpGlobals->time + 0.65;

	}
*/
	return fBlock;
}

bool CBuddyMeleeClass::Powerhit(bool fPlayAnim, CBuddy *pOther, Vector vecDirection,
								int iDirection, float flDamage, float flMaxSpeed, float flMinSpeed,
								float flDeacceleration, float flMinRecoverTime)
{
	if(!m_pOwner)
		return false;

	if (!CanMelee(pOther))
		return false;

	bool fBlock = false;

	/*
	// Get weapon pointer
	CBasePlayerWeapon *pWeapon = NULL;
	if(m_pAttacker->m_pActiveItem)
	{	pWeapon = (CBasePlayerWeapon*)m_pAttacker->m_pActiveItem;
	}
	// We're attacking too soon
	if(pWeapon && pWeapon->m_iId == WEAPON_MELEE && pWeapon->m_flNextSecondaryAttack > gpGlobals->time)
	{	return false;
	}*/

	
	// Damage + Anim
	if(iDirection != FRONT)
		pOther->TakeDamage(m_pOwner->pev, m_pOwner->pev, ((int)(flDamage * GetPowerRatio(pOther)) * 1.4), DMG_KICK);
	else
		pOther->TakeDamage(m_pOwner->pev, m_pOwner->pev, ((int)(flDamage * GetPowerRatio(pOther))), DMG_KICK);

	// Emit Shockwave
	MESSAGE_BEGIN( MSG_PVS, gmsgMeleeFX, m_pOwner->pev->origin);
		WRITE_BYTE (MELEE_SIMPLE);
		WRITE_BYTE ( m_pOwner->entindex() );
	MESSAGE_END();

	// Emit Sound
	PLAYBACK_EVENT_FULL( FEV_GLOBAL, /*GetSoundEdict()*/ m_pOwner->edict(), m_usMeleeSounds, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, (float)CHAN_WEAPON, /*(float)MELEESOUND_SHOCKWAVE*/1.0f, 0, 0, 0, 0 );

	if(fPlayAnim)
		SetPowerhitAnim( vecDirection, iDirection );

	if(pOther->IsAlive())
	{	// Toss
		if(BlocksMelee(pOther) ? !pOther->UseKi(BLOCK_BLOW_KI_COST) : true )
		{	pOther->m_Toss.StartToss( m_pOwner, true, vecDirection, flMaxSpeed, flMinSpeed, flDeacceleration, flMinRecoverTime );
		}
		else
		{	fBlock = true;/*
			if(pOther->m_pActiveItem)
			{	CBasePlayerWeapon *pWeapon = (CBasePlayerWeapon*)pOther->m_pActiveItem;
				pWeapon->m_flNextPrimaryAttack = pWeapon->m_flNextSecondaryAttack = gpGlobals->time + 0.8;
			}*/
		}
	}
	// Player is dead, push back his velocity a little
	else
	{	pOther->ApplyVelocity(vecDirection, flMaxSpeed, 1.0f);
	}
/*
	// Weapon delay
	if(pWeapon)
	{	if(fBlock)
			pWeapon->m_flNextPrimaryAttack = pWeapon->m_flNextSecondaryAttack = gpGlobals->time + 1.0;
		else
			pWeapon->m_flNextPrimaryAttack = pWeapon->m_flNextSecondaryAttack = gpGlobals->time + 0.65;

	}
*/
	return fBlock;
}

bool CBuddyMeleeClass::Powerhit( CBasePlayer *pOther, Vector vecDirection, int iDirection )
{	// If you're on the ground, force upwards direction
	if(FBitSet(m_pOwner->pev->flags, FL_ONGROUND))
	{	TraceResult tr;

		// Traceline to ensure we're not standing on a player
		UTIL_TraceHull(m_pOwner->pev->origin, m_pOwner->pev->origin + Vector(0,0,-16), dont_ignore_monsters, human_hull, ENT(m_pOwner->pev), &tr);
		if(tr.flFraction < 1)
		{	CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
			// Standing on a player, extreme knock down
			if(pEntity->IsPlayer())
			{/*	return Powerhit( pOther, vecDirection, iDirection, (pOther->m_Melee.m_fThrown ? POWERHIT_DAMAGE * 1.5 : POWERHIT_DAMAGE),
						 1400, 600, 350, 1.2 );*/
				return Powerhit(TRUE, pOther, vecDirection, iDirection, (pOther->m_Melee.m_fThrown ? POWERHIT_DAMAGE * 1.5 : POWERHIT_DAMAGE),
						 2000, 650, 500, 1.2 );
			}
		}

		vecDirection = Vector(0,0,1);
		iDirection = UP;
	}

	return Powerhit(TRUE, pOther, vecDirection, iDirection, (pOther->m_Melee.m_fThrown ? POWERHIT_DAMAGE * 1.5 : POWERHIT_DAMAGE),
			 800, 400, 250, 1.2 );
}

bool CBuddyMeleeClass::Powerhit( CBuddy *pOther, Vector vecDirection, int iDirection )
{	// If you're on the ground, force upwards direction
	if(FBitSet(m_pOwner->pev->flags, FL_ONGROUND))
	{	TraceResult tr;

		// Traceline to ensure we're not standing on a player
		UTIL_TraceHull(m_pOwner->pev->origin, m_pOwner->pev->origin + Vector(0,0,-16), dont_ignore_monsters, human_hull, ENT(m_pOwner->pev), &tr);
		if(tr.flFraction < 1)
		{	CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
			// Standing on a player, extreme knock down
			if(pEntity->IsPlayer())
			{/*	return Powerhit( pOther, vecDirection, iDirection, (pOther->m_Melee.m_fThrown ? POWERHIT_DAMAGE * 1.5 : POWERHIT_DAMAGE),
						 1400, 600, 350, 1.2 );*/
				return Powerhit(TRUE, pOther, vecDirection, iDirection, (pOther->m_bThrown ? POWERHIT_DAMAGE * 1.5 : POWERHIT_DAMAGE),
						 2000, 650, 500, 1.2 );
			}
		}

		vecDirection = Vector(0,0,1);
		iDirection = UP;
	}

	return Powerhit(TRUE, pOther, vecDirection, iDirection, (pOther->m_bThrown ? POWERHIT_DAMAGE * 1.5 : POWERHIT_DAMAGE),
			 800, 400, 250, 1.2 );
}

bool CBuddyMeleeClass::BlocksMelee(CBasePlayer *pPlayer)
{
	if (pPlayer->m_fBlock)
	{	//make sure we deal with positive angles
	/*	int iOtherYaw = ( (int)pPlayer->pev->v_angle.y + 360)%360;
		int iPlayerYaw = ( (int)m_pAttacker->pev->angles.y + 540)%360;
	
		//check if the player is facing the attack
		if(iOtherYaw < iPlayerYaw + 75)
		{	if (iOtherYaw > iPlayerYaw - 75)
			{	return true;
			}
		}*/
		if(pPlayer->m_Melee.GetBuddyEnemyPrepunch(m_pOwner))
		{	return true;
		}
	}
	return false;
}

bool CBuddyMeleeClass::BlocksMelee(CBuddy *pBuddy)
{
	if (pBuddy->m_bBlock)
	{	//make sure we deal with positive angles
	/*	int iOtherYaw = ( (int)pPlayer->pev->v_angle.y + 360)%360;
		int iPlayerYaw = ( (int)m_pAttacker->pev->angles.y + 540)%360;
	
		//check if the player is facing the attack
		if(iOtherYaw < iPlayerYaw + 75)
		{	if (iOtherYaw > iPlayerYaw - 75)
			{	return true;
			}
		}*/
		if(pBuddy->m_Melee.GetNearestBuddyToMelee(m_pOwner))
		{	return true;
		}
	}
	return false;
}

void CBuddyMeleeClass::SetPowerhitAnim( Vector vecDirection, int iDirection )
{
	// Auto set direction
	if(iDirection == -1)
		iDirection = FRONT;
	BOOL fInverseYaw = FALSE;

	char szAnim[256];
	strcpy(szAnim, "blow_");

	switch(iDirection)
	{	
	case UP:
		{	strcat(szAnim,"up");
			break;
		}
	case DOWN:
		{	strcat(szAnim,"down");
			break;
		}
	case LEFT:
		{	strcat(szAnim,"left");
			break;
		}
	case RIGHT:
		{	strcat(szAnim,"right");
			break;
		}
	default:
	case FRONT:
		{	if(vecDirection.z >= 0.45)
				strcat(szAnim,"up");
			else if(vecDirection.z <= -0.45)
				strcat(szAnim,"down");
			else
				strcat(szAnim,"kick_front");
			break;
		}
	case BACK:
		{	fInverseYaw = TRUE;
			strcat(szAnim,"kick_front");
			break;
		}
	}

	strcpy(m_szPowerHitAnim, szAnim);
	m_bInitPowerHitAnim = true;
	m_fLastPowerHitTime = gpGlobals->time;
/*
	plrmelee_anim_s *pAnim;
	if(!fInverseYaw)
	{	pAnim = AddAnimation(false,gpGlobals->time, 1, szAnim);
	}
	else
	{	pAnim = AddAnimationAFix(vecDirection, false, gpGlobals->time, szAnim);
	}*/
}

float CBuddyMeleeClass::GetPowerRatio(CBasePlayer *pPlayer)
{	if(!pPlayer)
		return 1;

	float flRatio = float((float)m_pOwner->GetPowerLevel() / (float)pPlayer->GetPowerLevel());
	if(flRatio > MAX_RATIO)
		flRatio = MAX_RATIO;
	else if(flRatio < MIN_RATIO)
		flRatio = MIN_RATIO;
	return flRatio;
}

float CBuddyMeleeClass::GetPowerRatio(CBuddy *pBuddy)
{	if(!pBuddy)
		return 1;

	float flRatio = float((float)m_pOwner->GetPowerLevel() / (float)pBuddy->GetPowerLevel());
	if(flRatio > MAX_RATIO)
		flRatio = MAX_RATIO;
	else if(flRatio < MIN_RATIO)
		flRatio = MIN_RATIO;
	return flRatio;
}

void CBuddyMeleeClass::SetThrowAnim(Activity &Act, int &Anim)
{
	int iDirection;
	int iStart;
	float flLargestDot = 0;
	Vector vecDirections[6];

	UTIL_MakeVectors(m_pOwner->pev->v_angle);
	
	vecDirections[UP] = Vector(0,0,1);
	vecDirections[DOWN] = Vector(0,0,-1);
	vecDirections[LEFT] = -gpGlobals->v_right;
	vecDirections[RIGHT] = gpGlobals->v_right;
	vecDirections[FRONT] = gpGlobals->v_forward;
	vecDirections[BACK] = -gpGlobals->v_forward;

/*	if(!fUseUpDown)
		iStart = LEFT;
	else*/
		iStart = 0;

	for(int i=iStart;i<6;i++)
	{	float flDot;
		flDot = DotProduct (vecDirections[i], m_pOwner->pev->velocity);

		if(flDot > flLargestDot)
		{	flLargestDot = flDot;
			iDirection = i;
		}
	}

	switch(iDirection)
	{
	case UP:
		Act = ACT_BLOWN_UP;
		Anim = m_pOwner->LookupSequence("hit_blow_up");
		break;
	case DOWN:
		Act = ACT_BLOWN_DOWN;
		Anim = m_pOwner->LookupSequence("hit_blow_down");
		break;
	case LEFT:
		Act = ACT_BLOWN_LEFT;
		Anim = m_pOwner->LookupSequence("hit_blow_left");
		break;
	case RIGHT:
		Act = ACT_BLOWN_RIGHT;
		Anim = m_pOwner->LookupSequence("hit_blow_right");
		break;
	case FRONT:
		Act = ACT_BLOWN_FRONT;
		Anim = m_pOwner->LookupSequence("hit_blow_front");
		break;
	case BACK:
		Act = ACT_BLOWN_BACK;
		Anim = m_pOwner->LookupSequence("hit_blow_back");
		break;
	}
}
