/**
* Player Melee
* @version 5-2-2003
* @author  Joseph 'Pcjoe' Florencio
*/

#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "effects.h"
#include "aura.h"
#include "classes.h"
#include "magicattack.h"
#include "explodingattack.h"
#include "player.h"
#include "gamerules.h"
#include "chargedattack.h"
#include "decals.h"
#include "melee.h"
#include "playermelee.h"
#include "animation.h"

#ifdef __linux__
	#include <string.h>
	//#include <cstring.h>
#else
	#include <string.h>
	#include <string>
#endif
// Added by Rick
#include "../bot/bot.h"
#include "../bot/bot_util.h"
#include "talkmonster.h"
#include "buddy_aura.h"
#include "buddy.h"
// end add by Rick

extern short g_sRockGibs;
extern cvar_t nomeleehittime;
unsigned short m_usMeleeSounds;

// Combo moves
typedef enum
{	COMBOMOVE_1=1,
	COMBOMOVE_2
};

// Client melee sounds
typedef enum
{	MELEESOUND_SHOCKWAVE=1,
	MELEESOUND_STOP
};

using namespace std;

/*
* Player Melee
* @version 5-2-2003
* @author Joseph 'Pcjoe' Florencio
*/

void CPlayerMelee::Reset( void )
{
#ifndef CLIENT_DLL
	/*
	* General
	*/
	RemoveAllAnims( );

	/*
	* Throw
	*/
	m_iConsecutiveHits = 0;
	m_flMaxSpeed = 0;
	m_flCurSpeed = 0;
	m_flMinSpeed = 0;
	m_flDeacceleration = 0;
	m_flMinRecoverTime = 0;
	m_flLastRecoverTime = 0;
	m_flLayStart = 0;
	m_flPreKnockStrug = 0;
	m_fThrown = FALSE;
	m_fTakeDmgOnCollision = FALSE;
	m_fOnGround = FALSE;
	m_fFlyRecover = FALSE;
	m_fStruggleBar = FALSE;
	m_fPowerhit = FALSE;
	m_fEndAdvMeleeToss = FALSE;
	m_vecDirection = Vector(0,0,0);
	m_eThrowStatus = THROW_DISABLE;
	m_pThrower = NULL;
	// Added by Rick
	m_pBuddyThrower = NULL;

	/*
	* Struggle Varibles
	*/
	m_iStrugArrowCount = 0;
	m_flStrugArrow = 0;
	m_fForceAtkDirs = FALSE;
	m_fForceDfdDirs = FALSE;
	m_fStopStruggle = FALSE;

	/*
	* Advanced Melee
	*/
	m_vecPrepunchDir = vec3_t(0,0,0);
	m_eAdvMeleeStatus = DISABLED;
	m_fPrepunchPinned = FALSE;
	m_fPrepunchBlock = FALSE;
	m_fPrepunchBehind = FALSE;
	m_fAttacker = FALSE;
	m_fDefender = FALSE;
	m_fStunned = FALSE;
	m_fHoldGrab = FALSE;
	m_fSpinSound = FALSE;
	m_fRetaliateEXE = FALSE;
	m_fWaitRetal = FALSE;
	m_fSwitching = FALSE;
	m_fOrigDefender = FALSE;
	m_fEndComboPower = FALSE;
	m_fPreKnockStrug = FALSE;
	m_fManualExe = FALSE;
	m_fDelayMelee = FALSE;
	m_fInvulnerable = FALSE;
	m_flStunnedTime = 0;
	m_flStartPrePunch = 0;
	m_flLastPrePunch = 0;
	m_flChargeGrab = 0;
	m_flKiUpdate = 0;
	m_flStartHoldGrab = 0;
	m_flStartWallStick = 0;
	m_flEndArrowTime = 0;
	m_flFrameTime = 0;
	m_flInvulnerableTime = 0;
	m_iNumPrepunches = 0;
	m_iTotalMoves = 0;
	m_iBlockedMoves = 0;
	m_iSwitch = 0;
	m_iCurAtkID = 0;
	m_iCurDfdID = 0;
	m_vecWallStickNormal = Vector(0,0,0);
	m_pExeStart = NULL;
	m_pExeCurrent = NULL;
	m_pInvulException= NULL;
	SetAttacker( NULL );
	SetAttackerOther( NULL );
	SetDefender( NULL );
	DelAllDirections( );
#endif
}

CPlayerMelee::CPlayerMelee()
{	
#ifndef CLIENT_DLL
	m_pAttackerMoves = NULL;
	m_pDefenderMoves = NULL;
	m_fSimpleMelee = FALSE;

	Reset();
	AddComboMoves( );
#endif
}

#ifndef CLIENT_DLL

/*
* Get Skill Varibles
*/
melee_settings_s *CPlayerMelee::GetSkillValues( void )
{	return g_pGameRules->GetMeleeSkillValues();
}

/*
* Get Original Defender
*/
CBasePlayer *CPlayerMelee::GetOrigDefender( void )
{	if(m_fFighting)
	{	if(m_fOrigDefender)
		{	return m_pAttacker;
		}
		else
		{	if(m_pDefender)
			{	return m_pDefender;
			}
		}
	}
	return NULL;
}

/*
* Get Sound Edict
*/
edict_t *CPlayerMelee::GetSoundEdict( void )
{	CBasePlayer *pPlayer = GetOrigDefender();
	if(!pPlayer)
	{	pPlayer = m_pAttacker;
	}
	return ENT(pPlayer->pev);
}


/*
* Set Attacker
*/
void CPlayerMelee::SetAttacker( CBasePlayer *pPlayer )
{	m_pAttacker = pPlayer;
}

/*
* Set Attacker Other ( person attacking defender )
*/
void CPlayerMelee::SetAttackerOther( CBasePlayer *pPlayer )
{	m_pAttackerOther = pPlayer;
	if(m_pAttackerOther)
	{	m_pAttackerMelee = &pPlayer->m_Melee;
	}
	else
	{	m_pAttackerMelee = NULL;
	}
}

/*
* Set Enemy
*/
void CPlayerMelee::SetDefender( CBasePlayer *pOther )
{	m_pDefender = pOther;
	if(m_pDefender)
	{	m_pDefenderMelee = &pOther->m_Melee;
	}
	else
	{	m_pDefenderMelee = NULL;
	}
}

/*
* Basic Melee calls
*/
void CPlayerMelee::ManageMelee( void )
{	ManageInvulnerability();
	if(IsAttacker() ? GetDefender()->IsAlive() && GetDefender()->pev->takedamage != DAMAGE_NO : true )
	{
		if(m_eAdvMeleeStatus == PREPUNCH_ATTACK)
		{	HandlePrepunchAttack( );
		}
		else if(m_eAdvMeleeStatus == PREPUNCH_DEFEND)
		{	HandlePrepunchDefend( );
		}
		else if(m_eAdvMeleeStatus == CHARGE_ATTACK)
		{	HandleChargeAttack( );
		}
		else if(m_eAdvMeleeStatus == CHARGE_DEFEND)
		{	HandleChargeDefend( );
		}
		else if(m_eAdvMeleeStatus == EXE_ATTACK)
		{	HandleExeAttack( );
		}
		else if(m_eAdvMeleeStatus == EXE_DEFEND)
		{	HandleExeDefend( );
		}
		else if(m_eAdvMeleeStatus == GRAB_ATTACK)
		{	HandleGrabAttack( );
		}
		else if(m_eAdvMeleeStatus == GRAB_DEFEND)
		{	HandleGrabDefend( );
		}
		else if(m_eAdvMeleeStatus == STRUGGLE_ATTACK)
		{	HandleStruggleAttack( );
		}
		else if(m_eAdvMeleeStatus == STRUGGLE_BURST_ATTACK)
		{	HandleBurstStruggleAttack( );
		}
		else if(m_eAdvMeleeStatus == STRUGGLE_DEFEND)
		{	HandleStruggleDefend( );
		}
		else if(m_eAdvMeleeStatus == KNOCKPRE_STRUGGLE_ATTACK)
		{	HandleKnockPreStruggleAttack();
		}
	}
	// Stop melee when character is dead
	else if(m_eAdvMeleeStatus != DISABLED)
	{	// Only allow attacker to stop melee
		if(IsAttacker())
		{	StopMelee(FALSE);
		}
	}
}


/*
* Manage Invulnerability
*/
void CPlayerMelee::ManageInvulnerability( void )
{	if(m_pAttacker && m_fInvulnerable)
	{	// turn invulnerability off
		if(m_flInvulnerableTime < gpGlobals->time)
		{	m_fInvulnerable = FALSE;
			m_pInvulException = NULL;
			m_flInvulnerableTime = 0;
		}
	}
}


/*
* ======================================
* Animation System
*
* ======================================
*/

void CPlayerMelee::ManageList( void )
{	if(!m_pAttacker)
	{	return;
	}

	// Manage Priority
	ManagePriority();

	plrmelee_anim_s *pCurrent = m_pMeleeAnim;
	plrmelee_anim_s *pCurrentAnim = GetCurrentAnim();

	// Dont delete animations while in advanced melee battle
	if(!InAdvMeleeBattle())
	{	// If we have too many playable items, delete the oldest items
		while(pCurrent)
		{
			// Old playable item, delete it
			if(pCurrent != pCurrentAnim && ((pCurrent->flTime < gpGlobals->time) || pCurrent->fInit))
			{	pCurrent = RemoveAnim(pCurrent);
			}
			else
			{	pCurrent = pCurrent->pNext;
			}
		}
	}
}


/*
* Set Anim Priority
*/
void CPlayerMelee::SetAnimPriority( ANIM_PRIORITY ePriority, plrmelee_anim_s *pAnim )
{	if(!pAnim)
	{	return;
	}

	pAnim->eAnimPriority = ePriority;
}


/*
* Can Play Medium Priority Anims
*/
BOOL CPlayerMelee::PlayMedPriorityAnim( void )
{	if(!m_pAttacker->m_fBlock && !m_pAttacker->m_fCharging &&
	   !m_pAttacker->m_fCharging2 && !m_pAttacker->m_fControl &&
	   !m_pAttacker->m_fHoldDisc && !m_pAttacker->m_fAscending &&
	   !m_pAttacker->m_fShield)
	{	return TRUE;
	}
	return FALSE;
}

/*
* Can Play Low Priority Anims
*/
BOOL CPlayerMelee::PlayLowPriorityAnim( void )
{	plrmelee_anim_s *pAnim = GetCurrentAnim();
	BOOL fOnGround = FBitSet(m_pAttacker->pev->flags,FL_ONGROUND);
	if(PlayMedPriorityAnim() && !m_pAttacker->m_fPowerUp && !m_pAttacker->m_fFlying &&
	   pAnim->fStartOnGround == fOnGround)
	{	return TRUE;
	}
	return FALSE;
}

/*
* Manage Priority
*/
void CPlayerMelee::ManagePriority( void )
{	if(!CanPlayAnimation())
	{	return;
	}

	plrmelee_anim_s *pAnim = GetCurrentAnim();

	// Make sure animations have ran atleast once
	if(pAnim->fInit)
	{	if(pAnim->eAnimPriority == ANIM_PRIORITY_MEDIUM)
		{	if(!PlayMedPriorityAnim() && !m_pAttacker->m_fPowerUp)
			{	RemoveAnim(pAnim);
			}
		}
		// Same as medium, just that powerup doesn't overwrite
		else if(pAnim->eAnimPriority == ANIM_PRIORITY_MEDIUM_HIGH)
		{	if(!PlayMedPriorityAnim())
			{	RemoveAnim(pAnim);
			}
		}
		else if(pAnim->eAnimPriority == ANIM_PRIORITY_LOW)
		{	if(!PlayLowPriorityAnim())
			{	RemoveAnim(pAnim);
			}
		}
	}
}

plrmelee_anim_s *CPlayerMelee::AddAnimationExe( float flTime, char *szString )
{	char szAnim[32];
	plrmelee_anim_s *pAnim;

	// Remove current exe anim
	pAnim = GetCurrentAnim();
	if(pAnim && pAnim->fExecution)
	{	RemoveAnim(pAnim);
		pAnim = NULL;
	}

	// Set Animation
	pAnim = AddAnimation( false, flTime, 1, szString );
	pAnim->fExecution = TRUE;

	// Set EXE info
	if(m_pExeCurrent)
	{	m_pExeCurrent->flStartTime = flTime;
	}
	else
	{	return NULL;
	}

	if(m_pDefenderMelee)
	{	strcpy(szAnim, szString);
	
		if(m_pExeCurrent->eBlock == BLOCK_TRUE)
		{	strcat(szAnim,"_block");
		}
		else
		{	strcat(szAnim,"_hit");
		}

		// Add block/hit anims
		m_pDefenderMelee->AddAnimation(true,gpGlobals->time,1,szAnim);
	}

	return pAnim;
}


plrmelee_anim_s *CPlayerMelee::AddAnimationAFix( Vector vecNormal, bool blLooping, float flTime, const char *szString )
{	// Add animation
	plrmelee_anim_s *pAnim = AddAnimation( blLooping, flTime, 1, szString );
	// Set angle fix
	if(pAnim)
	{	pAnim->fAngleFix = TRUE;
		UTIL_Model_FixAngles(m_pAttacker->entindex(), UTIL_VecToAngles(vecNormal));
	}

	return pAnim;
}

plrmelee_anim_s *CPlayerMelee::AddAnimation( bool blLooping, float flTime, int iNum, ... )
{	// Remove angle locks
	plrmelee_anim_s *pAnim = GetCurrentAnim();
	if(pAnim && pAnim->fAngleFix)
	{	if(m_pAttacker)
		{	UTIL_Model_RemoveAll(m_pAttacker->entindex());
		}
	}

	int i;
	bool blOdd = true;
	plrmelee_anim_s *pNewAnim = new plrmelee_anim_s;

	// Cap off max anims
	if(iNum > MAX_LINKED_ANIM)
	{	iNum = MAX_LINKED_ANIM;
	}

	// Insert info
	pNewAnim->eAnimPriority = ANIM_PRIORITY_HIGH;
	pNewAnim->flTime = flTime;
	pNewAnim->fLooping = blLooping;
	pNewAnim->fInit = FALSE;
	pNewAnim->iCurrentAnim = 0;
	pNewAnim->iNumAnims = iNum;
	pNewAnim->fExecution = FALSE;
	pNewAnim->fAngleFix = FALSE;
	pNewAnim->pNext = NULL;

	// Copy name(s)
	va_list arguments;
	va_start(arguments, iNum);

	for( i = 0; i < iNum; i++ )
	{	strcpy(pNewAnim->szAnim[i], va_arg(arguments, char *));

		// Set different activities every anim
		if(!i)
		{	if(m_pAttacker->m_IdealActivity == ACT_MELEE_ONE)
			{	pNewAnim->IdealActivity[i] = ACT_MELEE_THREE;
			}
			else
			{	pNewAnim->IdealActivity[i] = ACT_MELEE_ONE;
			}
		}
		else
		{	if(blOdd)
			{	pNewAnim->IdealActivity[i] = ACT_MELEE_TWO;
			}
			else
			{	pNewAnim->IdealActivity[i] = ACT_MELEE_THREE;
			}
			blOdd = !blOdd;
		}
	}

	va_end(arguments);


	// Check to see if this character has the animation
	if(m_pAttacker->LookupSequence( pNewAnim->szAnim[0] ) == -1 && !InAdvMeleeBattle())
	{	delete pNewAnim;
		return NULL;
	}

	// Nothing in first member? place it here!
	if(!m_pMeleeAnim)
	{	m_pMeleeAnim = pNewAnim;
	}
	// Add to the head of the list
	else
	{	pNewAnim->pNext = m_pMeleeAnim;
		m_pMeleeAnim = pNewAnim;
	}

	// Manage animation list
	ManageList();

	return pNewAnim;
}

plrmelee_anim_s *CPlayerMelee::AddToCurAnim( bool blLooping, char *szString )
{
	plrmelee_anim_s *pAnim = GetCurrentAnim( );

	if(pAnim && (pAnim->iNumAnims < MAX_LINKED_ANIM))
	{	strcpy(pAnim->szAnim[pAnim->iNumAnims], szString);
		pAnim->fLooping = blLooping;
		pAnim->iNumAnims++;
	}

	return pAnim;
}

plrmelee_anim_s *CPlayerMelee::GetCurrentAnim( void )
{	// Special finding routine for EXE anims
	if(InAdvMeleeBattle() && m_eAdvMeleeStatus == EXE_ATTACK)
	{	return GetCurrentExeAnim();
	}

	float flTime = 0;
	plrmelee_anim_s *pCurrent = m_pMeleeAnim;
	plrmelee_anim_s *pAnim = NULL;

	// Go through all animations, and save the one with the soonest play time
	while(pCurrent)
	{	if((pCurrent->flTime > flTime) && (pCurrent->flTime <= gpGlobals->time))
		{	flTime = pCurrent->flTime;
			pAnim = pCurrent;
		}
		pCurrent = pCurrent->pNext;
	}

	return pAnim;
}

plrmelee_anim_s *CPlayerMelee::GetCurrentExeAnim( void )
{
	float flTime = -1;
	plrmelee_anim_s *pCurrent = m_pMeleeAnim;
	plrmelee_anim_s *pAnim = NULL;

	// Go through all animations, and save the one with the soonest play time
	while(pCurrent)
	{	if((!pAnim || (pCurrent->flTime > flTime)) && pCurrent->fExecution)
		{	flTime = pCurrent->flTime;
			pAnim = pCurrent;
		}
		pCurrent = pCurrent->pNext;
	}

	return pAnim;
}

void CPlayerMelee::GetAnimForMove( melee_move_s *pMove, char *pAnim )
{	GetAnimForMove( pMove->iFlags, GetMeleeStrength(pMove), pAnim);
}

void CPlayerMelee::GetAnimForMove( int iFlags, MELEE_STRENGTH eStrength, char *pAnim )
{	strcpy(pAnim,"");

	// Set direction
	if(iFlags & IN_FORWARD)
	{	strcat(pAnim,"top_");
	}
	else if(iFlags & IN_BACK)
	{	strcat(pAnim,"bottom_");
	}
	else if(iFlags & IN_LEFT)
	{	strcat(pAnim,"left_");
	}
	else if(iFlags & IN_RIGHT)
	{	strcat(pAnim,"right_");
	}
	else
	{	strcpy(pAnim, "");
		return;
	}

	// Set Weak/Medium/Strong
	switch(eStrength)
	{
	case WEAK_HIT:
		strcat(pAnim,"weak_");
		break;
	case MEDIUM_HIT:
		strcat(pAnim,"medium_");
		break;
	default:
	case STRONG_HIT:
		strcat(pAnim,"strong_");
		break;
	}

	// Kick/punch
	if(iFlags & IN_ATTACK2)
	{	strcat(pAnim,"attack2");
	}
	else
	{	strcat(pAnim,"attack1");
	}
}


BOOL CPlayerMelee::CanPlayAnimation( void )
{	// See if the animation can play
	if(GetCurrentAnim())
	{	return TRUE;
	}
	else
	{	return FALSE;
	}
}

void CPlayerMelee::MeleeFrameAdvance( void )
{	char szModel[256];

	void *pmodel;
	int iSequence = m_pAttacker->pev->sequence;

	// Set model
	strcpy(szModel, m_pAttacker->m_szCurrentModel);
	UTIL_SetPlayerModel(m_pAttacker, "player");

	// Set sequence for new model + get sequence information
	plrmelee_anim_s *pAnim = GetCurrentAnim();
	if(pAnim)
	{	m_pAttacker->pev->sequence = m_pAttacker->LookupSequence( pAnim->szAnim[pAnim->iCurrentAnim] );
	}
	pmodel = GET_MODEL_PTR( ENT(m_pAttacker->pev) );
	GetSequenceInfo( pmodel, m_pAttacker->pev, &m_pAttacker->m_flFrameRate, &m_pAttacker->m_flGroundSpeed );

	// Advance frames
	m_pAttacker->StudioFrameAdvance( );
	
	// Set model back and set framerate to individual model speed
	UTIL_SetPlayerModel(m_pAttacker, szModel);
	pmodel = GET_MODEL_PTR( ENT(m_pAttacker->pev) );
	m_pAttacker->pev->sequence = iSequence;
	GetSequenceInfo( pmodel, m_pAttacker->pev, &m_pAttacker->m_flFrameRate, &m_pAttacker->m_flGroundSpeed );
	
	// Go to next exe attack if we've finished this one
	if(m_eAdvMeleeStatus == EXE_ATTACK && m_pAttacker->m_fSequenceFinished)
	{	m_pAttacker->PlayAnimation();
	}
}

plrmelee_anim_s *CPlayerMelee::RemoveAnim( plrmelee_anim_s *pAnim )
{	if(!pAnim)
	{	return NULL;
	}

	// Disable anglefix
	if(/*(pAnim == GetCurrentAnim()) && */pAnim->fAngleFix)
	{	if(m_pAttacker)
		{	UTIL_Model_RemoveAll(m_pAttacker->entindex());
		}
	}

	// First member on the list!
	if(m_pMeleeAnim == pAnim)
	{
		plrmelee_anim_s *pDelete = m_pMeleeAnim;
		m_pMeleeAnim = m_pMeleeAnim->pNext;
		delete pDelete;
		return m_pMeleeAnim;
	}
	// Search for it!
	else
	{
		plrmelee_anim_s *pCurrent = m_pMeleeAnim;
		
		while(pCurrent->pNext && pCurrent->pNext != pAnim)
		{	pCurrent = pCurrent->pNext;
		}

		// We must have found it, delete it!
		if(pCurrent->pNext)
		{
			plrmelee_anim_s *pPrev = pCurrent;
			pCurrent = pCurrent->pNext;
			pPrev->pNext = pCurrent->pNext;
			delete pCurrent;
		}
	}
	return NULL;
}

void CPlayerMelee::RemoveAnim( char *pName )
{	if(!m_pMeleeAnim)
	{	return;
	}

	if(strcmp(pName,m_pMeleeAnim->szAnim[0]))
	{	plrmelee_anim_s *pCurrent = m_pMeleeAnim;

		// Search for it
		while(pCurrent->pNext && strcmp(pCurrent->szAnim[0],pName))
		{	pCurrent = pCurrent->pNext;
		}
		RemoveAnim(pCurrent);
	}
	// First animation in list, get rid of it
	else
	{	RemoveAnim(m_pMeleeAnim);
	}
}

void CPlayerMelee::RemoveAllAnims( void )
{	// HACK HACK: Dont erase death anims
	if(m_pAttacker && m_pAttacker->pev->deadflag == DEAD_DYING)
	{	return;
	}
	plrmelee_anim_s *pCurrent = m_pMeleeAnim;
	// Remove everything from the list
	while(pCurrent)
	{	pCurrent = RemoveAnim(pCurrent);
	}
	m_pMeleeAnim = NULL;
}

/*
* Get Throw Anim Direction (ENUM)
*/
int CPlayerMelee::GetThrowDirection( BOOL fUseUpDown )
{	int iDirection;
	int iStart;
	float flLargestDot = 0;
	Vector vecDirections[6];

	UTIL_MakeVectors(m_pAttacker->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_pAttacker->pev->velocity);

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

	return iDirection;
}

/*
*	Throw system dealing with animations
*/

/*
* Get Throw Anim Direction
*/
void CPlayerMelee::GetThrowAnimDirection( int null, int iDirection, char *pAnim )
{	strcpy(pAnim,"");
	switch(iDirection)
	{
	case UP:
		{	strcpy(pAnim, "up");
			break;
		}
	case DOWN:
		{	strcpy(pAnim, "down");
			break;
		}
	case LEFT:
		{	strcpy(pAnim, "left");
			break;
		}
	case RIGHT:
		{	strcpy(pAnim, "right");
			break;
		}
	case FRONT:
		{	if((m_eThrowStatus == THROW_ROLL && FBitSet(m_pAttacker->pev->flags, FL_ONGROUND)) ||
				(m_eThrowStatus == THROW_RECOVER && !m_fFlyRecover))
			{	strcpy(pAnim, "forward");
			}
			else
			{	strcpy(pAnim, "front");
			}
			break;
		}
	case BACK:
		{	strcpy(pAnim, "back");
			break;
		}
	}
}

void CPlayerMelee::GetThrowAnimDirection( BOOL fUseUpDown, char *pAnim )
{	GetThrowAnimDirection(0, GetThrowDirection(fUseUpDown), pAnim);
}

