#include "gamesrv.h"

#include "StdAfx.h"
#include "DropScript.h"
#include "Drop_Common.h"
#include "GameFile.h"
#include "AppTimer.h"
#include "FileLoader.h"
#include "Tokenizer.h"
#include "MonsterScript.h"
#include "Monster_Common.h"


cDropScript* cDropScript::mpDropScript = NULL;



cDropScript::cDropScript(void)
{
	/// 싱글톤
	if( mpDropScript )
	{
		Verbose->WriteLog( "DropScript new error");
	}
	else
	{
		mpDropScript = this;
	}

}


bool cDropScript::Init()
{

	mpDropNTypeMap = new cPointrHashMap( 100 );
	mpDropSTypeMap = new cPointrHashMap( 100 );
	mpDropWTypeMap = new cPointrHashMap( 100 );
	mpDropExpIncreaseMap = new cDropExpIncrease( 20 );
	mpDropNTypeGatherMap = new cPointrHashMap( 100 );
	mpDropSTypeGatherMap = new cPointrHashMap( 100 );

	/// 파티인원별 경험치 증가폭
	if( !LoadPartyExpIncrease() )
		return false;

	/// N타입 드롭 정보 로드
	if( !LoadDropNType() )
		return false;

	/// S타입 드롭 정보 로드
	if( !LoadDropSType() )
		return false;

	/// 월드타입 드롭 정보 로드
	if( !LoadDropWType() )
		return false;

	if( LoadDropQType() == false )
		return false;

	/// 레벨차에 따른 수정치 로드
	if( !LoadDropExpIncrease() )
		return false;

	/// 채집
	if( !LoadDropNTypeGather() )
		return false;
	if( !LoadDropSTypeGather() )
		return false;
	if( !LoadDropQTypeGather() )
		return false;
	
	return true;

}



