#include "stdafx.h"
#include "SkillExecuter.h"

#include "SkillManager.h"
#include "ObjectManager.h"
#include "Hero.h"
#include "monster.h"
#include "protocol.h"

#include "skillscript.h"
#include "TotemScript.h"
#include "GameUIManager.h"
#include "SkillWindow.h"

#include "ItemManager.h"
#include "chatmanager.h"
#include "GameResourceManager.h"
#include "QuickManager.h"
#include "UICursor.h"
#include "CastingBar.h"

#include "DuelManager.h"
#include "PVPManager.h"

//////////////////////////////////////////////////////////////////////////
unsigned int cAttackPattern::GetAttackFlag()
{
	bool newPattern = false;
	if( mPatternIdx < 0 || mPatternIdx > 2 )
		newPattern = true;
	if( mProgressIdx > 5 )
		newPattern = true;

	if( newPattern == true )
	{
		/// 새로 생성
		unsigned int r = ::rand()%1000;
		if( r < 330 )		mPatternIdx = 0;
		else if( r < 660 )	mPatternIdx = 1;
		else				mPatternIdx = 2;

		mProgressIdx = 0;
	}
	else
	{
		if( mPattern[mPatternIdx][mProgressIdx] == -1 )
		{
			/// 새로 생성
			unsigned int r = ::rand()%1000;
			if( r < 330 )		mPatternIdx = 0;
			else if( r < 660 )	mPatternIdx = 1;
			else				mPatternIdx = 2;

			mProgressIdx = 0;
		}
	}

	int curIdx = mPattern[mPatternIdx][mProgressIdx];
	if( mOldAttackIdx == curIdx )
	{
		mProgressIdx++;

		if( mProgressIdx > 5 )
		{
			assert(0);
		}

		if( curIdx == mPattern[mPatternIdx][mProgressIdx] )
		{
			int a = 0;
			a = 1;
		}

	}

	mOldAttackIdx = mPattern[mPatternIdx][mProgressIdx];
	mProgressIdx++;

	return (unsigned int)mOldAttackIdx;
}

//////////////////////////////////////////////////////////////////////////
cSkillExecuter* cSkillExecuter::mpExec = NULL;

cSkillExecuter::cSkillExecuter()
{
	if(mpExec) assert(0);
	mpExec = this;

	mIsCharge = false;
	mIsFieldCheck = false;

	mChargeSkillIdx = ULONG_MAX;
	mSkillRange = FLT_MAX;

	mAttackTarget.index = 0;
	mAttackTarget.type = eOBJECTTYPE_NONE;

	mpCurrentHeroSkillObject = 0;
}

cSkillExecuter::~cSkillExecuter()
{
}

void cSkillExecuter::Close()
{
	mIsCharge = false;
	mIsFieldCheck = false;

	mChargeSkillIdx = ULONG_MAX;
	mSkillRange = FLT_MAX;

	mAttackTarget.index = 0;
	mAttackTarget.type = eOBJECTTYPE_NONE;

	mpCurrentHeroSkillObject = 0;
}

bool cSkillExecuter::AutoAttack( cBaseObject* pTarget )
{
	/// 서버로부터 무기교체완료 메세지 받기전까지 스킬 사용 불가
	if( HERO->IsWeaponChanging() == true )
		return true;

	if( pTarget == 0 )
		return false;

	if( HERO->IsTransformMonster() )
	{
		unsigned long skillIdx = GenerateTransMonsAttackIdx();
		if( skillIdx > eMONSTERATTACK_NORMAL2 )
		{
			assert(0);
		}

		return AutoAttack_TransMon( skillIdx, pTarget );
	}

	/// 스킬 사용 불가
	if( HERO->IsCantSkill( NORMAL_ATTACK_SKILL ) == true )
		return false;


	/// target의 상태 체크..
	unsigned char type = pTarget->GetObjectType();
	switch( type )
	{
	case eOBJECTTYPE_PLAYER:
		{
			cPlayer* pPlayer = (cPlayer*)pTarget;
			if( pPlayer->GetState() == eOBJECT_STATE_DIE )
				return false;

			/// 적인지 여부 판단
			if( DUELMAN->IsDuelEnemy( pPlayer ) != true && 
				PVPMAN->IsEnableAttack( pPlayer ) != true )
				return false;
		}
		break;
	case eOBJECTTYPE_MONSTER:
		{
			cMonster* pMon = (cMonster*)pTarget;
			if( pMon->GetState() == eOBJECT_STATE_DIE )
				return false;
		}
		break;
	default:
		return false;
	}

	/// 기본 공격 인덱스 산정 - 무기, 공격 인덱스
	ChargeOn( NORMAL_ATTACK_SKILL );

	/// 공격 거리 체크 - 후처리기
	HERO->AfterAttack( pTarget );

	return true;
}

