#include "stdafx.h"
#include "SkillManager.h"

#include "SkillExecuter.h"
#include "damageprintmanager.h"

#include "hero.h"
#include "Monster.h"
#include "ObjectManager.h"
#include "DramaturgyManager.h"
#include "WorldManager.h"

#include "Application.h"

#include "Protocol.h"
#include "ChatManager.h"
#include "Player_Common.h"

#include "FileSystem.h"

#include "Skill_Common.h"
#include "SkillScript.h"

#include "SkillWindow.h"
#include "GameUIManager.h"
#include "RevivalWindow.h"
#include "GameResourceManager.h"
#include "UIMsgboxEvent.h"
#include "BuffWindow.h"
#include "QuickManager.h"

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

cSkillManager* cSkillManager::mpSkillManager = NULL;

cSkillManager::cSkillManager()
{
	mpSkillManager = this;

	mpSkillExecuter = new cSkillExecuter;
	mpDamagePrintManager = new cDamagePrintManager;
}

cSkillManager::~cSkillManager()
{
	Close();

	///
	mSkillObjectPool.Clear();
	mInfluenceObjectPool.Clear();

	SAFE_DELETE( mpSkillExecuter );
	SAFE_DELETE( mpDamagePrintManager );
}

bool cSkillManager::Init()
{
	mSkillObjectPool.Reserve( 200, 50 );
	mInfluenceObjectPool.Reserve( 500, 50 );
	mApplyObjectPool.Reserve( 200, 50 );

	mDeleteSkillArray.Reserve( 100 );
	mDeleteInfluenceArray.Reserve( 100 );
	mDeleteApplyObjectArray.Reserve( 100 );

	return true;
}

void cSkillManager::Open()
{

}

void cSkillManager::Close()
{
	if( mpSkillExecuter )
		mpSkillExecuter->Close();

	///
	cSkillObject* pSkill = 0;
	cSkillObjectMap::cIterator i, iend;
	i = mDummySkillMap.Begin();
	iend = mDummySkillMap.End();
	for( ; i != iend; ++i )
	{
		pSkill = (cSkillObject*)(*i).mSecond;
		delete pSkill;
	}
	mDummySkillMap.Clear();

	/// 
	i = mSkillObjectMap.Begin();
	iend = mSkillObjectMap.End();
	for( ; i != iend; ++i )
	{
		pSkill = (cSkillObject*)(*i).mSecond;
		delete pSkill;
	}
	mSkillObjectMap.Clear();

	/// 
	i = mInfluenceMap.Begin();
	iend = mInfluenceMap.End();
	for( ; i != iend; ++i )
	{
		cInfluenceObject* pInf = (cInfluenceObject*)(*i).mSecond;
		delete pInf;
	}
	mInfluenceMap.Clear();

	i = mApplyObjectMap.Begin();
	iend = mApplyObjectMap.End();
	for( ; i != iend; ++i )
	{
		cApplyObject* pA = (cApplyObject*)(*i).mSecond;
		delete pA;
	}
	mApplyObjectMap.Clear();

	mDeleteSkillArray.Clear();
	mDeleteInfluenceArray.Clear();
	mDeleteApplyObjectArray.Clear();

	ClearAllKeepSkill();

	mDummyIndexGen.RestoreAll();
	mApplyIndexGen.RestoreAll();
}

unsigned long cSkillManager::CreateHeroSkillObject( unsigned long skillIdx, cBaseObject* pUser, cBaseObject* pTarget, float speedFactor )
{
	cSkillObject* pSkillObj = new cSkillObject;
	if( pSkillObj->Init( skillIdx, pUser, pTarget, speedFactor ) == false )
	{
		delete pSkillObj;
		return 0;
	}

	/// 새로운 더미키 생성
	unsigned long key = mDummyIndexGen.GenerateIndex();
	if( mDummySkillMap.Insert( key, pSkillObj ) == false )
	{
		assert(0);
		delete pSkillObj;
		mDummyIndexGen.RestoreIndex(key);
		return 0;
	}
	pSkillObj->SetManagedKey( key, true );

	mpSkillExecuter->SetCurrentHeroSkillObject( pSkillObj );

	return key;
}

unsigned long cSkillManager::CreateHeroSkillObject( unsigned long skillIdx, cBaseObject* pUser, NiPoint3 fieldPos, float speedFactor )
{
	cSkillObject* pSkillObj = new cSkillObject;
	if( pSkillObj->InitField( skillIdx, pUser, fieldPos, speedFactor ) == false )
	{
		delete pSkillObj;
		return 0;
	}

	/// 새로운 더미키 생성
	unsigned long key = mDummyIndexGen.GenerateIndex();
	if( mDummySkillMap.Insert( key, pSkillObj ) == false )
	{
		assert(0);
		delete pSkillObj;
		mDummyIndexGen.RestoreIndex(key);
		return 0;
	}
	pSkillObj->SetManagedKey( key, true );

	mpSkillExecuter->SetCurrentHeroSkillObject( pSkillObj );

	return key;
}

unsigned long cSkillManager::CreateHeroMapChangeSkillObject( unsigned long skillIdx, cBaseObject* pUser )
{
	cSkillObject* pSkillObj = new cSkillObject;
	if( pSkillObj->InitMapChange( skillIdx, pUser ) == false )
	{
		delete pSkillObj;
		return 0;
	}

	unsigned long key = mDummyIndexGen.GenerateIndex();
	if( mDummySkillMap.Insert( key, pSkillObj ) == false )
	{
		assert(0);
		delete pSkillObj;
		mDummyIndexGen.RestoreIndex(key);
		return 0;
	}
	pSkillObj->SetManagedKey( key, true );

	mpSkillExecuter->SetCurrentHeroSkillObject( pSkillObj );

	return key;
}

unsigned long cSkillManager::CreateHeroVehicleSkillObject( unsigned long skillIdx, cBaseObject* pUser )
{
	cSkillObject* pSkillObj = new cSkillObject;
	if( pSkillObj->InitVehicle( skillIdx, pUser ) == false )
	{
		delete pSkillObj;
		return 0;
	}

	unsigned long key = mDummyIndexGen.GenerateIndex();
	if( mDummySkillMap.Insert( key, pSkillObj ) == false )
	{
		assert(0);
		delete pSkillObj;
		mDummyIndexGen.RestoreIndex(key);
		return 0;
	}
	pSkillObj->SetManagedKey( key, true );

	mpSkillExecuter->SetCurrentHeroSkillObject( pSkillObj );

	return key;
}


void cSkillManager::CreateMapChangeSkillObject( unsigned long uIdx, unsigned long skillIdx, cBaseObject* pUser )
{
	if( pUser && pUser == HERO )
	{
		assert(0);
		return;
	}

	cSkillObject* pSkillObj = new cSkillObject;
	if( pSkillObj->InitMapChange( skillIdx, pUser ) == false )
	{
		delete pSkillObj;
		return;
	}

	if( mSkillObjectMap.Insert( uIdx, pSkillObj ) == false )
	{
		assert(0);
		delete pSkillObj;
		return;
	}
	pSkillObj->SetManagedKey( uIdx, false );
}

void cSkillManager::CreateVehicleSkillObject( unsigned long uIdx, unsigned long skillIdx, cBaseObject* pUser )
{
	if( pUser && pUser == HERO )
	{
		assert(0);
		return;
	}

	cSkillObject* pSkillObj = new cSkillObject;
	if( pSkillObj->InitVehicle( skillIdx, pUser ) == false )
	{
		delete pSkillObj;
		return;
	}

	if( mSkillObjectMap.Insert( uIdx, pSkillObj ) == false )
	{
		assert(0);
		delete pSkillObj;
		return;
	}
	pSkillObj->SetManagedKey( uIdx, false );
}

void cSkillManager::CreateSkillObject( unsigned long uIdx, unsigned long skillIdx, cBaseObject* pUser, cBaseObject* pTarget, float speedFactor )
{
	if( pUser && pUser == HERO )
	{
		assert(0);
		return;
	}

	cSkillObject* pSkillObj = new cSkillObject;
	if( pSkillObj->Init( skillIdx, pUser, pTarget, speedFactor ) == false )
	{
		delete pSkillObj;
		return;
	}

	if( mSkillObjectMap.Insert( uIdx, pSkillObj ) == false )
	{
		assert(0);
		delete pSkillObj;
		return;
	}
	pSkillObj->SetManagedKey( uIdx, false );
}

void cSkillManager::CreateSkillObject( unsigned long uIdx, unsigned long skillIdx, cBaseObject* pUser, NiPoint3 fieldPos, float speedFactor )
{
	if( pUser && pUser == HERO )
	{
		assert(0);
	}

	cSkillObject* pSkillObj = new cSkillObject;
	if( pSkillObj->InitField( skillIdx, pUser, fieldPos, speedFactor ) == false )
	{
		delete pSkillObj;
		return;
	}

	if( mSkillObjectMap.Insert( uIdx, pSkillObj ) == false )
	{
		assert(0);
		delete pSkillObj;
		return;
	}
	pSkillObj->SetManagedKey( uIdx, false );
}