/*
* Get Throw Activity (Animation)
*/
Activity CPlayerMelee::GetThrowActivity( void )
{	Activity activity;

	if(m_eThrowStatus == THROW_TOSS || m_eThrowStatus == THROW_WALLSTICK || 
		(m_eThrowStatus == THROW_ROLL && !FBitSet(m_pAttacker->pev->flags, FL_ONGROUND)))
	{	switch(GetThrowDirection(TRUE))
		{
		case UP:
			{	activity = ACT_BLOWN_UP;
				break;
			}
		case DOWN:
			{	activity = ACT_BLOWN_DOWN;
				break;
			}
		case LEFT:
			{	activity = ACT_BLOWN_LEFT;
				break;
			}
		case RIGHT:
			{	activity = ACT_BLOWN_RIGHT;
				break;
			}
		case FRONT:
			{	activity = ACT_BLOWN_FRONT;
				break;
			}
		case BACK:
			{	activity = ACT_BLOWN_BACK;
				break;
			}
		}
	}
	else if(m_eThrowStatus == THROW_ROLL)
	{	switch(GetThrowDirection(FALSE))
		{
		case LEFT:
			{	activity = ACT_ROLL2_LEFT;
				break;
			}
		case RIGHT:
			{	activity = ACT_ROLL2_RIGHT;
				break;
			}
		case FRONT:
			{	activity = ACT_ROLL_FRONT;
				break;
			}
		case BACK:
			{	activity = ACT_ROLL_BACK;
				break;
			}
		}
	}
	else if(m_eThrowStatus == THROW_LAY)
	{	if(m_flLayStart)
		{	activity = ACT_LAY;
		}
		else
		{	activity = ACT_LAY_RECOVER;
		}
	}
	else if(m_eThrowStatus == THROW_LANDRECOVER)
	{	activity = ACT_LANDRECOVER;
	}
	else if(m_eThrowStatus == THROW_RECOVER)
	{	activity = ACT_ROLL_RECOVER;
	}

	return activity;
}

/*
* Get Throw Anim
*/
void CPlayerMelee::SetThrowAnim( char *pAnim, Activity &m_IdealActivity )
{	BOOL fStopThrow = FALSE;
	char szThrowAnim[256];

	switch(m_eThrowStatus)
	{
	case THROW_TOSS:
	case THROW_WALLSTICK:
		{	m_IdealActivity = GetThrowActivity();
			GetThrowAnimDirection( TRUE, szThrowAnim );
			sprintf(pAnim, "hit_blow_%s", szThrowAnim);
			break;
		}
	case THROW_ROLL:
		{	if(FBitSet(m_pAttacker->pev->flags, FL_ONGROUND))
			{	m_IdealActivity = GetThrowActivity();
				GetThrowAnimDirection( FALSE, szThrowAnim );
				sprintf(pAnim, "tumble_%s", szThrowAnim);
			}
			else
			{	m_IdealActivity = GetThrowActivity();
				GetThrowAnimDirection( TRUE, szThrowAnim );
				sprintf(pAnim, "hit_blow_%s", szThrowAnim);
			}
			break;
		}
	case THROW_LAY:
		{	// Lay
			if(m_flLayStart)
			{	if(m_pAttacker->m_Activity == ACT_ROLL_BACK ||
					m_pAttacker->LookupSequence( "lay_ground" ) == m_pAttacker->pev->sequence)
				{	strcpy( pAnim, "lay_ground" );
				}
				else
				{	strcpy( pAnim, "lay_ground2" );
				}

				m_IdealActivity = GetThrowActivity();
			}
			// Recover
			else
			{	if(m_pAttacker->m_Activity == GetThrowActivity() && m_pAttacker->m_fSequenceFinished)
				{	fStopThrow = TRUE;
				}

				if(m_pAttacker->LookupSequence( "lay_ground" ) == m_pAttacker->pev->sequence ||
					m_pAttacker->LookupSequence( "lay_ground_recover" ) == m_pAttacker->pev->sequence)
				{	strcpy( pAnim, "lay_ground_recover" );
				}
				else
				{	strcpy( pAnim, "lay_ground_recover2" );
				}

				m_IdealActivity = GetThrowActivity();
			}
			break;
		}
	case THROW_LANDRECOVER:
		{	strcpy( pAnim, "throw_land" );
			m_IdealActivity = GetThrowActivity();
			break;
		}
	case THROW_RECOVER:
		{	if(m_pAttacker->m_Activity == GetThrowActivity() && m_pAttacker->m_fSequenceFinished)
			{	fStopThrow = TRUE;
			}

			// Recovering from roll
			if(!m_fFlyRecover)
			{	m_IdealActivity = GetThrowActivity();
				GetThrowAnimDirection( FALSE, szThrowAnim );
				sprintf(pAnim, "tumble_%s_recover", szThrowAnim);
			}
			// Recovering from blow
			else
			{	m_IdealActivity = GetThrowActivity();
				GetThrowAnimDirection( TRUE, szThrowAnim );
				sprintf( pAnim, "hit_blow_%s_recover", szThrowAnim );
			}
			break;
		}
	}

	if(fStopThrow)
	{	StopThrow();
	}
}

/*
* ======================================
* Toss System
*
* ======================================
*/

/*
* Manage Toss
*/
void CPlayerMelee::ManageToss( void )
{	// Make sure we're being thrown
	if(!m_fThrown)
	{	return;
	}

	switch(m_eThrowStatus)
	{
	case THROW_TOSS:
		{	HandleToss();
			break;
		}
	case THROW_ROLL:
		{	HandleRoll();
			break;
		}
	case THROW_WALLSTICK:
		{	HandleWallStick();
			break;
		}
	case THROW_LAY:
		{	HandleLay();
			break;
		}
	case THROW_LANDRECOVER:
		{	HandleLandRecover();
			break;
		}
	case THROW_RECOVER:
		{	HandleRecover();
			break;
		}
	}
}

/*
* Start "Toss"
*/
void CPlayerMelee::StartToss( CBasePlayer *pThrower, BOOL fDmgOnCollision, Vector vecDirection, float flMaxSpeed, float flMinSpeed, float flDeacceleration, float flMinRecoverTime )
{	if(!pThrower || !m_pAttacker->IsAlive())
	{	return;
	}

	if(m_fThrown)
	{	int iHits = m_iConsecutiveHits;
		StopThrow(TRUE);
		m_iConsecutiveHits = iHits;
		m_iConsecutiveHits++;
	}
	else
	{	m_iConsecutiveHits = 1;
	}

	// Disable Special Modes
	if(m_pAttacker->m_Swoop.m_fSwoop)
	{	m_pAttacker->StopSwoop();
	}
	if (m_pAttacker->m_fAscending)
	{	m_pAttacker->Descend( true );
	}
	if (m_pAttacker->m_fPowerUp)
	{	m_pAttacker->StopPowerUp();
	}
	if (m_pAttacker->m_fFlying)
	{	m_pAttacker->StopFly();
	}
	if(m_pAttacker->m_fTurbo)
	{	m_pAttacker->StopTurbo();
	}
	if(m_pAttacker->m_fWallJump)
	{	m_pAttacker->RemoveWallJump();
	}
	if(m_pAttacker)
	{	CBasePlayerWeapon *pWeapon = (CBasePlayerWeapon*)m_pAttacker->m_pActiveItem;
		if(pWeapon && (pWeapon->HolsterWhenMeleed()))
		{	// HACK HACK: Safely holster enemys weapon
			pWeapon->Holster();
			pWeapon->Deploy();
		}
	}

	// Set Varibles
	m_pThrower = pThrower;
	m_pBuddyThrower = NULL;
	m_fTakeDmgOnCollision = fDmgOnCollision;
	m_fThrown = TRUE;
	m_eThrowStatus = THROW_TOSS;
	m_vecLandRecoverAngles = Vector(0,0,0);
	m_flFrameTime = gpGlobals->time;

	m_flMaxSpeed = flMaxSpeed;
	m_flCurSpeed = flMaxSpeed;
	m_flMinSpeed = flMinSpeed;
	m_flDeacceleration = flDeacceleration;
	m_flMinRecoverTime = gpGlobals->time + flMinRecoverTime;

	// Set movetype
	m_pAttacker->m_fMelee = TRUE;
	m_pAttacker->pev->movetype = MOVETYPE_PLAYERTOSS;
	m_pAttacker->pev->gravity = 1;

	// Set Velocity
	m_vecDirection = vecDirection.Normalize();
	m_pAttacker->pev->vuser4 = m_vecDirection * m_flCurSpeed;

	// Remove Anims
	RemoveAllAnims();
}

// Added by Rick : Buddy version
/*
* Start "Toss"
*/
void CPlayerMelee::StartToss( CBuddy *pThrower, BOOL fDmgOnCollision, Vector vecDirection, float flMaxSpeed, float flMinSpeed, float flDeacceleration, float flMinRecoverTime )
{	if(!pThrower || !m_pAttacker->IsAlive())
	{	return;
	}

	if(m_fThrown)
	{	int iHits = m_iConsecutiveHits;
		StopThrow(TRUE);
		m_iConsecutiveHits = iHits;
		m_iConsecutiveHits++;
	}
	else
	{	m_iConsecutiveHits = 1;
	}

	// Disable Special Modes
	if(m_pAttacker->m_Swoop.m_fSwoop)
	{	m_pAttacker->StopSwoop();
	}
	if (m_pAttacker->m_fAscending)
	{	m_pAttacker->Descend( true );
	}
	if (m_pAttacker->m_fPowerUp)
	{	m_pAttacker->StopPowerUp();
	}
	if (m_pAttacker->m_fFlying)
	{	m_pAttacker->StopFly();
	}
	if(m_pAttacker->m_fTurbo)
	{	m_pAttacker->StopTurbo();
	}
	if(m_pAttacker->m_fWallJump)
	{	m_pAttacker->RemoveWallJump();
	}
	if(m_pAttacker)
	{	CBasePlayerWeapon *pWeapon = (CBasePlayerWeapon*)m_pAttacker->m_pActiveItem;
		if(pWeapon && (pWeapon->HolsterWhenMeleed()))
		{	// HACK HACK: Safely holster enemys weapon
			pWeapon->Holster();
			pWeapon->Deploy();
		}
	}

	// Set Varibles
	m_pBuddyThrower = pThrower;
	m_pThrower = NULL;
	m_fTakeDmgOnCollision = fDmgOnCollision;
	m_fThrown = TRUE;
	m_eThrowStatus = THROW_TOSS;
	m_vecLandRecoverAngles = Vector(0,0,0);
	m_flFrameTime = gpGlobals->time;

	m_flMaxSpeed = flMaxSpeed;
	m_flCurSpeed = flMaxSpeed;
	m_flMinSpeed = flMinSpeed;
	m_flDeacceleration = flDeacceleration;
	m_flMinRecoverTime = gpGlobals->time + flMinRecoverTime;

	// Set movetype
	m_pAttacker->m_fMelee = TRUE;
	m_pAttacker->pev->movetype = MOVETYPE_PLAYERTOSS;
	m_pAttacker->pev->gravity = 1;

	// Set Velocity
	m_vecDirection = vecDirection.Normalize();
	m_pAttacker->pev->vuser4 = m_vecDirection * m_flCurSpeed;

	// Remove Anims
	RemoveAllAnims();
}
// End add by Rick

/*
* Make Creater
*/
void CPlayerMelee::MakeCreater( void )
{	Vector vecDirection;

	// Get Direction
	if(m_eThrowStatus == THROW_TOSS)
		vecDirection = m_vecDirection;
	else
		vecDirection = (m_pAttacker->pev->velocity.Normalize() + Vector(0,0,-1)).Normalize();
	
	// Create imprint
	TraceResult tr;
	Vector vecEnd = m_pAttacker->pev->origin + vecDirection * 128;
	UTIL_TraceLine (m_pAttacker->pev->origin, vecEnd, ignore_monsters, ENT(m_pAttacker->pev), &tr );
	
	if(tr.flFraction != 1 && CBaseEntity::Instance(tr.pHit)->pev->solid == SOLID_BSP)
	{	UTIL_DecalTrace( &tr, DECAL_GARGSTOMP1 );
	}
}


/*
* Apply Velocity
*/
void CPlayerMelee::ApplyVelocity( void )
{	m_pAttacker->pev->vuser4 = m_vecDirection * m_flCurSpeed;
}

/*
* DeaccelerateToss (Using frametime)
*/
BOOL CPlayerMelee::DeaccelerateToss( void )
{	float flFrameTime = gpGlobals->time - m_flFrameTime;
	m_flFrameTime = gpGlobals->time;
	m_flCurSpeed -= m_flDeacceleration * flFrameTime;
	
	if(m_flCurSpeed < 0)
		m_flCurSpeed = 0;

	if(m_flCurSpeed >= m_flMinSpeed)
		return FALSE;
	else
		return TRUE;
}

/*
* Check for obsticales
*/
BOOL CPlayerMelee::CheckForObsticales( void )
{	TraceResult tr;
	Vector vecLOS;

	// Traceline
	UTIL_TraceHull(m_pAttacker->pev->origin, m_pAttacker->pev->origin + m_vecDirection * 32, dont_ignore_monsters, human_hull, ENT(m_pAttacker->pev), &tr);
	
	// We hit something
	if(tr.flFraction < 1)
	{	CBasePlayer	*pHit = (CBasePlayer*)CBaseEntity::Instance( tr.pHit );

		// Hit map
		if(pHit->pev->solid == SOLID_BSP)
		{	float flPitch;
			float flDot;
			
			// Get Pitch + Dot
			flPitch = UTIL_VecToAngles(tr.vecPlaneNormal).x;
			flDot = DotProduct (m_vecDirection, -tr.vecPlaneNormal);

			// Limit Pitch
			if(flPitch < -180)
				flPitch += 360;
			else if(flPitch > 180)
				flPitch -= 360;

			// Stop when we hit a wall
			if(!m_fTakeDmgOnCollision)
			{	StopThrow();
				return TRUE;
			}

			RemoveStruggleBar();

			// We were thrown directly into the ground, go strait to laying down
			if(flDot > 0.8 && flPitch < 115 && flPitch > 65 ) // +- 35 degrees
			{	MakeCreater();

				// Emit Sound
				EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/wallhit.wav", 1.0, ATTN_NORM);
				
				// Inflict damage
				if(!InflictWallhitDmg( TRUE ))
				{	return TRUE;
				}
				
				// If player is holding onto jump and has enough KI, do a ground recover
				if((m_pAttacker->pev->button & IN_JUMP) && m_pAttacker->UseKi(MELEE_WALLSTICK_RECOVER_COST))
				{	// Ground Recover
					StartLandRecover();
				}
				else
				{	// Lay Down
					StartLay();
				}
				return TRUE;
			}
			// Wallstick
			else if(flDot > VIEW_FIELD_NARROW && flPitch < 45 && flPitch > -45)	// +- 45 degrees
			{	MakeCreater();

				// Emit Sound
				EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/wallhit.wav", 1.0, ATTN_NORM);

				// Emit Rocks
				EmitExplosionRocks(tr.vecEndPos, tr.vecPlaneNormal * 125, 50, 20, 20);

				// Inflict damage
				if(!InflictWallhitDmg( TRUE ))
				{	return TRUE;
				}

				// Wallstick
				StartWallStick(tr.vecEndPos, tr.vecPlaneNormal);
				return TRUE;
			}
			// Change to roll
			else
			{	// Inflict damage
				if(!InflictWallhitDmg( FALSE ))
				{	return TRUE;
				}

				StartRoll();
				return TRUE;
			}
		}
		// Hit Player
		// Modified by Rick, Check if we have a m_pThrower or m_pBuddyThrower
		else if( pHit->IsPlayer() && pHit->IsAlive() && pHit != m_pThrower )
		{	if(!pHit->m_Melee.m_fThrown)
			{
				if (m_pThrower && m_pThrower->CanMelee(pHit))
				{
					EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/wallhit.wav", 1.0, ATTN_NORM);
					pHit->m_Melee.StartToss( m_pThrower, TRUE, m_vecDirection, m_flCurSpeed * 1.15, m_flMinSpeed, m_flDeacceleration * 0.85, 1.5);
				}
				else if (m_pBuddyThrower && m_pBuddyThrower->m_Melee.CanMelee(pHit))
				{
					EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/wallhit.wav", 1.0, ATTN_NORM);
					pHit->m_Melee.StartToss( m_pBuddyThrower, TRUE, m_vecDirection, m_flCurSpeed * 1.15, m_flMinSpeed, m_flDeacceleration * 0.85, 1.5);
				}
			}
		}
		// else check if hit buddy
		else if (tr.pHit && FStrEq(STRING(tr.pHit->v.classname), "player_buddy"))
		{
			CBuddy *pBuddy = (CBuddy *)CBaseEntity::Instance(tr.pHit);
			if (pBuddy && pBuddy->IsAlive() && !pBuddy->m_bThrown)
			{
				if (m_pThrower && m_pThrower->CanMelee(pBuddy))
				{
					EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/wallhit.wav", 1.0, ATTN_NORM);
					pBuddy->m_Toss.StartToss( m_pThrower, TRUE, m_vecDirection, m_flCurSpeed * 1.15, m_flMinSpeed, m_flDeacceleration * 0.85, 1.5);
				}
				else if (m_pBuddyThrower && m_pBuddyThrower->m_Melee.CanMelee(pBuddy))
				{	EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/wallhit.wav", 1.0, ATTN_NORM);
					pBuddy->m_Toss.StartToss( m_pBuddyThrower, TRUE, m_vecDirection, m_flCurSpeed * 1.15, m_flMinSpeed, m_flDeacceleration * 0.85, 1.5);
				}
			}
		}
	}

	return FALSE;
}

/*
* Handle Toss
*/
void CPlayerMelee::HandleToss( void )
{	if(DeaccelerateToss())
	{	StopThrow();
		return;
	}

	if(HandleRecover())
	{	return;
	}

	if(CheckForObsticales())
	{	return;
	}

	ApplyVelocity();

	// Update Struggle Bar
	float flSpeedBeforeStop = m_flCurSpeed - m_flMinSpeed;
	float flSpeedGap = m_flMaxSpeed - m_flMinSpeed;
	UpdateStruggleBar( -(flSpeedBeforeStop / flSpeedGap * 100) );
}


/*
* Start Roll
*/
void CPlayerMelee::StartRoll( void )
{	// Set Movetype info
	m_pAttacker->pev->movetype = MOVETYPE_STEP;
	m_pAttacker->pev->friction = 0.3;
	m_pAttacker->pev->gravity = 0.75;
	m_pAttacker->m_flSlowDown = 0.0;

	m_eThrowStatus = THROW_ROLL;
	m_fOnGround = FALSE;

	// Hardcode consecutive hits to 1, allowing for one more
	m_iConsecutiveHits = 1;
}

/*
* Check Creater
*/
void CPlayerMelee::CheckCreater( void )
{	if(FBitSet(m_pAttacker->pev->flags, FL_ONGROUND) && !m_fOnGround)
	{	m_fOnGround = TRUE;
		MakeCreater();
		return;
	}
	
	if(m_fOnGround && !FBitSet(m_pAttacker->pev->flags, FL_ONGROUND))
	{	m_fOnGround = FALSE;
	}
}


/*
* Handle Recover
*/
BOOL CPlayerMelee::HandleRecover( void )
{	// We're allowed to recover now
	if(m_eThrowStatus != THROW_RECOVER)
	{	if(m_flMinRecoverTime < gpGlobals->time)
		{	int iButton = m_pAttacker->pev->button;
			// Pressing Primary/Secondary or jump
			if((iButton & IN_ATTACK) || (iButton & IN_ATTACK2) || (iButton & IN_JUMP))
			{	
				// Higher KI cost for off ground
				if(FBitSet(m_pAttacker->pev->flags, FL_ONGROUND))
				{	if(m_pAttacker->UseKi(MELEE_RECOVER_COST/2.5))
					{	Recover();
						return TRUE;
					}
				}
				else
				{	if(m_pAttacker->UseKi(MELEE_RECOVER_COST))
					{	Recover();
						return TRUE;
					}
				}
			}
		}
	}
	else
	{	if(m_fFlyRecover)
		{	DeaccelerateToss();
			ApplyVelocity();
		}
	}
	return FALSE;
}

/*
* Handle Roll
*/
void CPlayerMelee::HandleRoll( void )
{	CheckCreater();

	// We stopped moving, enable lay
	if(m_pAttacker->pev->velocity.Length() < 10 && FBitSet(m_pAttacker->pev->flags, FL_ONGROUND))
	{	StartLay();
		return;
	}

	HandleRecover();
}


/*
* Recover
*/
void CPlayerMelee::Recover( void )
{	if(m_eThrowStatus == THROW_TOSS)
	{	m_fFlyRecover = TRUE;
		m_flCurSpeed *= 0.5;	// 1/2 speed
		m_flDeacceleration *= 2; // Double Deacceleration rate
		m_flFrameTime = gpGlobals->time; // Set frame time
		EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/airrecover.wav", 1.0, ATTN_NORM);
	}
	else
	{	m_fFlyRecover = FALSE;
		EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/groundrecover.wav", 1.0, ATTN_NORM);
	}

	m_eThrowStatus = THROW_RECOVER;
}


/*
* Start Land Recover ( land on all 4's, hop away )
*/
void CPlayerMelee::StartLandRecover( void )
{	// Set movetype
	m_pAttacker->pev->movetype = MOVETYPE_NONE;
	m_pAttacker->m_flSlowDown = 0;
	m_pAttacker->pev->friction = 1;
	m_pAttacker->pev->gravity = 1;
	m_pAttacker->pev->velocity = Vector(0,0,0);

	// Set land recover time
	m_flLandRecoverStart = gpGlobals->time;
	m_eThrowStatus = THROW_LANDRECOVER;

	// Fix Angles
	m_vecLandRecoverAngles = m_pAttacker->pev->angles;
	m_vecLandRecoverAngles.x = 0;
	UTIL_Model_FixAngles( m_pAttacker->entindex(), m_vecLandRecoverAngles );
}

/*
* Handle Land Recover
*/
void CPlayerMelee::HandleLandRecover( void )
{	// Time to recover
	if(m_flLandRecoverStart + LANDRECOVER_TIME < gpGlobals->time)
	{	m_flLandRecoverStart = 0;

		// Stop throw
		StopThrow();

		// Recover
		LandRecoverDash();
	}
}

/*
* Land Recover Dash
*/
void CPlayerMelee::LandRecoverDash( void )
{	UTIL_MakeVectors( m_vecLandRecoverAngles );
	Vector vecHop = Vector(0,0,0);
	BOOL fJump = FALSE;
	int iDirection = 0;
	int iButton = m_pAttacker->pev->button;

	if((iButton & IN_MOVELEFT) || (iButton & IN_LEFT))
	{	vecHop = -gpGlobals->v_right;
		iDirection = LEFT;
	}
	else if((iButton & IN_MOVERIGHT) || (iButton & IN_RIGHT))
	{	vecHop = gpGlobals->v_right;
		iDirection = RIGHT;
	}
	else if(iButton & IN_FORWARD)
	{	vecHop = gpGlobals->v_forward;
		iDirection = FRONT;
	}
	else if(iButton & IN_BACK)
	{	vecHop = -gpGlobals->v_forward;
		iDirection = BACK;
	}
	else if(iButton & IN_JUMP)
	{	fJump = TRUE;
		vecHop = Vector(0,0,1);
		iDirection = UP;
	}
	// No directions pressed
	else
	{	return;
	}

	// Slight Z
	if(!fJump)
	{	vecHop.z = 0;
		vecHop = vecHop.Normalize();
	}

	// Set Velocity
	vecHop = vecHop * LANDRECOVER_HOP_FORCE;
	if(!fJump)
		vecHop.z += 500;
	m_pAttacker->pev->velocity = vecHop;
	m_pAttacker->StopFly();

	// Add Animation
	char szAnim[256];
	char szThrow[256];
	if(!fJump)
	{	GetThrowAnimDirection( 0, iDirection, szThrow );
		sprintf(szAnim,"throw_recover_%s", szThrow);
		if(!strcmp(szAnim,"throw_recover_front"))
			strcpy(szAnim,"throw_recover_forward");
		else if(!strcmp(szAnim,"throw_recover_back"))
			strcpy(szAnim,"throw_recover_backward");
	}
	else
	{	strcpy(szAnim,"throw_recover_jump");
	}

	UTIL_MakeVectors( m_vecLandRecoverAngles );
	AddAnimationAFix( gpGlobals->v_forward, false, gpGlobals->time, szAnim);
	m_vecLandRecoverAngles = Vector(0,0,0);

	// Play sound
	EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_BODY, "weapons/recoverjump.wav", 1, ATTN_NORM);
}

/*
* Start Lay
*/
void CPlayerMelee::StartLay( void )
{	// Set movetype
	m_pAttacker->pev->movetype = MOVETYPE_NONE;
	m_pAttacker->m_flSlowDown = 0;
	m_pAttacker->pev->friction = 1;
	m_pAttacker->pev->gravity = 1;
	m_pAttacker->pev->velocity = Vector(0,0,0);

	// Set Lay
	m_flLayStart = gpGlobals->time;
	m_eThrowStatus = THROW_LAY;

	// Fix Angles
	Vector vecAngles = m_pAttacker->pev->angles;
	vecAngles.x = 0;
	UTIL_Model_FixAngles( m_pAttacker->entindex(), vecAngles );
}

