#include "StdAfx.h"
#include "PythonPlayer.h"
#include "PythonTextTail.h"
#include "PythonNetworkStream.h"
#include "InstanceBase.h"
#include "PythonChat.h"
#include "PythonGuild.h"
#include "GameLib/ItemManager.h"

void CPythonPlayer::ClearAffects()
{
	PyCallClassMemberFunc(m_ppyGameWindow, "ClearAffects", Py_BuildValue("()"));
}

void CPythonPlayer::SetAffect(UINT uAffect)
{
	PyCallClassMemberFunc(m_ppyGameWindow, "SetAffect", Py_BuildValue("(i)", uAffect));

	/////

	DWORD dwSkillIndex;
	if (!AffectIndexToSkillIndex(uAffect, &dwSkillIndex))
		return;

	CPythonSkill::TSkillData * pSkillData;
	if (!CPythonSkill::Instance().GetSkillData(dwSkillIndex, &pSkillData))
		return;

	if (!pSkillData->IsToggleSkill())
		return;

	DWORD dwSkillSlotIndex;
	if (!GetSkillSlotIndex(dwSkillIndex, &dwSkillSlotIndex))
		return;

	__ActivateSkillSlot(dwSkillSlotIndex);
}

void CPythonPlayer::ResetAffect(UINT uAffect)
{
	// 2004.07.17.myevan.스킬 아닌 이펙트가 안 사라지는 문제 
	PyCallClassMemberFunc(m_ppyGameWindow, "ResetAffect", Py_BuildValue("(i)", uAffect));

	DWORD dwSkillIndex;
	if (!AffectIndexToSkillIndex(uAffect, &dwSkillIndex))
		return;

	CPythonSkill::TSkillData * pSkillData;
	if (!CPythonSkill::Instance().GetSkillData(dwSkillIndex, &pSkillData))
		return;

	if (!pSkillData->IsToggleSkill())
		return;

	DWORD dwSkillSlotIndex;
	if (!GetSkillSlotIndex(dwSkillIndex, &dwSkillSlotIndex))
		return;

	__DeactivateSkillSlot(dwSkillSlotIndex);
}

bool CPythonPlayer::FindSkillSlotIndexBySkillIndex(DWORD dwSkillIndex, DWORD * pdwSkillSlotIndex)
{
	for (int i = 0; i < SKILL_MAX_NUM; ++i)
	{
		TSkillInstance & rkSkillInst = m_playerStatus.aSkill[i];
		if (dwSkillIndex == rkSkillInst.dwIndex)
		{
			*pdwSkillSlotIndex = i;
			return true;
		}
	}

	return false;
}

void CPythonPlayer::ChangeCurrentSkillNumberOnly(DWORD dwSlotIndex)
{
	if (dwSlotIndex >= SKILL_MAX_NUM)
		return;

	TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSlotIndex];

	CPythonSkill::TSkillData * pSkillData;
	if (!CPythonSkill::Instance().GetSkillData(rkSkillInst.dwIndex, &pSkillData))
		return;

	if (!pSkillData->IsCanUseSkill())
		return;

	if (!__IsRightButtonSkillMode())
	{
		if (!__IsTarget())
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NEED_TARGET"));
			return;
		}

		ClickSkillSlot(dwSlotIndex);
	}
	else
	{
		m_dwcurSkillSlotIndex = dwSlotIndex;
		PyCallClassMemberFunc(m_ppyGameWindow, "ChangeCurrentSkill", Py_BuildValue("(i)", dwSlotIndex));
	}
}