cSkillObject* cSkillManager::CreateRevisionSkillObject( unsigned long uIdx, unsigned long skillIdx, unsigned char attackerType, unsigned long dramaKey, bool tranMon )
{
	cSkillObject* pSkillObj = new cSkillObject;
	if( pSkillObj->RevisionInit( skillIdx, attackerType, dramaKey, tranMon ) == false )
	{
		delete pSkillObj;
		return 0;
	}

	if( mSkillObjectMap.Insert( uIdx, pSkillObj ) == false )
	{
		assert(0);
		delete pSkillObj;
		return 0;
	}
	pSkillObj->SetManagedKey( uIdx, false );

	return pSkillObj;
}

cInfluenceObject* cSkillManager::CreateInfluenceObject( unsigned long uIdx, unsigned long infIdx, unsigned long skillIdx, cBaseObject* pTarget, bool dieDelete )
{
	if( pTarget == 0 ) 
		return 0;

	sInfluenceScript* pInfo = SKILLSCRIPT->GetInfluenceInfo( infIdx );
	if( pInfo == 0 )
		return 0;

	bool buff = (pInfo->mType == 1);

	cInfluenceObject* p = new cInfluenceObject;
	if( p->Init( uIdx, infIdx, skillIdx, buff, pTarget, dieDelete ) == false )
	{
		delete p;
		return 0;
	}

	if( mInfluenceMap.Insert( uIdx, p ) == false )
	{
		assert(0);
		delete p;
		return 0;
	}

	/// 071024 PKH 스테이터스 재계산
	if( pTarget->GetObjectType() == eOBJECTTYPE_HERO )
		HERO->CalcStatus();

	return p;
}

cApplyObject* cSkillManager::CreateApplyObject( cBaseObject* pUser, cBaseObject* pTarget, unsigned char weaponType, eAPPLYDRAMA_TYPE type )
{
	if( pTarget == 0 )
		return 0;

	sObject target;
	target.index = pTarget->GetObjectID();
	target.type = pTarget->GetObjectType();

	/// 생성
	unsigned long key = mApplyIndexGen.GenerateIndex();
	cApplyObject* p = new cApplyObject;
	if( pUser )
	{
		sObject user;
		user.index = pUser->GetObjectID();
		user.type = pUser->GetObjectType();

		if( p->Init( key, &user, &target, weaponType, type ) == false )
		{
			delete p;
			mApplyIndexGen.RestoreIndex( key );
			return 0;
		}
	}
	else
	{
		if( p->Init( key, 0, &target, weaponType, type ) == false )
		{
			delete p;
			mApplyIndexGen.RestoreIndex( key );
			return 0;
		}
	}

	/// 추가
	if( mApplyObjectMap.Insert( key, p ) == false )
	{
		assert(0);
		delete p;
		mApplyIndexGen.RestoreIndex( key );
		return 0;
	}

	return p;
}

cApplyObject* cSkillManager::CreateApplyObject( cBaseObject* pTarget, unsigned long influenceIdx )
{
	if( pTarget == 0 )
		return 0;

	/// 생성
	unsigned long key = mApplyIndexGen.GenerateIndex();
	cApplyObject* p = new cApplyObject;
	if( p->Init( key, pTarget, influenceIdx ) == false )
	{
		delete p;
		mApplyIndexGen.RestoreIndex( key );
		return 0;
	}

	/// 추가
	if( mApplyObjectMap.Insert( key, p ) == false )
	{
		assert(0);
		delete p;
		mApplyIndexGen.RestoreIndex( key );
		return 0;
	}

	return p;
}

void cSkillManager::UpdateInfluenceObject()
{

}

void cSkillManager::DamageInfluenceObject()
{

}

void cSkillManager::Process( unsigned long deltaTime, unsigned long accumTime )
{
	/// 보유 스킬에 대한 쿨타임 처리
	cSkillMap::cIterator k, kend;
	k = mKeepSkillMap.Begin();
	kend = mKeepSkillMap.End();
	for( ; k != kend; ++k )
	{
		sKeepSkill* p = (sKeepSkill*)(*k).mSecond;

		/// 쿨타임 체크
		if( p->mRestTime != 0 )
		{
			if( p->mRestTime < deltaTime )
				p->mRestTime = 0;
			else
				p->mRestTime -= deltaTime;

			if( p->mRestTime <= 0 )
			{
				p->mStartTime = 0;
				p->mRestTime = 0;
				p->mTotalTime = 0;
			}
		}
	}

	cSkillObject* pSkill = 0;
	cSkillObjectMap::cIterator i, iend;

	/// Dummy 스킬 처리

	if( mDummySkillMap.IsEmpty() == false )
	{
		i = mDummySkillMap.Begin();
		iend = mDummySkillMap.End();
		for( ; i != iend; ++i )
		{
			pSkill = (cSkillObject*)(*i).mSecond;
			pSkill->Process( accumTime );
		}
	}

	/// 효과 처리
	if( mInfluenceMap.IsEmpty() == false )
	{
		cInfluenceObject* pInf = 0;
		i = mInfluenceMap.Begin();
		iend = mInfluenceMap.End();
		for( ; i != iend; ++i )
		{
			pInf = (cInfluenceObject*)(*i).mSecond;
			pInf->Process( accumTime );
		}
	}

	/// 인증 스킬 처리
	if( mSkillObjectMap.IsEmpty() == false )
	{
		i = mSkillObjectMap.Begin();
		iend = mSkillObjectMap.End();
		for( ; i != iend; ++i )
		{
			pSkill = (cSkillObject*)(*i).mSecond;
			pSkill->Process( accumTime );
		}
	}

	/// Apply Drama객체 처리
	if( mApplyObjectMap.IsEmpty() == false )
	{
		i = mApplyObjectMap.Begin();
		iend = mApplyObjectMap.End();
		for( ; i != iend; ++i )
		{
			cApplyObject* pA = (cApplyObject*)(*i).mSecond;
			pA->Process( accumTime );
		}
	}

	/// 삭제 목록에 등록된 객체에 대한 처리
	DeleteProcess();
}

void cSkillManager::DeleteProcess()
{
	/// 삭제 객체를 제거한다. (주의: Object참조는 이미 제거된 상태다)
	if( mDeleteSkillArray.IsEmpty() == false )
	{
		for( unsigned int i = 0, end = mDeleteSkillArray.GetSize(); i < end; ++i )
		{
			cSkillObject* p = (cSkillObject*)mDeleteSkillArray[i];
			if( p )
			{
				if( p == mpSkillExecuter->GetCurrentHeroSkillObject() )
					mpSkillExecuter->SetCurrentHeroSkillObject( 0 );

				unsigned long key = p->GetManagedKey();
				if( p->IsDummySkill() )
				{
					mDummyIndexGen.RestoreIndex( key );
					mDummySkillMap.Erase( key );
				}
				else
				{
					mSkillObjectMap.Erase( key );
				}
				delete p;
			}
		}
		mDeleteSkillArray.Clear();
	}

	if( mDeleteInfluenceArray.IsEmpty() == false )
	{
		bool calc = false;
		for( unsigned int i = 0, end = mDeleteInfluenceArray.GetSize(); i < end; ++i )
		{
			cInfluenceObject* p = (cInfluenceObject*)mDeleteInfluenceArray[i];
			if( p )
			{
				if( p->IsHeroInfluence() )
					calc = true;

				unsigned long key = p->GetManagedKey();
				mInfluenceMap.Erase( key );

				delete p;
			}
		}
		mDeleteInfluenceArray.Clear();

		/// 071024 PKH 스테이터스 재계산
		if( calc )
			HERO->CalcStatus();
	}

	if( mDeleteApplyObjectArray.IsEmpty() == false )
	{
		for( unsigned int i = 0, end = mDeleteApplyObjectArray.GetSize(); i < end; ++i )
		{
			cApplyObject* p = (cApplyObject*)mDeleteApplyObjectArray[i];
			if( p )
			{
				unsigned long key = p->GetManagedKey();
				mApplyIndexGen.RestoreIndex( key );
				mApplyObjectMap.Erase( key );
				delete p;
			}
		}
		mDeleteApplyObjectArray.Clear();
	}
}