bool cSkillExecuter::ExecuteAttack( cBaseObject* pTarget  )
{
	HERO->SetWaitMoveFlag( false );

	/// 080508 PKH 정지 상태일때 일반공격 하면 에니메이션이 바껴서 체크
	if( HERO->GetState() == eOBJECT_STATE_DIE || HERO->GetState() == eOBJECT_STATE_STOP )
		return false;

	/// 서버로부터 무기교체완료 메세지 받기전까지 스킬 사용 불가
	if( HERO->IsWeaponChanging() == true )
		return false;

	if( pTarget == 0 )
		return false;

	if( HERO->IsTransformMonster() )
	{
		unsigned long skillIdx = GenerateTransMonsAttackIdx();
		if( skillIdx > eMONSTERATTACK_NORMAL2 )
		{
			assert(0);
		}

		return ExecuteAttack_TransMon( skillIdx, pTarget );
	}

	/// 현재 보유 Target과 같은 Target을 공격하는 경우
	cBaseObject* pBeforeTarget = OBJECTMAN->GetObject( &mAttackTarget );
	if( pTarget == pBeforeTarget )
	{
		/// cooltime check
		if( SKILLMAN->IsUsedKeepSkill( NORMAL_ATTACK_SKILL ) == false )
			return false;
	}
	else
	{
		/// target window 및 hero 타겟 설정
		HERO->SetTargetObject( pTarget->GetObjectType(), pTarget->GetObjectID() );
	}

	sAfterAction* p = HERO->GetCurrentAfterAction();
	if( p->mActionType == eAfterAction_Attack &&
		p->mTarget.index == pTarget->GetObjectID() )
		return false;

	/// target의 상태 체크..
	unsigned char type = pTarget->GetObjectType();

	switch( type )
	{
	case eOBJECTTYPE_PLAYER:
		{
			cPlayer* pPlayer = (cPlayer*)pTarget;
			if( pPlayer->GetState() == eOBJECT_STATE_DIE )
				return false;

			/// 적인지 여부 판단
			if( DUELMAN->IsDuelEnemy( pPlayer ) != true &&
				PVPMAN->IsEnableAttack( pPlayer ) != true )
				return false;
		}
		break;
	case eOBJECTTYPE_MONSTER:
		{
			cMonster* pMon = (cMonster*)pTarget;
			if( pMon->GetState() == eOBJECT_STATE_DIE )
				return false;
		}
		break;
	default:
		return false;
	}

	/// 기본 공격 인덱스 산정 - 무기, 공격 인덱스
	ChargeOn( NORMAL_ATTACK_SKILL );

	/// 공격 거리 체크 - 후처리기
	HERO->AfterAttack( pTarget );

	ResetAttackFlag();

	mAttackTarget.index = pTarget->GetObjectID();
	mAttackTarget.type = pTarget->GetObjectType();
	return true;
}

/// 타겟을 기준으로 한 스킬에 사용
void cSkillExecuter::ExecuteSkill( unsigned long skillIdx, cBaseObject* pTarget )
{
	if( HERO->IsTransformMonster() )
	{
		ExecuteSkill_TransMon( skillIdx, pTarget );
		return;
	}

	HERO->SetWaitMoveFlag( false );

	ChargeOff( mChargeSkillIdx );

	/// 080508 PKH 정지 상태일때 일반공격 하면 에니메이션이 바껴서 체크
	if( HERO->GetState() == eOBJECT_STATE_DIE || HERO->GetState() == eOBJECT_STATE_STOP )
		return;

	/// 스킬 정보를 획득한다.
	sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( skillIdx );
	if( pInfo == 0 )
	{
		assert(0);
		return;
	}

	if( pInfo->mShotType == eSHOTTYPE_CASTING )
	{
		cCastingBar* pWin = (cCastingBar*)UIMAN->GetContainer( eUIID_GAME_CASTINGBAR );
		if( pWin && pWin->IsVisible() )
			return;
	}

	if( pInfo->mShotType == eSHOTTYPE_AURA )
	{
		cSkillWindow* pSkillWindow = GAMEUI->GetSkillWindow();
		if( pSkillWindow == 0 )
		{
			assert(0);
			return;
		}

		unsigned long uniqueIdx = pSkillWindow->GetAuraUniqueIdx( skillIdx );
		if( uniqueIdx )
		{
			MSG_REQ_INFLUENCE_AURA_DELETE msg;

			msg.Category = NM_SKILL;
			msg.Protocol = NM_SKILL_INFLUENCE_AURA_DELETE_REQ;
			msg.mUniqueIdx = uniqueIdx;
			msg.mSkillClassIdx = skillIdx;
			NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
			return;
		}
	}

	/// 서버로부터 무기교체완료 메세지 받기전까지 스킬 사용 불가
	if( HERO->IsWeaponChanging() == true )
		return;

	if( skillIdx < NORMAL_ATTACK_SKILL_MAX )
	{
		assert(0);
		return;
	}


	/// 사용 가능 여부 체크
	if( IsPossibleUseSkill( skillIdx ) == false )
		return;

	/// 
	bool targetCheck = true;
	if( pTarget == 0 )
		pTarget = HERO->GetTargetObject();

	if( pInfo->mBoundType == eBOUNDTYPE_FIELD )
	{
		/// field base skill
		if( HERO->IsReadyUseSkill() )
			FieldSkillOn( skillIdx );
		return;
	}
	else if( pInfo->mBoundType == eBOUNDTYPE_SELF_NOTARGET )
	{
		/// active
		targetCheck = false;
	}
	else if( pInfo->mBoundType == eBOUNDTYPE_NONE )
	{
		if( pInfo->mApplyType == eAPPLYTYPE_SELF )
			pTarget = HERO;

		targetCheck = true;
	}

	if( targetCheck )
	{
		/// 적용 타겟이 아닌 경우 charge
		if( IsPossibleUseSkillTarget( skillIdx, pTarget ) == false )
		{
			ChargeOn( skillIdx );
			return;
		}

		/// 
		cBaseObject* pBeforeTarget = OBJECTMAN->GetObject( &mAttackTarget );
		if( pTarget == pBeforeTarget )
		{
			/// cooltime check
			if( SKILLMAN->IsUsedKeepSkill( skillIdx ) == false )
				return;
		}

		sAfterAction* p = HERO->GetCurrentAfterAction();
		if( p->mActionType == eAfterAction_UseTargetSkill &&
			p->mExData1 == skillIdx &&
			p->mTarget.index == pTarget->GetObjectID() )
			return;
	}

	/// 스킬 발동
	ChargeOn( skillIdx );
	HERO->AfterUseSkill( pTarget );

	if( pTarget )
		mAttackTarget = *(pTarget->GetTargetInfo());
}