void CPythonPlayer::ClickSkillSlot(DWORD dwSlotIndex)
{
	if (dwSlotIndex >= SKILL_MAX_NUM)
		return;

	TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSlotIndex];

	CPythonSkill::TSkillData * pSkillData;
	if (!CPythonSkill::Instance().GetSkillData(rkSkillInst.dwIndex, &pSkillData))
		return;

	if (CPythonSkill::SKILL_TYPE_GUILD == pSkillData->byType)
	{
		UseGuildSkill(dwSlotIndex);
		return;
	}

	if (!pSkillData->IsCanUseSkill())
		return;

	if (pSkillData->IsStandingSkill())
	{
		if (pSkillData->IsToggleSkill())
		{
			if (IsSkillActive(dwSlotIndex))
			{
				CInstanceBase * pkInstMain = NEW_GetMainActorPtr();
				if (!pkInstMain)
					return;
				if (pkInstMain->IsUsingSkill())
					return;

				CPythonNetworkStream::Instance().SendUseSkillPacket(rkSkillInst.dwIndex);
				return;
			}
		}

		__UseSkill(dwSlotIndex);
		return;
	}

	if (m_dwcurSkillSlotIndex == dwSlotIndex)
	{
		__UseSkill(m_dwcurSkillSlotIndex);
		return;
	}

	if (!__IsRightButtonSkillMode())
	{
		__UseSkill(dwSlotIndex);
	}
	else
	{
		m_dwcurSkillSlotIndex = dwSlotIndex;
		PyCallClassMemberFunc(m_ppyGameWindow, "ChangeCurrentSkill", Py_BuildValue("(i)", dwSlotIndex));
	}
}

bool CPythonPlayer::__CheckSkillUsable(DWORD dwSlotIndex)
{
	CInstanceBase * pkInstMain = NEW_GetMainActorPtr();
	if (!pkInstMain)
		return false;

	if (dwSlotIndex >= SKILL_MAX_NUM)
		return false;

	TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSlotIndex];

	CPythonSkill::TSkillData * pSkillData;
	if (!CPythonSkill::Instance().GetSkillData(rkSkillInst.dwIndex, &pSkillData))
		return false;

	if (pkInstMain->IsMountingHorse())
	{
		if (!pSkillData->IsHorseSkill())
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_HORSE_SKILL"));
			return false;
		}
	}

	if (pSkillData->IsHorseSkill())
	{
		if (!pkInstMain->IsMountingHorse())
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "HAVE_TO_RIDE"));
			return false;
		}
	}

	// 2004.07.26.levites - 안전지대에서 공격 못하도록 수정
	// NOTE : 공격 스킬은 안전지대에서 사용하지 못합니다 - [levites]
	if (pSkillData->IsAttackSkill())
	{
		if (pkInstMain->IsInSafe())
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "IN_SAFE"));

			return false;
		}
	}	

	// NOTE : 패시브 스킬은 사용하지 못합니다 - [levites]
	if (!pSkillData->IsCanUseSkill())
		return false;
//	if (CPythonSkill::SKILL_TYPE_PASSIVE == pSkillData->byType)
//		return false;

	// NOTE : [Only Assassin] 빈병이 있는지 체크 합니다.
	if (pSkillData->IsNeedEmptyBottle())
	{
		if (!__HasItem(27995))
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NEED_EMPTY_BOTTLE"));
			return false;
		}
	}

	// NOTE : [Only Assassin] 독병이 있는지 체크 합니다.
	if (pSkillData->IsNeedPoisonBottle())
	{
		if (!__HasItem(27996))
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NEED_POISON_BOTTLE"));
			return false;
		}
	}

	// NOTE : 낚시 중일때는 스킬을 사용하지 못합니다.
	if (pkInstMain->IsFishingMode())
	{
		PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "REMOVE_FISHING_ROD"));
		return false;
	}

	// NOTE : 레벨 체크
	if (m_sysIsLevelLimit)
	{
		if (rkSkillInst.iLevel <= 0)
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_YET_LEARN"));
			return false;
		}
	}

	// NOTE : 들고 있는 무기 체크
	if (!pSkillData->CanUseWeaponType(pkInstMain->GetWeaponType()))
	{
		PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_MATCHABLE_WEAPON"));
		return false;
	}

	if (!pSkillData->IsHorseSkill()) // HORSE 스킬 중에 화살을 쓰지 않는 스킬이 있기 때문에
	{
		if (__CheckShortArrow(rkSkillInst, *pSkillData))
			return false;

		// NOTE : 활이 필요할 경우 화살 개수 체크
		if (pSkillData->IsNeedBow())
		{
			if (!__HasEnoughArrow())
				return false;
		}
	}

	if (__CheckDashAffect(*pkInstMain))
	{
		if (!pSkillData->IsChargeSkill())
		{
			if (__CheckRestSkillCoolTime(dwSlotIndex))
			{
				PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "WAIT_COOLTIME"));
				return false;
			}
		}
	}
	else
	{
		if (__CheckRestSkillCoolTime(dwSlotIndex))
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "WAIT_COOLTIME"));
			return false;
		}

		if (__CheckShortLife(rkSkillInst, *pSkillData))
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_ENOUGH_HP"));
			return false;
		}

		if (__CheckShortMana(rkSkillInst, *pSkillData))
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_ENOUGH_SP"));
			return false;
		}
	}

	return true;
}