bool cSkillManager::ProcessLButtonClick( int mouseX, int mouseY )
{
	cBaseObject* pObj = 0;
	if( SKILLEXECUTER->IsSkillCharge() == false )
	{
		eOBJECTTYPE type = (eOBJECTTYPE)OBJECTMAN->ObjectPicking( mouseX, mouseY, &pObj );
		if( pObj )
		{
			switch( type )
			{
			case eOBJECTTYPE_PLAYER:
				{
					cBaseObject* curTarget = HERO->GetTargetObject();
					if( pObj == curTarget )
					{
						if( DUELMAN->IsDuelEnemy( (cPlayer*)curTarget ) ||
							PVPMAN->IsEnableAttack( (cPlayer*)curTarget ) )
						{
							HERO->SetWaitMoveFlag( false );
							mpSkillExecuter->ExecuteAttack( pObj );
							return true;
						}
					}
				}
				break;
			case eOBJECTTYPE_MONSTER:
				{
					cBaseObject* curTarget = HERO->GetTargetObject();
					if( pObj == curTarget )
					{
						HERO->SetWaitMoveFlag( false );
						mpSkillExecuter->ExecuteAttack( pObj );
						return true;
					}
				}
				break;
			default:
				break;
			}
		}
		return false;
	}

	/// 스킬 장착
	/// 바닥 기준 스킬이 장착인 경우
	if( SKILLEXECUTER->IsFieldSkillCharge() == true )
	{
		NiPoint3 pos;
		if( WORLDMAN->Pick( &pos, mouseX, mouseY ) == false )
		{
			SKILLEXECUTER->ChargeOff( SKILLEXECUTER->GetChargeSkill() );
			return true;
		}
		else
		{
			/// 바닥 기준 스킬 사용..
			SKILLEXECUTER->ExecuteSkill( SKILLEXECUTER->GetChargeSkill(), pos );
		}

		return true;
	}

	///
	eOBJECTTYPE type = (eOBJECTTYPE)OBJECTMAN->ObjectPicking( mouseX, mouseY, &pObj );
	if( pObj == 0 )
	{
		/// 장착 해제
		SKILLEXECUTER->ChargeOff( SKILLEXECUTER->GetChargeSkill() );
		return true;
	}
	else
	{
		cBaseObject* curTarget = HERO->GetTargetObject();
		if( curTarget == 0 || curTarget->GetState() == eOBJECT_STATE_DIE )
		{
			/// 신규 타겟 등록후 발동
			HERO->SetTargetObject( type, pObj->GetObjectID() );
			SKILLEXECUTER->ExecuteSkill( SKILLEXECUTER->GetChargeSkill() );
		}
		else
		{
			/// 타겟 변경 없이 발동
			cBaseObject* target = OBJECTMAN->GetObject( type, pObj->GetObjectID() );
			SKILLEXECUTER->ExecuteSkill( SKILLEXECUTER->GetChargeSkill(), target );
		}
	}

	return true;
}

bool cSkillManager::ProcessLButtonDClick( int mouseX, int mouseY )
{
	if( SKILLEXECUTER->IsSkillCharge() == false )
	{
		/// 기본 공격
		cBaseObject* pObj = 0;
		eOBJECTTYPE type = (eOBJECTTYPE)OBJECTMAN->ObjectPicking( mouseX, mouseY, &pObj );
		if( pObj )
		{
			switch( type )
			{
			case eOBJECTTYPE_PLAYER:
				{
					cBaseObject* curTarget = HERO->GetTargetObject();
					if( pObj == curTarget )
					{
						if( DUELMAN->IsDuelEnemy( (cPlayer*)curTarget ) ||
							PVPMAN->IsEnableAttack( (cPlayer*)curTarget ) )
						{
							HERO->SetWaitMoveFlag( false );
							mpSkillExecuter->ExecuteAttack( pObj );
							return true;
						}
					}
				}
				break;
			case eOBJECTTYPE_MONSTER:
				{
					cBaseObject* curTarget = HERO->GetTargetObject();
					if( pObj == curTarget )
					{
						HERO->SetWaitMoveFlag( false );
						mpSkillExecuter->ExecuteAttack( pObj );
						return true;
					}
				}
				break;
			default:
				break;
			}
		}
		return false;
	}

	if( SKILLEXECUTER->IsFieldSkillCharge() == true )
	{
		NiPoint3 pos;
		if( WORLDMAN->Pick( &pos, mouseX, mouseY ) == false )
		{
			SKILLEXECUTER->ChargeOff( SKILLEXECUTER->GetChargeSkill() );
			return false;
		}
		else
			/// 바닥 기준 스킬 사용..
			SKILLEXECUTER->ExecuteSkill( SKILLEXECUTER->GetChargeSkill(), pos );

		return true;
	}

	/// skill charge
	cBaseObject* pObj = 0;
	eOBJECTTYPE type = (eOBJECTTYPE)OBJECTMAN->ObjectPicking( mouseX, mouseY, &pObj );
	if( pObj == 0 )
	{
		/// 장착 해제
		SKILLEXECUTER->ChargeOff( SKILLEXECUTER->GetChargeSkill() );
		return true;
	}
	else
	{
		cBaseObject* curTarget = HERO->GetTargetObject();
		if( curTarget == 0 || curTarget->GetState() == eOBJECT_STATE_DIE )
		{
			/// 신규 타겟 등록후 발동
			HERO->SetTargetObject( type, pObj->GetObjectID() );
			SKILLEXECUTER->ExecuteSkill( SKILLEXECUTER->GetChargeSkill() );
		}
		else
		{
			/// 타겟 변경 없이 발동
			cBaseObject* target = OBJECTMAN->GetObject( type, pObj->GetObjectID() );
			SKILLEXECUTER->ExecuteSkill( SKILLEXECUTER->GetChargeSkill(), target );
		}
	}

	return true;
}

void cSkillManager::InitKeepSkill( sHaveSkill* pdata )
{
	if( pdata == 0 )
	{
		assert(0);
		return;
	}

	sKeepSkill* pSkill = new sKeepSkill;
	pSkill->mStep = pdata->mSkillStep;
	pSkill->mRestTime = pdata->mRestCoolTime;

	pSkill->mTotalTime;
	pSkill->mStartTime;

	/// casting time setting
	sPlayerSkillBaseInfo* p = SKILLSCRIPT->GetPlayerSkillInfo( pdata->mSkillIdx );
	if( p == 0 )
	{
		assert(0);
		return;
	}
	if( p->mStepCount <= pdata->mSkillStep )
	{
		assert(0);
		return;
	}
	sPlayerSkillStepInfo stepInfo =  p->mpSetpInfoArray[pdata->mSkillStep];
	pSkill->mCastingTime = stepInfo.mCastingTime;


	if( mKeepSkillMap.Insert( pdata->mSkillIdx, pSkill ) == false )
	{
		assert(0);
	}

	if( p->mType != eSKILLTYPE_PASSIVE )
		DRAMATURGYMAN->DirectLoadPlayerDramaObj( pdata->mSkillIdx );

	UpdateSkillStep( pdata->mSkillIdx, pdata->mSkillStep );
	StartCoolTime( pdata->mSkillIdx, pSkill->mRestTime );
}

void cSkillManager::AddKeepSkill( unsigned long skillIdx, unsigned char skillStep )
{
	sKeepSkill* pSkill = new sKeepSkill;
	pSkill->mStep = skillStep;
	pSkill->mRestTime = 0;

	/// casting time setting
	sPlayerSkillBaseInfo* p = SKILLSCRIPT->GetPlayerSkillInfo( skillIdx );
	if( p == 0 )
	{
		assert(0);
	}
	if( p->mStepCount <= skillStep )
	{
		assert(0);
	}
	sPlayerSkillStepInfo stepInfo =  p->mpSetpInfoArray[skillStep];
	pSkill->mCastingTime = stepInfo.mCastingTime;

	if( mKeepSkillMap.Insert( skillIdx, pSkill ) == false )
	{
		assert(0);
	}

	if( p->mType != eSKILLTYPE_PASSIVE )
		DRAMATURGYMAN->DirectLoadPlayerDramaObj( skillIdx );

	UpdateSkillStep( skillIdx, skillStep );
}

void cSkillManager::UpdateAllSkill()
{
	cSkillWindow* pWin = (cSkillWindow*)UIMAN->GetContainer( eUIID_GAME_SKILLWINDOW );
	if( pWin == 0 )
	{
		assert(0);
		return;
	}

	/// 정보 갱신
	cSkillMap::cIterator i = mKeepSkillMap.Begin();
	cSkillMap::cIterator iend = mKeepSkillMap.End();
	for( ;i!=iend;i++ )
	{
		unsigned long idx = (*i).mFirst;
		sKeepSkill* p = (sKeepSkill*)(*i).mSecond;
		pWin->UpdateSkillStep( idx, p->mStep );
	}
}

void cSkillManager::ClearAllKeepSkill()
{
	cSkillMap::cIterator i = mKeepSkillMap.Begin();
	cSkillMap::cIterator iend = mKeepSkillMap.End();
	for( ;i!=iend;i++ )
	{
		sKeepSkill* p = (sKeepSkill*)(*i).mSecond;
		delete p;
	}
	mKeepSkillMap.Clear();
}

void cSkillManager::UpdateSkillStep( unsigned long idx, unsigned char step )
{
	sKeepSkill* p = (sKeepSkill*)mKeepSkillMap.GetAt( idx );
	if( p )
	{
		/// casting time setting
		sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( idx );
		if( pInfo == 0 )
		{
			assert(0);
		}
		if( pInfo->mStepCount <= step )
		{
			assert(0);
		}
		sPlayerSkillStepInfo stepInfo =  pInfo->mpSetpInfoArray[step];

		p->mCastingTime = stepInfo.mCastingTime;
		p->mStep = step;

		/// skill window cooltime변경
		cSkillWindow* pWin = (cSkillWindow*)UIMAN->GetContainer( eUIID_GAME_SKILLWINDOW );
		if( pWin )
			pWin->UpdateSkillStep( idx, p->mStep );
	}
	else
	{
		assert(0);
	}
}