/// BOUNDTYPE = eBOUNDTYPE_FIELD 사용
void cSkillExecuter::ExecuteSkill( unsigned long skillIdx, NiPoint3 applyPos )
{
	if( HERO->IsTransformMonster() )
	{
		ExecuteSkill_TransMon( skillIdx, applyPos );
		return;
	}

	HERO->SetWaitMoveFlag( false );

	ChargeOff( mChargeSkillIdx );

	if( HERO->GetState() == eOBJECT_STATE_DIE )
		return;

	/// 서버로부터 무기교체완료 메세지 받기전까지 스킬 사용 불가
	if( HERO->IsWeaponChanging() == true )
		return;

	if( skillIdx < NORMAL_ATTACK_SKILL_MAX )
	{
		assert(0);
		return;
	}

	sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( skillIdx );
	if( pInfo == 0 )
	{
		assert(0);
		return;
	}

	if( pInfo->mShotType == eSHOTTYPE_CASTING )
	{
		cCastingBar* pWin = (cCastingBar*)UIMAN->GetContainer( eUIID_GAME_CASTINGBAR );
		if( pWin && pWin->IsVisible() )
			return;
	}

	/// 사용 가능 여부 체크
	if( IsPossibleUseSkill( skillIdx ) == false )
		return;

	if( pInfo->mBoundType != eBOUNDTYPE_FIELD )
		return;

	sAfterAction* p = HERO->GetCurrentAfterAction();
	if( p->mActionType == eAfterAction_UseFieldSkill &&
		p->mExData1 == skillIdx )
		return;

	ChargeOn( skillIdx );
	HERO->AfterUseSkill( applyPos );
}