bool CPythonPlayer::__CheckShortArrow(TSkillInstance & rkSkillInst, CPythonSkill::TSkillData& rkSkillData)
{
	if (!rkSkillData.IsNeedBow())
		return false;

	if (__HasEnoughArrow())
		return false;
	
	return true;
}

bool CPythonPlayer::__CheckShortMana(TSkillInstance& rkSkillInst, CPythonSkill::TSkillData& rkSkillData)
{
	extern const DWORD c_iSkillIndex_Summon;
	if (c_iSkillIndex_Summon == rkSkillInst.dwIndex)
		return false;

	int iNeedSP = rkSkillData.GetNeedSP(rkSkillInst.fcurEfficientPercentage);
	int icurSP = GetStatus(POINT_SP);

	// NOTE : ToggleSkill 이 아닌데 소모 SP 가 0 이다.
	if (!rkSkillData.IsToggleSkill())
	{
		if (iNeedSP == 0)
		{
			CPythonChat::Instance().AppendChat(CHAT_TYPE_INFO, "!!! Find strange game data. Please reinstall metin2.");
			return true;
		}
	}

	if (rkSkillData.CanUseIfNotEnough())
	{
		if (icurSP <= 0)
			return true;
	}
	else
	{
		if (-1 != iNeedSP)
			if (iNeedSP > icurSP)
				return true;
	}

	return false;
}

bool CPythonPlayer::__CheckShortLife(TSkillInstance& rkSkillInst, CPythonSkill::TSkillData& rkSkillData)
{
	if (!rkSkillData.IsUseHPSkill())
		return false;
	
	DWORD dwNeedHP = rkSkillData.GetNeedSP(rkSkillInst.fcurEfficientPercentage);
	if (dwNeedHP <= GetStatus(POINT_HP))
		return false;

	return true;
}

bool CPythonPlayer::__CheckRestSkillCoolTime(DWORD dwSlotIndex)
{
	if (!m_sysIsCoolTime)
		return false;

	if (dwSlotIndex >= SKILL_MAX_NUM)
		return false;

	float fElapsedTime = CTimer::Instance().GetCurrentSecond() - m_playerStatus.aSkill[dwSlotIndex].fLastUsedTime;
	if (fElapsedTime >= m_playerStatus.aSkill[dwSlotIndex].fCoolTime)
		return false;	

	return true;
}

bool CPythonPlayer::__CheckDashAffect(CInstanceBase& rkInstMain)
{
	return rkInstMain.IsAffect(CInstanceBase::AFFECT_DASH);
}

void CPythonPlayer::__UseCurrentSkill()
{
	__UseSkill(m_dwcurSkillSlotIndex);
}

DWORD CPythonPlayer::__GetSkillTargetRange(CPythonSkill::TSkillData& rkSkillData)
{
	return rkSkillData.GetTargetRange() + GetStatus(POINT_BOW_DISTANCE)*100;
}