void cDropScript::Release()
{

	sPartyExp* pInfo = NULL;
	cPointrHashMap::cIterator i = mPartyExpIncrease.Begin();
	cPointrHashMap::cIterator end = mPartyExpIncrease.End();
	for( ; i != end; ++i )
	{
		pInfo = (sPartyExp*)((*i).mSecond);
		if( pInfo )
		{
			delete pInfo;
		}
	}
	mPartyExpIncrease.Clear();

	if( mpDropNTypeGatherMap )
	{
		sDropNTypeGather* pInfo = NULL;
		cAry* pInfoDataAry = NULL;
		sDropNTypeDataGather* pData = NULL;
		cPointrHashMap::cIterator i = mpDropNTypeGatherMap->Begin();
		cPointrHashMap::cIterator end = mpDropNTypeGatherMap->End();
		for( ; i != end; ++i )
		{
			pInfo = (sDropNTypeGather*)((*i).mSecond);
			if( pInfo == NULL)
				continue;

			pInfoDataAry = pInfo->mpData;
			if( pInfoDataAry == NULL )
				continue;

			for( unsigned long j = 0 ; j < pInfoDataAry->GetSize() ; ++j )
			{
				pData = (sDropNTypeDataGather*)(*pInfoDataAry)[j];
				delete pData;
			}
			pInfoDataAry->Clear();
			SAFE_DELETE( pInfoDataAry );
			SAFE_DELETE( pInfo );
		}
		mpDropNTypeGatherMap->Clear();
		SAFE_DELETE( mpDropNTypeGatherMap );
	}

	if( mpDropSTypeGatherMap )
	{
		sDropSTypeGather* pInfo = NULL;
		cAry* pInfoDataAry = NULL;
		sDropSTypeDataGather* pData = NULL;
		cPointrHashMap::cIterator i = mpDropSTypeGatherMap->Begin();
		cPointrHashMap::cIterator end = mpDropSTypeGatherMap->End();
		for( ; i != end; ++i )
		{
			pInfo = (sDropSTypeGather*)((*i).mSecond);
			if( pInfo == NULL)
				continue;

			pInfoDataAry = pInfo->mpData;
			if( pInfoDataAry == NULL )
				continue;

			for( unsigned long j = 0 ; j < pInfoDataAry->GetSize() ; ++j )
			{
				pData = (sDropSTypeDataGather*)(*pInfoDataAry)[j];
				delete pData;
			}
			pInfoDataAry->Clear();
			SAFE_DELETE( pInfoDataAry );
			SAFE_DELETE( pInfo );
		}
		mpDropSTypeGatherMap->Clear();
		SAFE_DELETE( mpDropSTypeGatherMap );
	}
	//

	if( mpDropNTypeMap )
	{
		sDropNType* pInfo = NULL;
		cAry* pInfoDataAry = NULL;
		sDropNTypeData* pData = NULL;
		cPointrHashMap::cIterator i = mpDropNTypeMap->Begin();
		cPointrHashMap::cIterator end = mpDropNTypeMap->End();
		for( ; i != end; ++i )
		{
			pInfo = (sDropNType*)((*i).mSecond);
			if( pInfo == NULL)
				continue;

			pInfoDataAry = pInfo->mpData;
			if( pInfoDataAry == NULL )
				continue;

			for( unsigned long j = 0 ; j < pInfoDataAry->GetSize() ; ++j )
			{
				pData = (sDropNTypeData*)(*pInfoDataAry)[j];
				delete pData;
			}
			pInfoDataAry->Clear();
			SAFE_DELETE( pInfoDataAry );
			SAFE_DELETE( pInfo );
		}
		mpDropNTypeMap->Clear();
		SAFE_DELETE( mpDropNTypeMap );
	}

	if( mpDropSTypeMap )
	{
		sDropSWType* pInfo = NULL;
		cAry* pInfoDataAry = NULL;
		sDropSWTypeData* pData = NULL;
		cPointrHashMap::cIterator i = mpDropSTypeMap->Begin();
		cPointrHashMap::cIterator end = mpDropSTypeMap->End();
		for( ; i != end; ++i )
		{
			pInfo = (sDropSWType*)((*i).mSecond);
			if( pInfo == NULL)
				continue;

			pInfoDataAry = pInfo->mpData;
			if( pInfoDataAry == NULL )
				continue;

			for( unsigned long j = 0 ; j < pInfoDataAry->GetSize() ; ++j )
			{
				pData = (sDropSWTypeData*)(*pInfoDataAry)[j];
				delete pData;
			}
			pInfoDataAry->Clear();
			SAFE_DELETE( pInfoDataAry );
			SAFE_DELETE( pInfo );
		}
		mpDropSTypeMap->Clear();
		SAFE_DELETE( mpDropSTypeMap );
	}

	mpDropExpIncreaseMap->Clear();
	SAFE_DELETE( mpDropExpIncreaseMap );

	sDropSWType* pInfo2 = NULL;
	cAry* pInfoDataAry = NULL;
	sDropSWTypeData* pData = NULL;
	for( unsigned long i = 0 ; i < mpShutDownDeleteWAry.GetSize() ; ++i )
	{
		pInfo2 = (sDropSWType*)mpShutDownDeleteWAry[i];
		if( pInfo2 == NULL )
			continue;

		pInfoDataAry = pInfo2->mpData;
		if( pInfoDataAry == NULL )
			continue;

		for( unsigned long j = 0 ; j < pInfoDataAry->GetSize() ; ++j )
		{
			pData = (sDropSWTypeData*)(*pInfoDataAry)[j];
			delete pData;
		}
		pInfoDataAry->Clear();
		SAFE_DELETE( pInfoDataAry );
		SAFE_DELETE( pInfo2 );
	}
	mpShutDownDeleteWAry.Clear();

	if( mpDropWTypeMap )
	{
		cAry* pAry = NULL;
		cPointrHashMap::cIterator i = mpDropWTypeMap->Begin();
		cPointrHashMap::cIterator end = mpDropWTypeMap->End();
		for( ; i != end; ++i )
		{
			pAry = (cAry*)((*i).mSecond);
			if( pAry == NULL )
				continue;

			for( unsigned long i = 0 ; i < pAry->GetSize() ; ++i )
                delete (*pAry)[i];

			pAry->Clear();
			SAFE_DELETE( pAry );
		}

		mpDropWTypeMap->Clear();
		SAFE_DELETE( mpDropWTypeMap );
	}

}