bool cSkillExecuter::IsPossibleUseSkill( unsigned long skillIdx )
{
	if( HERO->IsTransformMonster() )
		return IsPossibleUseSkill_TransMon( skillIdx );

	if( HERO->GetState() == eOBJECT_STATE_DIE )
		return false;

	/// 서버로부터 무기교체완료 메세지 받기전까지 스킬 사용 불가
	if( HERO->IsWeaponChanging() == true )
		return false;

	sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( skillIdx );
	if( pInfo == 0 )
	{
		assert(0);
		return false;
	}

	/// TODO : 보유 스킬인지 체크 및 쿨타임 체크
	if( SKILLMAN->IsUsedKeepSkill( skillIdx ) == false )
		return false;

	sKeepSkill* keep =  SKILLMAN->GetKeepInfo( skillIdx );
	if( keep == 0 )
	{
		assert(0);
		return false;
	}
	if( pInfo->mStepCount <= keep->mStep )
	{
		assert(0);
		return false;
	}

	sPlayerSkillStepInfo* pStepInfo = &pInfo->mpSetpInfoArray[keep->mStep];

	/// 소모 아이템 보유 여부 체크
	if( pInfo->mUseItem )
	{
		/// 인벤 체크
		unsigned int count = ITEMMAN->GetItemCount( pInfo->mUseItem );
		if( count < pStepInfo->mUseItemCount )
			return false;
	}

	if( HERO->GetLevel() < pStepInfo->mPlayerLevel )
		return false;

	/// 내 장비가 맞는지 체크
	if( pInfo->mUseEquipment )
	{
		eWEAPON_STATE weaponState = HERO->GetWeaponState();

		/// 착용 장비 체크
		switch( pInfo->mUseEquipment )
		{
		case eEQUIPTYPE_SWORD:
			if( weaponState != eWEAPON_STATE_SWORD &&
				weaponState != eWEAPON_STATE_SWORD_SHEILD )
				return false;
			break;
		case eEQUIPTYPE_LONGSWORD:
			if( weaponState != eWEAPON_STATE_LONGSWORD )
				return false;
			break;
		case eEQUIPTYPE_DOUBLESWORD:
			if( weaponState != eWEAPON_STATE_DOUBLESWORD )
				return false;
			break;
		case eEQUIPTYPE_SHORTSWORD:
			if( weaponState != eWEAPON_STATE_SHORTSWORD )
				return false;
			break;
		case eEQUIPTYPE_GUN:
			if( weaponState != eWEAPON_STATE_GUN )
				return false;
			break;
		case eEQUIPTYPE_STAFF:
			if( weaponState != eWEAPON_STATE_STAFF )
				return false;
			break;
		case eEQUIPTYPE_SHIELD:
			if( weaponState != eWEAPON_STATE_SHEILD &&
				weaponState != eWEAPON_STATE_SWORD_SHEILD )
				return false;
			break;
		case eEQUIPTYPE_SWORD_LONGSWORD:
			if( weaponState != eWEAPON_STATE_SWORD &&
				weaponState != eWEAPON_STATE_SWORD_SHEILD &&
				weaponState != eWEAPON_STATE_LONGSWORD )
				return false;
			break;
		case eEQUIPTYPE_SWORD_DOUBLESWORD:
			if( weaponState != eWEAPON_STATE_SWORD &&
				weaponState != eWEAPON_STATE_SWORD_SHEILD &&
				weaponState != eWEAPON_STATE_DOUBLESWORD )
				return false;
			break;
		case eEQUIPTYPE_LONGSWORD_DOUBLESWORD:
			if( weaponState != eWEAPON_STATE_LONGSWORD &&
				weaponState != eWEAPON_STATE_DOUBLESWORD )
				return false;
			break;
		case eEQUIPTYPE_SWORD_LONGSWORD_DOUBLESWORD:
			if( weaponState != eWEAPON_STATE_SWORD &&
				weaponState != eWEAPON_STATE_SWORD_SHEILD &&
				weaponState != eWEAPON_STATE_LONGSWORD &&
				weaponState != eWEAPON_STATE_DOUBLESWORD )
				return false;
			break;
		case eEQUIPTYPE_SHORTSWORD_GUN:
			if( weaponState != eWEAPON_STATE_SHORTSWORD &&
				weaponState != eWEAPON_STATE_GUN )
				return false;
			break;
		case eEQUIPTYPE_CLOTH:
			if( HERO->GetArmorSets() != ARMOR_SETS_ROBES )
				return false;
			break;
		case eEQUIPTYPE_LIGHTARMOR:
			if( HERO->GetArmorSets() != ARMOR_SETS_LIGHT_ARMOR )
				return false;
			break;
		case eEQUIPTYPE_HEAVYARMOR:
			if( HERO->GetArmorSets() != ARMOR_SETS_HEAVY_ARMOR )
				return false;
			break;
		}
	}

	/// 사용 상태가 맞는지 체크
	if( pInfo->mUseState )
	{
		/// 캐릭터 상태 체크
		pStepInfo->mUseStateValue;
	}

	/// 소모 HP, MP 체크
	if( HERO->GetHP() < pStepInfo->mUseHP )
	{
		return false;
	}
	if( HERO->GetMP() < pStepInfo->mUseMP )
	{
		CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6001 ) );
		return false;
	}

//	if( pInfo->mBoundType == eBOUNDTYPE_FIELD )
//		return true;

	return true;
}

bool cSkillExecuter::IsPossibleUseSkillTarget( unsigned long skillIdx, cBaseObject* pTarget )
{
	if( HERO->IsTransformMonster() )
		return IsPossibleUseSkillTarget_TransMon( skillIdx, pTarget );

	sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( skillIdx );
	if( pInfo == 0 )
	{
		assert(0);
		return false;
	}

	/// 타겟이 없어도 발동하는 스킬
	/// 1. 타겟이 자기 자신인 경우
	/// 2. 타겟이 없는 범위 스킬인 경우
	/// 그 외는 모두 발동 불가
	if( pInfo->mApplyType != eAPPLYTYPE_SELF &&
		pInfo->mBoundType != eBOUNDTYPE_SELF_NOTARGET )
	{
		if( pTarget == 0 )
			return false;

		if( pInfo->mApplyType == eAPPLYTYPE_DIEBUDDY )
		{
			if( pTarget->GetState() == eOBJECT_STATE_DIE )
			{
				if( pTarget->GetObjectType() == eOBJECTTYPE_PLAYER )
				{
					/// 적인지 아군인지 구분
					if( DUELMAN->IsDuelEnemy( (cPlayer*)pTarget ) ||
						PVPMAN->IsEnableAttack( (cPlayer*)pTarget ) )
						return false;

					return true;
				}
			}
			return false;
		}
		else
		{
			if( pTarget->GetState() == eOBJECT_STATE_DIE )
			{
				return false;
			}
		}

		unsigned char type = pTarget->GetObjectType();
		switch( type )
		{
		case eOBJECTTYPE_HERO:
			{
				if( pInfo->mApplyType == eAPPLYTYPE_ENEMY )
					return false;
			}
			break;
		case eOBJECTTYPE_MONSTER:
			{
				if( pInfo->mApplyType != eAPPLYTYPE_ENEMY )
					return false;
			}
			break;
		case eOBJECTTYPE_PLAYER:
			{
//				if( pInfo->mApplyType == eAPPLYTYPE_PARTY )
//				{
//					return false;
//				}
//				else if( pInfo->mApplyType == eAPPLYTYPE_BUDDY )
//				{
//					/// 적군이냐?
//					return false;
//				}
//				else if( pInfo->mApplyType == eAPPLYTYPE_ENEMY )
				if( pInfo->mApplyType == eAPPLYTYPE_ENEMY )
				{
					if( DUELMAN->IsDuelEnemy( (cPlayer*)pTarget ) ||
						PVPMAN->IsEnableAttack( (cPlayer*)pTarget ) )
						return true;

					return false;
				}
			}
			break;
		default: 
			return false;
		}
	}

	return true;
}