bool CPythonPlayer::__ProcessEnemySkillTargetRange(CInstanceBase& rkInstMain, CInstanceBase& rkInstTarget, CPythonSkill::TSkillData& rkSkillData, DWORD dwSkillSlotIndex)
{
	DWORD dwSkillTargetRange=__GetSkillTargetRange(rkSkillData);
	float fSkillTargetRange = float(dwSkillTargetRange);
	if (fSkillTargetRange <= 0.0f)
		return true;

	// #0000806: [M2EU] 수룡에게 무사(나한군) 탄환격 스킬 사용 안됨	
	float fTargetDistance = rkInstMain.GetDistance(&rkInstTarget);

	extern bool IS_HUGE_RACE(unsigned int vnum);
	if (IS_HUGE_RACE(rkInstTarget.GetRace()))
	{
		fTargetDistance -= 200.0f; // TEMP: 일단 하드 코딩 처리. 정석적으로는 바운드 스피어를 고려해야함
	}

	if (fTargetDistance >= fSkillTargetRange)
	{
		if (rkSkillData.IsChargeSkill())
		{
			if (!__IsReservedUseSkill(dwSkillSlotIndex))
				__SendUseSkill(dwSkillSlotIndex, 0);
		}

		__ReserveUseSkill(rkInstTarget.GetVirtualID(), dwSkillSlotIndex, dwSkillTargetRange);

		return false;
	}

	// 2004.07.05.myevan. 궁신탄영 사용시 맵에 끼임. 사용하기전 갈수 있는곳 체크
	TPixelPosition kPPosTarget;
	rkInstTarget.NEW_GetPixelPosition(&kPPosTarget);

	IBackground& rkBG=IBackground::Instance();
	if (rkBG.IsBlock(kPPosTarget.x, kPPosTarget.y))
	{
		PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "CANNOT_APPROACH"));
		return false;
	}

	return true;
}

bool CPythonPlayer::__CanUseSkill()
{
	CInstanceBase* pkInstMain=NEW_GetMainActorPtr();
	if (!pkInstMain)
		return false;

	if (IsObserverMode())
		return false;

	// Fix me
	// 뉴마운트. 승마스킬레벨 20 미만인 경우, 고급 마운트를 타고 승마 관련 스킬 못 쓰도록 못하도록 하드 코딩... 
	// 나중에 시간 나면 can use skill 체크를 서버에서 해주자...
	if (pkInstMain->IsMountingHorse() && (GetSkillGrade(109) < 1 && GetSkillLevel(109) < 20))
	{
		return false;
	}

	return pkInstMain->CanUseSkill();
}