void cSkillManager::NetworkMsgParser( char* pMsg )
{
	MSGROOT* pTemMsg = (MSGROOT*)pMsg;

	switch( pTemMsg->Protocol )
	{
	case NM_SKILL_USED_MON_RES:
	case NM_SKILL_USED_RES:
	case NM_SKILL_POS_USED_RES:
		{
			MSG_RES_SKILL_USED* pResMsg = (MSG_RES_SKILL_USED*)pMsg;
			cSkillObject* pObj = (cSkillObject*)mDummySkillMap.GetAt( pResMsg->mManagedKey );

			/// 발동 성공
			if( pResMsg->ErrorCode == 0 )
			{
				/// mp setting
				HERO->MPChange( pResMsg->mObjectMP, pResMsg->mMaxMP );

				if( pObj )
				{
					/// 인증 성공이므로 관리형태로 이동
					mDummyIndexGen.RestoreIndex( pResMsg->mManagedKey );
					mDummySkillMap.Erase( pResMsg->mManagedKey );

					/// 관리 구조에 포함 시킨다.
					if( mSkillObjectMap.Insert( pResMsg->mSkillIndex, pObj ) )
					{
						pObj->SetManagedKey( pResMsg->mSkillIndex, false );
						
						if( pTemMsg->Protocol == NM_SKILL_USED_MON_RES )
							SKILLMAN->StartCoolTime_Mon( pResMsg->mSkillClassIndex );
						else 
							SKILLMAN->StartCoolTime( pResMsg->mSkillClassIndex );
					}
					else
					{
						assert(0);
						SKILLMAN->DeleteSkillObject( pObj );

						if( HERO->IsReadyUseSkill() == false )
							HERO->SetReadyUseSkill( true );
						return;
					}
				}
			}
			else	/// 발동 실패
			{
				switch( pResMsg->ErrorCode )
				{
				case SKILL_USED_ERR_SKILLTYPE:	/// 스킬 종류 / 인덱스가 틀림
				case SKILL_USED_ERR_SCRIPT:		/// 스크립트 오류
				case SKILL_USED_ERR_UNIQUEIDX:	/// 스킬 객체 고유번호 오류
				case SKILL_USED_ERR_OBJECTINIT:	/// 스킬 객체 초기화 실패
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6200 ) );
					}
					break;

				case SKILL_USED_ERR_ATTAKCERPOS:	/// 공격자 위치가 안맞음
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6201 ) );
					}
					break;
				case SKILL_USED_ERR_USING:			/// 스킬 사용중
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6202 ) );
					}
					break;	
				case SKILL_USED_ERR_TARGETDIST:		/// 스킬 사거리밖에 타겟
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6203 ) );
					}
					break;
				case SKILL_USED_ERR_COOLTIME:		/// 쿨타임
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6204 ) );
					}
					break;
				case SKILL_USED_ERR_ATTACKERSTATE:	/// 공격자 상태 변경 불가
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6205 ) );
					}
					break;
				case SKILL_USED_ERR_USEVALUE:		/// 소모값 부족
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6206 ) );
					}
					break;
				case SKILL_USED_ERR_TARGETOBJECT:	/// 타겟 객체 오류
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6207 ) );
					}
					break;
				case SKILL_USED_ERR_TARGETSELECT:	/// 타겟선정 오류
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6207 ) );
					}
					break;
				case SKILL_USED_ERR_PASSIVE:		/// 패시브 사용
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6208 ) );
					}
					break;
				case SKILL_USED_ERR_DONTHAVE:		/// 보유스킬이 아님
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6209 ) );
					}
					break;
				case SKILL_USED_ERR_EQUIPMENT:		/// 장비 오류
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6210 ) );
					}
					break;
				case SKILL_USED_ERR_CHG_MONSTER:
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6213 ) );
					}
				}

				/// 실패 등록
				if( pObj )
                    pObj->VerifyFaile( false );
			}
		}
		break;
	case NM_SKILL_ITEMVEHICLE_SYN:
	case NM_SKILL_ITEMMAPCHANGE_SYN:
	case NM_SKILL_USED_SYN:
	case NM_SKILL_CAST_USED_SYN:
		{
			MSG_SYN_SKILL_USED* pSynMsg = (MSG_SYN_SKILL_USED*)pMsg;

			if( pSynMsg->mAttacker.type != eOBJECTTYPE_PLAYER )
			{
				assert(0);
				return;
			}

			cBaseObject* pAttacker = OBJECTMAN->GetObject( &pSynMsg->mAttacker );
			cBaseObject* pTarget = OBJECTMAN->GetObject( &pSynMsg->mTarget );
			if( pAttacker == 0 )
			{
				assert(0);
				return;
			}

			pAttacker->FixPos( pSynMsg->mAttackerPosX, pSynMsg->mAttackerPosY );
			if( pTarget )
				pTarget->FixPos( pSynMsg->mTargetPosX, pSynMsg->mTargetPosY );

			pAttacker->MPChange( pSynMsg->mObjectMP, pSynMsg->mObjectMaxMP );

			/// 기본 공격
			if( pSynMsg->mSkillClassIndex < NORMAL_ATTACK_SKILL_MAX )
			{
				cPlayer* pPlayer = (cPlayer*)pAttacker;
				pPlayer->PlayerAttack( pSynMsg->mSkillIndex, pSynMsg->mSkillClassIndex, pTarget );
			}
			else	/// 스킬 공격
			{
				cPlayer* pPlayer = (cPlayer*)pAttacker;
				sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( pSynMsg->mSkillClassIndex );
				if( pInfo )
				{
					sPlayerSkillStepInfo stepInfo = pInfo->mpSetpInfoArray[0];
					if( stepInfo.mApplyValueType1 == eSTATUSPLUS_MAPCHANGE )
					{
						pPlayer->PlayerMapChangeSkill( pSynMsg->mSkillIndex, pSynMsg->mSkillClassIndex );
					}
					else if( stepInfo.mApplyValueType1 == eSTATUSPLUS_VEHICLE )
					{
						pPlayer->PlayerVehicleSkill( pSynMsg->mSkillIndex, pSynMsg->mSkillClassIndex );
					}
					else
					{
						pPlayer->PlayerUseSkill( pSynMsg->mSkillIndex, pSynMsg->mSkillClassIndex, pTarget );
					}
				}
			}
		}
		break;
	case NM_SKILL_MONSTER_USED_SYN:
	case NM_SKILL_MONSTER_CAST_USED_SYN:
		{
			MSG_SYN_MONSTER_SKILL_USED* pSynMsg = (MSG_SYN_MONSTER_SKILL_USED*)pMsg;

			if( pSynMsg->mAttacker.type != eOBJECTTYPE_MONSTER )
			{
				assert(0);
				return;
			}

			cBaseObject* pAttacker = OBJECTMAN->GetObject( &pSynMsg->mAttacker );
			cBaseObject* pTarget = OBJECTMAN->GetObject( &pSynMsg->mTarget );
			if( pAttacker == 0 )
			{
				assert(0);
				return;
			}

			pAttacker->FixPos( pSynMsg->mAttackerPosX, pSynMsg->mAttackerPosY );

			cMonster* pMonster = (cMonster*)pAttacker;
			pMonster->MonsterAttack( pSynMsg->mSkillIndex, pSynMsg->mAttackType, pTarget, pSynMsg->mAttackSpeedFactor );
		}
		break;
	case NM_SKILL_ITEMVEHICLE_RES:
	case NM_SKILL_ITEMMAPCHANGE_RES:
	case NM_SKILL_CAST_USED_MON_RES:
	case NM_SKILL_CAST_USED_RES:
	case NM_SKILL_POS_CAST_USED_RES:
		{
			//MSG_RES_SKILL_USED
			MSG_RES_SKILL_USED* pResMsg = (MSG_RES_SKILL_USED*)pMsg;

			cSkillObject* pObj = (cSkillObject*)mDummySkillMap.GetAt( pResMsg->mManagedKey );
			if( pObj == 0 || pObj->GetSkillIdx() != pResMsg->mSkillClassIndex )
			{
				assert(0);
				return;
			}

			/// 발동 성공
			if( pResMsg->ErrorCode == 0 )
			{
				/// 인증 성공이므로 관리형태로 이동
				mDummyIndexGen.RestoreIndex( pResMsg->mManagedKey );
				mDummySkillMap.Erase( pResMsg->mManagedKey );

				/// 관리 구조에 포함 시킨다.
				if( mSkillObjectMap.Insert( pResMsg->mSkillIndex, pObj ) )
				{
					pObj->SetManagedKey( pResMsg->mSkillIndex, false );
				}
				else
				{
					assert(0);
					return;
				}
			}
			else /// 캐스팅 요청 실패
			{
				switch( pResMsg->ErrorCode )
				{
				case SKILL_USED_ERR_SKILLTYPE:	/// 스킬 종류 / 인덱스가 틀림
				case SKILL_USED_ERR_SCRIPT:		/// 스크립트 오류
				case SKILL_USED_ERR_UNIQUEIDX:	/// 스킬 객체 고유번호 오류
				case SKILL_USED_ERR_OBJECTINIT:	/// 스킬 객체 초기화 실패
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6200 ) );
					}
					break;

				case SKILL_USED_ERR_ATTAKCERPOS:	/// 공격자 위치가 안맞음
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6201 ) );
					}
					break;
				case SKILL_USED_ERR_USING:			/// 스킬 사용중
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6202 ) );
					}
					break;	
				case SKILL_USED_ERR_TARGETDIST:		/// 스킬 사거리밖에 타겟
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6203 ) );
					}
					break;
				case SKILL_USED_ERR_COOLTIME:		/// 쿨타임
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6204 ) );
					}
					break;
				case SKILL_USED_ERR_ATTACKERSTATE:	/// 공격자 상태 변경 불가
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6205 ) );
					}
					break;
				case SKILL_USED_ERR_USEVALUE:		/// 소모값 부족
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6206 ) );
					}
					break;
				case SKILL_USED_ERR_TARGETOBJECT:	/// 타겟 객체 오류
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6207 ) );
					}
					break;
				case SKILL_USED_ERR_TARGETSELECT:	/// 타겟선정 오류
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6207 ) );
					}
					break;
				case SKILL_USED_ERR_PASSIVE:		/// 패시브 사용
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6208 ) );
					}
					break;
				case SKILL_USED_ERR_DONTHAVE:		/// 보유스킬이 아님
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6209 ) );
					}
					break;
				case SKILL_USED_ERR_EQUIPMENT:		/// 장비 오류
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6210 ) );
					}
					break;
				case SKILL_USED_ERR_CHG_MONSTER:
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6213 ) );
					}
				}

				/// 실패 등록
				pObj->VerifyFaile( true );
			}
		}
		break;
	case NM_SKILL_CAST_ACTIVE_SYN:
	case NM_SKILL_POS_CAST_ACTIVE_SYN:
		{
			MSG_SYN_SKILL_CAST_ACTIVE* pSynMsg = (MSG_SYN_SKILL_CAST_ACTIVE*)pMsg;

			cSkillObject* pSkillObj = (cSkillObject*)mSkillObjectMap.GetAt( pSynMsg->mSkillIndex );;
			if( pSkillObj )
			{
				sObject& obj = pSynMsg->mAttacker;
//				if( obj.index == HERO->GetObjectID() )
				pSkillObj->EndCast();

				if( pSkillObj->GetSpecialType() > eSpecial_Field )
					return;

				///
				cBaseObject* pObj = (cBaseObject*)OBJECTMANAGER->GetObject( &pSynMsg->mAttacker );
				if( pObj )
				{
					if( pSynMsg->mAttacker.type == eOBJECTTYPE_HERO )
						SKILLMAN->StartCoolTime( pSkillObj->GetSkillIdx() );
					else if( pSynMsg->mAttacker.type == eOBJECTTYPE_PLAYER )
						pObj->MPChange( pSynMsg->mObjectMP, pSynMsg->mObjectMaxMp );

					pObj->FixPos( pSynMsg->mAttackerPosX, pSynMsg->mAttackerPosY );
				}
			}
		}
		break;
	case NM_SKILL_CAST_ACTIVITY_FAIL_SYN:
		{
			MSG_SYN_SKILL_CAST_ACTIVITY_FAIL* pSynMsg = (MSG_SYN_SKILL_CAST_ACTIVITY_FAIL*)pMsg;

			cSkillObject* pSkillObj = (cSkillObject*)mSkillObjectMap.GetAt( pSynMsg->mSkillIndex );
			if( pSkillObj )
				pSkillObj->VerifyFaile( true );

			cBaseObject* pObject = OBJECTMANAGER->GetObject( &pSynMsg->mAttacker );
			if( pObject->GetObjectType() == eOBJECTTYPE_HERO )
			{
				switch( pSynMsg->mFailCode )
				{
				case FAIL_SKILL_CASTING_MP_EMPTY:
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6206 ) );
					}
					break;
				case FAIL_SKILL_CASTING_DONT_TARGET:
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 6205 ) );
					}
					break;
				case FAIL_SKILL_CASTING_DONT_MAPCHANGE:
					{
						CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, GAMERESOURCEMAN->GetGameText( 98 ) );
					}
					break;
				}
			}
		}
		break;
	case NM_SKILL_CAST_CANCEL_RES:
		{
			/// cancel이 성공한 경우에만 받는다.
			MSG_RES_SKILL_CAST_CANCEL* pResMsg = (MSG_RES_SKILL_CAST_CANCEL*)pMsg;

			cSkillObject* pSkillObj = (cSkillObject*)mSkillObjectMap.GetAt( pResMsg->mSkillIndex );
			if( pSkillObj )
				pSkillObj->VerifyFaile();
		}
		break;
	case NM_SKILL_CAST_CANCEL_SYN:
		{
			/// cancel이 성공한 경우에만 받는다.
			MSG_SYN_SKILL_CAST_CANCEL* pSynMsg = (MSG_SYN_SKILL_CAST_CANCEL*)pMsg;

			cSkillObject* pSkillObj = (cSkillObject*)mSkillObjectMap.GetAt( pSynMsg->mSkillIndex );
			if( pSkillObj )
				pSkillObj->VerifyFaile( true );
		}
		break;
	case NM_SKILL_POS_USED_SYN:
	case NM_SKILL_POS_CAST_USED_SYN:
		{
			//MSG_SYN_POS_USED;
			MSG_SYN_POS_USED* pSynMsg = (MSG_SYN_POS_USED*)pMsg;

			if( pSynMsg->mAttacker.type != eOBJECTTYPE_PLAYER )
			{
				assert(0);
				return;
			}

			cBaseObject* pAttacker = OBJECTMAN->GetObject( &pSynMsg->mAttacker );
			if( pAttacker == 0 )
			{
				assert(0);
				return;
			}

			pAttacker->FixPos( pSynMsg->mAttackerPosX, pSynMsg->mAttackerPosY );
			pAttacker->MPChange( pSynMsg->mObjectMP, pSynMsg->mObjectMaxMP );

			/// 기본 공격
			if( pSynMsg->mSkillClassIndex < NORMAL_ATTACK_SKILL_MAX )
			{
				assert(0);
				return;
			}

			NiPoint3 pos;
			pos.x = pSynMsg->mTargetPosX;
			pos.y = pSynMsg->mTargetPosY;

			cPlayer* pPlayer = (cPlayer*)pAttacker;
			pPlayer->PlayerUseSkill( pSynMsg->mSkillIndex, pSynMsg->mSkillClassIndex, pos );
		}
		break;
	case NM_SKILL_USED_POS_ERROR_RES:
		{
			MSG_RES_SKILL_POS* pResMsg = (MSG_RES_SKILL_POS*)pMsg;

			HERO->FixPos( pResMsg->mAttackerPosX, pResMsg->mAttackerPosY );

			cBaseObject* pTarget = OBJECTMANAGER->GetObject( &pResMsg->mTarget );
			if( pTarget )
			{
				pTarget->FixPos( pResMsg->mTargetPosX, pResMsg->mTargetPosY );
			}
		}
		break;
	case NM_SKILL_DAMAGE_SYN:
	case NM_SKILL_DAMAGEMP_SYN:
		{
			MSG_SYN_SKILL_DAMAGE* pSynMsg = (MSG_SYN_SKILL_DAMAGE*)pMsg;

			cSkillObject* pObj = (cSkillObject*)mSkillObjectMap.GetAt( pSynMsg->mSkillIndex );
			if( pObj == 0 )
			{
				if( pSynMsg->mAttackerDie == true )
					return;

				/// 스킬 객체가 없는 경우..
				/// 연출 보정을 위해서 객체를 생성해서 적용한다.
				pObj = SKILLMAN->CreateRevisionSkillObject( pSynMsg->mSkillIndex, 
															pSynMsg->mSkillClassIndex, 
															pSynMsg->mAttackerType,
															pSynMsg->mDramaKey, 
															pSynMsg->mIsChangeMonster );
				if( pObj == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, _T("Wrong revision skill object(2)!") );
					assert(0);
					return;
				}
			}

			if( pSynMsg->mAttackerDie == true )
			{
				pObj->VerifyFaile( false );
				return;
			}

			if( pSynMsg->mTargetCount == 0 )
			{
				pObj->VerifySuccess();
				return;
			}

			cBaseObject* attacker = pObj->GetUser();
			sTargetDamage* pTargetDamage = pSynMsg->mTargetDamage;
			for( unsigned char i=0; i<pSynMsg->mTargetCount; ++i )
			{
				/// 클라이언트 스킬객체 삭제 목적의 메세지 인경우 타겟 hp 감소 안함
				if( pTargetDamage->mIsOnlyClientObjectDel == false )
				{
					cBaseObject* pTarget = (cBaseObject*)OBJECTMANAGER->GetObject( &pTargetDamage->mTarget );
					if( pTarget )
					{
						if( pTargetDamage->mInfluenceMiss == true )
							pTarget->ApplyDamageDrama( 0, eDAMAGEPRINT_MISS );
					}
				}

				pObj->AddDamageTargetInfo( pTargetDamage );
				pObj->VerifySuccess();

				/// 080710 PKH 가변에 가변 길이 메세지 포인터위치 재계산
				pTargetDamage = (sTargetDamage*)((char*)pTargetDamage + pTargetDamage->GetLength( ));
			}
		}
		break;
	case NM_SKILL_DAMAGE_HP_SYN:
		{
			MSG_SYN_SKILL_DAMAGE_HP* pSynMsg = (MSG_SYN_SKILL_DAMAGE_HP*)pMsg;

			cBaseObject* pAttacker = OBJECTMANAGER->GetObject( &pSynMsg->mAttacker );
			for( unsigned int i=0; i<pSynMsg->mCount; i++ )
			{
				 cBaseObject* pTarget = OBJECTMANAGER->GetObject( &pSynMsg->mTargetDamage[i].mTarget );
				 if( pTarget == 0 )
					 continue;

				 pTarget->MPChange( pSynMsg->mTargetDamage[i].mObjectMP, pSynMsg->mTargetDamage[i].mObjectMaxMP );
				 pTarget->HPChange( &pSynMsg->mTargetDamage[i], pAttacker );
			}
		}
		break;
	case NM_SKILL_HEAL_SYN:
		{
			MSG_SYN_SKILL_HEAL* pSynMsg = (MSG_SYN_SKILL_HEAL*)pMsg;
			cSkillObject* pObj = (cSkillObject*)mSkillObjectMap.GetAt( pSynMsg->mSkillIndex );
			if( pObj == 0 )
			{
				if( pSynMsg->mAttackerDie == true )
					return;

				/// 스킬 객체가 없는 경우..
				/// 연출 보정을 위해서 객체를 생성해서 적용한다.
				pObj = SKILLMAN->CreateRevisionSkillObject( pSynMsg->mSkillIndex, 
															pSynMsg->mSkillClassIndex, 
															pSynMsg->mAttackerType,
															pSynMsg->mDramaKey,
															pSynMsg->mIsChangeMonster );
				if( pObj == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, _T("Wrong revision skill object(2)!") );
					assert(0);
					return;
				}
			}

			if( pSynMsg->mAttackerDie == true )
			{
				pObj->VerifyFaile( false );
				return;
			}

			if( pSynMsg->mTargetCount == 0 )
			{
				pObj->VerifySuccess();
				return;
			}

			for( unsigned char i=0; i<pSynMsg->mTargetCount; ++i )
			{
				/// hp setting
				sTargetHeal* pTargetHeal = &pSynMsg->mTargetHeal[i];
				cBaseObject* pTarget = (cBaseObject*)OBJECTMANAGER->GetObject( &pTargetHeal->mTarget );
				if( pTarget )
				{
					pTarget->HPChange( pTargetHeal->mObjectHP, pTargetHeal->mObjectMaxHP, false );

					if( pTargetHeal->mInfluenceMiss == true )
					{
						pTarget->ApplyDamageDrama( 0, eDAMAGEPRINT_MISS );
					}
				}

				pObj->AddHealTargetInfo( pTargetHeal );
				pObj->VerifySuccess();
			}
		}
		break;
	case NM_SKILL_APPLY_SYN:
		{
			/// None_Active중 Heal을 제외한 모든 스킬의 적용 메세지..
			MSG_SYN_SKILL_APPLY* pSynMsg = (MSG_SYN_SKILL_APPLY*)pMsg;
			cSkillObject* pObj = (cSkillObject*)mSkillObjectMap.GetAt( pSynMsg->mSkillIndex );
			if( pObj == 0 )
			{
				if( pSynMsg->mAttackerDie == true )
					return;

				/// 스킬 객체가 없는 경우..
				/// 연출 보정을 위해서 객체를 생성해서 적용한다.
				pObj = SKILLMAN->CreateRevisionSkillObject( pSynMsg->mSkillIndex, 
															pSynMsg->mSkillClassIndex, 
															pSynMsg->mAttackerType,
															pSynMsg->mDramaKey,
															pSynMsg->mIsChangeMonster );
				if( pObj == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, _T("Wrong revision skill object(1)!") );
					assert(0);
					return;
				}
			}

			if( pSynMsg->mAttackerDie == true )
			{
				pObj->VerifyFaile( false );
				return;
			}

			if( pSynMsg->mApplyCount == 0 )
			{
				pObj->VerifySuccess();
				return;
			}

			for( unsigned char i=0; i<pSynMsg->mApplyCount; ++i )
			{
				sTargetApply pTargetApply = pSynMsg->mApplyObject[i];
				cBaseObject* pTarget = (cBaseObject*)OBJECTMANAGER->GetObject( &pTargetApply.mTarget );
				if( pTarget )
				{
					if( pTargetApply.mInfluenceMiss == true )
					{
						pTarget->ApplyDamageDrama( 0, eDAMAGEPRINT_MISS );
					}
				}

				pObj->AddTargetInfo( &pTargetApply.mTarget );
				pObj->VerifySuccess();
			}
		}
		break;
	case NM_SKILL_DELTARGET_SYN:
		{
			/// None_Active중 Heal을 제외한 모든 스킬의 적용 메세지..
			MSG_SYN_SKILL_DELTARGET* pSynMsg = (MSG_SYN_SKILL_DELTARGET*)pMsg;
			cSkillObject* pObj = (cSkillObject*)mSkillObjectMap.GetAt( pSynMsg->mSkillIndex );
			if( pObj == 0 )
			{
				if( pSynMsg->mAttackerDie == true )
					return;

				/// 스킬 객체가 없는 경우..
				/// 연출 보정을 위해서 객체를 생성해서 적용한다.
				pObj = SKILLMAN->CreateRevisionSkillObject( pSynMsg->mSkillIndex, 
					pSynMsg->mSkillClassIndex, 
					pSynMsg->mAttackerType,
					pSynMsg->mDramaKey,
					false );
				if( pObj == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, _T("Wrong revision skill object(1)!") );
					assert(0);
					return;
				}
			}

			if( pSynMsg->mAttackerDie == true )
			{
				pObj->VerifyFaile( false );
				return;
			}

			if( pSynMsg->mDelTargetIndex != 0 )
			{
				/// 타겟 해제
				const sObject* target = HERO->GetTargetInfo();
				if( target->type == pSynMsg->mDelTargetType && target->index == pSynMsg->mDelTargetIndex )
					HERO->SetTargetObject( eOBJECTTYPE_NONE, 0 );
			}

			if( pSynMsg->mApplyCount == 0 )
			{
				pObj->VerifySuccess();
				return;
			}

			for( unsigned char i=0; i<pSynMsg->mApplyCount; ++i )
			{
				sTargetApply pTargetApply = pSynMsg->mApplyObject[i];
				cBaseObject* pTarget = (cBaseObject*)OBJECTMANAGER->GetObject( &pTargetApply.mTarget );
				if( pTarget )
				{
					if( pTargetApply.mInfluenceMiss == true )
					{
						pTarget->ApplyDamageDrama( 0, eDAMAGEPRINT_MISS );
					}
				}

				pObj->AddTargetInfo( &pTargetApply.mTarget );
				pObj->VerifySuccess();
			}
		}
		break;
	case NM_SKILL_INFLUENCE_CREATE_SYN:
		{
			MSG_SYN_INFLUENCE_CREATE* pSynMsg = (MSG_SYN_INFLUENCE_CREATE*)pMsg;

			cSkillWindow* pSkillWindow = GAMEUI->GetSkillWindow();

			cBaseObject* pObj = OBJECTMAN->GetObject( &(pSynMsg->mTarget) );
			if( pObj )
			{
				cInfluenceObject* p = CreateInfluenceObject( pSynMsg->mUniqueIdx, pSynMsg->mInfluenceClassIdx, pSynMsg->mAuraSkillClassIdx, pObj, pSynMsg->mDieDelete );
				if( p )
				{
					p->StartProcess( -1, true );

					if( p->IsHeroInfluence() && pSynMsg->mAuraSkillClassIdx > 0 )
					{
						/// 오라버프를 거는 스킬이면 윈도우에도 세팅
						if( pSkillWindow )
							pSkillWindow->SetOnAura( pSynMsg->mAuraSkillClassIdx, pSynMsg->mUniqueIdx, true );
					}
				}
				else
				{
					assert(0);
					return;
				}
			}
		}
		break;
	case NM_SKILL_INFLUENCE_ADDLIST_SYN:
		{
			MSG_SYN_INFLUENCE_ADDLIST* pmsg = (MSG_SYN_INFLUENCE_ADDLIST*)pMsg;

			sInfluenceClient* pInfluence;
			cBaseObject* pObj = OBJECTMAN->GetObject( &pmsg->mObject );
			if( pObj )
			{
				for( long i = 0 ; i < pmsg->mRowCount ; ++i )
				{
					pInfluence = &pmsg->mTable[i];
					cInfluenceObject* p = CreateInfluenceObject( pInfluence->mUniqueIdx, pInfluence->mInfluenceClassIdx, pInfluence->mAuraSkillClassIdx, pObj, pInfluence->mDieDelete );
					if( p )
					{
						p->StartProcess( pInfluence->mRestTime, true );
					}
					else
					{
						assert(0);
						return;
					}
				}
			}
		}
		break;

	case NM_SKILL_INFLUENCE_DELETE_SYN:
		{
			MSG_SYN_INFLUENCE_DELETE* pSynMsg = (MSG_SYN_INFLUENCE_DELETE*)pMsg;

			DeleteInfluenceObject( pSynMsg->mUniqueIdx );
		}
		break;
	case NM_SKILL_INFLUENCE_DELLIST_SYN:
		{
			MSG_SYN_INFLUENCE_DELLIST* pmsg = (MSG_SYN_INFLUENCE_DELLIST*)pMsg;

			unsigned long uniqueIdx;
			cBaseObject* pObj = OBJECTMAN->GetObject( &pmsg->mObject );
			if( pObj )
			{
				for( long i = 0 ; i < pmsg->mRowCount ; ++i )
				{
					uniqueIdx = pmsg->mUniqueIdx[i];

					DeleteInfluenceObject( uniqueIdx );
				}
			}
		}
		break;

	case NM_SKILL_INFLUENCE_HPCHAGNE_SYN:
		{
			MSG_SYN_SKILL_INFLUENCE_HPCHANGE* pmsg = (MSG_SYN_SKILL_INFLUENCE_HPCHANGE*)pMsg;

			cBaseObject* pTarget = (cBaseObject*)OBJECTMANAGER->GetObject( &pmsg->mTarget );
			if( pTarget )
			{
				pTarget->HPChange( pmsg->mObjectHP, pmsg->mObjectMaxHP, pmsg->mDie );

				cInfluenceObject* pObj = (cInfluenceObject*)mInfluenceMap.GetAt( pmsg->mInfluenceIdx );
				if( pObj )
				{
					/// 적용
					pObj->SetTickInfo( cInfluenceObject::eTick_HP, pmsg->mChangeValue );
				}
				else
				{
					assert(0);
				}
			}
		}
		break;
	case NM_SKILL_INFLUENCE_MPCHAGNE_SYN:
		{
			MSG_SYN_SKILL_INFLUENCE_MPCHANGE* pmsg = (MSG_SYN_SKILL_INFLUENCE_MPCHANGE*)pMsg;

			cBaseObject* pTarget = (cBaseObject*)OBJECTMANAGER->GetObject( &pmsg->mTarget );
			if( pTarget )
			{
				pTarget->MPChange( pmsg->mObjectMP, pmsg->mObjectMaxMP );

				cInfluenceObject* pObj = (cInfluenceObject*)mInfluenceMap.GetAt( pmsg->mInfluenceIdx );
				if( pObj )
				{
					/// 적용
					pObj->SetTickInfo( cInfluenceObject::eTick_MP, pmsg->mChangeValue );
				}
				else
				{
					assert(0);
				}
			}
		}
		break;
	case NM_SKILL_MP_DAMAGE_SYN:
		{
			/// 081013 PKH mp 대미지
			MSG_SYN_SKILL_MP_DMAMGE* pmsg = (MSG_SYN_SKILL_MP_DMAMGE*)pMsg;

			cBaseObject* pTarget = (cBaseObject*)OBJECTMANAGER->GetObject( &pmsg->mTarget );
			if( pTarget )
			{
				pTarget->MPChange( pmsg->mObjectMP, pmsg->mObjectMaxMP );

				/// 
				CreateApplyObject( pTarget, pmsg->mInfluenceClassIdx );
				pTarget->ApplyDamageDrama( pmsg->mChangeValue, eDAMAGEPRINT_NORMAL_ENEMY );
			}
		}
		break;
	case NM_SKILL_NONSKILL_HPCHANGE_SYN:
		{
			MSG_SYN_SKILL_NONSKILL_HPCHANGE* pmsg = (MSG_SYN_SKILL_NONSKILL_HPCHANGE*)pMsg;

			cBaseObject* pTarget = (cBaseObject*)OBJECTMANAGER->GetObject( &pmsg->mTarget );
			if( pTarget )
			{
				pTarget->HPChange( pmsg->mObjectHP, pmsg->mObjectMaxHP, false );

				/// 
				CreateApplyObject( pTarget, pmsg->mInfluenceClassIdx );

				pTarget->ApplyDamageDrama( pmsg->mChangeValue, eDAMAGEPRINT_HEAL_OUR );
			}
		}
		break;
	case NM_SKILL_NONSKILL_MPCHANGE_SYN:
		{
			MSG_SYN_SKILL_NONSKILL_MPCHANGE* pmsg = (MSG_SYN_SKILL_NONSKILL_MPCHANGE*)pMsg;

			cBaseObject* pTarget = (cBaseObject*)OBJECTMANAGER->GetObject( &pmsg->mTarget );
			if( pTarget )
			{
				pTarget->MPChange( pmsg->mObjectMP, pmsg->mObjectMaxMP );

				/// 
				CreateApplyObject( pTarget, pmsg->mInfluenceClassIdx );
				pTarget->ApplyDamageDrama( pmsg->mChangeValue, eDAMAGEPRINT_HEAL_ENEMY );
			}
		}
		break;
	case NM_SKILL_RESURRECTION_RES:
		{
			cStringT str;

			MSG_RES_SKILL_RESURRECTION* msg = (MSG_RES_SKILL_RESURRECTION*)pMsg;
			
			cPlayer* player = OBJECTMANAGER->GetPlayer( msg->mAttackerIdx );
			if( player )
			{
				UIMAN->SendEventToMsgbox( false, eMBEVENT_REVIVAL_STAND );

				str.Format( GAMERESOURCEMAN->GetGameText( 902 ), player->GetName() );
				UIMAN->CreateModal(	eStage_Game,
									eMBEVENT_REVIVAL_SKILL, 
									(LPCTSTR)str.Cstr(),	// 
									GAMERESOURCEMAN->GetGameText( 301 ),	// 알림
									eSKIN_YESNO
									);
			}
		}
		break;
	case NM_SKILL_RESURRECTION_SYN:
		{
			/// 부활 처리
			MSG_SYN_SKILL_RESURRECTION* synMsg = (MSG_SYN_SKILL_RESURRECTION*)pMsg;

			if( synMsg->mTarget.type == eOBJECTTYPE_PLAYER )
			{
				cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( synMsg->mTarget.index );
				if( pPlayer )
				{
					pPlayer->SetState( eOBJECT_STATE_IDLE );
					pPlayer->HPChange( synMsg->mTargetHP, synMsg->mTargetMaxHp, false );
					pPlayer->MPChange( synMsg->mTargetMP, synMsg->mTargetMaxMp );
				}
			}
		}
		break;
	case NM_SKILL_CHGMON_SKILLCOOLTIME:
		{
			MSG_RES_SKILL_CHGMON_COOLTIME* pmsg = (MSG_RES_SKILL_CHGMON_COOLTIME*)pMsg;

			/// 남은 쿨타임이 있는 경우에만 셋팅
			if( !( pmsg->mSkill1CoolTime == ULONG_MAX || pmsg->mSkill1CoolTime == 0 ) )
				SKILLMAN->StartCoolTime_Mon( eMONSTERATTACK_SKILL1, pmsg->mSkill1CoolTime );
			if( !( pmsg->mSkill2CoolTime == ULONG_MAX || pmsg->mSkill2CoolTime == 0 ) )
				SKILLMAN->StartCoolTime_Mon( eMONSTERATTACK_SKILL2, pmsg->mSkill2CoolTime );
			if( !( pmsg->mSkill3CoolTime == ULONG_MAX || pmsg->mSkill3CoolTime == 0 ) )
				SKILLMAN->StartCoolTime_Mon( eMONSTERATTACK_SKILL3, pmsg->mSkill3CoolTime );

			QUICKMAN->LoadCoolTimeMon();
		}
		break;
	}
}