/*
* Handle Lay
*/
void CPlayerMelee::HandleLay( void )
{	// Time to recover
	if(m_flLayStart + TOSS_LAYTIME < gpGlobals->time)
	{	m_flLayStart = 0;
	}
}


/*
* Inflict Wallhit Dmg
*/
BOOL CPlayerMelee::InflictWallhitDmg( BOOL fObjectStick )
{	float flVelocityDamage = 1 + m_flCurSpeed / 1000;
	CBasePlayer *pAttacker = m_pAttacker;

	// Modified by Rick, Check if we have a m_pThrower or m_pBuddyThrower
	if (m_pThrower)
		m_pAttacker->TakeDamage(m_pThrower->pev, m_pThrower->pev, ((int)(BLOW_KICK_DAMAGE/2 * flVelocityDamage) * (fObjectStick ? 0.5 : 1)), DMG_KICK);
	else if (m_pBuddyThrower)
		m_pAttacker->TakeDamage(m_pBuddyThrower->pev, m_pBuddyThrower->pev, ((int)(BLOW_KICK_DAMAGE/2 * flVelocityDamage) * (fObjectStick ? 0.5 : 1)), DMG_KICK);

	if(pAttacker->IsAlive())
	{	return TRUE;
	}

	return FALSE;
}


/*
* Start Wallstick
*/
void CPlayerMelee::StartWallStick( Vector vecOrigin, Vector vecNormal )
{	// Set Varibles
	m_pAttacker->pev->movetype = MOVETYPE_NONE;
	m_pAttacker->pev->gravity = 0.0000001;
	m_pAttacker->m_flSlowDown = 0;

	m_eThrowStatus = THROW_WALLSTICK;
	m_vecWallStickNormal = vecNormal;
	m_flStartWallStick = gpGlobals->time;

	// Set origin + velocity
	UTIL_SetOrigin(m_pAttacker->pev, vecOrigin);
	m_pAttacker->pev->velocity = Vector(0,0,0);
	
	// Set animation
	AddAnimationAFix(vecNormal, true, gpGlobals->time, "wall_collide");
	// HACK HACK: Can't have varible length arguments on afix function, so manually add next anim
	AddToCurAnim(true, "wall_idle");
}

/*
* Handle Wallstick
*/
void CPlayerMelee::HandleWallStick( void )
{	// Keep fixed velocity
	m_pAttacker->pev->velocity = Vector(0,0,0);
	m_pAttacker->pev->movetype = MOVETYPE_NONE;

	// Can't unstick yet
	if(m_flStartWallStick > gpGlobals->time - melee_wallstick_mintime.value)
	{	return;
	}

	// We have jump pushed down, lets try to recover
	if(m_pAttacker->pev->button & IN_JUMP)
	{	// Recover
		if(m_pAttacker->UseKi(MELEE_WALLSTICK_RECOVER_COST))
		{	Vector vecWall = m_vecWallStickNormal;
			// Stop Throw
			StopThrow();

			// Set velocity
			UTIL_MakeVectors( vecWall );
			m_pAttacker->pev->velocity = (vecWall*0.65 + gpGlobals->v_up*0.35) * 1200;

			// Set animation
			SetAnimPriority( ANIM_PRIORITY_LOW, AddAnimationAFix(vecWall, false, gpGlobals->time, "wall_recover"));

			// Play sound
			EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_BODY, "weapons/jump.wav", 1, ATTN_NORM);

			return;
		}
	}

	// We cant recover, fall from the wall
	if(m_flStartWallStick + melee_wallstick_maxtime.value < gpGlobals->time)
	{	// Start Roll
		StartRoll();

		// Set blowtime
		m_flMinRecoverTime += gpGlobals->time - m_flStartWallStick;

		// Set velocity
		m_pAttacker->pev->velocity = m_vecWallStickNormal * 100;

		// Reset wallstick vars
		m_vecWallStickNormal = Vector(0,0,0);
		m_flStartWallStick = 0;

		// Unset fixed angles
		UTIL_Model_RemoveAll(m_pAttacker->entindex());

		// Set Falling off animation
		RemoveAllAnims();

		// HACK HACK: Gives player a little time so he can't be hit as soon as he falls off the wall
		m_flLastRecoverTime = gpGlobals->time;
	}
}

/*
* Update Struggle Bar
*/
void CPlayerMelee::UpdateStruggleBar( int iUpdate )
{	if((m_flPSBarUpdate + UPDATE_PS_MSG) > gpGlobals->time)
	{	return;
	}
	m_flPSBarUpdate = gpGlobals->time;
	m_fStruggleBar = TRUE;
	MESSAGE_BEGIN( MSG_ONE, gmsgPowerStruggle, NULL, m_pAttacker->pev ); 
		WRITE_CHAR(iUpdate);
	MESSAGE_END();
}

/*
* Remove Struggle Bar
*/
void CPlayerMelee::RemoveStruggleBar( void )
{	if(m_fStruggleBar)
	{	MESSAGE_BEGIN( MSG_ONE, gmsgPowerStruggle, NULL, m_pAttacker->pev ); 
			WRITE_CHAR(127);
		MESSAGE_END();
	}
	m_flPSBarUpdate = 0;
	m_fStruggleBar = FALSE;
}

/*
* Stop Throw
*/
void CPlayerMelee::StopThrow( void )
{	StopThrow( FALSE );
}

#define INVUL_RECOVER_TIME	1.0

/*
* Stop Throw
*/
void CPlayerMelee::StopThrow( BOOL fMultiHit )
{	// Remove model lock if stopping from Lay
	if(m_eThrowStatus == THROW_LAY || m_eThrowStatus == THROW_LANDRECOVER)
	{	UTIL_Model_RemoveAll(m_pAttacker->entindex());
	}

	BOOL fStartFly = TRUE;
	if(m_eThrowStatus == THROW_WALLSTICK)
	{	fStartFly = FALSE;
	}
	else if(!fMultiHit)
	{	// Add currently pressed directions to null keyset for swoop
		m_pAttacker->m_Swoop.AddAllToNullKeyset();
		m_pAttacker->m_Swoop.ResetAllDT();
	}

	// Enable invulnerability
	if(m_fEndAdvMeleeToss && !fMultiHit)
	{	m_fInvulnerable = TRUE;
		m_pInvulException = m_pThrower;
		m_flInvulnerableTime = gpGlobals->time + INVUL_RECOVER_TIME;
	}

	// Remove struggle bar
	RemoveStruggleBar();

	// Remove all animations
	RemoveAllAnims();

	// Reset Varibles
	m_pThrower = NULL;
	// Added by Rick
	m_pBuddyThrower = NULL;
	m_fTakeDmgOnCollision = FALSE;
	m_fThrown = FALSE;
	m_fFlyRecover = FALSE;
	m_fEndAdvMeleeToss = FALSE;
	m_pAttacker->m_fMelee = FALSE;
	m_eThrowStatus = THROW_DISABLE;

	m_flMaxSpeed = 0;
	m_flCurSpeed = 0;
	m_flMinSpeed = 0;
	m_flDeacceleration = 0;
	m_flMinRecoverTime = 0;
	m_flStartWallStick = 0;
	m_iConsecutiveHits = 0;
	m_flLastRecoverTime = gpGlobals->time;
	m_vecWallStickNormal = Vector(0,0,0);

	// Set movetype
	m_pAttacker->m_flSlowDown = 1;
	m_pAttacker->pev->friction = 1;
	m_pAttacker->pev->gravity = 1;
	if(!fStartFly || FBitSet(m_pAttacker->pev->flags, FL_ONGROUND))
	{	m_pAttacker->pev->movetype = MOVETYPE_WALK;
	}
	else
	{	m_pAttacker->StartFly();
	}

	// Set Velocity
	m_pAttacker->pev->vuser4 = Vector(0,0,0);
}

/*
* ======================================
* Combo System
*
* ======================================
*/

void CPlayerMelee::AddComboMoves( void )
{	for(int i=1;i<PC_LAST;i++)
	{	
		m_pComboMoves[i]=NULL;

		// Entering Format
		// Character, Combo ID ( Unique ), Number of Moves, combo type, ...(strength,direction)

		/* 
		* Add 'shared' moves
		*/

		// Down Punch (w), down+left punch (w), left punch (w)
		AddMove(i,COMBOMOVE_1,3,WEAK_HIT,PUNCH_DOWN,WEAK_HIT,PUNCH_LOWERLEFT,WEAK_HIT,PUNCH_LEFT);

		// Down punch (w), down+right punch (w), right punch (w), left kick (m)
		AddMove(i,COMBOMOVE_2,4,WEAK_HIT,PUNCH_DOWN,WEAK_HIT,PUNCH_LOWERRIGHT,WEAK_HIT,PUNCH_RIGHT,MEDIUM_HIT, KICK_LEFT);

		// Set combo moves depending in character
		switch (i)
		{
		case PC_BUU:
			{
				break;
			}
		case PC_GOKU:
			{
				break;
			}
		case PC_GOHAN:
			{
				break;
			}
		case PC_KRILLIN:
			{
				break;
			}
		case PC_FRIEZA:
			{
				break;
			}
		case PC_PICCOLO:
			{
				break;
			}
		case PC_TRUNKS:
			{
				break;
			}
		case PC_VEGETA:
			{
				break;
			}
		case PC_CELL:
			{
				break;
			}
		}
	}
}

void CPlayerMelee::AddMove( int character, int comboid, int num,  ... )
{	int i;
	if(num <= 0)
	{	return;
	}
	
	combo_move_s *pComboMove = new combo_move_s;
	pComboMove->iNumDirections = num;
	pComboMove->iComboID = comboid;
	pComboMove->pPrev = NULL;
	pComboMove->pNext = NULL;

	// Copy move(s)
	va_list arguments;
	va_start(arguments, num);

	// Enter in combos
	for( i = 0 ; i < num; i++ )
	{	/* harSens: linux compatibility
		pComboMove->directions[i].eStrength = va_arg(arguments, MELEE_STRENGTH);
		pComboMove->directions[i].iFlags = DirectionsToFlags(va_arg(arguments, ADV_MELEE_DIRECTION));
		*/
		pComboMove->directions[i].eStrength = (MELEE_STRENGTH)va_arg(arguments, int);
		pComboMove->directions[i].iFlags = DirectionsToFlags(va_arg(arguments, int));
	}

	va_end(arguments);

	// Add to list
	if(m_pComboMoves[character])
	{	m_pComboMoves[character]->pNext = pComboMove;
		pComboMove->pPrev = m_pComboMoves[character];
	}
	m_pComboMoves[character] = pComboMove;
}