bool CPythonPlayer::__UseSkill(DWORD dwSlotIndex)
{
	// PrivateShop
	if (IsOpenPrivateShop())
	{
		return true;
	}

	if (!__CanUseSkill())
	{
		return false;
	}

	if (dwSlotIndex >= SKILL_MAX_NUM)
	{
		Tracenf("CPythonPlayer::__UseSkill(dwSlotIndex=%d) It's not available skill slot number", dwSlotIndex);
		return false;
	}

	TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSlotIndex];

	if (__CheckSpecialSkill(rkSkillInst.dwIndex))
	{
		return true;
	}

	CPythonSkill::TSkillData * pSkillData;
	if (!CPythonSkill::Instance().GetSkillData(rkSkillInst.dwIndex, &pSkillData))
	{
		Tracenf("CPythonPlayer::__UseSkill(dwSlotIndex=%d) There is no skill data", dwSlotIndex);
		return false;
	}

	if (pSkillData->IsToggleSkill())
	{
		if (IsSkillActive(dwSlotIndex))
		{
			CPythonNetworkStream::Instance().SendUseSkillPacket(rkSkillInst.dwIndex, dwSlotIndex);
			return false;
		}
	}

	if (!__CheckSkillUsable(dwSlotIndex))
	{
		return false;
	}

	CInstanceBase * pkInstMain = NEW_GetMainActorPtr();
	if (!pkInstMain)
	{
		Tracenf("CPythonPlayer::__UseSkill(dwSlotIndex=%d) There is no main player", dwSlotIndex);
		return false;
	}

	if (pkInstMain->IsUsingSkill())
	{
		return false;
	}

	CInstanceBase * pkInstTarget = NULL;

	// NOTE : 타겟이 필요한 경우
	if (pSkillData->IsNeedTarget() ||
		pSkillData->CanChangeDirection() ||
		pSkillData->IsAutoSearchTarget())
	{
		if (pSkillData->IsNeedCorpse())
			pkInstTarget=__GetDeadTargetInstancePtr();
		else
			pkInstTarget=__GetAliveTargetInstancePtr();

		// 현재 타겟이 없으면..
		if (!pkInstTarget)
		{
			// 업데이트하고..
			__ChangeTargetToPickedInstance();

			// 다시 얻어낸다.
			if (pSkillData->IsNeedCorpse())
				pkInstTarget=__GetDeadTargetInstancePtr();
			else
				pkInstTarget=__GetAliveTargetInstancePtr();
		}

		if (pkInstTarget)
		{
			if (pSkillData->IsOnlyForAlliance())
			{
				if (pkInstMain == pkInstTarget)
				{
					if (!pSkillData->CanUseForMe())
					{
						PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "CANNOT_USE_SELF"));
						return false;
					}
				}
				else if (!pkInstMain->IsAttackableInstance(*pkInstTarget) && pkInstTarget->IsPC())
				{
					DWORD dwSkillRange = __GetSkillTargetRange(*pSkillData);

					if (dwSkillRange > 0)
					{
						float fDistance=pkInstMain->GetDistance(pkInstTarget);
						if (fDistance>=float(dwSkillRange))
						{
							__ReserveUseSkill(pkInstTarget->GetVirtualID(), dwSlotIndex, dwSkillRange);
							return false;
						}
					}
				}
				else
				{
					if (pSkillData->CanUseForMe())
					{
						pkInstTarget = pkInstMain;
						Tracef(" [ALERT] 동료에게 사용하는 기술임에도 적에게 타겟팅 되어있어서 자신에게로 재설정\n");
					}
					else
					{
						PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "ONLY_FOR_ALLIANCE"));
						return false;
					}
				}
			}
			else
			{
				if (pkInstTarget->IsInSafe())
				{
					PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "CANNOT_ATTACK_ENEMY_IN_SAFE_AREA"));
					return false;
				}

				if (pkInstMain->IsAttackableInstance(*pkInstTarget))
				{
					if (!__ProcessEnemySkillTargetRange(*pkInstMain, *pkInstTarget, *pSkillData, dwSlotIndex))
						return false;
				}
				else
				{
					PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "CANNOT_ATTACK"));
					return false;
				}
			}

			pkInstMain->SetFlyTargetInstance(*pkInstTarget);

			if (pkInstMain != pkInstTarget)
			{
				if (pkInstMain->IsFlyTargetObject())
				{
					pkInstMain->NEW_LookAtFlyTarget();
				}
				else
				{
					pkInstMain->NEW_LookAtDestInstance(*pkInstTarget);
				}
			}
		}
		else
		{
			if (pSkillData->IsAutoSearchTarget())
			{
				if (pkInstMain->NEW_GetFrontInstance(&pkInstTarget, 2000.0f))
				{
					SetTarget(pkInstTarget->GetVirtualID());
					if (!__ProcessEnemySkillTargetRange(*pkInstMain, *pkInstTarget, *pSkillData, dwSlotIndex))
						return false;
				}
				else
				{
					PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NEED_TARGET"));
					return false;
				}
			}

			if (pSkillData->CanUseForMe())
			{
				pkInstTarget = pkInstMain;
				pkInstMain->SetFlyTargetInstance(*pkInstMain);
				Tracef(" [ALERT] 타겟이 없어서 플레이어에게 사용합니다\n");
			}
			else if (pSkillData->IsNeedCorpse())
			{
				PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "ONLY_FOR_CORPSE"));
				return false;
			}
			else
			{
				PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NEED_TARGET"));
				return false;
			}
		}
	}

	if (pSkillData->CanChangeDirection())
	{
		DWORD dwPickedActorID;
		TPixelPosition kPPosPickedGround;

		if (pkInstTarget && pkInstTarget!=pkInstMain)
		{
			pkInstMain->NEW_LookAtDestInstance(*pkInstTarget);
		}
		else if (__GetPickedActorID(&dwPickedActorID))
		{
			CInstanceBase* pkInstVictim=NEW_FindActorPtr(dwPickedActorID);
			if (pkInstVictim)
				pkInstMain->NEW_LookAtDestInstance(*pkInstVictim);
		}
		else if (__GetPickedGroundPos(&kPPosPickedGround))
		{
			pkInstMain->NEW_LookAtDestPixelPosition(kPPosPickedGround);
		}
		else
		{
			Tracenf("CPythonPlayer::__UseSkill(%d) - 화면 기준 방향 설정을 해야함", dwSlotIndex);
		}
	}

	// 관격술 처리
	DWORD dwTargetMaxCount = pSkillData->GetTargetCount(rkSkillInst.fcurEfficientPercentage);
	DWORD dwRange = __GetSkillTargetRange(*pSkillData);
	if (dwTargetMaxCount>0 && pkInstTarget)
	{
		DWORD dwTargetCount=1;
		std::vector<CInstanceBase*> kVct_pkInstTarget;

		if (pSkillData->IsFanRange())
		{
			if (pkInstMain->NEW_GetInstanceVectorInFanRange(float(dwRange), *pkInstTarget, &kVct_pkInstTarget))
			{
				std::vector<CInstanceBase*>::iterator i;
				for (i=kVct_pkInstTarget.begin(); i!=kVct_pkInstTarget.end(); ++i)
				{
					if (dwTargetCount>=dwTargetMaxCount)
						break;

					CInstanceBase* pkInstEach=*i;

					if (pkInstTarget!=pkInstEach && !pkInstEach->IsDead())
					{
						pkInstMain->AddFlyTargetInstance(*pkInstEach);
						CPythonNetworkStream::Instance().SendAddFlyTargetingPacket(pkInstEach->GetVirtualID(), pkInstEach->GetGraphicThingInstanceRef().OnGetFlyTargetPosition());

						dwTargetCount++;
					}
				}
			}
		}
		else if (pSkillData->IsCircleRange())
		{
			if (pkInstMain->NEW_GetInstanceVectorInCircleRange(float(dwRange), &kVct_pkInstTarget))
			{
				std::vector<CInstanceBase*>::iterator i;
				for (i=kVct_pkInstTarget.begin(); i!=kVct_pkInstTarget.end(); ++i)
				{
					if (dwTargetCount>=dwTargetMaxCount)
						break;

					CInstanceBase* pkInstEach=*i;

					if (pkInstTarget!=pkInstEach && !pkInstEach->IsDead())
					{
						pkInstMain->AddFlyTargetInstance(*pkInstEach);
						CPythonNetworkStream::Instance().SendAddFlyTargetingPacket(pkInstEach->GetVirtualID(), pkInstEach->GetGraphicThingInstanceRef().OnGetFlyTargetPosition());

						dwTargetCount++;
					}
				}
			}
		}

		if (dwTargetCount<dwTargetMaxCount)
		{
			while (dwTargetCount<dwTargetMaxCount)
			{
				TPixelPosition kPPosDst;
				pkInstMain->NEW_GetRandomPositionInFanRange(*pkInstTarget, &kPPosDst);

				kPPosDst.x=kPPosDst.x;
				kPPosDst.y=-kPPosDst.y;

				pkInstMain->AddFlyTargetPosition(kPPosDst);
				CPythonNetworkStream::Instance().SendAddFlyTargetingPacket(0, kPPosDst);

				dwTargetCount++;
			}
		}
	}

	/////
	// NOTE : 멀리서 적을 클릭해놓고 스킬을 쓰면 스킬을 쓴뒤 바로 적을 공격하는 문제를 수정하기 위한 코드 - [levites]
	__ClearReservedAction();
	/////

	if (!pSkillData->IsNoMotion())
	{
		DWORD dwMotionIndex = pSkillData->GetSkillMotionIndex(rkSkillInst.iGrade);
		DWORD dwLoopCount = pSkillData->GetMotionLoopCount(rkSkillInst.fcurEfficientPercentage);
		if (!pkInstMain->NEW_UseSkill(rkSkillInst.dwIndex, dwMotionIndex, dwLoopCount, pSkillData->IsMovingSkill() ? true : false))
		{
			Tracenf("CPythonPlayer::__UseSkill(%d) - pkInstMain->NEW_UseSkill - ERROR", dwSlotIndex);
			return false;
		}
	}

	DWORD dwTargetVID=pkInstTarget ? pkInstTarget->GetVirtualID() : 0;

	__SendUseSkill(dwSlotIndex, dwTargetVID);
	return true;
}