bool cSkillManager::CheckBuySkill( unsigned long skillIdx, unsigned char skillStep )
{
	if( skillStep )
	{
		/// 보유 스킬 아니면 구매 불가능
		if( mKeepSkillMap.GetAt( skillIdx ) == 0 )
			return false;
	}

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

	sPlayerSkillStepInfo pStepInfo = pInfo->mpSetpInfoArray[skillStep];

	if( HERO->GetMoney() < pStepInfo.mUseMoney )
		return false;

	if( HERO->GetSkillPointRemain() < pStepInfo.mRequireSP )
		return false;

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

	/// 종족 체크
	switch( HERO->GetRace() )
	{
	case eRACE_HUMAN:
		if( pInfo->mRace != 0 && pInfo->mRace != 1 && pInfo->mRace != 4 && pInfo->mRace != 5 )
			return false;
		break;
	case eRACE_BEAST:
		if( pInfo->mRace != 0 && pInfo->mRace != 2 && pInfo->mRace != 4 && pInfo->mRace != 6 )
			return false;
		break;
	case eRACE_ELF:
		if( pInfo->mRace != 0 && pInfo->mRace != 3 && pInfo->mRace != 5 && pInfo->mRace != 6 )
			return false;
		break;
	default:
		assert(0);
		return false;
	}

	// 총사용 SP Check
	if( pInfo->mJobStep !=0 && pInfo->mJobStep != 9 )
	{
		unsigned long point = HERO->GetJobUsedSkillPoint( pInfo->mJobStep-1 );
		if( point < pInfo->mBeforeReqSP )
			return false;
	}

	// 선행 스킬 1
	if( pInfo->mLearnSkillIdx1 != 0 )
	{
		sKeepSkill* p = SKILLMAN->GetKeepInfo( pInfo->mLearnSkillIdx1 );
		if( p == 0 )
			return false;

		if( pInfo->mLearnSkillStep1 > p->mStep + 1 )
			return false;
	}

	// 선행 스킬 2
	if( pInfo->mLearnSkillIdx2 != 0 )
	{
		sKeepSkill* p = SKILLMAN->GetKeepInfo( pInfo->mLearnSkillIdx2 );
		if( p == 0 )
			return false;

		if( pInfo->mLearnSkillStep2 > p->mStep + 1 )
			return false;
	}

	/// 직업 체크
	if( SKILLSCRIPT->IsPlayerSkillJob( pStepInfo.mJobType, HERO->GetJob() ) == false )
		return false;

	return true;
}