bool cDropScript::LoadDropNType()
{

	cFileLoader loader;
	cString pathName = "./Script/resource/Item_DropN.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load Item_DropN.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	while( tokenizer.IsEnd() == false )
	{

		/// 몬스터 종류
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long classIdx = str.ToInt();	

		/// 돈드랍 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float moneyPercent = str.ToFloat();					

		/// 돈 드랍 최소 금액
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long minMoney = str.ToInt();						

		/// 돈 드랍 최대 금액
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long maxMoney = str.ToInt();						

		/// 드롭 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float dropPercent = str.ToFloat();

		/// 드랍 종류 개수1
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass1Cnt = str.ToInt();					

		/// 드랍 종류 개수1 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass1Per = str.ToInt();					

		/// 드랍 종류 개수2
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass2Cnt = str.ToInt();					

		/// 드랍 종류 개수2 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass2Per = str.ToInt();					

		/// 드랍 종류 개수3
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass3Cnt = str.ToInt();					

		/// 드랍 종류 개수3 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass3Per = str.ToInt();					

		sDropNType* pList = new sDropNType;

		pList->mClassIdx = classIdx;	
		pList->mMoneyPercent = moneyPercent;
		pList->mMinMoney = minMoney;
		pList->mMaxMoney = maxMoney;
		pList->mDropPercent = dropPercent;
		pList->mDropClass1Cnt = dropClass1Cnt;
		pList->mDropClass1Per = dropClass1Per;
		pList->mDropClass2Cnt = dropClass2Cnt;
		pList->mDropClass2Per = dropClass2Per;
		pList->mDropClass3Cnt = dropClass3Cnt;
		pList->mDropClass3Per = dropClass3Per;

		pList->mItemTotalPer = 0;
		cAry* pAry = new cAry;
		pList->mpData = pAry;

		/// 해쉬에 몬스터 별로 기록
		if( mpDropNTypeMap->Insert( pList->mClassIdx, pList ) == false )
		{
			assert(NULL);
			return false;
		}
	}

	return LoadDropNTypeData();
}


bool cDropScript::LoadDropNTypeData()
{
	cFileLoader loader;
	cString pathName = "./Script/resource/Item_DropNData.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load Item_DropNData.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	sDropNType* pHead;
	while( tokenizer.IsEnd() == false )
	{
		/// 몬스터 종류
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long monsterClassIdx = str.ToInt();	

		/// 아이템 Idx
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemIdx = str.ToInt();

		/// 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemPer = str.ToInt();

		/// 수량
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemCnt = str.ToInt();

		sDropNTypeData* pList = new sDropNTypeData;

		pList->mItemIdx = itemIdx;
		pList->mItemPer = itemPer;
		pList->mItemCnt = itemCnt;

		pHead = (sDropNType*)mpDropNTypeMap->GetAt( monsterClassIdx );
		if( pHead == NULL )
		{
			assert(NULL);
			return false;
		}

		cAry* pAry = pHead->mpData;
		if( pAry == NULL )
		{
			assert(NULL);
			return false;
		}

		pAry->PushBack( pList );
		pHead->mItemTotalPer = pHead->mItemTotalPer + itemPer;
	}

	return true;
}


sDropNType* cDropScript::GetDropNType( unsigned long idx )
{
	sDropNType*	pDropNType;
	pDropNType = (sDropNType*)mpDropNTypeMap->GetAt( idx );

	if( !pDropNType )
	{
		return NULL;
	}

	return pDropNType;
}


bool cDropScript::LoadDropSType()
{

	cFileLoader loader;
	cString pathName = "./Script/resource/Item_DropS.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load Item_DropS.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	while( tokenizer.IsEnd() == false )
	{

		/// 몬스터 종류
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long monsterClassIdx = str.ToInt();	

		/// 아이템 드롭 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float dropPercent = str.ToFloat();					

		sDropSWType* pList = new sDropSWType;

		pList->mIdx = monsterClassIdx;
		pList->mDropPercent = dropPercent;	

		pList->mItemTotalPer = 0;
		cAry* pAry = new cAry;
		pList->mpData = pAry;

		/// 해쉬에 몬스터 별로 기록
		if( mpDropSTypeMap->Insert( monsterClassIdx, pList ) == false )
		{
			assert(NULL);
			return false;
		}
	}

	return LoadDropSTypeData();
}