void CPythonPlayer::__SendUseSkill(DWORD dwSkillSlotIndex, DWORD dwTargetVID)
{
	TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSkillSlotIndex];

	CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance();
	rkNetStream.SendUseSkillPacket(rkSkillInst.dwIndex, dwTargetVID);

	__RunCoolTime(dwSkillSlotIndex);
}

BYTE CPythonPlayer::__GetSkillType(DWORD dwSkillSlotIndex)
{
	TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSkillSlotIndex];

	CPythonSkill::TSkillData * pkSkillData;
	CPythonSkill& rkPythonSkill = CPythonSkill::Instance();
	if (!rkPythonSkill.GetSkillData(rkSkillInst.dwIndex, &pkSkillData))
	{
		//TraceError("CPythonPlayer::__GetSkillType(dwSkillSlotIndex=%d) - NOT CHECK", dwSkillSlotIndex);
		return 0;
	}
	return pkSkillData->GetType();
}

void CPythonPlayer::__RunCoolTime(DWORD dwSkillSlotIndex)
{
	TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSkillSlotIndex];

	CPythonSkill::TSkillData * pkSkillData;
	if (!CPythonSkill::Instance().GetSkillData(rkSkillInst.dwIndex, &pkSkillData))
	{
		TraceError("CPythonPlayer::__SendUseSkill(dwSkillSlotIndex=%d) - NOT CHECK", dwSkillSlotIndex);
		return;
	}

	CPythonSkill::TSkillData& rkSkillData=*pkSkillData;

	rkSkillInst.fCoolTime = rkSkillData.GetSkillCoolTime(rkSkillInst.fcurEfficientPercentage);
	rkSkillInst.fLastUsedTime = CTimer::Instance().GetCurrentSecond();

	int iSpd = 100 - GetStatus(POINT_CASTING_SPEED);
	if (iSpd > 0)
		iSpd = 100 + iSpd;
	else if (iSpd < 0)
		iSpd = 10000 / (100 - iSpd);
	else
		iSpd = 100;

	rkSkillInst.fCoolTime = rkSkillInst.fCoolTime * iSpd / 100;

	PyCallClassMemberFunc(m_ppyGameWindow, "RunUseSkillEvent", Py_BuildValue("(if)", dwSkillSlotIndex, rkSkillInst.fCoolTime));
}