/*
* Get power ratio between local player and other player
*/
float CPlayerMelee::GetPowerRatio( CBasePlayer *pOther )
{	if(!pOther)
		return 1;

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

/* Added by Rick
*
* Get power ratio between local player and enemy buddy
*/
float CPlayerMelee::GetPowerRatio( CBuddy *pOther )
{	if(!pOther)
		return 1;

	float flRatio = float((float)m_pAttacker->GetPowerLevel() / (float)pOther->GetPowerLevel());
	if(flRatio > MAX_RATIO)
		flRatio = MAX_RATIO;
	else if(flRatio < MIN_RATIO)
		flRatio = MIN_RATIO;
	return flRatio;
}
// End add by Rick
/*
* Can Inflict Damage
*/
BOOL CPlayerMelee::CanInflictDamage( CBasePlayer *pInflictor, int iDmgBits )
{	if((m_fEndAdvMeleeToss||m_fInvulnerable) && pInflictor != m_pInvulException && (iDmgBits & DMG_MAGIC))
	{	return FALSE;
	}
	return TRUE;
}

/*
* Execute Combo
*/
void CPlayerMelee::ExecuteCombo( void )
{	// Disable delay
	m_fDelayMelee = FALSE;
	// Stop Charged attack
	StopChargedAttack();
	// Switch over to ComboExecution mode
	SetMode(EXE_ATTACK);
}

/*
* Can Switch Attack + Defender rolls
*/
BOOL CPlayerMelee::CanSwitch( void )
{	if(m_iSwitch >= melee_maxextanges.value)
	{	return FALSE;
	}
	return TRUE;
}

/*
* Switch Attack + Defender rolls
*/
void CPlayerMelee::Switch( void )
{	CPlayerMelee *pOtherMelee = m_pDefenderMelee;
	CBasePlayer *pOther = m_pDefender;
	float flStunTime = -1;
	BOOL fExeCombo = FALSE;
	BOOL fRetalExe = pOtherMelee->m_fRetaliateEXE;

	// Exe combo
	fExeCombo = pOtherMelee->m_fWaitRetal;

	// End of melee fight? dont bother on switching, just end fight
	if(!fExeCombo && !fRetalExe)
	{	StopMelee();
		return;
	}

	// Get Stun Time
	if(!fRetalExe)
	{	flStunTime = pOtherMelee->GetStunTime();
		// Set ratio
		flStunTime *= GetBlockRatio(m_iBlockedMoves, m_iTotalMoves);
	}
	else
	{	fExeCombo = pOtherMelee->m_fWaitRetal;
	}

	// Switch turns
	SimpleSwitch( pOtherMelee, flStunTime, CHARGE_ATTACK );

	// Disable Retaliation
	m_fRetaliateEXE = FALSE;
	pOtherMelee->m_fRetaliateEXE = FALSE;

	// Player already has a full combo bar, execute
	if(fExeCombo)
	{	if(!pOtherMelee->SetDelayEndBlock(pOtherMelee->GetAttackerMoves(), GetDefenderMoves()))
		{	pOtherMelee->ExecuteCombo();
		}
	}
}


/*
* Simple Switch
*/
void CPlayerMelee::SimpleSwitch( CPlayerMelee *pOther )
{	SimpleSwitch( pOther, -1, DISABLED );
}

/*
* Simple Switch
*/
void CPlayerMelee::SimpleSwitch( CPlayerMelee *pOther, float flStunTime, ADV_MELEE_STATUS eMeleeMode )
{	// Can't switch if you're not the attacker, try calling other playerzz
	if(!IsAttacker())
	{	if(pOther->IsAttacker())
		{	SimpleSwitch( this, flStunTime, eMeleeMode );
		}
		return;
	}
	// add switch turns
	m_iSwitch++;
	pOther->m_iSwitch++;

	// Enable switch mode
	m_fSwitching = TRUE;
	pOther->m_fSwitching = TRUE;

	// "switch" turns serverside
	StopMelee(FALSE);
	pOther->InitMelee( m_pAttacker );

	// Set stun time
	if(flStunTime != -1)
	{	SetActiveStunTime(flStunTime);
	}

	// Set new melee mode
	if(eMeleeMode != DISABLED)
		pOther->SetMode(eMeleeMode);

	// Disable Switch mode
	m_fSwitching = FALSE;
	pOther->m_fSwitching = FALSE;
}

/*
* Emit combo damage
*/
void CPlayerMelee::EmitComboDamage( melee_combo_hit_s *pComboHit )
{	if(!pComboHit)
	{	return;
	}

	if(pComboHit->fEmitDamage || !pComboHit->fExecute)
	{	return;
	}

	pComboHit->fEmitDamage = TRUE;

	// FIXME: Emit Damage and sound
	if(pComboHit->flDamage)
	{	float flDmg = pComboHit->flDamage * GetPowerRatio(m_pDefender);
		if(flDmg < 1)
			flDmg = 1;
		else if(flDmg > 6)
			flDmg = 6;
		m_pDefender->TakeDamage( m_pAttacker->pev, m_pAttacker->pev, flDmg, DMG_MELEE );

		// Play sound
		EmitExeSound( GetSoundEdict() );
	//	EMIT_SOUND(GetSoundEdict(), CHAN_BODY, "weapons/strongpunch.wav", 1.0, ATTN_NORM);
		// Print to hud
		MeleeText(MELEETXT_DAMAGE,flDmg);
	}

	// Callback
	if(pComboHit->pComboCallBack)
	{	pComboHit->pComboCallBack(GetAttacker(),GetDefender());
	}
}

/*
* Handle Combo Execution
*/
void CPlayerMelee::HandleExeAttack( void )
{	// Checks on the animation
	plrmelee_anim_s *pAnim = GetCurrentAnim();
	if(!pAnim)
	{	ALERT(at_console,"No pAnim!\n");
		StopMelee();
		return;
	}
	if(!pAnim->fExecution)
	{	ALERT(at_console,"Non execute anim!\n");
		StopMelee();
		return;
	}

	// Now check for damage/sound emittions
	if(!m_pExeCurrent->fEmitDamage && !m_pExeCurrent->fCombo)
	{	if((m_pExeCurrent->flStartTime + m_pExeCurrent->flEmitDamage) < gpGlobals->time)
		{	EmitDamage();
	
			// Make sure we're still fighting 
			if(!m_fFighting)
			{	return;
			}
		}
	}

	// Handle Combos
	if(m_pExeCurrent->fCombo)
	{	for(int i=0;i<m_pExeCurrent->iComboHits;i++)
		{	melee_combo_hit_s *pComboHit = &m_pExeCurrent->combohit[i];
			if(!pComboHit->fEmitDamage && pComboHit->fExecute)
			{	// Emit damage damage at appropiate time
				if(pComboHit->flHitTime < gpGlobals->time)
				{	EmitComboDamage(pComboHit);
				}
			}
		}
	}

	if(m_pDefenderMelee->m_fRetaliateEXE)
	{	SetBlockingDirections();
	}
}

/*
* Can Retaliate ( called in HandleExeDefend )
*/
BOOL CPlayerMelee::CanRetaliate( void )
{	int iFlags=0;
	melee_move_s *pMove = GetCurrentDirection();
	SetAttackFlags(iFlags);

	return (m_fRetaliateEXE || (pMove && pMove->fFinished &&
			((iFlags & IN_ATTACK) || (iFlags & IN_ATTACK2)) &&
			(GetMoveCount() == m_pAttackerMelee->GetMoveCount())));
}


/*
* Handle Combo Execution (defender)
*/
void CPlayerMelee::HandleExeDefend( void )
{	// We blocked all the directions, start charging
	if(!m_fWaitRetal && CanRetaliate() && CanSwitch())
	{	if(!m_fRetaliateEXE)
		{	m_fRetaliateEXE = TRUE;
			StartChargedAttackRetaliate();
		}

		m_fWaitRetal = SetDirections();
	}
	else if(!m_fRetaliateEXE)
	{	// Set blocking directions ( to counter moves )
		SetBlockingDirections( );
	}
}

/*
* Start Combo Execution Attack
*/
void CPlayerMelee::StartExeAttack( void )
{	if(!m_fManualExe)
	{	// Set Moves to combo execution list
		CopyMoveToExe( );

		// Get first move rolling
		NewExeMovePost();
	}
	else
	{	m_fManualExe = FALSE;
	}
}

/*
* Stop Combo Execution Attack
*/
void CPlayerMelee::StopExeAttack( void )
{	// Reset anims
	if(m_eAdvMeleeStatus == EXE_ATTACK)
	{	m_eAdvMeleeStatus = DISABLED;

		if(m_fEndComboPower)
		{	plrmelee_anim_s *pAnim = GetCurrentAnim();
			if(pAnim)
			{	pAnim->fExecution = FALSE;
			}
		}
		else
		{	RemoveAllAnims();
		}

		if(!m_pDefenderMelee->m_fRetaliateEXE)
		{	DelAllDirections();
		}

		melee_execution_s *pCurrent = m_pExeStart;

		// Remove everything from the list
		while(pCurrent)
		{	melee_execution_s *pDelete = pCurrent;
			pCurrent = pCurrent->pNext;
			delete pDelete;
		}

		m_pExeStart = NULL;
		m_pExeCurrent = NULL;

		// Call defenders function
		m_pDefenderMelee->StopExeAttack();

	}
	else if(m_eAdvMeleeStatus == EXE_DEFEND)
	{	m_eAdvMeleeStatus = DISABLED;
		RemoveAllAnims();
		if(!m_fRetaliateEXE)
		{	DelAllDirections();
		}
	}
}

/*
* Can Use Trunks Sword
*/
BOOL CPlayerMelee::CanUseTrunksSword( CBasePlayer *pDefender )
{	return (m_pAttacker->m_pClass->HasSword() && !m_pExeCurrent->pNext && 
			((m_pExeCurrent->eBlock == BLOCK_FAIL) || m_pExeCurrent->fBlockStun) &&
			m_pExeCurrent->eStrength == STRONG_HIT && (m_pExeCurrent->iFlags & IN_ATTACK) &&
			(pDefender->pev->health / pDefender->m_pClass->GetStartHealth()) < MIN_SLICE_PERCNT);
}

/*
* Emit Damage
*/
void CPlayerMelee::EmitDamage( void )
{	// Handle combo moves differently
	if(m_pExeCurrent->fCombo)
	{	return;
	}

	BOOL fUseTrunksSword = FALSE;

	if(!m_pExeCurrent->fEmitDamage)
	{	if(!CanUseTrunksSword(m_pDefender))
		{	if(m_pExeCurrent->eBlock == BLOCK_FAIL || m_pExeCurrent->fBlockStun)
			{	// Emit Damage
				float flDmg = GetDamage() * GetPowerRatio(m_pDefender);
				if(flDmg < 1)
					flDmg = 1;
				m_pDefender->TakeDamage( m_pAttacker->pev, m_pAttacker->pev, flDmg, DMG_MELEE );

				// Block breaker, send to both attacker and defender
				if(m_pExeCurrent->fBlockStun && m_pExeCurrent->eBlock == BLOCK_TRUE)
				{	MeleeText(MELEETXT_BLOCKBREAK,0);
					m_pDefenderMelee->MeleeText(MELEETXT_BLOCKBREAK,0);
				}

				// Regular damage
				MeleeText(MELEETXT_DAMAGE,flDmg);
			}
			else
			{	// Print dodged to hud
				MeleeText(MELEETXT_DODGED,0);
			}
			// Play sound
			EmitExeSound( GetSoundEdict() );
		}
		else
		{	fUseTrunksSword = TRUE;
		}
		
		m_pExeCurrent->fEmitDamage = TRUE;
	}

	// Knock back player if this is the final hit, unblocked, and powerful (strong)
	if(m_pDefender->IsAlive() && !m_pExeCurrent->pNext &&
		(m_pExeCurrent->eBlock == BLOCK_FAIL || m_pExeCurrent->fBlockStun) && m_pExeCurrent->eStrength == STRONG_HIT)
	{	// Saving Varibles
		CBasePlayer *pDefender = m_pDefender;
		CPlayerMelee *pDefenderMelee = m_pDefenderMelee;
		BOOL fOrigDefender = m_fOrigDefender;
		Vector vecVelocity = m_vecPrepunchDir.Normalize();
		if(fOrigDefender)
		{	vecVelocity = -vecVelocity;
		}

		// Knock the player upwards
		if(m_pExeCurrent->iFlags & IN_FORWARD)
		{	vecVelocity = Vector(0,0,1);
		}
		// Knock the player downwards
		else if(m_pExeCurrent->iFlags & IN_BACK)
		{	vecVelocity = Vector(0,0,-1);
		}
		else
		{	if(m_pExeCurrent->fForceZStrait)
			{	vecVelocity.z = 0;
				vecVelocity = vecVelocity.Normalize();
			}
		}

		// Add delay to weapon fire
		if(m_pAttacker->m_pActiveItem)
		{	CBasePlayerWeapon *pWeapon = (CBasePlayerWeapon*)m_pAttacker->m_pActiveItem;
			pWeapon->m_flNextPrimaryAttack = pWeapon->m_flNextSecondaryAttack = gpGlobals->time + 1;
		}

		// Used so melee wont delete animations
		m_fEndComboPower = TRUE;
		// Disable melee
		StopMelee(FALSE);
		m_fEndComboPower = FALSE;

		
		// Slice and kill enemy ( trunks sword )
		if(fUseTrunksSword)
		{	
			pDefender->m_fInvulnerable = FALSE;
			pDefender->m_flInvulnerableTime = 0;
			pDefenderMelee->m_fInvulnerable = FALSE;

			// Kill
			pDefender->TakeDamage( m_pAttacker->pev, m_pAttacker->pev, 999, (DMG_MELEE|DMG_NEVERGIB) );
			
			if(!pDefender->IsAlive())
			{	// Slice Sound
				EMIT_SOUND(ENT(pDefender->pev), CHAN_BODY, "weapons/swordkill.wav", 1.0, ATTN_NORM);
				// Hud Printout
				MeleeText(MELEETXT_SWORDKILL,0);
				// Gib
				pDefender->pev->solid = SOLID_NOT;
				/* modified by harSens, don't wiggle for now
				CBodySlice::SpawnBodySlices(pDefender->pev,true);
				*/
				CBodySlice::SpawnBodySlices(pDefender->pev,false);
				pDefender->pev->effects |= EF_NODRAW;// This clears pev->model

				// TEST - HACK HACK: Dont 'drop' player, keep him in the air
				pDefender->pev->velocity = Vector(0,0,0);
				pDefender->pev->movetype = MOVETYPE_FLY;
				pDefender->pev->gravity = 0;
				return;
			}
		}

		// Knock Back
		pDefenderMelee->StartToss( m_pAttacker, TRUE, vecVelocity, 1200, 600, 275, 1.5 );
	}
}

/*
* Push player back after death
*/
void CPlayerMelee::PushAfterDeath( void )
{	if(!m_pDefender->IsAlive())
	{	if(m_fOrigDefender)
			m_pDefender->pev->velocity = -m_vecPrepunchDir * 400;
		else
			m_pDefender->pev->velocity = m_vecPrepunchDir * 400;
	}
}

/*
* Set Combo Moves
*/
BOOL CPlayerMelee::SetComboMoves( void )
{	int i, iCount;
	// Start From the beginning
	melee_move_s *pMove = GetCurrentDirection();
	if(pMove)
	{	while(pMove->pPrev)
		{	pMove = pMove->pPrev;
		}
	}
	else
	{	return FALSE;
	}

	// Search through main combo move linked list
	combo_move_s *pCMoves = m_pComboMoves[m_pAttacker->m_pClass->Classify()];
	while(pCMoves)
	{	melee_move_s *pCurrent;
		melee_move_s *pStart = pMove;
		iCount = 0;

		while(pStart)
		{	bool blCombo = true;

			iCount++;
			
			if(pStart->eComboStatus != COMBO_NONE)
			{	pStart = pStart->pNext;
				continue;
			}

			pCurrent = pStart;

			for(i = 0; i < pCMoves->iNumDirections; i++)
			{	if(pCurrent && 
					(pCurrent->eComboStatus == COMBO_NONE) &&
					(pCMoves->directions[i].iFlags == pCurrent->iFlags) &&
					(pCMoves->directions[i].eStrength == GetMoveStrength(pCurrent)))
				{	pCurrent = pCurrent->pNext;
					continue;
				}
				else
				{	blCombo = false;
					break;
				}
			}

			// Looks like we have a combo sequence, set values
			if(blCombo)
			{	pCurrent = pStart;

				for(i = 0; i < pCMoves->iNumDirections; i++)
				{	
					pCurrent->iComboID = pCMoves->iComboID;

					// First move in list
					if(i == 0)
					{	pCurrent->eComboStatus = COMBO_START;
					}
					// Last move in list
					else if(i == pCMoves->iNumDirections - 1)
					{	pCurrent->eComboStatus = COMBO_END;
					}
					// Middle move in list
					else
					{	pCurrent->eComboStatus = COMBO_IDLE;
					}
					
					pCurrent = pCurrent->pNext;
				}

			}
			pStart = pStart->pNext;
		}

		pCMoves = pCMoves->pPrev;
	}

	return TRUE;
}

/*
* Copy Combo Move to Execution
*/
void CPlayerMelee::CopyMoveToExe( void )
{	m_pExeStart = NULL;
	m_pExeCurrent = NULL;
	m_iBlockedMoves = 0;
	m_iTotalMoves = 0;

	// Set Combo moves
	if(!SetComboMoves())
	{	return;
	}

	// Go to the 'first' combo in the list
	melee_move_s *pMove = GetCurrentDirection();
	if(pMove)
	{	while(pMove->pPrev)
		{	pMove = pMove->pPrev;
		}
	}
	else
	{	StopMelee();
		return;
	}

	// Now enter + convert
	while(pMove)
	{
		// Directionless, go to next move
		if(IsDirectionless(pMove->iFlags))
		{	pMove = pMove->pNext;
			continue;
		}

		m_iTotalMoves++;

		// set animation
		char szAnim[256];
		GetAnimForMove(pMove, szAnim);

		// Add exe move
		AddExeMove( CreateExeMove( pMove->iFlags, pMove->iComboID, GetDamageDelay(pMove), m_iTotalMoves,
									pMove->eComboStatus, GetMeleeStrength(pMove), szAnim) );

		pMove = pMove->pNext;
	}
}


/*
* Add Exe Move
*/
melee_execution_s *CPlayerMelee::AddExeMove( melee_execution_s *pExe )
{	// Add to linked list
	if(!m_pExeStart)
	{	m_pExeStart = pExe;
		m_pExeCurrent = pExe;
	}
	else
	{	// Go to last member of list and add it there
		melee_execution_s *pCurrent = m_pExeStart;
		while(pCurrent->pNext)
		{	pCurrent = pCurrent->pNext;
		}

		pCurrent->pNext = pExe;
		pExe->pPrev = pCurrent;
	}
	return pExe;
}


/*
* Create Exe Move
*/
melee_execution_s *CPlayerMelee::CreateExeMove( int iFlags, int iComboID, float flDamageDelay, int iNumMove, MELEE_COMBO_STATUS eComboStatus, MELEE_STRENGTH eStrength, char *pAnim )
{	melee_execution_s *pNewExe = new melee_execution_s;
	pNewExe->fEmitDamage = FALSE;
	pNewExe->fCombo = FALSE;
	pNewExe->fBlockStun = FALSE;
	pNewExe->fForceZStrait = TRUE;
	pNewExe->iFlags = iFlags;	// Flags
	pNewExe->iComboID = iComboID;// Combo ID
	pNewExe->flEmitDamage = flDamageDelay;		// Damage emittion time
	pNewExe->flStartTime = 0;			// Start time
	pNewExe->iComboHits = 0;
	pNewExe->iNum = iNumMove;
	pNewExe->eBlock = BLOCK_NONE;
	pNewExe->eComboStatus = eComboStatus; // Combo Status;
	pNewExe->eStrength = eStrength; // Get strength ( weak/medium/strong )
	strcpy(pNewExe->szAnim,pAnim);	// Anim name
	pNewExe->pNext = NULL;
	pNewExe->pPrev = NULL;

	// Clear out combo array
	ResetComboArray(pNewExe);

	return pNewExe;
}

/*
* Reset Combo Array
*/
void CPlayerMelee::ResetComboArray( melee_execution_s *pExe )
{	// Clear out combo array
	for(int i=0;i<MAX_COMBOHITS;i++)
	{	pExe->combohit[i].iAttackNum = i;
		pExe->combohit[i].flHitTime = 0;
		pExe->combohit[i].flDamage = 0;
		pExe->combohit[i].fEmitDamage = FALSE;
		pExe->combohit[i].fExecute = FALSE;
		pExe->combohit[i].pComboCallBack = NULL;
	}
}

/*
* Get Melee Strength
*/
MELEE_STRENGTH CPlayerMelee::GetMeleeStrength( melee_move_s *pMove )
{	if(pMove)
		return GetMeleeStrength(GetCmbTime(pMove));
	else
		return WEAK_HIT;

}

MELEE_STRENGTH CPlayerMelee::GetMeleeStrength( float flCmbTime )
{	if(flCmbTime < GetSkillValues()->flWeakRange)
	{	return WEAK_HIT;
	}
	else if(flCmbTime < GetSkillValues()->flMediumRange)
	{	return MEDIUM_HIT;
	}
	else
	{	return STRONG_HIT;
	}
}


/*
* Get damage delay ( when executing attack )
*/
float CPlayerMelee::GetDamageDelay( melee_move_s *pMove )
{	// Punch
	if(pMove->iFlags & IN_ATTACK)
	{	switch(GetMeleeStrength(pMove))
		{
		case WEAK_HIT:
			{	return 0.1;
			}
		case MEDIUM_HIT:
			{	return 0.15;
			}
		case STRONG_HIT:
			{	return 0.25;
			}
		}

	}
	// Kick
	else if(pMove->iFlags & IN_ATTACK2)
	{	switch(GetMeleeStrength(pMove))
		{
		case WEAK_HIT:
			{	return 0.15;
			}
		case MEDIUM_HIT:
			{	return 0.25;
			}
		case STRONG_HIT:
			{	return 0.35;
			}
		}
	}

	return 0;
}

/*
* Get damage on current exe move ( damage infliction )
*/
float CPlayerMelee::GetDamage( void )
{	// Punch
	if(m_pExeCurrent->iFlags & IN_ATTACK)
	{	switch(m_pExeCurrent->eStrength)
		{
		case WEAK_HIT:
			{	return 3;
			}
		case MEDIUM_HIT:
			{	return 5;
			}
		case STRONG_HIT:
			{	return 7;
			}
		}

	}
	// Kick
	else if(m_pExeCurrent->iFlags & IN_ATTACK2)
	{	switch(m_pExeCurrent->eStrength)
		{
		case WEAK_HIT:
			{	return 4;
			}
		case MEDIUM_HIT:
			{	return 6;
			}
		case STRONG_HIT:
			{	return 8;
			}
		}
	}

	return 0.0;
}

/*
* Get Exe Sound on current exe move
*/
void CPlayerMelee::EmitExeSound(edict_t *ed)
{	// Dodged
	if(m_pExeCurrent->eBlock == BLOCK_TRUE && !m_pExeCurrent->fBlockStun)
	{	PLAYBACK_EVENT_FULL( FEV_GLOBAL, ed, m_usMeleeSounds, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, 0, 0, true, 0 );
	}
	else if(m_pExeCurrent->eBlock == BLOCK_FAIL || m_pExeCurrent->fBlockStun)
	{	// Sword hit sound
		if(m_pAttacker->m_pClass->HasSword() && m_pExeCurrent->fCombo)
		{	PLAYBACK_EVENT_FULL( FEV_GLOBAL, ed, m_usMeleeSounds, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, 0, 0, 0, true );
		}
		// regular punch/kick sounds
		else
		{	PLAYBACK_EVENT_FULL( FEV_GLOBAL, ed, m_usMeleeSounds, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_pExeCurrent->iFlags, (int)m_pExeCurrent->eStrength, 0, 0 );
		}
	}
}

/*
* Emit Client Sound
*/
void CPlayerMelee::EmitClientSound( edict_t *ed, int iChannel, int iSound )
{	PLAYBACK_EVENT_FULL( FEV_GLOBAL, ed, m_usMeleeSounds, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, (float)iChannel, (float)iSound, 0, 0, 0, 0 );
}

/*
* Block
*/
BOOL CPlayerMelee::Block( int iAttackerFlags, int iDefenderFlags )
{	// Remove Attack Flags
	if(iAttackerFlags & IN_ATTACK)
	{	iAttackerFlags &= ~IN_ATTACK;
	}
	if(iAttackerFlags & IN_ATTACK2)
	{	iAttackerFlags &= ~IN_ATTACK2;
	}

	// Dont allow user to hold extra directions
	for( int i = LEFT; i <= BACK; i++ )
	{	int iFlags = m_pAttacker->m_Swoop.DirectionsToFlags(i);
		if(!(iAttackerFlags & iFlags) && (iDefenderFlags & iFlags))
		{	return FALSE;
		}
	}

	// Do the moves match?
	if(iAttackerFlags == iDefenderFlags)
	{	return TRUE;
	}
	// Check for diags
	else
	{	if((iAttackerFlags & (IN_BACK|IN_LEFT)) || (iAttackerFlags & (IN_BACK|IN_RIGHT)) ||
			(iAttackerFlags & (IN_FORWARD|IN_LEFT)) || (iAttackerFlags & (IN_FORWARD|IN_RIGHT)))
		{	
			// If the blocker blocks one of the adjacent directions, allow it
			if(iAttackerFlags & iDefenderFlags)
			{	return TRUE;
			}
		}
	}
	return FALSE;
}

/*
* Get Block Ratio
*/
float CPlayerMelee::GetBlockRatio( int iBlocked, int iTotal )
{	float flRatio = float(iBlocked)/float(iTotal);
	if(flRatio < MIN_SWITCH_RATIO)
	{	flRatio = MIN_SWITCH_RATIO;
	}
	return flRatio;
}

/*
* Predict Blocking Ratio
*/
float CPlayerMelee::PredictBlockRatio( melee_execution_s *pAttack, melee_move_s *pDefend, float flStunTime )
{	int iTotal=0;
	int iBlocked=0;
	MELEE_STRENGTH eStart = WEAK_HIT;

	if(!pAttack || !pDefend)
	{	return 0;
	}

	// Go to first move
	while(pDefend->pPrev)
	{	pDefend = pDefend->pPrev;
	}

	int iBlockStun=0;

	// Get blocked / total moves
	while(pAttack)
	{	if(pAttack->fCombo)
		{	pAttack = pAttack->pNext;
			continue;
		}
		
		iTotal++;
		if(pDefend)
		{	if(iBlockStun && ContinueBlockStun(iBlockStun, eStart, pAttack->eStrength))
			{	iBlockStun--;
			}
			else if(Block(pAttack->iFlags, pDefend->iFlags) || pAttack->fBlockStun)
			{	iBlocked++;
				iBlockStun = 0;
			}
			else
			{	iBlockStun = GetDefender()->m_Melee.GetBlockStunAmt( pAttack->eStrength );
				eStart = pAttack->eStrength;
			}
			pDefend = pDefend->pNext;
		}
		pAttack = pAttack->pNext;
	}

	return (flStunTime*GetBlockRatio( iBlocked, iTotal ));
}


/*
* Predict Blocking Ratio
*/
float CPlayerMelee::PredictBlockRatio( melee_move_s *pAttack, melee_move_s *pDefend, float flStunTime )
{	int iTotal=0;
	int iBlocked=0;

	if(!pAttack || !pDefend)
	{	return 0;
	}

	// Go to first move
	while(pDefend->pPrev)
	{	pDefend = pDefend->pPrev;
	}
	while(pAttack->pPrev)
	{	pAttack = pAttack->pPrev;
	}

	// Get blocked / total moves
	while(pAttack)
	{	iTotal++;
		if(pDefend)
		{	if(Block(pAttack->iFlags, pDefend->iFlags))
			{	iBlocked++;
			}
			pDefend = pDefend->pNext;
		}
		pAttack = pAttack->pNext;
	}

	return (flStunTime*GetBlockRatio( iBlocked, iTotal ));
}

/*
* Set Block
*/
BLOCK_STATUS CPlayerMelee::SetBlock( melee_execution_s *pExe )
{	melee_move_s *pDefenderMove = m_pDefenderMelee->m_pDefenderMoves;
	if(pDefenderMove && pExe)
	{	while(pDefenderMove->pPrev)
		{	pDefenderMove = pDefenderMove->pPrev;
		}
	}
	else
	{	return BLOCK_FAIL;
	}

	if(pExe->iNum>1)
	{	for(int i=2; (i <= pExe->iNum) && pDefenderMove; i++)
		{	pDefenderMove = pDefenderMove->pNext;
		}
	}

	// We have a valid move, compair and see if it's blocked
	if(pDefenderMove)
	{	// We blocked the move
		if(Block(pExe->iFlags, pDefenderMove->iFlags))
		{	// Add blocked move
			if(pExe->eBlock != BLOCK_TRUE)
			{	m_iBlockedMoves++;
			}
			return BLOCK_TRUE;
		}
	}
	return BLOCK_FAIL;
}

/*
* Get Block Stun Move amt
*/
int CPlayerMelee::GetBlockStunAmt( MELEE_STRENGTH eStrength )
{	int iAmt=0;
	switch(eStrength)
	{
	case WEAK_HIT:
		iAmt = BLOCKSTUN_WEAK;
		break;
	case MEDIUM_HIT:
		iAmt = BLOCKSTUN_MEDIUM;
		break;
	case STRONG_HIT:
		iAmt = BLOCKSTUN_STRONG;
		break;
	}

	return iAmt;
}

/*
* Continue Block Stun
*/
BOOL CPlayerMelee::ContinueBlockStun( int &iCurrentStun, MELEE_STRENGTH eStartStrength, MELEE_STRENGTH eStrength )
{	BOOL fReturn = TRUE;
	switch(eStrength)
	{
	case WEAK_HIT:
		fReturn = TRUE;
		break;
	case MEDIUM_HIT:
		if(eStartStrength == STRONG_HIT)
		{	if(iCurrentStun == GetBlockStunAmt( STRONG_HIT ))
			{	iCurrentStun = 0;
				fReturn = TRUE;
			}
			else
			{	fReturn = FALSE;
			}
		}
		else if(eStartStrength == MEDIUM_HIT)
		{	fReturn = FALSE;
		}
		break;
	case STRONG_HIT:
		fReturn = FALSE;
		break;
	}

	if(!fReturn)
	{	iCurrentStun = 0;
	}
	return fReturn;
}

/*
* Set Block Stun
*/
void CPlayerMelee::SetBlockStun( melee_execution_s *pExe )
{	int iAmt=0;
	MELEE_STRENGTH eStart = WEAK_HIT;
	if(pExe->eBlock == BLOCK_FAIL)
	{	// Unblocked because of blockstun, skip
		if(pExe->fBlockStun || pExe->fCombo)
		{	return;
		}

		iAmt = m_pDefenderMelee->GetBlockStunAmt(pExe->eStrength);
		
		// No moves to "unblock"
		if(!iAmt)
		{	return;
		}
		else
		{	eStart = pExe->eStrength;
		}

		int iCount=iAmt;
		pExe = pExe->pNext;

		// Loop through and force block fails
		while(pExe && (iCount > 0))
		{	if(ContinueBlockStun(iCount, eStart, pExe->eStrength))
			{	pExe->fBlockStun = TRUE;
				pExe = pExe->pNext;
			}
			else
			{	break;
			}
			iCount--;
		}
	}
}

/*
* Get Animation For Combo
*/
void CPlayerMelee::GetAnimForCombo( int iComboID, char *pAnim )
{	strcpy(pAnim,"");

	switch(iComboID)
	{
	case COMBOMOVE_1:
		strcpy(pAnim,"combo_1");
		break;
	case COMBOMOVE_2:
		strcpy(pAnim,"combo_2");
		break;
	default:
		strcpy(pAnim,"combo_1");
		break;
	}
}


/*
* Add Exe Combo Move
*/
void CPlayerMelee::AddExeCombo( melee_execution_s *pExe, float flDmg, float flHitTime, void (*pCallBack)(CBasePlayer*,CBasePlayer*))
{	if(!pExe)
	{	return;
	}

	// Maxed out on combo hits, dont overflow
	if(pExe->iComboHits >= MAX_COMBOHITS)
	{	return;
	}

	// Save move number and increase
	int iMove = pExe->iComboHits;
	pExe->iComboHits++;

	// Save data on move
	pExe->combohit[iMove].fExecute = TRUE;
	pExe->combohit[iMove].flDamage = flDmg;
	pExe->combohit[iMove].flHitTime = gpGlobals->time + flHitTime;
	pExe->combohit[iMove].pComboCallBack = pCallBack;
}

/*
* Setup Combo
*/
melee_execution_s *CPlayerMelee::SetupCombo( int iComboID )
{	char szAnim[256];
	GetAnimForCombo(iComboID, szAnim);
	melee_execution_s *pNewExe = CreateExeMove(IN_ATTACK, iComboID, 0, 0, COMBO_NONE, STRONG_HIT, szAnim);
	pNewExe->fCombo = TRUE;
	pNewExe->eBlock = BLOCK_FAIL;

	switch(pNewExe->iComboID)
	{
	case COMBOMOVE_1:
		AddExeCombo(pNewExe, 2, 0.075, NULL);
		AddExeCombo(pNewExe, 2, 0.275, NULL);
		AddExeCombo(pNewExe, 2, 0.475, NULL);
		AddExeCombo(pNewExe, 2, 0.650, NULL);
		AddExeCombo(pNewExe, 2, 0.850, NULL);
		AddExeCombo(pNewExe, 1, 1.050, NULL);
		AddExeCombo(pNewExe, 1, 1.350, NULL);
		break;
	case COMBOMOVE_2:
		AddExeCombo(pNewExe, 2, 0.45, NULL);
		AddExeCombo(pNewExe, 3, 0.65, NULL);
		AddExeCombo(pNewExe, 4, 1.2, NULL);
		AddExeCombo(pNewExe, 4, 1.4, NULL);
		break;
	// Non-valid ID number, remove combo
	default:
		ALERT(at_console,"Removing invalid combo move!\n");
		delete pNewExe;
		return NULL;
	}

	// Add combo message to hud
	MeleeText(MELEETXT_COMBO,0);

	return pNewExe;
}


/*
* Add Combo
*/
void CPlayerMelee::AddCombo( melee_execution_s *pCurrent, int iComboID )
{	// Make combo
	melee_execution_s *pCombo = SetupCombo(pCurrent->iComboID);
	if(pCombo)
	{	// Add to list
		if(!pCurrent)
		{	pCombo = pCurrent;
		}
		else
		{	pCombo->pNext = pCurrent->pNext;
			pCurrent->pNext = pCombo;
			pCombo->pPrev = pCurrent;
		}
	}
}

/*
* Can Execute Combo
*/
BOOL CPlayerMelee::CanEXECombo( melee_execution_s *pExe )
{	int iTotal=0;
	int iBlocked=0;
	melee_execution_s *pCurrent = pExe;
	while(pCurrent)
	{	// Skip combomoves
		if(pCurrent->fCombo)
		{	pCurrent = pCurrent->pPrev;
		}

		// Add to total
		iTotal++;

		// Add blocked
		if(pCurrent->eBlock==BLOCK_TRUE)
		{	iBlocked++;
		}

		// Check to see if this is the last combo move of this sequence
		if(pCurrent->eComboStatus == COMBO_START)
		{	break;
		}
		pCurrent = pCurrent->pPrev;
	}

	// FIXME: If 25% (by default) of the moves are executed without blocks, land combo
	if(float(iBlocked/iTotal) <= melee_percentblocked.value)
	{	return TRUE;
	}
	
	return FALSE;
}

/*
* Get Next EXE move
*/
melee_execution_s *CPlayerMelee::GetNextExe( void )
{	// Add combo move if possible
	if(m_pExeCurrent->eComboStatus == COMBO_END)
	{	// Check if we can add a combo move
		if(CanEXECombo(m_pExeCurrent))
		{	// Add Combo
			AddCombo(m_pExeCurrent, m_pExeCurrent->iComboID);
		}
	}
	return m_pExeCurrent->pNext;
}

/*
* Next EXE move
*/
void CPlayerMelee::NextExeMove( void )
{	// Make sure the damage was emitted for the last move before we change
	if(m_pExeCurrent && !m_pExeCurrent->fEmitDamage)
	{	EmitDamage();
		// Make sure we're still fighting 
		if(!m_fFighting)
		{	return;
		}
	}
	// Emit all undone combo damage
	else if(m_pExeCurrent && m_pExeCurrent->fCombo)
	{	for(int i=0;i<m_pExeCurrent->iComboHits;i++)
		{	EmitComboDamage(&m_pExeCurrent->combohit[i]);
			// Make sure we're still fighting 
			if(!m_fFighting)
			{	return;
			}
		}
	}

	// Next move
	if(m_pExeCurrent)
	{	m_pExeCurrent = GetNextExe();
	}

	NewExeMovePost();
}

/*
* Next Exe Move Post
*/
void CPlayerMelee::NewExeMovePost( void )
{	// We still have more moves, continue!
	if(m_pExeCurrent)
	{	// Set Block Status
		m_pExeCurrent->eBlock = SetBlock( m_pExeCurrent );

		// Set Block stun
		SetBlockStun(m_pExeCurrent);

		// Get first move rolling
		AddAnimationExe(gpGlobals->time,m_pExeCurrent->szAnim);

		// Motion Blur for strong hits
		if(m_pExeCurrent->eStrength == STRONG_HIT)
		{	UTIL_Model_MotionBlur(m_pAttacker->entindex(), m_pAttacker->LookupSequence(m_pExeCurrent->szAnim));
		}
	}
	// We're done, stop melee
	else
	{	if(CanSwitch())
		{	Switch();
		}
		else
		{	StopMelee();
		}
	}
}

/*
* Set directions
*/
BOOL CPlayerMelee::SetDirections( void )
{
	melee_move_s *pMove = NULL;
	int iFlags = 0;
	BOOL fExecute = FALSE;

	// Set flags
	SetMovementFlags(iFlags);

	pMove = GetAttackerMoves();

	// We have no moves, create one!
	if(!pMove)
	{	if(SetAttackFlags( iFlags ))
		{	AddDirection( iFlags );
			return false;
		}
		else
		{	return true;
		}
	}
	// We have some combos in our list, lets set moves accordingly
	else
	{	// Not pressing anything, continue with current move
		if(!iFlags)
		{	if(SetAttackFlags(iFlags))
			{	ResetDirection(iFlags, pMove);
				fExecute = HoldDirection(pMove);
			}
			else
			{	LetGoDirection(pMove);
				return true;
			}
		}
		else
		{	// Holding onto attack
			if(SetAttackFlags(iFlags))
			{	// Hold down button, we're using the same directions as before
				if(!pMove->fFinished && (pMove->iFlags == iFlags))
				{	fExecute = HoldDirection(pMove);
				}
				// End this direction, and start a new one
				else
				{	// If directionless, set this as a valid direction
					if(IsDirectionless(pMove->iFlags) && !IsDirectionless(iFlags))
					{	SetDirection(pMove,iFlags);
						fExecute = HoldDirection(pMove);
					}
					// Changing punch move to kick move, vise versa
					else if(!ResetDirection(iFlags, pMove))
					{	// Are we allowed to 'let go' yet?
						if(CanLetGo(pMove))
						{	fExecute = LetGoDirection(pMove);
							if(!fExecute)
							{	AddDirection(iFlags);
							}
						}
						else
						{	fExecute = HoldDirection(pMove);
						}
					}
					else
					{	fExecute = HoldDirection(pMove);
					}
				}
			}
			// Let go of attack, force end combo
			else
			{	LetGoDirection(pMove);
				return true;
			}
		}
	}

	return fExecute;
}

/*
* Set blocking directions
*/
void CPlayerMelee::SetBlockingDirections( void )
{
	melee_move_s *pMove;
	int iFlags = 0;

	// Set flags
	SetMovementFlags(iFlags);

	pMove = m_pDefenderMoves;

	// We have no moves, create one!
	if(!pMove)
	{	if(iFlags)
		{	AddDirection( iFlags );
			return;
		}
	}
	// We have some combos in our list, lets set moves accordingly
	else
	{	// Not pressing anything, lets release our current move
		if(!iFlags)
		{	LetGoDirection(pMove);
			return;
		}
		else
		{
			// Hold down button, we're using the same directions as before
			if(!pMove->fFinished && (pMove->iFlags == iFlags))
			{	HoldDirection(pMove);
				return;
			}
			// End this direction, and start a new one
			else
			{	LetGoDirection(pMove);
				AddDirection(iFlags);
				return;
			}
		}
	}
}

/*
* Set Movement Flags
*/
void CPlayerMelee::SetMovementFlags( int &iFlags )
{
	BOOL fLeft = ((m_pAttacker->pev->button & IN_LEFT) || (m_pAttacker->pev->button & IN_MOVELEFT));
	BOOL fRight = ((m_pAttacker->pev->button & IN_RIGHT) || (m_pAttacker->pev->button & IN_MOVERIGHT));
	BOOL fDown = (m_pAttacker->pev->button & IN_BACK);
	BOOL fUp = (m_pAttacker->pev->button & IN_FORWARD);
	// Set flags
	// Diags
	if(fLeft && fUp)
	{	iFlags |= (IN_LEFT|IN_FORWARD);
	}
	else if(fLeft && fDown)
	{	iFlags |= (IN_LEFT|IN_BACK);
	}
	else if(fRight && fUp)
	{	iFlags |= (IN_RIGHT|IN_FORWARD);
	}
	else if(fRight && fDown)
	{	iFlags |= (IN_RIGHT|IN_BACK);
	}
	// Regular directions
	else if(fLeft)
	{	iFlags |= IN_LEFT;
	}
	else if(fRight)
	{	iFlags |= IN_RIGHT;
	}
	else if(fDown)
	{	iFlags |= IN_BACK;
	}
	else if(fUp)
	{	iFlags |= IN_FORWARD;
	}
}

/*
* Can Add Direction
*/
BOOL CPlayerMelee::CanAddDirection( void )
{	if(m_fForceDfdDirs || (!m_fRetaliateEXE && IsDefender()))
	{	// You can't block moves that havn't been executed yet
		if(m_fForceDfdDirs)
		{	if(GetMoveCountFinishedOnly(GetAttackerMoves()) == GetMoveCount(GetDefenderMoves()))
				return FALSE;
		}
		else if(GetMoveCount(GetDefenderMoves()) == GetMoveCountFinishedOnly(m_pAttackerMelee->GetAttackerMoves()))
		{	return FALSE;
		}
	}
	else if(IsAttacker() && m_pDefenderMelee && m_pDefenderMelee->m_fRetaliateEXE)
	{	// Retaliation
		if(GetMoveCount(GetDefenderMoves()) == GetMoveCountFinishedOnly(m_pDefenderMelee->GetAttackerMoves()))
			return FALSE;
	}

	return TRUE;
}

/*
* Add Direction
*/
void CPlayerMelee::AddDirection( int iFlags )
{	if(!CanAddDirection())
	{	return;
	}
	

	melee_move_s *pNewMove = new melee_move_s;

	pNewMove->iFlags = iFlags;
	pNewMove->flTimeStart = gpGlobals->time;
	pNewMove->flTimeEnd = gpGlobals->time;
	pNewMove->fFinished = FALSE;
	pNewMove->iComboID = 0;
	pNewMove->eComboStatus = COMBO_NONE;
	pNewMove->pPrev = NULL;
	pNewMove->pNext = NULL;

	// Add to list
	if(UseAttackerMoves())
	{	// Set and Increase ID
		pNewMove->iNumID = m_iCurAtkID;
		m_iCurAtkID++;
		// Add to linked list
		if(m_pAttackerMoves)
		{	m_pAttackerMoves->pNext = pNewMove;
			pNewMove->pPrev = m_pAttackerMoves;
		}
		m_pAttackerMoves = pNewMove;
	}
	else
	{	// Set and Increase ID
		pNewMove->iNumID = m_iCurDfdID;
		m_iCurDfdID++;
		// Add to linked list
		if(m_pDefenderMoves)
		{	m_pDefenderMoves->pNext = pNewMove;
			pNewMove->pPrev = m_pDefenderMoves;
		}
		m_pDefenderMoves = pNewMove;
	}

	// Send messages to the hud
	if(!m_fForceAtkDirs)
	{	if(UseAttackerMoves())
		{	MeleeHudFlags(M_ARROW_HUD,iFlags);
		}
		// Update block
		else
		{	UpdateBlockClient(pNewMove);
		}
	}
}


/*
* Is Directionless?
*/
BOOL CPlayerMelee::IsDirectionless( int iFlags )
{	if((iFlags & IN_LEFT) || (iFlags & IN_BACK) || (iFlags & IN_RIGHT) || (iFlags & IN_FORWARD))
	{	return FALSE;
	}
	else
	{	return TRUE;
	}
}


/*
* Set Direction, unsets Directionless bool + sets flags
*/
void CPlayerMelee::SetDirection( melee_move_s *pMove, int iFlags )
{	if(pMove)
	{	pMove->iFlags = iFlags;
		// Switch attackers flags
		MeleeHudFlags(M_ARROW_HUD_SWITCH,iFlags);
	}
}

/*
* Remove Direction
*/
melee_move_s *CPlayerMelee::RemoveDir( melee_move_s *remove )
{	// Return null if we're given a null pointer
	if(!remove)
	{	return NULL;
	}

	int i;
	melee_move_s *pMoves = NULL;
	for(i=0;i<2;i++)
	{
		if(!i)
		{	pMoves = GetAttackerMoves();
		}
		else
		{	pMoves = GetDefenderMoves();
		}

		// First element in list, remove it
		if(pMoves == remove)
		{	
			melee_move_s *pRemove = pMoves;
			if(i)
			{	m_pAttackerMoves = m_pAttackerMoves->pPrev;
			}
			else
			{	m_pDefenderMoves = m_pDefenderMoves->pPrev;
			}
			delete pRemove;
			return pMoves;
		}
		// We need to search for it
		else
		{	melee_move_s *pCurrent = pMoves;

			while(pCurrent->pPrev && (pCurrent->pPrev != remove))
			{	pCurrent = pCurrent->pPrev;
			}

			// found it. Delete it + fill in the empty space
			if(pCurrent->pPrev)
			{
				melee_move_s *pPrev = remove->pPrev;
				pCurrent->pPrev = pPrev;
				if(pPrev)
				{	pPrev->pNext = pCurrent;
				}
				delete remove;
				return pPrev;
			}
		}
	}
	return NULL;
}

/*
* Reset Direction
*/
BOOL CPlayerMelee::ResetDirection( int iFlags, melee_move_s *pMove )
{	
	if(!pMove->fFinished)
	{
		if(pMove->iFlags & IN_ATTACK)
		{	
			if(iFlags & IN_ATTACK2)
			{
				pMove->iFlags &= ~IN_ATTACK;
				pMove->iFlags |= IN_ATTACK2;

				MeleeHudSwitchAtk(pMove);	// Send message to client
				return true;
			}
		}
		else if(pMove->iFlags & IN_ATTACK2 && !(iFlags & IN_ATTACK2))
		{	
			if(iFlags & IN_ATTACK)
			{
				pMove->iFlags &= ~IN_ATTACK2;
				pMove->iFlags |= IN_ATTACK;

				MeleeHudSwitchAtk(pMove);	// Send message to client
				return true;
			}
		}
	}
	return false;
}

/*
* Set Attack Flags
*/
BOOL CPlayerMelee::SetAttackFlags( int &iFlags )
{	if(m_pAttacker->pev->button & IN_ATTACK2)
	{	iFlags |= IN_ATTACK2;
	}
	else if(m_pAttacker->pev->button & IN_ATTACK)
	{	iFlags |= IN_ATTACK;
	}
	else
	{	return FALSE;
	}
	return TRUE;
}

/*
* Hold direction
*/
BOOL CPlayerMelee::HoldDirection( melee_move_s *pMove )
{	if(pMove)
	{	pMove->flTimeEnd = gpGlobals->time;

		if(UseAttackerMoves())
		{
			// Check to see if we're over the max time
			float flTotalCmbTime = TotalCmbTime();
			float flStunTime = m_pDefenderMelee->GetStunTime();
			int iFlags=0;

			// Our combo is over the stun time, cap off the last move and execute the combo
			if(flTotalCmbTime > flStunTime)
			{	LetGoDirection(pMove);
				return TRUE;
			}

			// This combo has been 'held down' for the max amount of time, cut this move off and start a new one
			if((GetCmbTime(pMove)) > GetSkillValues()->flStrongRange)
			{	// Make time exact
				pMove->flTimeEnd = pMove->flTimeStart + GetSkillValues()->flStrongRange;
				
				// Create new direction
				if(LetGoDirection(pMove))
				{	return TRUE;
				}
				else
				{	// Get current flags
					SetAttackFlags(iFlags);
					SetMovementFlags(iFlags);
					// Add new direction
					AddDirection(iFlags);
				}
			}
		}
	}
	return FALSE;
}

/*
* Let Go Direction
*/
BOOL CPlayerMelee::LetGoDirection( melee_move_s *pMove )
{	bool blReturn = false;

	if(pMove)
	{	if(!pMove->fFinished)
		{	pMove->fFinished = TRUE;
			pMove->flTimeEnd = gpGlobals->time;

			// Set end arrow time
			m_flEndArrowTime = pMove->flTimeEnd;

			if(UseAttackerMoves())
			{	if(!m_fForceAtkDirs)
				{	float flTotalCmbTime = TotalCmbTime();
					float flStunTime = m_pDefenderMelee->GetStunTime();

					// Our combo is over the stun time, cap off the last move and execute the combo
					if(flTotalCmbTime > flStunTime)
					{
						float flLastMoveTime = flStunTime - TotalCmbTimeNC();
						pMove->flTimeEnd = pMove->flTimeStart + flLastMoveTime;

						blReturn = true;
					}

					// We dont have enough time to execute another direction
					if(!blReturn && ((flStunTime - flTotalCmbTime) < GetSkillValues()->flMinRange))
					{	blReturn = true;
					}

					// End combo clientside
					MeleeHudFlags(M_ARROW_HUD_END,pMove->iFlags, GetCmbTime(pMove));
				}
					
				// Send block flash
				if(!IsDirectionless(pMove->iFlags))
				{	if(m_fRetaliateEXE)
					{	SendBlockFlash(m_pAttackerOther, pMove);
					}
					else
					{	if(m_fForceAtkDirs)
							SendBlockFlash(m_pAttacker, pMove);
						else
							SendBlockFlash(m_pDefender, pMove);
					}
				}
			}
		}
	}

	return blReturn;
}


/*
* Can let go
*/
BOOL CPlayerMelee::CanLetGo( melee_move_s *pMove )
{	if(GetCmbTime(pMove) < GetSkillValues()->flMinRange)
	{	return FALSE;
	}

	return TRUE;
}

/*
* Delete all directions for attacker
*/
void CPlayerMelee::DelAllDirectionsAttacker( void )
{	// Delete all
	while(m_pAttackerMoves)
	{	melee_move_s *pDelete = m_pAttackerMoves;
		m_pAttackerMoves= m_pAttackerMoves->pPrev;
		delete pDelete;
	}
	m_iCurAtkID = 0;
	m_pAttackerMoves = NULL;
}

/*
* Delete all directions for defender
*/
void CPlayerMelee::DelAllDirectionsDefender( void )
{	// Delete all
	while(m_pDefenderMoves)
	{	melee_move_s *pDelete = m_pDefenderMoves;
		m_pDefenderMoves= m_pDefenderMoves->pPrev;
		delete pDelete;
	}
	m_iCurDfdID = 0;
	m_pDefenderMoves = NULL;
}

/*
* Delete all directions ( for both )
*/
void CPlayerMelee::DelAllDirections( void )
{	DelAllDirectionsAttacker();
	DelAllDirectionsDefender();
}

/*
* Get current direction
*/
melee_move_s *CPlayerMelee::GetCurrentDirection( void )
{	if(UseAttackerMoves())
	{	return GetAttackerMoves();
	}
	else
	{	return GetDefenderMoves();
	}
	return NULL;
}

/*
* Get move count
*/
int CPlayerMelee::GetMoveCount( void )
{	return GetMoveCount( GetCurrentDirection() );
}

/*
* Get move count ( only of finished moves )
*/
int CPlayerMelee::GetMoveCountFinishedOnly( void )
{	return GetMoveCountFinishedOnly( GetCurrentDirection() );
}
int CPlayerMelee::GetMoveCountFinishedOnly( melee_move_s *pMove )
{	int i = 0;
	melee_move_s *pCurrent = pMove;

	// Move list works backwards
	while(pCurrent)
	{	if(!IsDirectionless(pCurrent->iFlags) && pCurrent->fFinished)
		{	i++;
		}
		pCurrent = pCurrent->pPrev;
	}

	return i;
}
/*
* Get move count ( specific )
*/
int CPlayerMelee::GetMoveCount( melee_move_s *pMove )
{	int i = 0;
	melee_move_s *pCurrent = pMove;

	// Move list works backwards
	while(pCurrent)
	{	if(!IsDirectionless(pCurrent->iFlags))
		{	i++;
		}
		pCurrent = pCurrent->pPrev;
	}

	return i;
}

/*
* Use Attacker Moveset
*/
BOOL CPlayerMelee::UseAttackerMoves( void )
{	return (!m_fForceDfdDirs && (m_fForceAtkDirs || m_fRetaliateEXE || (IsAttacker() ? !m_pDefenderMelee->m_fRetaliateEXE : false)));
}

/*
* Get Combo Time
*/
float CPlayerMelee::GetCmbTime( melee_move_s *pMove )
{	float flTime = 0;
	if(pMove)
	{	flTime = pMove->flTimeEnd - pMove->flTimeStart;
	}
	return flTime;
}


/*
* Get Move Strength
*/
int CPlayerMelee::GetMoveStrength( melee_move_s *pMove )
{	
	int iStrength = 0;
	if(pMove)
	{	
		if(GetCmbTime(pMove) < GetSkillValues()->flWeakRange)
		{	iStrength = WEAK_HIT;
		}
		else if(GetCmbTime(pMove) < GetSkillValues()->flMediumRange)
		{	iStrength = MEDIUM_HIT;
		}
		else
		{	iStrength = STRONG_HIT;
		}
	}
	return iStrength;
}

/*
* Get total combo time
*/
float CPlayerMelee::TotalCmbTime( void )
{	float flTime = 0;
	melee_move_s *pCurrent = GetCurrentDirection();
	while(pCurrent)
	{	flTime += GetCmbTime(pCurrent);
		pCurrent = pCurrent->pPrev;
	}
	return flTime;
}

/*
* Get total combo time not including the current direction
*/
float CPlayerMelee::TotalCmbTimeNC( void )
{	float flTime = 0;
	melee_move_s *pStart = GetCurrentDirection();
	if(pStart)
	{	flTime = TotalCmbTime() - GetCmbTime(pStart);
	}
	return flTime;
}

/*
* Send Block Flashes
*/
void CPlayerMelee::SendBlockFlash( CBasePlayer *pOther, melee_move_s *pMove )
{	int iRand=0;
	if(GetMeleeStrength(pMove) == WEAK_HIT)
	{	iRand = 15;
	}
	else if(GetMeleeStrength(pMove) == MEDIUM_HIT)
	{	iRand = 25;
	}
	else
	{	iRand = 35;
	}

	// Calculate PL differences
	int iPowerDiff = iRand + MAX_PL_DIFF_BLKFLASH * (m_pAttacker->GetPowerLevel() / pOther->GetPowerLevel());
	if(abs(iPowerDiff-iRand) > MAX_PL_DIFF_BLKFLASH)
	{	
		if(iPowerDiff>iRand)
		{	iPowerDiff = iRand + MAX_PL_DIFF_BLKFLASH;
		}
		else
		{	iPowerDiff = iRand - MAX_PL_DIFF_BLKFLASH;
		}
	}

	if(RANDOM_LONG(0,100) < iPowerDiff)
	{	pOther->m_Melee.MeleeHud( M_FLASH_HUD, PUNCH_NODIR );

		// Added by Rick: let bots know what to defend
		if (UTIL_IsBot(pOther))
		{
			CBot *pBot = UTIL_GetBotPointer(pOther);
			if (pBot)
				pBot->m_MeleeDefendButtons.AddNode(0);
		}
	}
	else
	{	pOther->m_Melee.MeleeHud( M_FLASH_HUD, FlagsToDirections(pMove->iFlags) );

		// Added by Rick: let bots know what to defend
		if (UTIL_IsBot(pOther))
		{
			CBot *pBot = UTIL_GetBotPointer(pOther);
			if (pBot)
				pBot->m_MeleeDefendButtons.AddNode(pMove->iFlags);
		}
	}
}

/*
* Melee Hud
*/
void CPlayerMelee::MeleeHud( int iType, int iDirection )
{
	MESSAGE_BEGIN(MSG_ONE, gmsgMeleeAtkHud, NULL, m_pAttacker->pev);
		WRITE_BYTE(iType);
		WRITE_BYTE(iDirection);
	MESSAGE_END();
}

/*
* Melee Hud
*/
void CPlayerMelee::MeleeHudRemove( int iType )
{
	MESSAGE_BEGIN(MSG_ONE, gmsgMeleeAtkHud, NULL, m_pAttacker->pev);
		WRITE_BYTE(iType);
	MESSAGE_END();
}


/*
* Melee Text output
*/
void CPlayerMelee::MeleeText( int iType, int iNum )
{	
	MESSAGE_BEGIN(MSG_ONE, gmsgMeleeTxtHud, NULL, m_pAttacker->pev);
		WRITE_BYTE(iType);
		WRITE_BYTE(iNum);
	MESSAGE_END();
}

/*
* Flags to directions
*/
int CPlayerMelee::FlagsToDirections( int iFlags )
{	int iDirection = 0;

	// Switch it over from punches to kicks
	if(iFlags & IN_ATTACK2)
	{	iDirection += KICK_UP;
	}

	// Set direction
	if(iFlags & IN_FORWARD)
	{
		if(iFlags & IN_LEFT)
		{	iDirection += PUNCH_UPPERLEFT;
		}
		else if(iFlags & IN_RIGHT)
		{	iDirection += PUNCH_UPPERRIGHT;
		}
		else
		{	iDirection += PUNCH_UP;
		}
	}
	else if(iFlags & IN_BACK)
	{
		if(iFlags & IN_LEFT)
		{	iDirection += PUNCH_LOWERLEFT;
		}
		else if(iFlags & IN_RIGHT)
		{	iDirection += PUNCH_LOWERRIGHT;
		}
		else
		{	iDirection += PUNCH_DOWN;
		}
	}
	else if(iFlags & IN_LEFT)
	{	iDirection += PUNCH_LEFT;
	}
	else if(iFlags & IN_RIGHT)
	{	iDirection += PUNCH_RIGHT;
	}
	else
	{	if(iFlags & IN_ATTACK)
		{	iDirection = PUNCH_NODIR;
		}
		else
		{	iDirection = KICK_NODIR;
		}
	}

	return iDirection;
}

/*
* directions to flags
*/
int CPlayerMelee::DirectionsToFlags( int iDirection )
{	int iFlag = 0;

	if(iDirection == PUNCH_NODIR)
	{	iFlag = IN_ATTACK;
		return iFlag;
	}
	else if(iDirection == KICK_NODIR)
	{	iFlag = IN_ATTACK2;
		return iFlag;
	}
	else if(iDirection < KICK_UP)
	{	iFlag = IN_ATTACK;
	}
	else
	{	iFlag = IN_ATTACK2;
	}
	
	switch(iDirection)
	{
	case PUNCH_UP:
	case KICK_UP:
		{	iFlag |= IN_FORWARD;
			break;
		}
	case PUNCH_UPPERLEFT:
	case KICK_UPPERLEFT:
		{	iFlag |= (IN_FORWARD|IN_LEFT);
			break;
		}
	case PUNCH_LEFT:
	case KICK_LEFT:
		{	iFlag |= IN_LEFT;
			break;
		}
	case PUNCH_LOWERLEFT:
	case KICK_LOWERLEFT:
		{	iFlag |= (IN_BACK|IN_LEFT);
			break;
		}
	case PUNCH_DOWN:
	case KICK_DOWN:
		{	iFlag |= IN_BACK;
			break;
		}
	case PUNCH_LOWERRIGHT:
	case KICK_LOWERRIGHT:
		{	iFlag |= (IN_BACK|IN_RIGHT);
			break;
		}
	case PUNCH_RIGHT:
	case KICK_RIGHT:
		{	iFlag |= IN_RIGHT;
			break;
		}
	case PUNCH_UPPERRIGHT:
	case KICK_UPPERRIGHT:
		{	iFlag |= (IN_FORWARD|IN_RIGHT);
			break;
		}
	}

	return iFlag;
}

/*
* Melee Hud Flags ( turns flags into directions )
*/
void CPlayerMelee::MeleeHudFlags( int iType, int iFlags )
{	// Call regular melee hud function
	MeleeHud(iType,FlagsToDirections(iFlags));
}


/*
* Update Block Client
*/
void CPlayerMelee::UpdateBlockClient( melee_move_s *pBlock )
{	melee_move_s *pDefenderCurrent = GetDefenderMoves();
	melee_move_s *pAttackerCurrent = NULL;

	// Select attackers moves
	if(m_fForceDfdDirs)
	{	pAttackerCurrent = GetAttackerMoves();
	}
	else if(m_pDefenderMelee ? m_pDefenderMelee->m_fRetaliateEXE : false)
	{	pAttackerCurrent = m_pDefenderMelee->GetAttackerMoves();
	}
	else if(m_pAttackerMelee)
	{	pAttackerCurrent = m_pAttackerMelee->GetAttackerMoves();
	}
	else
	{	ALERT(at_console,"ERROR: NON-VALID UPDATE BLOCK\n");
	}

	if(!pDefenderCurrent || !pAttackerCurrent)
	{	return;
	}

	// Go to start of linked list
	while(pDefenderCurrent->pPrev)
	{	pDefenderCurrent = pDefenderCurrent->pPrev;
	}
	while(pAttackerCurrent->pPrev)
	{	pAttackerCurrent = pAttackerCurrent->pPrev;
	}

	// Find what place the blocking direction is stored in
	int iDfdCount=0;
	while(pDefenderCurrent)
	{	iDfdCount++;
		if(pDefenderCurrent == pBlock)
		{	break;
		}
		pDefenderCurrent = pDefenderCurrent->pNext;
	}

	if(!pDefenderCurrent)
	{	return;
	}

	// Using the above count number, find the correct attackers direction and see if we blocked it
	int iAtkCount=0;
	while(pAttackerCurrent)
	{	if(IsDirectionless(pAttackerCurrent->iFlags))
		{	pAttackerCurrent = pAttackerCurrent->pNext;
			continue;
		}
		iAtkCount++;
		if(iAtkCount == iDfdCount)
		{	break;
		}
		pAttackerCurrent = pAttackerCurrent->pNext;
	}

	if(!pAttackerCurrent)
	{	return;
	}

	int iBlockStatus;
	if(Block(pAttackerCurrent->iFlags, pDefenderCurrent->iFlags))
	{	iBlockStatus = BLOCK_TRUE;
	}
	else
	{	iBlockStatus = BLOCK_FAIL;
	}

//	ALERT(at_console,"Def - %i | Atk - %i\n", FlagsToDirections(pAttackerCurrent->iFlags), FlagsToDirections(pDefenderCurrent->iFlags));

	MESSAGE_BEGIN(MSG_ONE, gmsgMeleeAtkHud, NULL, m_pAttacker->pev);
		WRITE_BYTE(M_FLASHUPDATE_HUD);
		WRITE_BYTE(iBlockStatus);
		WRITE_BYTE(pBlock->iNumID);
	MESSAGE_END();
}

#define MSG_FLOAT_SCALE	100

/*
* Melee Hud Flags ( turns flags into directions ), only used for M_ARROW_HUD_END
*/
void CPlayerMelee::MeleeHudFlags( int iType, int iFlags, float flDurration )
{
	int iDirection = FlagsToDirections(iFlags);

	MESSAGE_BEGIN(MSG_ONE, gmsgMeleeAtkHud, NULL, m_pAttacker->pev);
		WRITE_BYTE(iType);
		WRITE_BYTE(iDirection);
		WRITE_SHORT(flDurration * MSG_FLOAT_SCALE);
	MESSAGE_END();
}

/*
* Switch Melee Attack Flags ( client side )
*/
void CPlayerMelee::MeleeHudSwitchAtk( melee_move_s *pMove )
{	MeleeHudFlags(M_ARROW_HUD_SWITCH,pMove->iFlags);
}

/*
* Send varibles to client so we can predict correctly
*/
void CPlayerMelee::SendPredictVars( float flStunTime )
{	
	MESSAGE_BEGIN(MSG_ONE, gmsgMeleeAtkHud, NULL, m_pAttacker->pev);
		WRITE_BYTE(M_INIT_HUD);	// INIT hud message
		WRITE_SHORT(GetSkillValues()->flWeakRange * MSG_FLOAT_SCALE);	// Weak range
		WRITE_SHORT(GetSkillValues()->flMediumRange * MSG_FLOAT_SCALE);	// Med range
		WRITE_SHORT(GetSkillValues()->flStrongRange * MSG_FLOAT_SCALE);	// Strong range
		WRITE_SHORT(flStunTime * MSG_FLOAT_SCALE);	// Defenders Stun time
	MESSAGE_END();
}

/*
* Disable Melee Hud
*/
void CPlayerMelee::MeleeHudDisable( void )
{
	MESSAGE_BEGIN(MSG_ONE, gmsgMeleeAtkHud, NULL, m_pAttacker->pev);
		WRITE_BYTE(0);
	MESSAGE_END();
}

/*
* ======================================
* Advanced Melee System
*
* ======================================
*/


/*
* Set mode
*/
void CPlayerMelee::SetMode( ADV_MELEE_STATUS eMode )
{
	m_eAdvMeleeStatus = eMode;
	m_pDefenderMelee->m_eAdvMeleeStatus = eMode;

	// If we arn't on disabled, we set the opposite of the attack
	if(eMode != DISABLED)
	{	
		if(eMode == PREPUNCH_ATTACK)
		{	m_pDefenderMelee->m_eAdvMeleeStatus = PREPUNCH_DEFEND;
			StartPrePunchAttack();
		}
		if(eMode == CHARGE_ATTACK)
		{	m_pDefenderMelee->m_eAdvMeleeStatus = CHARGE_DEFEND;
			StartChargedAttack();
		}
		if(eMode == GRAB_ATTACK)
		{	m_pDefenderMelee->m_eAdvMeleeStatus = GRAB_DEFEND;
			StartGrabbedAttack();
		}
		if(eMode == EXE_ATTACK)
		{	m_pDefenderMelee->m_eAdvMeleeStatus = EXE_DEFEND;
			StartExeAttack();
		}
		if(eMode == STRUGGLE_ATTACK)
		{	m_pDefenderMelee->m_eAdvMeleeStatus = STRUGGLE_DEFEND;
			StartStruggleAttack();
		}
		if(eMode == STRUGGLE_BURST_ATTACK)
		{	m_pDefenderMelee->m_eAdvMeleeStatus = STRUGGLE_DEFEND;
			StartBurstStruggleAttack();
		}
		if(eMode == KNOCKPRE_STRUGGLE_ATTACK)
		{	m_pDefenderMelee->m_eAdvMeleeStatus = KNOCKPRE_STRUGGLE_DEFEND;
			StartKnockPreStruggle();
		}
	}
}

/*
* Init melee
*/
void CPlayerMelee::InitMelee( CBasePlayer *pOther )
{
	// defender
	SetDefender( pOther );
	SetAttackerOther( NULL );
	m_pDefenderMelee->SetAttackerOther( m_pAttacker );
	m_pDefenderMelee->SetDefender( NULL );

	// Set melee
	m_pAttacker->m_fMelee = FALSE;
	m_pDefender->m_fMelee = FALSE;

	if(!m_fSwitching)
	{	// Save Block
		BOOL fSaveBlock = m_pDefender->m_fBlock;

		// disable Special Modes
		if(m_pAttacker->m_fFlying)
		{	m_pAttacker->StopFly();
		}
		if(m_pAttacker->m_fTurbo)
		{	m_pAttacker->StopTurbo();
		}
		if(m_pDefender->m_fPowerUp)
		{	m_pDefender->StopPowerUp();
		}
		if(m_pDefender->m_fFlying)
		{	m_pDefender->StopFly();
		}
		if(m_pDefender->m_fTurbo)
		{	m_pDefender->StopTurbo();
		}
		if(m_pDefender->m_Swoop.m_fSwoop)
		{	m_pDefender->StopSwoop();
		}
		if(m_pDefender->m_fWallJump)
		{	m_pDefender->RemoveWallJump();
		}

		// Restore block
		m_pDefender->m_fBlock = fSaveBlock;

		// Holster enemy weapon
		if(m_pDefender->m_pActiveItem)
		{	CBasePlayerWeapon *pWeapon = (CBasePlayerWeapon*)m_pDefender->m_pActiveItem->GetWeaponPtr();
			if(pWeapon)
			{
				if(pWeapon->HolsterWhenMeleed())	
				{	// HACK HACK: Reset Disk Status
					pWeapon->Holster();
					pWeapon->Deploy();
				}
				// Controllable weapons auto-holster when melee is set
				else if(m_pDefender->m_fControl)
				{	m_pDefender->m_fMelee = TRUE;
					pWeapon->WeaponIdle();
				}
			}
		}

		RemoveAllAnims();
		m_pDefenderMelee->RemoveAllAnims();
	}

	// Set melee
	m_pAttacker->m_fMelee = TRUE;
	m_pDefender->m_fMelee = TRUE;

	m_fAttacker = TRUE;
	m_fDefender = FALSE;
	m_pDefenderMelee->m_fAttacker = FALSE;
	m_pDefenderMelee->m_fDefender = TRUE;

	
	// Set fighting ( advanced melee )
	m_fFighting = TRUE;
	m_pDefenderMelee->m_fFighting = TRUE;

	if(!m_fSwitching)
	{	// Make the attacker not-solid
		m_pAttacker->pev->solid = SOLID_NOT;

		// Set original Defender
		m_fOrigDefender = FALSE;
		m_pDefenderMelee->m_fOrigDefender = TRUE;

		// Normal slow down
		m_pAttacker->m_flSlowDown = 1;
		m_pDefender->m_flSlowDown = 1;

		// Set movetypes
		m_pAttacker->pev->movetype = MOVETYPE_RIDEBEAM;
		m_pDefender->pev->movetype = MOVETYPE_RIDEBEAM;
	}
}


/*
* Stop Melee
*/
void CPlayerMelee::StopMelee( void )
{	StopMelee( TRUE );
}

/*
* Stop Melee
*/
void CPlayerMelee::StopMelee( BOOL fKnockBack )
{	ADV_MELEE_STATUS eAdvStatus = m_eAdvMeleeStatus;

	if(m_eAdvMeleeStatus == PREPUNCH_ATTACK)
	{	StopPrepunchAttack();
	}
	else if(m_eAdvMeleeStatus == CHARGE_ATTACK)
	{	StopChargedAttack();
	}
	else if(m_eAdvMeleeStatus == GRAB_ATTACK)
	{	StopGrabbedAttack();
	}
	else if(m_eAdvMeleeStatus == EXE_ATTACK)
	{	StopExeAttack();
	}
	else if(m_eAdvMeleeStatus == STRUGGLE_ATTACK)
	{	StopStruggleAttack();
	}
	else if(m_eAdvMeleeStatus == STRUGGLE_BURST_ATTACK)
	{	m_eAdvMeleeStatus = STRUGGLE_ATTACK;
		StopStruggleAttack();
	}
	// We're not in advanced melee
	else if(!InAdvMeleeBattle())
	{	return;
	}

	// Disable all modes
	SetMode(DISABLED);

	// Remove Combo Directions
	if(!m_fSwitching && !m_fRetaliateEXE)
	{	DelAllDirections();
		MeleeHudDisable();
		m_pDefenderMelee->DelAllDirections();
		m_pDefenderMelee->MeleeHudDisable();

		// Push back surrounding players
		PushAwayOtherPlayers();
	}
	else
	{	DelAllDirectionsAttacker();
		m_pDefenderMelee->DelAllDirectionsDefender();
	}

	// Disable everything
	m_pAttacker->m_fMelee = FALSE;
	m_fFighting = FALSE;
	m_pDefender->m_fMelee = FALSE;
	m_pDefenderMelee->m_fFighting = FALSE;

	// Disable attacker / defender bools
	m_fAttacker = FALSE;
	m_fDefender = FALSE;
	m_pDefenderMelee->m_fAttacker = FALSE;
	m_pDefenderMelee->m_fDefender = FALSE;

	// Reset wait retal
	m_fWaitRetal = FALSE;
	m_pDefenderMelee->m_fWaitRetal = FALSE;

	// Reset manual EXE
	m_fManualExe = FALSE;
	m_pDefenderMelee->m_fManualExe = FALSE;

	// Prepunch / knockback struggle
	m_fPreKnockStrug = FALSE;

	// Not switching rolls
	if(!m_fSwitching)
	{	// Make the attacker solid again
		m_pAttacker->pev->solid = SOLID_SLIDEBOX;
		m_pDefender->pev->solid = SOLID_SLIDEBOX;

		// Set movetypes
		m_pAttacker->pev->movetype = MOVETYPE_WALK;
		m_pDefender->pev->movetype = MOVETYPE_WALK;

		// Disable retaliate
		m_fRetaliateEXE = FALSE;
		m_pDefenderMelee->m_fRetaliateEXE = FALSE;

		// Reset prepunching from behind / in block
		m_fPrepunchBlock = FALSE;
		m_fPrepunchBehind = FALSE;
		m_pDefenderMelee->m_fPrepunchBlock = FALSE;
		m_pDefenderMelee->m_fPrepunchBehind = FALSE;

		// Normal slow down
		m_pAttacker->m_flSlowDown = 1;
		m_pDefender->m_flSlowDown = 1;

		// Set movetypes
		m_pAttacker->pev->gravity = 1;
		m_pDefender->pev->gravity = 1;
		if( !FBitSet ( m_pAttacker->pev->flags, FL_ONGROUND ) )
		{	m_pAttacker->m_fFlying = FALSE;
			m_pAttacker->StartFly();
		}
		if( !FBitSet ( m_pDefender->pev->flags, FL_ONGROUND ) )
		{	m_pDefender->m_fFlying = FALSE;
			m_pDefender->StartFly();
		}

		if((eAdvStatus == GRAB_ATTACK) ? fKnockBack : true)
		{	// Move attacker away from defender
			Vector vecDir, vecStart, vecEnd;
			CBasePlayer *pMove, *pTrace;
			TraceResult tr;

			// Get Original Defenders info and move accordingly
			if(m_fOrigDefender)
			{	vecDir = -m_vecPrepunchDir;
				vecStart = m_pDefender->pev->origin;
				vecEnd = vecStart + vecDir * MELEE_END_OFFSET;
				pMove = m_pDefender;
				pTrace = m_pAttacker;
			}
			else
			{	vecDir = -m_vecPrepunchDir;
				vecStart = m_pAttacker->pev->origin;
				vecEnd = vecStart + vecDir * MELEE_END_OFFSET;
				pMove = m_pAttacker;
				pTrace = m_pDefender;
			}
			// Move origin
			UTIL_TraceHull(vecStart, vecEnd, ignore_monsters, human_hull, ENT(pTrace->pev), &tr);
			UTIL_SetOrigin( pMove->pev, tr.vecEndPos );

			// Move tracer back if moved hits something
			if(tr.flFraction != 1)
			{	float flMove = 1-tr.flFraction;
				vecStart = pTrace->pev->origin;
				vecEnd = vecStart - vecDir * MELEE_END_OFFSET * flMove;
				UTIL_TraceHull(vecStart, vecEnd, ignore_monsters, human_hull, ENT(pMove->pev), &tr);
				UTIL_SetOrigin( pTrace->pev, tr.vecEndPos );
			}
		}

		// Apply knockback if player died in the combo phase
		if(eAdvStatus == EXE_ATTACK)
		{	PushAfterDeath();
		}

		// reset prepunch dir
		Vector vecPrepunch = m_vecPrepunchDir.Normalize();
		m_vecPrepunchDir = vec3_t(0,0,0);
		m_pDefenderMelee->m_vecPrepunchDir = vec3_t(0,0,0);

		// Reset Switches
		m_iSwitch = 0;
		m_pDefenderMelee->m_iSwitch = 0;

		// Reset Stun Times
		m_flTotalStun = 0;
		m_pDefenderMelee->m_flTotalStun = 0;
			
		// Reset delayed melee
		m_flEndArrowTime = 0;
		m_fDelayMelee = FALSE;
		m_pDefenderMelee->m_flEndArrowTime = 0;
		m_pDefenderMelee->m_fDelayMelee = FALSE;

		// Update last recover time
		m_flLastRecoverTime = gpGlobals->time;
		
		// Remove all clientside model manipulation
		UTIL_Model_RemoveAll(m_pAttacker->entindex());
		UTIL_Model_RemoveAll(m_pDefender->entindex());

		// Send both players backwards
		if(fKnockBack)
		{	// Give both players knock back immunities
			m_fEndAdvMeleeToss = TRUE;
			m_pDefenderMelee->m_fEndAdvMeleeToss = TRUE;

			if(m_fOrigDefender)
			{	StartToss( m_pDefender, FALSE, vecPrepunch, 600, 300, 350, 5 );
				m_pDefenderMelee->StartToss( m_pAttacker, FALSE, -vecPrepunch, 600, 300, 350, 5 );
			}
			else
			{	StartToss( m_pDefender, FALSE, -vecPrepunch, 600, 300, 350, 5 );
				m_pDefenderMelee->StartToss( m_pAttacker, FALSE, vecPrepunch, 600, 300, 350, 5 );
			}
		}
		// We're not knocking back, so atleast enable flight
		else
		{	m_pAttacker->StartFly();
		}

		// Reset Original Defender
		m_fOrigDefender = FALSE;
		m_pDefenderMelee->m_fOrigDefender = FALSE;
	}

	// Reset defenders melee if he's dead
	if(!m_pDefender->IsAlive())
	{	m_pDefenderMelee->Reset();
	}

	m_pDefenderMelee->SetAttackerOther( NULL );
	m_pDefenderMelee->SetDefender( NULL );
	SetAttackerOther( NULL );
	SetDefender( NULL );
}

/*
* Pushback Surrounding Players
*/
void CPlayerMelee::PushAwayOtherPlayers( void )
{	CBaseEntity *pEntity = NULL;
	vec3_t vecOrigin;
	if(m_pDefender)
		vecOrigin = m_pDefender->pev->origin;
	else
		vecOrigin = m_pAttacker->pev->origin;

	while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecOrigin, PUSHBACK_RANGE )) != NULL)
	{	if(!pEntity->IsPlayer())
		{	continue;
		}

		if(pEntity == m_pAttacker || pEntity == m_pDefender)
		{	continue;
		}

		CBasePlayer *pPlayer = (CBasePlayer*)pEntity;

		// Stop player from powering up
		if(pPlayer->m_fPowerUp)
			pPlayer->StopPowerUp();

		// Melee checks
		if(pPlayer->m_Melee.m_eThrowStatus != THROW_DISABLE)
		{	continue;
		}
		if(pPlayer->m_fPowerStruggling || pPlayer->m_fBlockStruggling || pPlayer->m_fBlockStruggleAttacker ||
			pPlayer->m_fAscending ||	pPlayer->m_fShield || pPlayer->m_fSpawnInvulnerable || !pPlayer->IsAlive() || pPlayer->m_Melee.InAdvMeleeBattle() ||
			pPlayer->m_Melee.m_flLastRecoverTime > gpGlobals->time - nomeleehittime.value)
		{	continue;
		}
  
		// Disable flight/blocking and push player back
		if(pPlayer->m_fFlying)
			pPlayer->StopFly();

		if(pPlayer->m_fBlock)
			pPlayer->StopBlock();

		// If you're in the inner 4th, toss the player back
		if((pPlayer->pev->origin - vecOrigin).Length() < PUSHBACK_RANGE/4)
		{	pPlayer->m_Melee.StartToss( m_pAttacker, FALSE, (pPlayer->pev->origin - vecOrigin).Normalize(), 1500, 800, 250, 2);
		}
		// Apply to other players velocity
		else
		{	pPlayer->pev->velocity = (pPlayer->pev->origin - vecOrigin).Normalize() * PUSHBACK_FORCE;
		}
	}

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

	// Emit Sound
	EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/meleeflash.wav", 1.0, ATTN_NORM);
}