bool cDropScript::LoadDropSTypeData()
{

	cFileLoader loader;
	cString pathName = "./Script/resource/Item_DropSData.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load Item_DropSData.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	sDropSWType* pHead;
	while( tokenizer.IsEnd() == false )
	{
		/// 몬스터 종류
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long monsterClassIdx = str.ToInt();	

		/// 아이템 Idx
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemIdx = str.ToInt();

		/// 선택확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float itemPer = str.ToFloat();

		/// 수량
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemCnt = str.ToInt();

		/// 드랍 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long enoughCnt = str.ToInt();

		/// 시간 제약
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long enoughTime = str.ToInt();

		sDropSWTypeData* pList = new sDropSWTypeData;

		pList->mIdx = monsterClassIdx;
		pList->mItemIdx = itemIdx;
		pList->mItemPer = itemPer;
		pList->mItemCnt = itemCnt;
		pList->mEnoughCnt = enoughCnt;
		pList->mEnoughTime = enoughTime;
		pList->mEnoughCntNow = 0;
		pList->mEnoughTimeEnd = 0;

		pHead = (sDropSWType*)mpDropSTypeMap->GetAt( monsterClassIdx );
		if( pHead == NULL )
		{
			assert(NULL);
			return false;
		}

		cAry* pAry = pHead->mpData;
		if( pAry == NULL )
		{
			assert(NULL);
			return false;
		}

		pAry->PushBack( pList );
		pHead->mItemTotalPer = pHead->mItemTotalPer + itemPer;
	}

	return true;
}


sDropSWType* cDropScript::GetDropSType( unsigned long monsterClassIdx )
{
	sDropSWType* pDropSType;
	pDropSType = (sDropSWType*)mpDropSTypeMap->GetAt( monsterClassIdx );

	if( !pDropSType )
	{
		return NULL;
	}

	return pDropSType;
}


bool cDropScript::LoadDropWType()
{

	if( LoadDropWTypeData() == false )
		return false;

	cFileLoader loader;
	cString pathName = "./Script/resource/Item_DropW.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load Item_DropW.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	cAry* pHeadAry = NULL;
	while( tokenizer.IsEnd() == false )
	{
		/// 월드 인덱스 - Item_DropWData 파일과 단순 연결을 위한 일련번호
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long wIdx  = str.ToInt();

		/// 몬스터 최소레벨
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned char monsterLvMin = (unsigned char)str.ToInt();

		/// 몬스터 최대레벨
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned char monsterLvMax = (unsigned char)str.ToInt();

		/// 몬스터 유형
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned char monsterType = (unsigned char)str.ToInt();

		/// 아이템 드롭 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float dropPercent = str.ToFloat();					

		/// 스크립트 한줄(레벨,타입의 묶음)당 추가확률, 추가시간은 함께 처리된다
		sDropSWType* pList = new sDropSWType;

		pList->mIdx = wIdx;
		pList->mDropPercent = dropPercent;	
		pList->mItemTotalPer = 0;
		pList->mpData = new cAry;

		sDropSWTypeData* pData;
		for( unsigned long i = 0 ; i < mpTempWData.GetSize() ; ++i )
		{
			pData = (sDropSWTypeData*)mpTempWData[i];
			if( pData == NULL )
			{
				assert(NULL);
				return false;
			}

			if( pData->mIdx == wIdx )
			{
				pList->mpData->PushBack( pData );
				pList->mItemTotalPer = pList->mItemTotalPer + pData->mItemPer;
			}
		}

		mpShutDownDeleteWAry.PushBack( pList );

		sDropWTypeLink* pWTypeLink = NULL;
		pHeadAry = NULL;

		for( unsigned char level = monsterLvMin ; level <= monsterLvMax ; ++level )
		{
			pHeadAry =(cAry*)mpDropWTypeMap->GetAt( level );
			if( pHeadAry == NULL )
			{
				pHeadAry = new cAry;

				/// 해쉬에 몬스터 별로 기록
				if( mpDropWTypeMap->Insert( level, pHeadAry ) == false )
				{
					assert(NULL);
					return false;
				}
			}

			pWTypeLink = new sDropWTypeLink;
			pWTypeLink->mMonsterType = monsterType;
			pWTypeLink->mpWType = pList;

			pHeadAry->PushBack( pWTypeLink );
		}
	}
	mpTempWData.Clear();

	return true;
}