void cSkillManager::StartCoolTime( unsigned long skillIdx, unsigned long restTime, float speedFactor )
{
	/*if( HERO->IsTransformMonster() )
	{
		StartCoolTime_Mon( skillIdx, restTime, speedFactor );
		return;
	}*/

	unsigned long idx = skillIdx;
	if( skillIdx < NORMAL_ATTACK_SKILL_MAX )
	{
		/// 기본공격 (보유스킬 절대번호)
		idx = NORMAL_ATTACK_SKILL;
	}

	/// 스킬 사용
	sKeepSkill* p = (sKeepSkill*)mKeepSkillMap.GetAt( idx );
	if( p == 0 )
	{
		assert(0);
		return;
	}

	sPlayerSkillBaseInfo* pInfo = (sPlayerSkillBaseInfo*)SKILLSCRIPT->GetPlayerSkillInfo( skillIdx );
	if( pInfo == 0 )
	{
		assert(0);
		return;
	}
	if( p->mStep >= pInfo->mStepCount )
	{
		assert(0);
		return;
	}
	sPlayerSkillStepInfo* pStep = &pInfo->mpSetpInfoArray[p->mStep];
	p->mTotalTime = (unsigned long)(pStep->mCoolTime * speedFactor);
	if( restTime == ULONG_MAX )
	{
		p->mRestTime = (unsigned long)(pStep->mCoolTime * speedFactor);

		/// 그룹 쿨타임 체크..
		if( idx != NORMAL_ATTACK_SKILL )
			UpdateExtraCooltime( skillIdx, p->mRestTime, pInfo->mGroupCoolTimeIdx );
	}
	else
	{
		p->mRestTime = (unsigned long)(restTime * speedFactor);
	}

	p->mStartTime = THEAPP->GetWorldAccumTime();

	/// skill window cooltime변경
	cSkillWindow* pWin = (cSkillWindow*)UIMAN->GetContainer( eUIID_GAME_SKILLWINDOW );
	if( pWin == 0 )
		return;

    pWin->StartCoolTime( idx, p->mRestTime, p->mTotalTime );
}