void cSkillExecuter::ChargeOn( unsigned long skillIdx )
{
	if( IsSkillCharge() )
	{
		ChargeOff( mChargeSkillIdx );
		return;
	}

	/// 
	if( HERO->IsTransformMonster() )
	{
		ChargeOn_TransMon( skillIdx );
		return;
	}

	if( skillIdx < NORMAL_ATTACK_SKILL_MAX )
	{
		unsigned int state = (unsigned int)HERO->GetWeaponState();
		if( state > eWEAPON_STATE_MAX )
			state -= eWEAPON_STATE_SHEILD;

		unsigned int flag = 0;//mAttackPattern.GetAttackFlag();
		mChargeSkillIdx = flag*10 + state + 1;
	}
	else
	{
		mChargeSkillIdx = skillIdx;
	}
	
	sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( mChargeSkillIdx );
	assert(pInfo);

	if( SKILLMAN->IsUsedKeepSkill( skillIdx ) == false )
	{
//		assert(0);
		return;
	}
	sKeepSkill* keep =  SKILLMAN->GetKeepInfo( skillIdx );
	if( keep == 0 )
	{
		assert(0);
		return;
	}
	if( pInfo->mStepCount <= keep->mStep )
	{
		assert(0);
		return;
	}

	/// skill step은 획득한다. 추가해야 한다.
	mSkillRange = pInfo->mpSetpInfoArray[keep->mStep].mTargetDist;

	/// 080225 PKH 스킬+아이템+효과 사거리
	mSkillRange = HERO->CalcStatusSkillRange( mSkillRange, pInfo->mRangeType, mChargeSkillIdx < NORMAL_ATTACK_SKILL_MAX );

	/// 퀵슬롯 스킬에 차지 세팅
	QUICKMAN->SetCharge( skillIdx, true );
	CURSOR->SetCursor( eCURSOR_SKILL );

	mIsCharge = true;
}

void cSkillExecuter::ChargeOff( unsigned long skillIdx )
{
	/// 
	if( HERO->IsTransformMonster() )
	{
		ChargeOff_TransMon( skillIdx );
		return;
	}

	if( mChargeSkillIdx != skillIdx )
		return;

	mIsCharge = false;
	mIsFieldCheck = false;

	/// 퀵슬롯 스킬에 차지 세팅
	QUICKMAN->SetCharge( skillIdx, false );
	CURSOR->SetCursor( eCURSOR_DEFAULT );
}

bool cSkillExecuter::IsSkillCharge()
{
	if( mIsCharge == false )
		return false;

	if( HERO->IsTransformMonster() )
	{
		if( mChargeSkillIdx < eMONSTERATTACK_SKILL1 )
			return false;
	}
	else
	{
		if( mChargeSkillIdx < NORMAL_ATTACK_SKILL_MAX )
			return false;
	}

	return true;
}

unsigned long cSkillExecuter::GetChargeSkill()
{
	/// 
	if( HERO->IsTransformMonster() )
		return mChargeSkillIdx;


	if( mChargeSkillIdx < NORMAL_ATTACK_SKILL_MAX )
	{
		unsigned int state = (unsigned int)HERO->GetWeaponState();
		if( state > eWEAPON_STATE_MAX )
			state -= eWEAPON_STATE_SHEILD;

		unsigned int flag = mAttackPattern.GetAttackFlag();
		unsigned long skillIdx = flag*10 + state + 1;

		if( skillIdx != mChargeSkillIdx )
		{
			/// 무기가 교체된 경우는 사정거리 재계산
			mChargeSkillIdx = skillIdx;

			sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( mChargeSkillIdx );
			assert(pInfo);

			if( pInfo->mStepCount == 0 )
			{
				assert(0);
			}

			mSkillRange = pInfo->mpSetpInfoArray[0].mTargetDist;

			/// 080225 PKH 스킬+아이템+효과 사거리
			mSkillRange = HERO->CalcStatusSkillRange( mSkillRange, pInfo->mRangeType, true );

		}
	}
	return mChargeSkillIdx;
}