/*
* Check defender Stuntime
*/ 
void CPlayerMelee::CheckStunTime( void )
{	// We are draining
	if(m_fDrainStun)
	{	// Hey, time is up, disable the stun
		if(m_flStunnedTime < gpGlobals->time)
		{	m_fDrainStun = FALSE;
			m_flStunnedTime = 0;
			m_fStunned = FALSE;
			// Set Anim
			if(IsDefender())
			{	AddAnimation(true, gpGlobals->time, 1, "ref_stance");
			}
		}
	}
}

/*
* Get Stun time
*/
float CPlayerMelee::GetStunTime( void )
{
	if(m_fStunned)
	{	if(m_fDrainStun)
		{	return m_flTotalStun;
		}
		else
		{	return m_flStunnedTime;
		}
	}
	else
	{	return m_flTotalStun;
	}
}

/*
* Set Active Stun Time
*/
void CPlayerMelee::SetActiveStunTime( float flStunTime )
{	if(flStunTime)
	{	m_flTotalStun = flStunTime;
		m_flStunnedTime = gpGlobals->time + flStunTime;
		m_fDrainStun = TRUE;
		m_fStunned = TRUE;
	}
	else
	{	m_flTotalStun = 0;
		m_flStunnedTime = 0;
		m_fDrainStun = FALSE;
		m_fStunned = FALSE;
	}
}