bool cDropScript::LoadDropWTypeData()
{

	cFileLoader loader;
	cString pathName = "./Script/resource/Item_DropWData.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load Item_DropWData.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	cPointrHashMap::cIterator headBegin;
	cPointrHashMap::cIterator headEnd;

	while( tokenizer.IsEnd() == false )
	{
		/// 월드 인덱스
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long wIdx = str.ToInt();	

		/// 아이템 Idx
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemIdx = str.ToInt();

		/// 선택확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float itemPer = str.ToFloat();

		/// 수량
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemCnt = str.ToInt();

		/// 드랍 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long enoughCnt = str.ToInt();

		/// 시간 제약
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long enoughTime = str.ToInt();

		sDropSWTypeData* pList = new sDropSWTypeData;

		pList->mIdx = wIdx;
		pList->mItemIdx = itemIdx;
		pList->mItemPer = itemPer;
		pList->mItemCnt = itemCnt;
		pList->mEnoughCnt = enoughCnt;
		pList->mEnoughTime = enoughTime;
		pList->mEnoughCntNow = 0;
		pList->mEnoughTimeEnd = 0;

		mpTempWData.PushBack( pList );
	}

	return true;
}


tArray<void*>* cDropScript::GetDropWType( unsigned long monsterLv )
{
	return (cAry*)mpDropWTypeMap->GetAt( monsterLv );
}


bool cDropScript::LoadDropQType()
{
	cFileLoader loader;
	cString pathName = "./Script/Resource/Item_DropQ.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load Item_DropQ.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	sMonsterScript* pMonsterScript = NULL;
	/// 몬스터 스크립트에 정의된 퀘스트아이템드롭 해쉬맵 포인터의 포인터
	cPointrHashMap** pMap = NULL;
	cAry* pAry = NULL;
	sDropQType* pList = NULL;

	while( tokenizer.IsEnd() == false )
	{
		/// 퀘스트 번호
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long questIdx = str.ToInt();

		/// 몬스터 종류 index
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long monsterClassIdx = str.ToInt();

		/// 아이템 index
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemIdx = str.ToInt();

		/// 드랍 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropPer = str.ToInt();

		/// 해당 몬스터를 찾아 퀘스트 아이템 정보를 넣는다.
		pMonsterScript = MONSTERSCRIPT->GetMonsterListInfo( monsterClassIdx );
		if( pMonsterScript == NULL )
			return false;

		/// 퀘스트 인덱스를 키로하는 해쉬 맵을 만든다.
		pMap = &((cPointrHashMap*)pMonsterScript->mpQuestItemDropMap);
		if( *pMap == NULL )
			*pMap = new cPointrHashMap( 999 );

		/// 퀘스트 인덱스를 키로하는 해쉬맵에 드롭 item 정보를 추가한다.
		pAry = (cAry*)((*pMap)->GetAt( questIdx ));
		if( pAry == NULL )
		{
			pAry = new cAry;
			if( (*pMap)->Insert( questIdx, pAry ) == false )
				return false;
		}

		/// 퀘스트 아이템 드롭 정보 스트럭처
		pList = new sDropQType;

		pList->mItemIdx = itemIdx;
		pList->mDropPer = dropPer;

		pAry->PushBack( pList );
	}

	return true;
}



tArray<void*>* cDropScript::GetDropQtype( unsigned long monsterClassIdx, unsigned long questIdx )
{
	sMonsterScript* pMonsterScript = MONSTERSCRIPT->GetMonsterListInfo( monsterClassIdx );
	if( pMonsterScript == NULL )
		return NULL;

	cPointrHashMap* pMap = (cPointrHashMap*)pMonsterScript->mpQuestItemDropMap;
	if( pMap == NULL )
		return NULL;

	cAry* pAry = (cAry*)pMap->GetAt( questIdx );

	return pAry;
}