bool CPythonPlayer::__HasEnoughArrow()
{
	CItemData * pItemData;
	if (CItemManager::Instance().GetItemDataPointer(GetItemIndex(TItemPos(INVENTORY, c_Equipment_Arrow)), &pItemData))
	if (CItemData::ITEM_TYPE_WEAPON == pItemData->GetType())
	if (CItemData::WEAPON_ARROW == pItemData->GetSubType())
	{
		return true;
	}

	PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotShotError", Py_BuildValue("(is)", GetMainCharacterIndex(), "EMPTY_ARROW"));
	return false;
}

bool CPythonPlayer::__HasItem(DWORD dwItemID)
{
	for (int i = 0; i < c_Inventory_Count; ++i)
	{
		if (dwItemID == GetItemIndex(TItemPos (INVENTORY, i)))
			return true;
	}
	for (int i = 0; i < c_DragonSoul_Inventory_Count; ++i)
	{
		if (dwItemID == GetItemIndex(TItemPos (DRAGON_SOUL_INVENTORY, i)))
			return true;
	}

	return false;
}

extern const DWORD c_iSkillIndex_Tongsol;
extern const DWORD c_iSkillIndex_Fishing;
extern const DWORD c_iSkillIndex_Mining;
extern const DWORD c_iSkillIndex_Making;
extern const DWORD c_iSkillIndex_Combo;
extern const DWORD c_iSkillIndex_Language1;
extern const DWORD c_iSkillIndex_Language2;
extern const DWORD c_iSkillIndex_Language3;
extern const DWORD c_iSkillIndex_Polymorph;