bool cSkillManager::IsUsedKeepSkill( unsigned long skillIdx )
{
	/// 스킬 사용 불가
	if( HERO->IsCantSkill( skillIdx ) == true )
		return false;

	sKeepSkill* p = (sKeepSkill*)mKeepSkillMap.GetAt( skillIdx );
	if( p == 0 )
		return false;

	if( p->mRestTime == 0  || p->mRestTime == ULONG_MAX )
		return true;

	return false;
}

bool cSkillManager::IsUsedMonsterSkill( unsigned long skillIdx )
{
	/// 스킬 사용 불가
	if( HERO->IsCantSkill( skillIdx ) == true )
		return false;

	/// 쿨타임은 별도로 저장하지 않고 아이콘에 저장된 값을 사용한다.

	return true;
}

void cSkillManager::UpdateExtraCooltime( unsigned long skillIdx, unsigned long restTime, unsigned long groupIdx  )
{
	/// skill window cooltime변경
	cSkillWindow* pWin = (cSkillWindow*)UIMAN->GetContainer( eUIID_GAME_SKILLWINDOW );
	if( pWin == 0 )
		return;

	cSkillMap::cIterator k, kend;
	k = mKeepSkillMap.Begin();
	kend = mKeepSkillMap.End();
	for( ; k != kend; ++k )
	{
		unsigned long idx = (unsigned long)(*k).mFirst;
		if( skillIdx == idx )
			continue;
		sKeepSkill* pKeepSkill = (sKeepSkill*)(*k).mSecond;

		sPlayerSkillBaseInfo* pInfo = SKILLSCRIPT->GetPlayerSkillInfo( idx );
		if( pInfo == 0 )
			continue;

		bool applyGroup = false;
		if( groupIdx != 0 && pInfo->mGroupCoolTimeIdx == groupIdx )
			applyGroup = true;

		if( applyGroup == true )
		{
			/// Apply Group cooltime
			if( pInfo->mStepCount <= pKeepSkill->mStep )
			{
				assert(0);
			}

			sPlayerSkillStepInfo* pStep = &pInfo->mpSetpInfoArray[pKeepSkill->mStep];
			if( pKeepSkill->mRestTime != 0 )
			{
				if( pKeepSkill->mRestTime >= restTime )
					continue;

				pKeepSkill->mRestTime = restTime;
				pKeepSkill->mTotalTime = restTime;
			}
			else
			{
				if( pStep->mCoolTime > restTime )
				{
					pKeepSkill->mRestTime = restTime;
					pKeepSkill->mTotalTime = restTime;
				}
				else
				{
					pKeepSkill->mRestTime = pStep->mCoolTime;
					pKeepSkill->mTotalTime = pStep->mCoolTime;
				}
			}
		}
		else
		{
			/// Apply Global cooltime 1min
			if( pKeepSkill->mRestTime == 0 )
			{
				if( pInfo->mType == eSKILLTYPE_PASSIVE )
					continue;

				pKeepSkill->mRestTime = 1000;
				pKeepSkill->mTotalTime = 1000;
			}
		}

		pKeepSkill->mStartTime = THEAPP->GetWorldAccumTime();
		pWin->StartCoolTime( idx, pKeepSkill->mRestTime, pKeepSkill->mTotalTime );
	}
}