bool cDropScript::LoadDropNTypeGather()
{
	cFileLoader loader;
	cString pathName = "./Script/resource/item_gatheringn.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load item_gatheringn.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	while( tokenizer.IsEnd() == false )
	{
		
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long classIdx = str.ToInt();	

		/// 돈드랍 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float moneyPercent = str.ToFloat();					

		/// 돈 드랍 최소 금액
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long minMoney = str.ToInt();						

		/// 돈 드랍 최대 금액
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long maxMoney = str.ToInt();						

		/// 드롭 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float dropPercent = str.ToFloat();

		/// 드랍 종류 개수1
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass1Cnt = str.ToInt();					

		/// 드랍 종류 개수1 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass1Per = str.ToInt();					

		/// 드랍 종류 개수2
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass2Cnt = str.ToInt();					

		/// 드랍 종류 개수2 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass2Per = str.ToInt();					

		/// 드랍 종류 개수3
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass3Cnt = str.ToInt();					

		/// 드랍 종류 개수3 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropClass3Per = str.ToInt();					

		sDropNTypeGather* pList = new sDropNTypeGather;

		pList->mClassIdx = classIdx;	
		pList->mMoneyPercent = moneyPercent;
		pList->mMinMoney = minMoney;
		pList->mMaxMoney = maxMoney;
		pList->mDropPercent = dropPercent;
		pList->mDropClass1Cnt = dropClass1Cnt;
		pList->mDropClass1Per = dropClass1Per;
		pList->mDropClass2Cnt = dropClass2Cnt;
		pList->mDropClass2Per = dropClass2Per;
		pList->mDropClass3Cnt = dropClass3Cnt;
		pList->mDropClass3Per = dropClass3Per;

		pList->mItemTotalPer = 0;
		cAry* pAry = new cAry;
		pList->mpData = pAry;

		/// 해쉬에 기록
		if( mpDropNTypeGatherMap->Insert( pList->mClassIdx, pList ) == false )
		{
			assert(NULL);
			return false;
		}
	}

	return LoadDropNTypeDataGather();
}



bool cDropScript::LoadDropNTypeDataGather()
{
	cFileLoader loader;
	cString pathName = "./Script/resource/item_gatheringndata.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load item_gatheringndata.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	sDropNTypeGather* pHead;
	while( tokenizer.IsEnd() == false )
	{
		/// 종류Idx
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long classIdx = str.ToInt();	

		/// 아이템 Idx
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemIdx = str.ToInt();

		/// 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemPer = str.ToInt();

		/// 수량
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemCnt = str.ToInt();

		sDropNTypeDataGather* pList = new sDropNTypeDataGather;

		pList->mItemIdx = itemIdx;
		pList->mItemPer = itemPer;
		pList->mItemCnt = itemCnt;

		pHead = (sDropNTypeGather*)mpDropNTypeGatherMap->GetAt( classIdx );
		if( pHead == NULL )
		{
			assert(NULL);
			return false;
		}

		cAry* pAry = pHead->mpData;
		if( pAry == NULL )
		{
			assert(NULL);
			return false;
		}

		pAry->PushBack( pList );
		pHead->mItemTotalPer = pHead->mItemTotalPer + itemPer;
	}

	return true;
}


sDropNTypeGather* cDropScript::GetDropNTypeGather( unsigned long idx )
{
	sDropNTypeGather*	pDropNTypeGather;
	pDropNTypeGather = (sDropNTypeGather*)mpDropNTypeGatherMap->GetAt( idx );

	if( !pDropNTypeGather )
	{
		return NULL;
	}

	return pDropNTypeGather;
}


bool cDropScript::LoadDropSTypeGather()
{

	cFileLoader loader;
	cString pathName = "./Script/resource/item_gatherings.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load item_gatherings.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	while( tokenizer.IsEnd() == false )
	{

		/// 종류IDX
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long classIdx = str.ToInt();	

		/// 아이템 드롭 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float dropPercent = str.ToFloat();					

		sDropSTypeGather* pList = new sDropSTypeGather;

		pList->mIdx = classIdx;
		pList->mDropPercent = dropPercent;	

		pList->mItemTotalPer = 0;
		cAry* pAry = new cAry;
		pList->mpData = pAry;

		/// 해쉬에 기록
		if( mpDropSTypeGatherMap->Insert( classIdx, pList ) == false )
		{
			assert(NULL);
			return false;
		}
	}

	return LoadDropSTypeDataGather();
}