/*
* Set Total Stun Time
*/
void CPlayerMelee::SetTotalStunTime( float flStunTime )
{	m_flTotalStun = flStunTime;
}

/* ======================================
*	Prepunch Attacks
*
*  ======================================
*/

/*
* Get enemy in prepunching area
*/
CBasePlayer *CPlayerMelee::GetEnemyPrepunch( 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_pAttacker->pev->origin, MELEE_RADIUS )) != NULL)
	{
		flLength = (pEntity->pev->origin - m_pAttacker->pev->origin).Length();

		if(flLength < flMaxDist && pEntity != (CBaseEntity*)m_pAttacker && pEntity->IsPlayer() && pEntity->IsAlive() && !((CBasePlayer*)pEntity)->m_Melee.InAdvMeleeBattle())
		{
			// Set up dotproduct
			vecLOS = pEntity->pev->origin - m_pAttacker->pev->origin;
			vecLOS = vecLOS.Normalize();

			flDot = DotProduct (vecLOS, m_pAttacker->m_Swoop.GetCurrentDirection());

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

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

	return (CBasePlayer*)pCEntity;
}

// Added by Rick
/*
* Get enemy in prepunching area, buddy version
*/
CBuddy *CPlayerMelee::GetBuddyEnemyPrepunch( 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 player in sphere
	while ((pEntity = UTIL_FindEntityInSphere( pEntity, m_pAttacker->pev->origin, MELEE_RADIUS )) != NULL)
	{
		flLength = (pEntity->pev->origin - m_pAttacker->pev->origin).Length();

		if ((flLength < flMaxDist) && (pEntity != (CBaseEntity*)m_pAttacker) && pEntity->IsAlive() &&
			/*!((CBasePlayer*)pEntity)->m_Melee.InAdvMeleeBattle()*/ FStrEq(STRING(pEntity->pev->classname), "player_buddy"))
		{
			// Set up dotproduct
			vecLOS = pEntity->pev->origin - m_pAttacker->pev->origin;
			vecLOS = vecLOS.Normalize();

			flDot = DotProduct (vecLOS, m_pAttacker->m_Swoop.GetCurrentDirection());

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

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

	return (CBuddy*)pCEntity;
}
//end add by Rick

/*
* Attack From Behind and Blocking prepunches
*/
void CPlayerMelee::SetAtkBehindAndBlocking( void )
{	Vector vecAttacker, vecDefender;
	float flDot;
	// Reset varibles
	m_fPrepunchBlock = FALSE;
	m_fPrepunchBehind = FALSE;

	// Get forward vectors
	UTIL_MakeVectorsPrivate(m_pAttackerOther->pev->v_angle, vecAttacker, NULL, NULL);
	UTIL_MakeVectorsPrivate(m_pAttacker->pev->v_angle, vecDefender, NULL, NULL);

	// Setup dot product
	flDot = DotProduct (-vecDefender, vecAttacker);

	// Player arn't facing eachother, attack from behind
	if (flDot < VIEW_FIELD_FULL )
	{	m_fPrepunchBehind = TRUE;
		m_pAttacker->m_fBlock = FALSE;
		return;
	}

	// Set Block
	// HACK HACK: Set fighting to false so it will pick up attacking player correctly
	m_pAttackerMelee->m_fFighting = FALSE;
	m_fFighting = FALSE;
	m_fPrepunchBlock = m_pAttackerMelee->BlocksAttack(m_pAttacker);
	m_pAttackerMelee->m_fFighting = TRUE;
	m_fFighting = TRUE;
	// Disable regular blocking
	m_pAttacker->m_fBlock = FALSE;
}

/*
* Start Pre-Punches
*/
void CPlayerMelee::StartPrePunchAttack( void )
{	// Set "connection" clientside
	UTIL_Model_Connect( m_pAttacker->entindex(), m_pDefender->entindex(), 9 );

	// Set Blocking + Attack from behind
	m_pDefenderMelee->SetAtkBehindAndBlocking();

	// Set animations
	AddAnimation(true, gpGlobals->time, 1, "ref_autopunch");
	if(m_pDefenderMelee->m_fPrepunchBehind)
	{	m_pDefenderMelee->AddAnimation(true, gpGlobals->time, 1, "ref_autopunch_hit_back");
	}
	else if(m_pDefenderMelee->m_fPrepunchBlock)
	{	m_pDefenderMelee->AddAnimation(true, gpGlobals->time, 1, "ref_autopunch_block");
	}
	else
	{	m_pDefenderMelee->AddAnimation(true, gpGlobals->time, 1, "ref_autopunch_hit");
	}

	// Set prepunch modes
	m_flStartPrePunch = gpGlobals->time;
	m_flLastPrePunch = 0;
	m_iNumPrepunches = 0;
	m_fDrainStun = FALSE;
	m_pDefenderMelee->m_fPrepunchPinned = FALSE;
	m_pDefenderMelee->m_flStunnedTime = 0;
	m_pDefenderMelee->m_flTotalStun = 0;
	m_pDefenderMelee->m_fDrainStun = FALSE;

	// Prepunch/knockback struggles already have a direction set
	if(m_vecPrepunchDir == Vector(0,0,0))
	{	// Set direction of fight
		UTIL_MakeVectors( m_pAttacker->pev->v_angle );
		m_vecPrepunchDir = gpGlobals->v_forward;
	}
	// Copy over
	m_pDefenderMelee->m_vecPrepunchDir = m_vecPrepunchDir;

	// Place attacker origin infront of defender
	vec3_t vecDir = -m_vecPrepunchDir;
	UTIL_SetOrigin(m_pAttacker->pev, m_pDefender->pev->origin + vecDir * 11 );

	// Set angles
	UTIL_Model_MeleeStruggle_Anglefix(m_pAttacker->entindex(), UTIL_VecToAngles(vecDir));

	// Emit Sound
	EMIT_SOUND(GetSoundEdict(), CHAN_BODY,"weapons/prepunch1.wav", 1.0, ATTN_NORM);
}

/*
* Stop prepunches
*/
void CPlayerMelee::StopPrepunchAttack( void )
{	if(m_eAdvMeleeStatus == PREPUNCH_ATTACK)
	{	
		// Reset vars
		m_iNumPrepunches = 0;
		m_flStunnedTime = 0;
		m_flTotalStun= 0;
		m_flStartPrePunch = 0;
		m_eAdvMeleeStatus = DISABLED;

		// Reset Anims
		RemoveAllAnims();

		// Stop Sound
	//	STOP_SOUND(ENT(m_pDefender->pev), CHAN_BODY, "weapons/prepunch1.wav");
		EMIT_SOUND(ENT(m_pDefender->pev), CHAN_BODY, "common/null.wav", 1.0, ATTN_NORM);

		// Remove Z component of prepunch direction
		m_vecPrepunchDir.z = 0;
		m_vecPrepunchDir = m_vecPrepunchDir.Normalize();
		m_pDefenderMelee->m_vecPrepunchDir = m_vecPrepunchDir;

		// Stop movement
		m_pAttacker->pev->vuser4 = Vector(0,0,0);
		m_pAttacker->pev->origin = m_pDefender->pev->origin + m_vecPrepunchDir * 11;
		// Reset origin
		UTIL_SetOrigin( m_pAttacker->pev, m_pAttacker->pev->origin );

		// Call defenders function
		m_pDefenderMelee->StopPrepunchAttack();
	}
	else if(m_eAdvMeleeStatus == PREPUNCH_DEFEND)
	{	m_eAdvMeleeStatus = DISABLED;
		RemoveAllAnims();

		// Stop movement
		m_pAttacker->pev->vuser4 = Vector(0,0,0);

		// Start draining stun time
		if(!m_fDrainStun && m_flStunnedTime)
		{	SetActiveStunTime(m_flStunnedTime);
		}
		else if(m_fDrainStun)
		{	SetTotalStunTime(m_flStunnedTime - gpGlobals->time);
		}
	}
}


/*
* Get Stun Per Punch
*/
float CPlayerMelee::GetStunPerPunch( void )
{	float flStun = GetSkillValues()->flStunPerPunch;

	if(m_pDefenderMelee->m_fPrepunchBehind)
	{	flStun *= 1.2;
	}
	else if(m_pDefenderMelee->m_fPrepunchBlock)
	{	flStun *= 0.65;
	}
	return flStun;
}

/*
* Get Dmg Per Punch
*/
float CPlayerMelee::GetDmgPerPunch( void )
{	float flDmg;
	// Pinned to wall
	if(m_pDefenderMelee->m_fPrepunchPinned)
	{	flDmg = PREPUNCH_DMG_PINNED;
	}
	// Regular
	else
	{	flDmg = PREPUNCH_DMG_REG;
	}

	// Blocking
	if(m_pDefenderMelee->m_fPrepunchBlock)
	{	flDmg *= PREPUNCH_DMG_BLOCKMULTI;
	}
	// Atked from behind
	else if(m_pDefenderMelee->m_fPrepunchBehind)
	{	flDmg *= PREPUNCH_DMG_BEHINDNULTI;
	}

	// Equate power ratio
	flDmg *= GetPowerRatio(m_pDefender);

	// Emit a min of 1 dmg per punch, and a max of 5 dmg per punch
	if(flDmg < 1)
		flDmg = 1;
	else if(flDmg > 5)
		flDmg = 5;
	return flDmg;
}

/*
* Handle attacking prepunch
*/
void CPlayerMelee::HandlePrepunchAttack( void )
{
	// Drift with defender
	if(!m_pDefenderMelee->m_fPrepunchPinned)
	{	m_pAttacker->pev->vuser4 = m_vecPrepunchDir * melee_prepunch_driftspeed.value;
	}
	else
	{	m_pAttacker->pev->vuser4 = Vector(0,0,0);
	}

	// Stop prepunches, start combos
	if( (m_pAttacker->pev->button & IN_ATTACK) && (m_iNumPrepunches >= melee_prepunch_mincombo.value) )
	{	if(m_fPreKnockStrug)
		{	StopMelee();
		}
		else
		{	// Stop prepunches
			StopPrepunchAttack();

			// Enable charging combo
			SetMode(CHARGE_ATTACK);
		}
		return;
	}
	// Stop prepunches, start grab
	else if( (m_pAttacker->pev->button & IN_ATTACK2) && (m_iNumPrepunches >= melee_prepunch_mincombo.value) )
	{	if(m_fPreKnockStrug)
		{	StopMelee();
		}
		else
		{	int iNumPrepunches = m_iNumPrepunches;
			// Stop Prepunches
			StopPrepunchAttack();

			// Don't allow throwing if the player blocked the attack
			if(m_pDefenderMelee->m_fPrepunchBlock || (iNumPrepunches > 6))
			{	// Enable charging combo
				SetMode(CHARGE_ATTACK);
			}
			else
			{	// Enable Grab
				SetMode(GRAB_ATTACK);
			}
		}
		return;
	}
	// Time for another prepunch
	else if((m_flLastPrePunch + 
		(m_fPreKnockStrug ? melee_prepunch_delaystruggle.value : melee_prepunch_delay.value)) < gpGlobals->time)
	{	
		m_flLastPrePunch = gpGlobals->time;	// reset time
		m_iNumPrepunches++;	// Add to total amt of punches

		// Send melee hud updates
		if(m_iNumPrepunches == 1)
			MeleeText(MELEETXT_HIT, m_iNumPrepunches);
		else
			MeleeText(MELEETXT_HITS, m_iNumPrepunches);

		// add stun time
		if(m_iNumPrepunches < melee_prepunch_maxstun.value)
		{	m_pDefenderMelee->m_flStunnedTime += GetStunPerPunch();
			if(!m_pDefenderMelee->m_fStunned)
			{	m_pDefenderMelee->m_fStunned = TRUE;
			}
			// Drain KI
			if(!m_pAttacker->UseKi(PREPUNCH_STUN_COST * (m_fPreKnockStrug ? 1.5 : 1)))
			{	CPlayerMelee *pDefenderMelee = m_pDefenderMelee;
				Vector vecPrepunch = m_vecPrepunchDir;

				StopMelee(FALSE);
				// Blow character back because he ran out of KI while prepunching
				pDefenderMelee->Powerhit(m_pAttacker, -vecPrepunch, FRONT);
				return;
			}
		}
		else
		{	// Start draining stun time
			if(!m_pDefenderMelee->m_fDrainStun)
			{	m_pDefenderMelee->m_fDrainStun = TRUE;
				m_pDefenderMelee->m_flTotalStun = m_pDefenderMelee->m_flStunnedTime;
				m_pDefenderMelee->m_flStunnedTime += gpGlobals->time;
			}

			// Drain 1/2 perpunch stun time
			m_pDefenderMelee->m_flTotalStun -= (GetStunPerPunch()/2);
			m_pDefenderMelee->m_flStunnedTime -= (GetStunPerPunch()/2);
			if(m_pDefenderMelee->m_flTotalStun < 0)
			{	m_pDefenderMelee->m_flStunnedTime -= m_pDefenderMelee->m_flTotalStun;
				m_pDefenderMelee->m_flTotalStun = 0;
			}

			// Drain KI
			if(!m_pAttacker->UseKi(PREPUNCH_AFTER_COST * (m_fPreKnockStrug ? 1.5 : 1)))
			{	CPlayerMelee *pDefenderMelee = m_pDefenderMelee;
				Vector vecPrepunch = m_vecPrepunchDir;

				StopMelee(FALSE);
				// Blow character back because he ran out of KI while prepunching
				pDefenderMelee->Powerhit(m_pAttacker, -vecPrepunch, FRONT);
				return;
			}
		}

		// If player blocked, drain hits from KI
		if(m_pDefenderMelee->m_fPrepunchBlock)
		{	if(!m_pDefender->UseKi(PREPUNCH_KI_BLK_COST * (m_pDefenderMelee->m_fPrepunchPinned ? 1.5 : 1)))
			{	// Disable blocking, do dmg, and change animation
				m_pDefenderMelee->m_fPrepunchBlock = FALSE;
				m_pDefender->TakeDamage( m_pAttacker->pev, m_pAttacker->pev, GetDmgPerPunch(), DMG_MELEE );
				m_pDefenderMelee->AddAnimation(true, gpGlobals->time, 1, "ref_autopunch_hit");
			}
		}
		// Emit damage
		else
		{	m_pDefender->TakeDamage( m_pAttacker->pev, m_pAttacker->pev, GetDmgPerPunch(), DMG_MELEE );
		}

		// Emit rocks if defender is pinned
		if(m_pDefenderMelee->m_fPrepunchPinned)
		{	
			// On even punches emit rocks from the right, odd punches emit rocks from the left
			double dTemp = m_iNumPrepunches/2;
			UTIL_MakeVectors(-m_vecPrepunchDir);

			if(dTemp == ceil(dTemp))
				m_pDefenderMelee->EmitExplosionRocks( m_pDefender->pev->origin + gpGlobals->v_right * 2.5, -m_vecPrepunchDir * 75, 5, 10, 6 );
			else
				m_pDefenderMelee->EmitExplosionRocks( m_pDefender->pev->origin - gpGlobals->v_right * 2.5, -m_vecPrepunchDir * 75, 5, 10, 6 );
		}
	}

	// Max amount of prepunches, disable melee
	if(m_iNumPrepunches == melee_prepunch_max.value && m_pDefender->pev->deadflag == DEAD_NO)
	{	StopMelee();
		return;
	}
}

/*
* Handle defending prepunch
*/
void CPlayerMelee::HandlePrepunchDefend( void )
{	// Give the player some backwards velocity
	if(!m_fPrepunchPinned)
	{	
		// Are we pinned to a wall?
		TraceResult tr;
		UTIL_TraceHull(m_pAttacker->pev->origin, m_pAttacker->pev->origin + m_vecPrepunchDir * BACK_TRACE_DIST, ignore_monsters, human_hull, ENT(m_pAttacker->pev), &tr);
		
		// Hit something? Disable movement
		if(tr.flFraction < 1)
		{	m_fPrepunchPinned = TRUE;
			m_pAttacker->pev->vuser4 = vec3_t(0,0,0);

			int iPitch = abs(UTIL_VecToAngles(tr.vecPlaneNormal).x);
			if(iPitch <= 45)
			{	// Get surface normal of the object we stopped on, and fix the player angles to it
				Vector vecDir, vecAngles;

				vecDir = tr.vecPlaneNormal;
				vecDir.z = -vecDir.z;
				
				vecAngles = UTIL_VecToAngles(vecDir);

				// Send info to client
				UTIL_Model_MeleeStruggle_Anglefix(m_pAttackerOther->entindex(), vecAngles);
			}

			if(!m_fPrepunchBlock && !m_fPrepunchBehind)
			{	// Add animation
				AddAnimation(true,gpGlobals->time,1,"wall_autopunched");
			}
		}
		else
		{	m_pAttacker->pev->vuser4 = m_vecPrepunchDir.Normalize() * melee_prepunch_driftspeed.value;
		}
	}
	else
	{	m_pAttacker->pev->vuser4 = Vector(0,0,0);
	}

	// Check stuntime
	CheckStunTime();
}

/* ======================================
*	Charged Attacks
*
*  ======================================
*/

/*
* Start harged Attack
*/
void CPlayerMelee::StartChargedAttack( void )
{	
	if(!m_fSwitching)
	{	// Connect models clientside
		UTIL_Model_Connect( m_pAttacker->entindex(), m_pDefender->entindex(), 11 );
		// Set angles
		UTIL_Model_MeleeStruggle_Anglefix(m_pAttacker->entindex(), UTIL_VecToAngles(-m_vecPrepunchDir));
	}

	// Remove all directions for combo system
	if(!m_fRetaliateEXE)
	{	DelAllDirections( );
		m_pDefenderMelee->DelAllDirections( );
		// Send info to client
		SendPredictVars( m_pDefenderMelee->GetStunTime() );
	}

	// Set stun animation
	if(m_pDefenderMelee->m_fStunned)
	{	if(m_pDefenderMelee->m_fPrepunchBehind)
		{	m_pDefenderMelee->AddAnimation(true, gpGlobals->time, 2, "ref_autopunch_spin", "ref_stun");
		}
		else
		{	m_pDefenderMelee->AddAnimation(true, gpGlobals->time, 1, "ref_stun");
		}
	}
	else
	{	m_pDefenderMelee->AddAnimation(true, gpGlobals->time, 1, "ref_stance");
	}

	AddAnimation(true, gpGlobals->time, 1, "ref_stance");
}

/*
* Start Charged Attack (Retaliate In EXE)
*/
void CPlayerMelee::StartChargedAttackRetaliate( void )
{	float flStunTime;
	// Remove all directions for combo system
	DelAllDirectionsAttacker( );

	// Set Defender
	SetDefender( m_pAttackerOther );

	// Get stun time
	flStunTime = PredictBlockRatio(m_pDefenderMelee->m_pExeStart, m_pDefenderMoves, GetStunTime());
	
	// Set defender stun time
	m_pDefenderMelee->SetActiveStunTime(flStunTime);
	// Reset local stun time
	SetActiveStunTime(0);

	// Send info to client
	MeleeHudDisable();
	SendPredictVars( flStunTime );
}

/*
* Stop Charged Attack
*/
void CPlayerMelee::StopChargedAttack( void )
{	// Reset anims
	if(m_eAdvMeleeStatus == CHARGE_ATTACK)
	{	m_eAdvMeleeStatus = DISABLED;
		RemoveAllAnims();
		MeleeHudDisable();
		m_fWaitRetal = FALSE;

		// Call defenders function
		m_pDefenderMelee->StopChargedAttack();

	}
	else if(m_eAdvMeleeStatus == CHARGE_DEFEND)
	{	m_eAdvMeleeStatus = DISABLED;
		RemoveAllAnims();
		// Re-set Stun time
		m_flTotalStun = m_pAttackerMelee->TotalCmbTime();
	}
}

/*
* Handle Delayed Block
*/
BOOL CPlayerMelee::HandleDelayedBlock( melee_move_s *pAtk, melee_move_s *pDfd )
{	if(GetMoveCount(pAtk) == GetMoveCount(pDfd))
	{	return TRUE;
	}
	else if(m_flEndArrowTime + CHARGE_MIN_LASTMOVE < gpGlobals->time)
	{	return TRUE;
	}
	return FALSE;
}

/*
* Set Delay End Block
*/
BOOL CPlayerMelee::SetDelayEndBlock( melee_move_s *pAtk, melee_move_s *pDfd )
{	if(GetMoveCount(pAtk) <= MAX_DELAY_MOVES && GetMoveCount(pAtk) > GetMoveCount(pDfd))
	{	// Give the defender more time to block attacks
		if(m_flEndArrowTime + CHARGE_MIN_LASTMOVE > gpGlobals->time)
		{	m_fDelayMelee = TRUE;
		}
	}
	return m_fDelayMelee;
}

/*
* Handle charge combo
*/
void CPlayerMelee::HandleChargeAttack( void )
{	// Handle delayed situations
	if(m_fDelayMelee)
	{	if(HandleDelayedBlock(GetAttackerMoves(), m_pDefenderMelee->GetDefenderMoves()))
		{	ExecuteCombo();
		}
	}
	// Set combo directions
	else if(SetDirections())
	{	if(!SetDelayEndBlock(GetAttackerMoves(), m_pDefenderMelee->GetDefenderMoves()))
		{	ExecuteCombo();
		}
	}
}

/*
* Handle charge defend ( block combos )
*/
void CPlayerMelee::HandleChargeDefend( void )
{	// Check stuntime
	CheckStunTime();

	// Set blocking directions ( to counter moves )
	SetBlockingDirections( );
}

/* ======================================
*	Grabbing Attacks
*
*  ======================================
*/

/*
* Start Grabbed Attack
*/
void CPlayerMelee::StartGrabbedAttack( void )
{	
	//	Set clientside model status to throw
	UTIL_Model_RemoveAll(m_pAttacker->entindex());
	UTIL_Model_Grab(m_pDefender->entindex(), m_pAttacker->entindex());

	// Reset Anims
	m_pDefenderMelee->RemoveAllAnims();
	RemoveAllAnims();

	// Move origin
	m_pAttacker->pev->origin = m_pDefender->pev->origin;
	UTIL_SetOrigin( m_pAttacker->pev, m_pAttacker->pev->origin );

	// Set solid bbox for attacker, and solid not for defender
	m_pAttacker->pev->solid = SOLID_SLIDEBOX;
	m_pDefender->pev->solid = SOLID_NOT;

	// Set animations
	AddAnimation(true, gpGlobals->time, 2, "ref_start_throw","ref_swinger_slow");
	m_pDefenderMelee->AddAnimation(true, gpGlobals->time, 2, "ref_start_swung", "ref_swung");

	// Set times
	m_flChargeGrab = 0;
	m_flStartHoldGrab = 0;
	m_flFrameTime = gpGlobals->time;
	m_pDefenderMelee->m_flFrameTime = gpGlobals->time;
	m_fHoldGrab = FALSE;
	m_fSpinSound = FALSE;
}

/*
* Stop Grabbed Attack
*/
void CPlayerMelee::StopGrabbedAttack( void )
{	// Reset anims
	if(m_eAdvMeleeStatus == GRAB_ATTACK)
	{	/* Modifed by Rick
		// Stop charge bar
		MESSAGE_BEGIN( MSG_ONE, gmsgCharge, NULL, m_pAttacker->pev ); 
			WRITE_BYTE(0);	//amount charged in %
		MESSAGE_END();*/

		m_pAttacker->DrawChargeBar(0); // Stop charge bar
	
		// Reset vars
		m_eAdvMeleeStatus = DISABLED;
		m_flChargeGrab = 0;
		m_flStartHoldGrab = 0;
		m_fHoldGrab = FALSE;

		// Reset Anims
		RemoveAllAnims();

		// Null sounds
		if(m_fSpinSound)
		{	m_fSpinSound = FALSE;
			STOP_SOUND( ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/spin.wav" );
		}

		// Call defenders function
		m_pDefenderMelee->StopGrabbedAttack();
	}
	else if(m_eAdvMeleeStatus == GRAB_DEFEND)
	{	m_eAdvMeleeStatus = DISABLED;
		m_flTotalStun = 0;
		RemoveAllAnims();

		// Remove struggle bar
		if(m_fStruggleBar)
		{	RemoveStruggleBar();
		}
	}
}


/*
* Can Throw
*/
BOOL CPlayerMelee::CanThrow( int iOriginOffset, Vector &vecOrigin )
{	TraceResult tr;
	// Set Angles
	UTIL_MakeVectors( m_pAttacker->pev->v_angle );

	// Increase offset if we're throwing up / down
/*	float flOriginOffset = iOriginOffset;
	float flAngle = m_pAttacker->pev->v_angle.x;
	if(flAngle < 0)
		flAngle = -flAngle;
	if(flAngle > 90)
		flAngle = 90;
	// Inverse angle and turn into percent
	flAngle = 90/(90-flAngle);
	// Add offset
	flOriginOffset += flAngle * THROW_ORIGIN_PITCH_OFFSET;
	ALERT(at_console,"Origin Offset 1: %f\n", flOriginOffset);
	if((flOriginOffset) > THROW_ORIGIN_PITCH_OFFSET + iOriginOffset)
	{	flOriginOffset = iOriginOffset + THROW_ORIGIN_PITCH_OFFSET;
	}
	ALERT(at_console,"Origin Offset 2: %f\n", flOriginOffset);
	iOriginOffset = (int)flOriginOffset;*/

	// Do a traceline to see if we have space for the throw
	Vector vecStart = m_pAttacker->pev->origin;
	Vector vecEnd = vecStart + gpGlobals->v_forward * iOriginOffset;
	UTIL_TraceHull(vecStart, vecEnd, dont_ignore_monsters, human_hull, ENT(m_pAttacker->pev), &tr);

	vecOrigin = tr.vecEndPos;
//vecPlaneNormal
	// Something is blocking our way, attempt to move the thrower back to create space
	if(tr.flFraction < 1)
	{	// Print entity in the way
	//	ALERT(at_console,"ERROR #1 THROW: ENT %i IN THE WAY!\n", CBaseEntity::Instance( tr.pHit )->entindex());
		// Do another trace backwards
		if(CBaseEntity::Instance(tr.pHit)->pev->solid == SOLID_BSP)
		{	vecEnd = vecStart + tr.vecPlaneNormal * float(iOriginOffset * (float(1)-tr.flFraction));
		}
		else
		{	vecEnd = vecStart - gpGlobals->v_forward * float(iOriginOffset * (float(1)-tr.flFraction));
		}
		UTIL_TraceHull(vecStart, vecEnd, dont_ignore_monsters, human_hull, ENT(m_pAttacker->pev), &tr);

		// We have something blocking us from behind too, cancel throw
		if(tr.flFraction < 1)
		{//	ALERT(at_console,"ERROR #2 THROW: ENT %i IN THE WAY!\n", CBaseEntity::Instance( tr.pHit )->entindex());
			return FALSE;
		}
		// move thrower origin
		else
		{	m_pAttacker->pev->origin = tr.vecEndPos;
			UTIL_SetOrigin(m_pAttacker->pev, m_pAttacker->pev->origin);
			return TRUE;
		}
	}

	return TRUE;
}

/*
* Throw
*/
void CPlayerMelee::Throw( CBasePlayer *pOther, int iSpeed, float flMinBlowTime, Vector vecOrigin )
{	// Add Animation
	AddAnimation(false, gpGlobals->time, 1, "ref_swinger_letgo");

	// Emit Sound
	EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/throw.wav", 1.0, ATTN_NORM);
	// Toss sound
	EMIT_SOUND(ENT(pOther->pev), CHAN_WEAPON, "weapons/swoophit.wav", 1.0, ATTN_NORM);

	// Weapon delay
	if(m_pAttacker->m_pActiveItem)
	{	CBasePlayerWeapon *pWeapon = (CBasePlayerWeapon*)m_pAttacker->m_pActiveItem;
		pWeapon->m_flNextPrimaryAttack = pWeapon->m_flNextSecondaryAttack = gpGlobals->time + 0.9;
	}
	
	// Toss
	pOther->m_Melee.StartToss( m_pAttacker, TRUE, gpGlobals->v_forward, iSpeed, iSpeed/2, iSpeed/5, flMinBlowTime );

	// Add beam invul to both players
	m_fInvulnerable = TRUE;
	m_pInvulException = NULL;
	m_flInvulnerableTime = gpGlobals->time + INVUL_RECOVER_TIME;
}

#define MAX_GRAB		float(100)
#define GRAB_FILL_RATE_B 15
#define GRAB_FILL_RATE_A 40
#define GRAB_KIBURN_B	150
#define GRAB_KIBURN_A	100
#define GRAB_MAXAFTERHOLD 2.5
#define THIRD_PERCENT	0.333333

/*
* Handle grabs
*/
void CPlayerMelee::HandleGrabAttack( void )
{	BOOL fToss = FALSE;		// Can we toss
	BOOL fThird = FALSE;	// Third done charging
	float flPercent = m_flChargeGrab/MAX_GRAB;
	// set third percent
	if(flPercent < THIRD_PERCENT)
	{	fThird = TRUE;
	}
	
	// HACK HACK: Constantly update enemys origin
	SetGrabbedOrigin();

	// Let go of secondary attack, throw
	if(!(m_pAttacker->pev->button & IN_ATTACK2))
	{	fToss = TRUE;
	}
	else
	{	// Get frame time
		float flFrameTime = gpGlobals->time - m_flFrameTime;
		m_flFrameTime = gpGlobals->time;
		// Burn KI
		if(!m_fHoldGrab)
		{	if(fThird)
			{	if(!m_pAttacker->UseKi((GRAB_KIBURN_B*flFrameTime) * (1/m_pAttacker->m_pClass->GetKiEfficiency())))
				{	fToss = TRUE;
				}
			}
			else
			{	if(!m_pAttacker->UseKi(GRAB_KIBURN_A*flFrameTime * (1/m_pAttacker->m_pClass->GetKiEfficiency())))
				{	fToss = TRUE;
				}
			}

			// Add power to throw
			if(!fToss)
			{	if(fThird)
				{	float flFill = GRAB_FILL_RATE_B;

					// Get enemy struggle fill amount
					if(((m_pDefender->pev->button & IN_ATTACK) || (m_pDefender->pev->button & IN_ATTACK2)) &&
							m_pDefender->UseKi(GRAB_KIBURN_B*0.5*flFrameTime*(1/m_pDefender->m_pClass->GetKiEfficiency())))
					{	float flDefenderStruggle = 0;
						float flPercent = 0;

						// prepunched from behind, reduced power
						if(m_pDefenderMelee->m_fPrepunchBehind)
						{	flPercent = .80;
						}
						// normal prepunches, normal power
						else
						{	flPercent = .60;
						}

						// Add power ratio and cap off
						float flRatio = m_pDefenderMelee->GetPowerRatio(m_pAttacker);
						flRatio -= 1.25;
						flRatio = flRatio/1.25;
						flPercent -= flRatio*.10;
						// Apply
						flFill *= flPercent;
					}

					m_flChargeGrab += flFill * flFrameTime;
				}
				else
				{	m_flChargeGrab += GRAB_FILL_RATE_A * flFrameTime;
				}

				if(m_flChargeGrab > MAX_GRAB)
				{	m_flChargeGrab = MAX_GRAB;
				}
			}
		}

		// We're 'holding' the grab now
		if((m_flChargeGrab == MAX_GRAB) && !m_fHoldGrab)
		{	m_fHoldGrab = TRUE;
			m_flStartHoldGrab = gpGlobals->time;
		}

		// Don't throw under 1/3rd mark
		if(!fThird && !m_fSpinSound)
		{	m_fSpinSound = TRUE;
			EMIT_SOUND(ENT(m_pAttacker->pev), CHAN_WEAPON, "weapons/spin.wav", 1.0, ATTN_NORM);
		}

		// See if we're over our max throw time
		if(m_fHoldGrab)
		{	if(m_flStartHoldGrab + GRAB_MAXAFTERHOLD < gpGlobals->time)
			{	fToss = TRUE;
			}
		}

		// Charge bar
		if(!fToss)
		{	/* Modified by Rick
			MESSAGE_BEGIN( MSG_ONE, gmsgCharge, NULL, m_pAttacker->pev ); 
				WRITE_BYTE( flPercent * 100 );	//amount charged in %
			MESSAGE_END();*/
			m_pAttacker->DrawChargeBar(flPercent * 100); // Update charge bar
		}
	}

	// Toss?
	if(fToss)
	{	CBasePlayer *pOther = m_pDefender;
		Vector vecOrigin;

		// Stop melee
		if(CanThrow(THROW_ORIGIN_OFFSET, vecOrigin) && !fThird)
		{	StopMelee(FALSE);

			// Physically throw player
			Throw(pOther, 1000 + (flPercent * 500), 1.5 * flPercent, vecOrigin);
		}
		else
		{	StopMelee();
		}
	}
}


/*
* Set Grabbed Origin ( while in toss )
*/
void CPlayerMelee::SetGrabbedOrigin( void )
{	vec3_t vecOrigin = vec3_t(0,0,0);
	CanThrow(THROW_ORIGIN_OFFSET, vecOrigin);
/*	UTIL_MakeVectors( m_pAttacker->pev->v_angle );
	vec3_t vecOrigin = m_pAttacker->pev->origin + gpGlobals->v_forward * 96;*/
	m_pDefender->pev->origin = vecOrigin;
	UTIL_SetOrigin( m_pDefender->pev, vecOrigin );
}

/*
* Handle defending/being grabbed
*/
void CPlayerMelee::HandleGrabDefend( void )
{	float flPercent = m_pAttackerMelee->m_flChargeGrab/MAX_GRAB;
	float flMulti = 1/THIRD_PERCENT;

	// Under 33 percent, display struggle status
	if(flPercent < THIRD_PERCENT)
	{	flPercent *= flMulti;
		UpdateStruggleBar(-flPercent * 100);
	}
	// Remove struggle bar if we're displaying one
	else
	{	if(m_fStruggleBar)
		{	RemoveStruggleBar();
		}
	}
}


/*
* Start Struggle Attack
*/
void CPlayerMelee::StartStruggleAttack( void )
{	// Set "connection" clientside
	UTIL_Model_MeleeStruggle( m_pAttacker->entindex(), m_pDefender->entindex() );

	// Set animations
	AddAnimation(true, gpGlobals->time, 1, "ref_grapple");
	m_pDefenderMelee->AddAnimation(true, gpGlobals->time, 1, "ref_grapple");

	// Set direction of fight
	UTIL_MakeVectors( m_pAttacker->pev->v_angle );
	m_vecPrepunchDir = gpGlobals->v_forward;
	// Copy over to defender
	m_pDefenderMelee->m_vecPrepunchDir = m_vecPrepunchDir;

	// Set starting time of arrow emittion
	m_flStrugArrow = gpGlobals->time + melee_struggle_startdelay.value;

	// Set angles
	UTIL_Model_MeleeStruggle_Anglefix(m_pAttacker->entindex(), UTIL_VecToAngles(-m_vecPrepunchDir));

	// Set attacker origin if there is space
	TraceResult tr;
	UTIL_TraceHull(m_pAttacker->pev->origin, m_pAttacker->pev->origin - m_vecPrepunchDir * 11, dont_ignore_monsters, human_hull, ENT(m_pAttacker->pev), &tr);
	if(tr.flFraction == 1)
	{	UTIL_SetOrigin( m_pAttacker->pev, tr.vecEndPos );
	}

	// emit sound
	EMIT_SOUND(GetSoundEdict(), CHAN_BODY, "weapons/meleestruggleinit.wav", 1.0, ATTN_NORM);

	// Display melee text
	MeleeText( MELEETXT_HEADON, 0 );
	m_pDefenderMelee->MeleeText( MELEETXT_HEADON, 0 );

	// clear varibles
	m_iSwitch = 0;
	m_iStrugArrowCount = 0;
	m_fForceAtkDirs = FALSE;
	m_fForceDfdDirs = FALSE;
	m_fStopStruggle = FALSE;
	m_pDefenderMelee->m_iStrugArrowCount = 0;
	m_pDefenderMelee->m_flStrugArrow = 0;
	m_pDefenderMelee->m_fForceAtkDirs = FALSE;
	m_pDefenderMelee->m_fForceDfdDirs = FALSE;
}


/*
* Retry Struggle Attack ( tie )
*/
void CPlayerMelee::RetryStruggleAttack( void )
{	// Set starting time of arrow emittion
	m_flStrugArrow = gpGlobals->time + melee_struggle_startdelay.value;

	// clear varibles
	m_iStrugArrowCount = 0;
	m_fForceAtkDirs = FALSE;
	m_fForceDfdDirs = FALSE;
	m_fStopStruggle = FALSE;
	m_pDefenderMelee->m_iStrugArrowCount = 0;
	m_pDefenderMelee->m_flStrugArrow = 0;
	m_pDefenderMelee->m_fForceAtkDirs = FALSE;
	m_pDefenderMelee->m_fForceDfdDirs = FALSE;

}

/*
* Start Burst Struggle Attack
*/
void CPlayerMelee::StartBurstStruggleAttack( void )
{	// Set "connection" clientside
	UTIL_Model_Connect( m_pAttacker->entindex(), m_pDefender->entindex(), 9 );

	// Set animations
	AddAnimation(true, gpGlobals->time, 1, "struggle_attack");
	m_pDefenderMelee->AddAnimation(true, gpGlobals->time, 1, "struggle_defend");

	// Set direction of fight
	UTIL_MakeVectors( m_pAttacker->pev->v_angle );
	m_vecPrepunchDir = gpGlobals->v_forward;
	// Copy over
	m_pDefenderMelee->m_vecPrepunchDir = m_vecPrepunchDir;

	// Place attacker origin infront of defender
	vec3_t vecDir = -m_vecPrepunchDir;
	// Move player origin
	UTIL_SetOrigin(m_pAttacker->pev, m_pDefender->pev->origin + vecDir * 9 );
	// Set angles
	UTIL_Model_MeleeStruggle_Anglefix(m_pAttacker->entindex(), UTIL_VecToAngles(vecDir));
}

/*
* Stop Struggle Attack
*/
void CPlayerMelee::StopStruggleAttack( void )
{	if(m_eAdvMeleeStatus == STRUGGLE_ATTACK)
	{	
		// Reset varibles
		m_iStrugArrowCount = 0;
		m_flStrugArrow = 0;
		m_fForceAtkDirs = FALSE;
		m_fForceDfdDirs = FALSE;
		m_fStopStruggle = FALSE;

		// Reset all directions
		DelAllDirections();

		// Reset Anims
		RemoveAllAnims();

		// Stop movement
		m_pAttacker->pev->vuser4 = Vector(0,0,0);

		// Call defenders function
		m_pDefenderMelee->StopStruggleAttack();
	}
	else if(m_eAdvMeleeStatus == STRUGGLE_DEFEND)
	{	
		// Reset varibles
		m_iStrugArrowCount = 0;
		m_flStrugArrow = 0;
		m_fForceAtkDirs = FALSE;
		m_fForceDfdDirs = FALSE;
		m_fStopStruggle = FALSE;

		// Reset all directions
		DelAllDirections();

		// Reset Anims
		RemoveAllAnims();

		// Stop movement
		m_pAttacker->pev->vuser4 = Vector(0,0,0);
	}
}

/*
* Manage Struggle Arrows
*/
void CPlayerMelee::ManageStruggleArrows( void )
{	if(IsAttacker())
	{	// Time to emit another arrow
		if(gpGlobals->time > m_flStrugArrow)
		{	// Stop struggle
			if(m_fStopStruggle)
			{	CheckStruggleArrows();
				return;
			}

			m_iStrugArrowCount++;
			
			// Add Delay
			if(m_iStrugArrowCount >= melee_struggle_maxarrows.value)
			{	m_flStrugArrow = gpGlobals->time + melee_struggle_enddelay.value;
				m_fStopStruggle = TRUE;
			}
			else
			{	m_flStrugArrow = gpGlobals->time + melee_struggle_arrowtime.value;
			}

			// Force atk flags
			m_fForceAtkDirs = TRUE;
			m_pDefenderMelee->m_fForceAtkDirs = TRUE;

			// Emit directions
			AddDirection( DirectionsToFlags( RANDOM_LONG( PUNCH_UP, PUNCH_UPPERRIGHT ) ) );
			LetGoDirection(m_pAttackerMoves);
			m_pDefenderMelee->AddDirection( DirectionsToFlags( RANDOM_LONG( PUNCH_UP, PUNCH_UPPERRIGHT ) ) );
			m_pDefenderMelee->LetGoDirection(m_pDefenderMelee->m_pAttackerMoves);

			// disabled forced atk flags
			m_fForceAtkDirs = FALSE;
			m_pDefenderMelee->m_fForceAtkDirs = FALSE;
		}
	}

	m_fForceAtkDirs = FALSE;
	m_fForceDfdDirs = TRUE;
	SetBlockingDirections();
	m_fForceDfdDirs = FALSE;
}

/*
* Check Struggle Arrows ( when the struggle is complete and ready to execute )
*/
void CPlayerMelee::CheckStruggleArrows( void )
{
	float flPlayerBlkRatio = PredictBlockRatio( GetAttackerMoves(), GetDefenderMoves(), 1 );
	float flOtherBlkRatio = PredictBlockRatio( m_pDefenderMelee->GetAttackerMoves(), m_pDefenderMelee->GetDefenderMoves(), 1 );

	// Again!
	if(flPlayerBlkRatio == flOtherBlkRatio)
	{	// Send Message
		MeleeText( MELEETXT_TIE, 0 );
		m_pDefenderMelee->MeleeText( MELEETXT_TIE, 0 );

		// Increase switches
		m_iSwitch++;

		if(m_iSwitch >= melee_struggle_maxextanges.value)
		{	StopMelee();
			return;
		}

		// Remove arrow directions
		MeleeHudDisable();
		m_pDefenderMelee->MeleeHudDisable();
		DelAllDirections();
		m_pDefenderMelee->DelAllDirections();


		// Try struggle again
		RetryStruggleAttack();

		// emit retry sound
		EMIT_SOUND(GetSoundEdict(), CHAN_BODY, "weapons/meleestruggletie.wav", 1.0, ATTN_NORM);
	}
	// Attacker wins
	else if(flPlayerBlkRatio > flOtherBlkRatio)
	{	// Send Message
		MeleeText( MELEETXT_WINNER, 0 );
		m_pDefenderMelee->MeleeText( MELEETXT_LOOSER, 0 );

		// stop struggle and do combo
		StopStruggleAttack();
		WinStruggle();

	}
	// Defender wins
	else
	{	// Send Message
		MeleeText( MELEETXT_LOOSER, 0 );
		m_pDefenderMelee->MeleeText( MELEETXT_WINNER, 0 );

		// stop struggle and do combo
		CPlayerMelee *pOther = m_pDefenderMelee;
		SimpleSwitch( pOther, 0, DISABLED );
		pOther->WinStruggle();
	}
}


/*
* Struggle Win Knockback
*/
void CPlayerMelee::WinStruggle( void )
{	m_fManualExe = TRUE;
	SetMode(EXE_ATTACK);

	// Remove previous model manisp
	UTIL_Model_RemoveAll( m_pAttacker->entindex() );
	UTIL_Model_RemoveAll( m_pDefender->entindex() );

	// Connect models clientside
	UTIL_Model_Connect( m_pAttacker->entindex(), m_pDefender->entindex(), 11 );

	// Set angles
	if(m_fOrigDefender)
	{	UTIL_Model_MeleeStruggle_Anglefix(m_pAttacker->entindex(), UTIL_VecToAngles(m_vecPrepunchDir));
	}
	else
	{	UTIL_Model_MeleeStruggle_Anglefix(m_pAttacker->entindex(), UTIL_VecToAngles(-m_vecPrepunchDir));
	}

	melee_execution_s *pMove = NULL;
	m_pExeStart = NULL;
	m_pExeCurrent = NULL;

	// Add Combo
	pMove = AddExeMove( SetupCombo(COMBOMOVE_1) );
	pMove->eBlock = BLOCK_FAIL;
	// Add Left/Right Strong Kick/Punch
	int iFlags = IN_ATTACK2;
	iFlags |= (RANDOM_LONG(0,1) ? IN_LEFT : IN_RIGHT);
	char szAnim[256];
	GetAnimForMove( iFlags, STRONG_HIT, szAnim );

	pMove = AddExeMove( CreateExeMove( iFlags, 0, 0.35, 1, COMBO_NONE, STRONG_HIT, szAnim) );
	pMove->eBlock = BLOCK_FAIL;
	pMove->fForceZStrait = FALSE;

	m_pExeCurrent = m_pExeStart;

	NewExeMovePost();
}


/*
* Handle Struggle Attack
*/
void CPlayerMelee::HandleStruggleAttack( void )
{	ManageStruggleArrows();
}

/*
* Handle Burst Struggle Attack
*/
void CPlayerMelee::HandleBurstStruggleAttack( void )
{	ManageStruggleArrows();
}

/*
* Handle Struggle defend
*/
void CPlayerMelee::HandleStruggleDefend( void )
{	ManageStruggleArrows();
}

/*
* Start Knockback - prepunch Attack
*/
void CPlayerMelee::StartKnockPreStruggle( void )
{	// emit damage for knockbacker
	EmitShockwave();
	m_pAttacker->TakeDamage(m_pDefender->pev, m_pDefender->pev, (int)(POWERHIT_DAMAGE * GetPowerRatio(m_pAttacker)), DMG_KICK);
	if(!m_pAttacker->IsAlive())
	{	return;
	}
	
	// Set "connection" clientside
	UTIL_Model_Connect( m_pAttacker->entindex(), m_pDefender->entindex(), 11 );

	// Set animations
	m_pDefenderMelee->AddAnimation(true, gpGlobals->time, 1, "blow_kick_front");
	AddAnimation(true, gpGlobals->time, 1, "hit_blow_back");

	m_flPreKnockStrug = gpGlobals->time + 0.75;

	// Set direction of fight
	UTIL_MakeVectors( m_pAttacker->pev->v_angle );
	m_vecPrepunchDir = gpGlobals->v_forward;
	// Copy over
	m_pDefenderMelee->m_vecPrepunchDir = m_vecPrepunchDir;

	// knocback mode
	m_fPreKnockStrug = TRUE;

	// Place attacker origin infront of defender
	vec3_t vecDir = -m_vecPrepunchDir;
	// Move player origin
	UTIL_SetOrigin(m_pAttacker->pev, m_pDefender->pev->origin + vecDir * 9 );
	// Set angles
	UTIL_Model_MeleeStruggle_Anglefix(m_pAttacker->entindex(), UTIL_VecToAngles(vecDir));

	// Melee text output
	MeleeText( MELEETXT_HEADON, 0 );
	MeleeText( MELEETXT_KNOCKBACK, 0 );
	m_pDefenderMelee->MeleeText( MELEETXT_HEADON, 0 );
	m_pDefenderMelee->MeleeText( MELEETXT_KNOCKBACK, 0 );
}

/*
* Handle Knockback - prepunch attack
*/
void CPlayerMelee::HandleKnockPreStruggleAttack ( void )
{	if(m_flPreKnockStrug < gpGlobals->time)
	{	// Set mode
		SetMode(PREPUNCH_ATTACK);
		// Melee text output
		MeleeText( MELEETXT_PREPUNCH, 0 );
		m_pDefenderMelee->MeleeText( MELEETXT_PREPUNCH, 0 );
	}
}

/*
* Blowback struggle ( knocback vs knockback )
*/
void CPlayerMelee::BlowbackStruggle( vec3_t vecDirection, float flPlayerSwoop, float flOtherSwoop, CBasePlayer *pOther )
{	CBasePlayer *pWinner;
	CBasePlayer *pLooser;

	// Set winner/looser
	if((flPlayerSwoop > flOtherSwoop) && m_pAttacker->UseKi(BLOW_KICK_KI_COST))
	{	pWinner = m_pAttacker;
		pLooser = pOther;
	}
	else if(pOther->UseKi(BLOW_KICK_KI_COST))
	{	pWinner = pOther;
		pLooser = m_pAttacker;
		vecDirection = -vecDirection;
	}
	// Both players have no KI
	else
	{	StartToss( pOther, FALSE, -vecDirection, 700, 400, 200, 1 );
		pOther->m_Melee.StartToss( m_pAttacker, FALSE, vecDirection, 700, 400, 200, 1 );
		return;
	}

	// Knock players back
	if(m_fSimpleMelee)
	{	pWinner->m_Melee.Powerhit( FALSE, pLooser, vecDirection, FRONT, POWERHIT_DAMAGE*1.1, 1400, 800, 450, 1.5 );
	/*	if(pLooser->IsAlive())
			pLooser->m_Melee.Powerhit( FALSE, pWinner, -vecDirection, FRONT, POWERHIT_DAMAGE*0.65, 1400, 800, 450, 1.5 );*/
	}
	else
	{	pWinner->m_Melee.Powerhit( FALSE, pLooser, vecDirection, FRONT, POWERHIT_DAMAGE*1.1, 900, 500, 300, 1.5 );
		if(pLooser->IsAlive())
			pLooser->m_Melee.Powerhit( FALSE, pWinner, -vecDirection, FRONT, POWERHIT_DAMAGE*0.65, 900, 500, 300, 1.5 );
	}
}

/*
* Emit Shockwave
*/
void CPlayerMelee::EmitShockwave( void )
{	// Send msg to local clients
	MESSAGE_BEGIN( MSG_PVS, gmsgMeleeFX, m_pAttacker->pev->origin);
		WRITE_BYTE (MELEE_SIMPLE);
		WRITE_BYTE ( m_pAttacker->entindex() );
	MESSAGE_END();

	// Emit Sound
//	EMIT_SOUND(GetSoundEdict(), CHAN_WEAPON, "weapons/meleeflash.wav", 1.0, ATTN_NORM);
	EmitClientSound(GetSoundEdict(), CHAN_WEAPON, MELEESOUND_SHOCKWAVE);
}

/*
* Emit Explosion Rocks
*/
void CPlayerMelee::EmitExplosionRocks( Vector vecSrc, Vector vecVelocity, float flSize, int iRandom, int iCount )
{	MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY);
		WRITE_BYTE(TE_BREAKMODEL);		// box of models or sprites
		WRITE_COORD( vecSrc.x );		// coord, coord, coord (position)
		WRITE_COORD( vecSrc.y );
		WRITE_COORD( vecSrc.z );
		WRITE_COORD( flSize );				// coord, coord, coord (size)
		WRITE_COORD( flSize );
		WRITE_COORD( flSize );
		WRITE_COORD( vecVelocity.x );	// coord, coord, coord (velocity)
		WRITE_COORD( vecVelocity.y );
		WRITE_COORD( vecVelocity.z );
		WRITE_BYTE(iRandom);					// byte (random velocity in 10's)
		WRITE_SHORT(g_sRockGibs);		// short (sprite or model index)
		WRITE_BYTE(iCount);				// byte (count)
		WRITE_BYTE(50);					// byte (life in 0.1 secs)
		WRITE_BYTE(0);					// byte (flags)
	MESSAGE_END();
}

/*
* Can Block Attack
*/
BOOL CPlayerMelee::BlocksAttack( 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.GetEnemyPrepunch(m_pAttacker))
		{	return true;
		}
	}
	return false;
}

/* Added by Rick
*
* Can Block Attack, buddy version
*/
BOOL CPlayerMelee::BlocksAttack( 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.GetNearestPlayerToMelee(m_pAttacker))
		{	return true;
		}
	}
	return false;
}
// End add by Rick
/*
* Set Powerhit Anim
*/
void CPlayerMelee::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;
		}
	}

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