///

unsigned long cSkillExecuter::GenerateTransMonsAttackIdx()
{
	unsigned long monsterClassIdx = HERO->GetTransMonsterClassIdx();

	/// monster skill
	unsigned long rd = ::rand() % mTotalMonsterAttackPer + 1;

	sMonsterSkillScript* info;
	/// 기본 공격중에 조건을 만족하는 것을 리턴한다.
	for( unsigned int i=0;i<eMONSTERATTACK_SKILL1;i++ )
	{
		if( mMonsterAttackInfo[i].mUsePer == 0 )
			continue;

		info = SKILLSCRIPT->GetMonsterSkillInfo( monsterClassIdx, (eMONSTERATTACK_TYPE)i );
		if( info == 0 )
			continue;
		if( info->mUseMP > HERO->GetMP() )
			continue;

		if( mMonsterAttackInfo[i].mUsePer <= rd )
			return i;
	}

	return eMONSTERATTACK_NORMAL1;
}

void cSkillExecuter::ChargeOn_TransMon( unsigned long skillIdx )
{
	if( skillIdx >= eMONSTERATTACK_MAX )
	{
		assert(0);
		return;
	}

	mIsCharge = true;
	CURSOR->SetCursor( eCURSOR_SKILL );

	mChargeSkillIdx = skillIdx;

	mSkillRange = mMonsterAttackInfo[mChargeSkillIdx].mRange;

	QUICKMAN->SetMonCharge( skillIdx, true );
}

void cSkillExecuter::ChargeOff_TransMon( unsigned long skillIdx )
{
	if( mIsCharge == false )
		return;

	if( skillIdx >= eMONSTERATTACK_MAX )
	{
		assert(0);
		return;
	}

	mIsCharge = false;
	mIsFieldCheck = false;

	CURSOR->SetCursor( eCURSOR_DEFAULT );
	QUICKMAN->SetMonCharge( skillIdx, false );
}

void cSkillExecuter::SetMonsterSkillInfo( unsigned long monsterClassIdx )
{
	mTotalMonsterAttackPer = 0;

	sMonsterSkillScript* info;
	for( unsigned int i=0;i<eMONSTERATTACK_MAX;i++ )
	{
		mMonsterAttackInfo[i].mUsePer = 0;

		info = SKILLSCRIPT->GetMonsterSkillInfo( monsterClassIdx, (eMONSTERATTACK_TYPE)i );
		if( info == 0 )
			continue;

		mMonsterAttackInfo[i].mUsePer = info->mSkillUsePer;
		mMonsterAttackInfo[i].mRange = info->mTargetDist;

		if( i < eMONSTERATTACK_SKILL1 )
			mTotalMonsterAttackPer += mMonsterAttackInfo[i].mUsePer;
	}
}

bool cSkillExecuter::IsPossibleUseSkill_TransMon( unsigned long skillIdx )
{
	if( HERO->GetState() == eOBJECT_STATE_DIE )
		return false;

	/// 서버로부터 무기교체완료 메세지 받기전까지 스킬 사용 불가
	if( HERO->IsWeaponChanging() == true )
		return false;

	unsigned long monsterClassIdx = HERO->GetTransMonsterClassIdx();
	if( monsterClassIdx == 0 )
		return false;

	sMonsterSkillScript* pInfo = SKILLSCRIPT->GetMonsterSkillInfo( monsterClassIdx, (eMONSTERATTACK_TYPE)skillIdx );
	if( pInfo == 0 )
		return false;

	/// 소모 MP 체크
	if( HERO->GetMP() < pInfo->mUseMP )
	{
		CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6001 ) );
		return false;
	}
//	if( pInfo->mBoundType == eBOUNDTYPE_FIELD )
//		return true;

	return true;
}