bool cDropScript::LoadDropSTypeDataGather()
{

	cFileLoader loader;
	cString pathName = "./Script/resource/item_gatheringsdata.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load item_gatheringsdata.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	sDropSTypeGather* pHead;
	while( tokenizer.IsEnd() == false )
	{
		/// 종류
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long classIdx = str.ToInt();	

		/// 아이템 Idx
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemIdx = str.ToInt();

		/// 선택확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float itemPer = str.ToFloat();

		/// 수량
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemCnt = str.ToInt();

		/// 드랍 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long enoughCnt = str.ToInt();

		/// 시간 제약
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long enoughTime = str.ToInt();

		sDropSTypeDataGather* pList = new sDropSTypeDataGather;

		pList->mIdx = classIdx;
		pList->mItemIdx = itemIdx;
		pList->mItemPer = itemPer;
		pList->mItemCnt = itemCnt;
		pList->mEnoughCnt = enoughCnt;
		pList->mEnoughTime = enoughTime;
		pList->mEnoughCntNow = 0;
		pList->mEnoughTimeEnd = 0;

		pHead = (sDropSTypeGather*)mpDropSTypeGatherMap->GetAt( classIdx );
		if( pHead == NULL )
		{
			assert(NULL);
			return false;
		}

		cAry* pAry = pHead->mpData;
		if( pAry == NULL )
		{
			assert(NULL);
			return false;
		}

		pAry->PushBack( pList );
		pHead->mItemTotalPer = pHead->mItemTotalPer + itemPer;
	}

	return true;
}


sDropSTypeGather* cDropScript::GetDropSTypeGather( unsigned long classIdx )
{
	sDropSTypeGather* pDropSTypeGather;
	pDropSTypeGather = (sDropSTypeGather*)mpDropSTypeGatherMap->GetAt( classIdx );

	if( !pDropSTypeGather )
	{
		return NULL;
	}

	return pDropSTypeGather;
}


bool cDropScript::LoadDropQTypeGather()
{
	cFileLoader loader;
	cString pathName = "./Script/Resource/item_gatheringq.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load item_gatheringq.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	sGatheringList* pGatheringInfo = NULL;
	/// 채집 스크립트에 정의된 퀘스트아이템드롭 해쉬맵 포인터의 포인터
	cPointrHashMap** pMap = NULL;
	cAry* pAry = NULL;
	sDropQTypeGather* pList = NULL;

	while( tokenizer.IsEnd() == false )
	{
		/// 퀘스트 번호
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long questIdx = str.ToInt();

		/// 종류 index
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long classIdx = str.ToInt();

		/// 아이템 index
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long itemIdx = str.ToInt();

		/// 드랍 확률
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned long dropPer = str.ToInt();

		/// 해당 채집오브젝트를 찾아 퀘스트 아이템 정보를 넣는다.
		pGatheringInfo = GATHERINGSCRIPT->GetGatheringInfo( classIdx );
		if( pGatheringInfo == NULL )
			return false;

		/// 퀘스트 인덱스를 키로하는 해쉬 맵을 만든다.
		pMap = &((cPointrHashMap*)pGatheringInfo->mpQuestItemDropMap);
		if( *pMap == NULL )
			*pMap = new cPointrHashMap( 999 );

		/// 퀘스트 인덱스를 키로하는 해쉬맵에 드롭 item 정보를 추가한다.
		pAry = (cAry*)((*pMap)->GetAt( questIdx ));
		if( pAry == NULL )
		{
			pAry = new cAry;
			if( (*pMap)->Insert( questIdx, pAry ) == false )
				return false;
		}

		/// 퀘스트 아이템 드롭 정보 스트럭처
		pList = new sDropQTypeGather;

		pList->mItemIdx = itemIdx;
		pList->mDropPer = dropPer;

		pAry->PushBack( pList );
	}

	return true;
}