void cSkillManager::StartCoolTime_Mon( unsigned long skillIdx, unsigned long restTime, float speedFactor )
{
	unsigned long classIdx = HERO->GetTransMonsterClassIdx();
	if( classIdx == 0 )
	{
		assert(0);
		return;
	}

	if( skillIdx < eMONSTERATTACK_SKILL1 || skillIdx >= eMONSTERATTACK_MAX )
		return;

	/// 스킬 사용
	sMonsterSkillScript* pInfo = (sMonsterSkillScript*)SKILLSCRIPT->GetMonsterSkillInfo( classIdx, (eMONSTERATTACK_TYPE)skillIdx );
	if( pInfo == 0 )
	{
		assert(0);
		return;
	}

	unsigned long total = unsigned long(pInfo->mCoolTime * speedFactor * 3.0f );
	if( restTime == ULONG_MAX )
		QUICKMAN->StartMonSkillCoolTime( (short)skillIdx, total );
	else
		QUICKMAN->InitMonSkillCooltime( (short)skillIdx, restTime, total );
}

void cSkillManager::DeleteInfluenceObject( unsigned long uniqueIdx )
{
	cInfluenceObject* p = (cInfluenceObject*)mInfluenceMap.GetAt( uniqueIdx );
	if( p )
	{
		cSkillWindow* pSkillWindow = GAMEUI->GetSkillWindow();
		cBuffWindow* pBuffWindow = GAMEUI->GetBuffWindow();
		if( p->IsHeroInfluence() )
		{
			/// 오라버프를 거는 스킬이면 윈도우에도 세팅
			if( pSkillWindow &&  p->IsAuraType() )
				pSkillWindow->SetOnAura( p->GetSkillIdx(), 0, false );

			if( pBuffWindow && pBuffWindow->IsNetLock() == true )
				pBuffWindow->NetUnLock();
		}

		bool calc = true;
		if( p->IsRemoved() == false )
		{
			p->Removed();

			unsigned long key = p->GetManagedKey();
			mInfluenceMap.Erase( key );

			calc = p->IsHeroInfluence();

			delete p;

			/// 071024 PKH 스테이터스 재계산
			if( calc )
				HERO->CalcStatus();

//			mDeleteInfluenceArray.PushBack( p );
		}
	}
}

void cSkillManager::DeleteInfluenceObject( cInfluenceObject* p )
{
	if( p )
	{
		cSkillWindow* pSkillWindow = GAMEUI->GetSkillWindow();
		cBuffWindow* pBuffWindow = GAMEUI->GetBuffWindow();
		if( p->IsHeroInfluence() )
		{
			/// 오라버프를 거는 스킬이면 윈도우에도 세팅
			if( pSkillWindow &&  p->IsAuraType() )
				pSkillWindow->SetOnAura( p->GetSkillIdx(), 0, false );

			if( pBuffWindow && pBuffWindow->IsNetLock() == true )
				pBuffWindow->NetUnLock();

			HERO->CalcStatus();
		}

		if( p->IsRemoved() == false )
		{
			p->Removed();

			mDeleteInfluenceArray.PushBack( p );
		}
	}
}