bool cSkillExecuter::IsPossibleUseSkillTarget_TransMon( unsigned long skillIdx, cBaseObject* pTarget )
{
	unsigned long monsterClassIdx = HERO->GetTransMonsterClassIdx();
	if( monsterClassIdx == 0 )
		return false;

	sMonsterSkillScript* pInfo = SKILLSCRIPT->GetMonsterSkillInfo( monsterClassIdx, (eMONSTERATTACK_TYPE)skillIdx );
	if( pInfo == 0 )
		return false;

	/// 타겟이 없어도 발동하는 스킬
	/// 1. 타겟이 자기 자신인 경우
	/// 2. 타겟이 없는 범위 스킬인 경우
	/// 그 외는 모두 발동 불가
	if( pInfo->mApplyType != eAPPLYTYPE_SELF &&
		pInfo->mBoundType != eBOUNDTYPE_SELF_NOTARGET )
	{
		if( pTarget == 0 )
			return false;

		if( pInfo->mApplyType == eAPPLYTYPE_DIEBUDDY )
		{
			if( pTarget->GetState() == eOBJECT_STATE_DIE )
			{
				if( pTarget->GetObjectType() == eOBJECTTYPE_PLAYER )
				{
					/// 적인지 아군인지 구분
					if( DUELMAN->IsDuelEnemy( (cPlayer*)pTarget ) != true &&
						PVPMAN->IsEnableAttack( (cPlayer*)pTarget ) != true )
						return false;

					return true;
				}
			}
			return false;
		}
		else
		{
			if( pTarget->GetState() == eOBJECT_STATE_DIE )
			{
				return false;
			}
		}

		unsigned char type = pTarget->GetObjectType();
		switch( type )
		{
		case eOBJECTTYPE_HERO:
			{
				if( pInfo->mApplyType == eAPPLYTYPE_ENEMY )
					return false;
			}
			break;
		case eOBJECTTYPE_MONSTER:
			{
				if( pInfo->mApplyType != eAPPLYTYPE_ENEMY )
					return false;
			}
			break;
		case eOBJECTTYPE_PLAYER:
			{
//				if( pInfo->mApplyType == eAPPLYTYPE_PARTY )
//				{
//					return false;
//				}
//				else if( pInfo->mApplyType == eAPPLYTYPE_BUDDY )
//				{
//					/// 적군이냐?
//					return false;
//				}
//				else if( pInfo->mApplyType == eAPPLYTYPE_ENEMY )
				if( pInfo->mApplyType == eAPPLYTYPE_ENEMY )
				{
					if( DUELMAN->IsDuelEnemy( (cPlayer*)pTarget ) ||
						PVPMAN->IsEnableAttack( (cPlayer*)pTarget ) )
						return true;

					return false;
				}
			}
			break;
		default: 
			return false;
		}
	}

	return true;
}

bool cSkillExecuter::AutoAttack_TransMon( unsigned long skillIdx, cBaseObject* pTarget )
{
	/// target의 상태 체크..
	unsigned char type = pTarget->GetObjectType();
	switch( type )
	{
	case eOBJECTTYPE_PLAYER:
		{
			cPlayer* pPlayer = (cPlayer*)pTarget;
			if( pPlayer->GetState() == eOBJECT_STATE_DIE )
				return false;

			/// 적인지 여부 판단
			if( DUELMAN->IsDuelEnemy( pPlayer ) != true &&
				PVPMAN->IsEnableAttack( pPlayer ) != true )
				return false;
		}
		break;
	case eOBJECTTYPE_MONSTER:
		{
			cMonster* pMon = (cMonster*)pTarget;
			if( pMon->GetState() == eOBJECT_STATE_DIE )
				return false;
		}
		break;
	default:
		return false;
	}

	/// 기본 공격 인덱스 산정 - 무기, 공격 인덱스
	ChargeOn( skillIdx );

	/// 공격 거리 체크 - 후처리기
	HERO->AfterAttack( pTarget );

	return true;
}

bool cSkillExecuter::ExecuteAttack_TransMon( unsigned long skillIdx, cBaseObject* pTarget )
{
	/// target window 및 hero 타겟 설정
	HERO->SetTargetObject( pTarget->GetObjectType(), pTarget->GetObjectID() );

	sAfterAction* p = HERO->GetCurrentAfterAction();
	if( p->mActionType == eAfterAction_Attack &&
		p->mTarget.index == pTarget->GetObjectID() )
		return false;

	/// target의 상태 체크..
	unsigned char type = pTarget->GetObjectType();

	switch( type )
	{
	case eOBJECTTYPE_PLAYER:
		{
			cPlayer* pPlayer = (cPlayer*)pTarget;
			if( pPlayer->GetState() == eOBJECT_STATE_DIE )
				return false;

			/// 적인지 여부 판단
			if( DUELMAN->IsDuelEnemy( pPlayer ) != true &&
				PVPMAN->IsEnableAttack( pPlayer ) != true )
				return false;
		}
		break;
	case eOBJECTTYPE_MONSTER:
		{
			cMonster* pMon = (cMonster*)pTarget;
			if( pMon->GetState() == eOBJECT_STATE_DIE )
				return false;
		}
		break;
	default:
		return false;
	}

	/// 기본 공격 인덱스 산정 - 무기, 공격 인덱스
	ChargeOn( skillIdx );

	/// 공격 거리 체크 - 후처리기
	HERO->AfterAttack( pTarget );

	ResetAttackFlag();

	mAttackTarget.index = pTarget->GetObjectID();
	mAttackTarget.type = pTarget->GetObjectType();
	return true;
}