void CPythonPlayer::UseGuildSkill(DWORD dwSkillSlotIndex)
{
	CInstanceBase* pkInstMain = NEW_GetMainActorPtr();
	if (!pkInstMain)
		return;
	if (!pkInstMain->CanUseSkill())
		return;

	///////////////////////////////////////////////////////////////////////////////////////////////

	if (dwSkillSlotIndex >= SKILL_MAX_NUM)
	{
		Tracenf("CPythonPlayer::UseGuildSkill(dwSkillSlotIndex=%d) It's not available skill slot number", dwSkillSlotIndex);
		return;
	}

	TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSkillSlotIndex];

	DWORD dwSkillIndex = rkSkillInst.dwIndex;

	CPythonSkill::TSkillData * pSkillData;
	if (!CPythonSkill::Instance().GetSkillData(dwSkillIndex, &pSkillData))
		return;

	if (__CheckRestSkillCoolTime(dwSkillSlotIndex))
	{
		PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "WAIT_COOLTIME"));
		return;
	}

	if (pSkillData->IsOnlyForGuildWar())
	{
		if (!CPythonGuild::Instance().IsDoingGuildWar())
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "ONLY_FOR_GUILD_WAR"));
			return;
		}
	}

	DWORD dwMotionIndex = pSkillData->GetSkillMotionIndex();
	if (!pkInstMain->NEW_UseSkill(dwSkillIndex, dwMotionIndex, 1, false))
	{
		Tracenf("CPythonPlayer::UseGuildSkill(%d) - pkInstMain->NEW_UseSkill - ERROR", dwSkillIndex);
	}

	///////////////////////////////////////////////////////////////////////////////////////////////

	CPythonNetworkStream::Instance().SendGuildUseSkillPacket(dwSkillIndex, 0);
	__RunCoolTime(dwSkillSlotIndex);
}

void CPythonPlayer::SetComboSkillFlag(BOOL bFlag)
{
	DWORD dwSlotIndex;
	if (!GetSkillSlotIndex(c_iSkillIndex_Combo, &dwSlotIndex))
	{
		Tracef("CPythonPlayer::SetComboSkillFlag(killIndex=%d) - Can't Find Slot Index\n", c_iSkillIndex_Combo);
		return;
	}

	int iLevel = GetSkillLevel(dwSlotIndex);
	if (iLevel <= 0)
	{
		Tracef("CPythonPlayer::SetComboSkillFlag(skillIndex=%d, skillLevel=%d) - Invalid Combo Skill Level\n", c_iSkillIndex_Combo, iLevel);
		return;
	}

	iLevel = MIN(iLevel, 2);

	CInstanceBase* pkInstMain = NEW_GetMainActorPtr();
	if (!pkInstMain)
		return;

	if (bFlag)
	{
		pkInstMain->SetComboType(iLevel);
		__ActivateSkillSlot(dwSlotIndex);
	}
	else
	{
		pkInstMain->SetComboType(0);
		__DeactivateSkillSlot(dwSlotIndex);
	}
}

bool CPythonPlayer::__CheckSpecialSkill(DWORD dwSkillIndex)
{
	CInstanceBase* pkInstMain = NEW_GetMainActorPtr();
	if (!pkInstMain)
		return false;

	// Fishing
	if (c_iSkillIndex_Fishing == dwSkillIndex)
	{
		if (pkInstMain->IsFishingMode())
		{
			NEW_Fishing();
		}
		else
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "EQUIP_FISHING_ROD"));
		}
		return true;
	}

	// Combo
	else if (c_iSkillIndex_Combo == dwSkillIndex)
	{
		DWORD dwSlotIndex;
		if (!GetSkillSlotIndex(dwSkillIndex, &dwSlotIndex))
			return false;

		int iLevel = GetSkillLevel(dwSlotIndex);
		if (iLevel > 0)
		{
			CPythonNetworkStream::Instance().SendUseSkillPacket(dwSkillIndex);
		}
		else
		{
			PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_YET_LEARN"));
		}

		return true;
	}

	return false;
}