tArray<void*>* cDropScript::GetDropQtypeGather( unsigned long classIdx, unsigned long questIdx )
{
	sGatheringList* pGatheringInfo = GATHERINGSCRIPT->GetGatheringInfo( classIdx );
	if( pGatheringInfo == NULL )
		return NULL;

	cPointrHashMap* pMap = (cPointrHashMap*)pGatheringInfo->mpQuestItemDropMap;
	if( pMap == NULL )
		return NULL;

	cAry* pAry = (cAry*)pMap->GetAt( questIdx );

	return pAry;
}


bool cDropScript::LoadDropExpIncrease()
{
	cFileLoader loader;
	cString pathName = "./Script/Resource/DropExpIncrease.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load DropExpIncrease.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	mScriptMinLevelDifferent = 0;
	mScriptMaxLevelDifferent = 0;

	char levelDifference = 0;
	float expIncrease = 0;

	while( tokenizer.IsEnd() == false )
	{
		/// 레벨차
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		levelDifference = (unsigned char)str.ToInt();

		/// 경험치 증가치
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		expIncrease = str.ToFloat();

		/// 해쉬에 몬스터 별로 기록
		if( mpDropExpIncreaseMap->Insert( levelDifference, expIncrease ) == NULL )
		{
			assert(0);
			return false;
		}

		/// 최소,최대값을 기록
		if( mScriptMinLevelDifferent > levelDifference )	{ mScriptMinLevelDifferent = levelDifference; }
		if( mScriptMaxLevelDifferent < levelDifference )	{ mScriptMaxLevelDifferent = levelDifference; }

	}

	return true;

}



float cDropScript::GetDropExpIncrease( char levelDifference )
{

	cDropExpIncrease::cIterator key = mpDropExpIncreaseMap->Find( levelDifference );
	cDropExpIncrease::cIterator end = mpDropExpIncreaseMap->End();

	if( key == end )
	{
		return 0.0f;
	}

	return (*key).mSecond;
}



bool cDropScript::LoadPartyExpIncrease()
{

	cFileLoader loader;
	cString pathName = "./Script/Resource/Party_Exp.txt";

	if( loader.Open( pathName, true ) == false )
	{
		assert( 0 && "failed to load Party_Exp.txt" );
		return false;
	}

	cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() );
	cString str;

	while( tokenizer.IsEnd() == false )
	{
		/// 파티 인원
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		unsigned char partyMemberCnt = (unsigned char)str.ToInt();	

		/// exp 증가치 
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float expIncrease = str.ToFloat();

		/// sxp 증가치
		if( tokenizer.GetNext( &str ) == false )	{ return false; }
		float sxpIncrease = str.ToFloat();	

		sPartyExp* pList = new sPartyExp;

		pList->mPartyMemberCnt = partyMemberCnt;	
		pList->mExpIncrease = expIncrease / 100.0f;	
		pList->mSxpIncrease = sxpIncrease / 100.0f;	

		/// 해쉬에 몬스터 별로 기록
		if( mPartyExpIncrease.Insert( partyMemberCnt, pList ) == false )
		{
			return false;
		}
	}

	return true;

}



float cDropScript::GetPartyExpIncrease( unsigned char partyMemberCnt )
{
	cPointrHashMap::cIterator key = mPartyExpIncrease.Find( partyMemberCnt );
	cPointrHashMap::cIterator end = mPartyExpIncrease.End();

	if( key == end )
	{
		return 0.0f;
	}

	sPartyExp* pPartyExp = (sPartyExp*)((*key).mSecond);
	return pPartyExp->mExpIncrease;
}



float cDropScript::GetPartySxpIncrease( unsigned char partyMemberCnt )
{
	cPointrHashMap::cIterator key = mPartyExpIncrease.Find( partyMemberCnt );
	cPointrHashMap::cIterator end = mPartyExpIncrease.End();

	if( key == end )
	{
		return 0.0f;
	}

	sPartyExp* pPartyExp = (sPartyExp*)((*key).mSecond);
	return pPartyExp->mSxpIncrease;
}