bool cSkillExecuter::ExecuteSkill_TransMon( unsigned long skillIdx, cBaseObject* pTarget )
{
	HERO->SetWaitMoveFlag( false );

	ChargeOff( mChargeSkillIdx );

	if( HERO->GetState() == eOBJECT_STATE_DIE )
		return false;

	/// 서버로부터 무기교체완료 메세지 받기전까지 스킬 사용 불가
	if( HERO->IsWeaponChanging() == true )
		return false;

	unsigned long monsterClassIdx = HERO->GetTransMonsterClassIdx();
	if( monsterClassIdx == 0 )
		return false;

	sMonsterSkillScript* pInfo = SKILLSCRIPT->GetMonsterSkillInfo( monsterClassIdx, (eMONSTERATTACK_TYPE)skillIdx );
	if( pInfo == 0 )
		return false;

	/// 사용 가능 여부 체크
	if( IsPossibleUseSkill( skillIdx ) == false )
		return false;

	/// 
	bool targetCheck = true;
	if( pTarget == 0 )
		pTarget = HERO->GetTargetObject();

	if( pInfo->mBoundType == eBOUNDTYPE_FIELD )
	{
		/// field base skill
		FieldSkillOn_TransMon( monsterClassIdx, skillIdx );
		return true;
	}
	else if( pInfo->mBoundType == eBOUNDTYPE_SELF_NOTARGET )
	{
		/// active
		targetCheck = false;
	}
	else if( pInfo->mBoundType == eBOUNDTYPE_NONE )
	{
		if( pInfo->mApplyType == eAPPLYTYPE_SELF )
			pTarget = HERO;

		targetCheck = true;
	}

	if( targetCheck )
	{
		/// 적용 타겟이 아닌 경우 charge
		if( IsPossibleUseSkillTarget( skillIdx, pTarget) == false )
		{		
			ChargeOn( skillIdx );
			return false;
		}

		sAfterAction* p = HERO->GetCurrentAfterAction();
		if( p->mActionType == eAfterAction_UseTargetSkill &&
			p->mExData1 == skillIdx &&
			p->mTarget.index == pTarget->GetObjectID() )
			return false;
	}

	/// 스킬 발동
	ChargeOn( skillIdx );
	HERO->AfterUseSkill( pTarget );

	if( pTarget )
		mAttackTarget = *(pTarget->GetTargetInfo());

	return true;
}

bool cSkillExecuter::ExecuteSkill_TransMon( unsigned long skillIdx, NiPoint3 applyPos )
{
	HERO->SetWaitMoveFlag( false );

	ChargeOff( mChargeSkillIdx );

	if( HERO->GetState() == eOBJECT_STATE_DIE )
		return false;

	/// 서버로부터 무기교체완료 메세지 받기전까지 스킬 사용 불가
	if( HERO->IsWeaponChanging() == true )
		return false;

	unsigned long monsterClassIdx = HERO->GetTransMonsterClassIdx();
	if( monsterClassIdx == 0 )
		return false;

	sMonsterSkillScript* pInfo = SKILLSCRIPT->GetMonsterSkillInfo( monsterClassIdx, (eMONSTERATTACK_TYPE)skillIdx );
	if( pInfo == 0 )
		return false;

	/// 사용 가능 여부 체크
	if( IsPossibleUseSkill( skillIdx ) == false )
		return false;

	if( pInfo->mBoundType != eBOUNDTYPE_FIELD )
		return false;

	sAfterAction* p = HERO->GetCurrentAfterAction();
	if( p->mActionType == eAfterAction_UseFieldSkill &&
		p->mExData1 == skillIdx )
		return false;

	ChargeOn( skillIdx );
	HERO->AfterUseSkill( applyPos );

	return true;
}

void cSkillExecuter::FieldSkillOn( unsigned long skillIdx )
{
	if( HERO->IsTransformMonster() == true )
		return;

	if( IsPossibleUseSkill( skillIdx ) == false )
		return;

	sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( skillIdx );
	if( pInfo == 0 )
	{
		assert(0);
		return;
	}
	if( SKILLMAN->IsUsedKeepSkill( skillIdx ) == false )
		return;

	sKeepSkill* keep =  SKILLMAN->GetKeepInfo( skillIdx );
	if( keep == 0 )
		return;
	if( pInfo->mStepCount <= keep->mStep )
	{
		assert(0);
		return;
	}

	sPlayerSkillStepInfo* pStepInfo = &pInfo->mpSetpInfoArray[keep->mStep];

	if( pInfo->mType == eSKILLTYPE_TOTEM )
	{
		sTotemScript* totemInfo = TOTEMSCRIPT->GetTotemInfo( pStepInfo->mInfulenceIdx );
		if( totemInfo == 0 )
		{
			assert(0);
			HERO->SetFieldEffRadius( (float)pStepInfo->mBoundDist );
		}
		else
		{
			HERO->SetFieldEffRadius( (float)totemInfo->mApplyRange );
		}
	}
	else
		HERO->SetFieldEffRadius( (float)pStepInfo->mBoundDist );

	mIsFieldCheck = true;
	ChargeOn( skillIdx );

	::SetCursor(NULL);
}

void cSkillExecuter::FieldSkillOn_TransMon( unsigned long monsterClassIdx, unsigned long skillIdx )
{
	if( HERO->IsTransformMonster() == false )
		return;

	if( IsPossibleUseSkill( skillIdx ) == false )
		return;

	sMonsterSkillScript* pInfo = SKILLSCRIPT->GetMonsterSkillInfo( monsterClassIdx, (eMONSTERATTACK_TYPE)skillIdx );
	if( pInfo == 0 )
		return;

	HERO->SetFieldEffRadius( (float)pInfo->mBoundDist );

	mIsFieldCheck = true;
	ChargeOn( skillIdx );
}