/*
* Powerhit
*/
BOOL CPlayerMelee::Powerhit( CBasePlayer *pOther, Vector vecDirection, int iDirection, float flDamage, float flMaxSpeed, float flMinSpeed, float flDeacceleration, float flMinRecoverTime )
{	return Powerhit(TRUE, pOther, vecDirection, iDirection, flDamage, flMaxSpeed, flMinSpeed, flDeacceleration, flMinRecoverTime);
}

/*
* Powerhit (animation optional)
*/
BOOL CPlayerMelee::Powerhit( BOOL fPlayAnim, CBasePlayer *pOther, Vector vecDirection, int iDirection, float flDamage, float flMaxSpeed, float flMinSpeed, float flDeacceleration, float flMinRecoverTime )
{	if(!m_pAttacker)
		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_pAttacker->pev, m_pAttacker->pev, ((int)(flDamage * GetPowerRatio(pOther)) * 1.4), DMG_KICK);
	else
		pOther->TakeDamage(m_pAttacker->pev, m_pAttacker->pev, ((int)(flDamage * GetPowerRatio(pOther))), DMG_KICK);
	EmitShockwave();
	if(fPlayAnim)
		SetPowerhitAnim( vecDirection, iDirection );

	if(pOther->IsAlive())
	{	// Toss
		if(BlocksAttack(pOther) ? !pOther->UseKi(BLOCK_BLOW_KI_COST) : true )
		{	pOther->m_Melee.StartToss( m_pAttacker, 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;
}

// Added by Rick: Buddy version
/*
* Powerhit (animation optional)
*/
BOOL CPlayerMelee::Powerhit( BOOL fPlayAnim, CBuddy *pOther, Vector vecDirection, int iDirection, float flDamage, float flMaxSpeed, float flMinSpeed, float flDeacceleration, float flMinRecoverTime )
{	if(!m_pAttacker)
		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_pAttacker->pev, m_pAttacker->pev, ((int)(flDamage * GetPowerRatio(pOther)) * 1.4), DMG_KICK);
	else
		pOther->TakeDamage(m_pAttacker->pev, m_pAttacker->pev, ((int)(flDamage * GetPowerRatio(pOther))), DMG_KICK);
	EmitShockwave();
	if(fPlayAnim)
		SetPowerhitAnim( vecDirection, iDirection );

	if(pOther->IsAlive())
	{	// Toss
		if(BlocksAttack(pOther) ? !pOther->UseKi(BLOCK_BLOW_KI_COST) : true )
		{	pOther->m_Toss.StartToss( m_pAttacker, 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;
}
// End add by Rick
/*
* Default Powerhit
*/
BOOL CPlayerMelee::Powerhit( CBasePlayer *pOther, Vector vecDirection, int iDirection )
{	// If you're on the ground, force upwards direction
	if(FBitSet(m_pAttacker->pev->flags, FL_ONGROUND))
	{	TraceResult tr;

		// Traceline to ensure we're not standing on a player
		UTIL_TraceHull(m_pAttacker->pev->origin, m_pAttacker->pev->origin + Vector(0,0,-16), dont_ignore_monsters, human_hull, ENT(m_pAttacker->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( 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( pOther, vecDirection, iDirection, (pOther->m_Melee.m_fThrown ? POWERHIT_DAMAGE * 1.5 : POWERHIT_DAMAGE),
			 800, 400, 250, 1.2 );
}

/* Added by Rick
*
* Default Powerhit, buddy version
*/
BOOL CPlayerMelee::Powerhit( CBuddy *pOther, Vector vecDirection, int iDirection )
{	// If you're on the ground, force upwards direction
	if(FBitSet(m_pAttacker->pev->flags, FL_ONGROUND))
	{	TraceResult tr;

		// Traceline to ensure we're not standing on a player
		UTIL_TraceHull(m_pAttacker->pev->origin, m_pAttacker->pev->origin + Vector(0,0,-16), dont_ignore_monsters, human_hull, ENT(m_pAttacker->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 );
}
// End add by Rick


/*
* Simple Melee Powerhit
*/
void CPlayerMelee::SimpleMeleePowerhit( CBasePlayer *pOther, Vector vecDirection, int iDirection )
{
	// If you're on the ground, force upwards direction
	if(FBitSet(m_pAttacker->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 );
}

// Added by Rick : Buddy version of SimpleMeleePowerhit
void CPlayerMelee::SimpleMeleePowerhit( CBuddy *pOther, Vector vecDirection, int iDirection )
{
	// If you're on the ground, force upwards direction
	if(FBitSet(m_pAttacker->pev->flags, FL_ONGROUND))
	{	vecDirection = Vector(0,0,1);
		iDirection = UP;
	}

	Powerhit(TRUE, pOther, vecDirection, iDirection, (pOther->m_bThrown ? BLOW_KICK_DAMAGE * 1.5 : BLOW_KICK_DAMAGE),
			 1600, 500, 400, 1.75 );
}
// End add by Rick

#endif
