void __QuestEndComplete( int nPcId, int nNpcId, int& nGlobal, int nVal, int nQuestId )
{
	CUser* pUser	= prj.GetUser( nPcId );
	LPQUEST lpQuest		= pUser->GetQuest( nQuestId );

#ifdef __VTN_TIMELIMIT
	//	mulcom	BEGIN100315	베트남 시간 제한
	if( ::GetLanguage() == LANG_VTN )
	{
		if( pUser->IsPlayer() == TRUE )
		{
			if( pUser->m_nAccountPlayTime > MIN( 180 ) )
			{
				pUser->AddDefinedText( TID_GAME_ERROR_QUEST_1 );
				return;
			}
		}
	}
	//	mulcom	END100315	베트남 시간 제한
#endif // __VTN_TIMELIMIT

	// 퀘스트가 진행 중인 경우 
	if( lpQuest && pUser->IsCompleteQuest( nQuestId ) == FALSE
		&& __IsEndQuestCondition( pUser, nQuestId ) )
	{
		CMover* pMover = prj.GetMover( nNpcId );
		if( __EndQuest( nPcId, nQuestId ) == TRUE )
			pMover->m_pNpcProperty->RunDialog( "#questEndComplete", NULL, 0, nNpcId, nPcId, nQuestId );
#if __VER >= 15 // __IMPROVE_QUEST_INTERFACE
		__QuestEnd( nPcId, nNpcId, nGlobal, nQuestId, TRUE );
#else // __IMPROVE_QUEST_INTERFACE
		__QuestEnd( nPcId, nNpcId, nGlobal );
#endif // __IMPROVE_QUEST_INTERFACE
	}	
}
int __RemoveQuest( int nPcId, int nQuest )      
{
	QuestProp* pQuestProp	= prj.m_aPropQuest.GetAt( nQuest );
	if( pQuestProp )
	{
		CUser* pUser	= prj.GetUser( nPcId );
		LPQUEST pQuest	= pUser->GetQuest( nQuest );

		if( pQuest && pQuest->m_nState < 14 ) 
			pUser->AddDefinedText( TID_EVE_CANCELQUEST, "\"%s\"", pQuestProp->m_szTitle );
		pUser->RemoveQuest( nQuest );
		pUser->AddRemoveQuest( nQuest );
		// 시작시 변신을 했으면 퀘스트 삭제시 변신 해제시킨다.
		if( pQuest && pQuestProp->m_nBeginSetDisguiseMoverIndex )
		{
			CUser* pUser = prj.GetUser( nPcId );
			pUser->NoDisguise( NULL );
			g_UserMng.AddNoDisguise( pUser );
		}
	}
	return 1;
}
void __QuestBeginYes( int nPcId, int nNpcId, int nQuestId )
{
	CUser* pUser	= prj.GetUser( nPcId );

#ifdef __VTN_TIMELIMIT
	//	mulcom	BEGIN100315	베트남 시간 제한
	if( ::GetLanguage() == LANG_VTN )
	{
		if( pUser->IsPlayer() == TRUE )
		{
			if( pUser->m_nAccountPlayTime > MIN( 180 ) )
			{
				pUser->AddDefinedText( TID_GAME_ERROR_QUEST_1 );

				return;
			}
		}
	}
	//	mulcom	END100315	베트남 시간 제한
#endif // __VTN_TIMELIMIT

	LPQUEST lpQuest		= pUser->GetQuest( nQuestId );
	if( __IsBeginQuestCondition( pUser, nQuestId )
		&& lpQuest == NULL
		&& pUser->IsCompleteQuest( nQuestId ) == FALSE )
	{
		__SayQuest( nPcId, nQuestId, QSAY_BEGIN_YES );
		__RunQuest( nPcId, nNpcId, nQuestId );
		CMover* pMover = prj.GetMover( nNpcId );
#if __VER >= 15 // __IMPROVE_QUEST_INTERFACE
		__RemoveAllKey( nPcId );
		pMover->m_pNpcProperty->RunDialog( "#addKey", NULL, 0, nNpcId, nPcId, 0 );
		LPQUEST lpQuestList;
		// 퀘스트 리스트 send
		vector<int> vecNewQuest;
		vector<int> vecNextQuest;
		vector<int> vecEndQuest;
		vector<int> vecCurrQuest;
		LPCHARACTER lpChar = prj.GetCharacter( pMover->m_szCharacterKey );
		if( lpChar )
		{
			for( int i = 0; i < lpChar->m_awSrcQuest.GetSize(); i++ )
			{
				int nQuest = lpChar->m_awSrcQuest.GetAt( i );
				lpQuestList = pUser->GetQuest( nQuest );
				
				// new quest
				if( lpQuestList == NULL && pUser->IsCompleteQuest( nQuest ) == FALSE )
				{
					// now
					if( __IsBeginQuestCondition( pUser, nQuest ) )
						vecNewQuest.push_back( nQuest );
					// next
					else if( __IsNextLevelQuest( pUser, nQuest ) )
						vecNextQuest.push_back( nQuest );
				}
				// current quest
				else if( lpQuestList && pUser->IsCompleteQuest( nQuest ) == FALSE )
				{
					// complete
					if( __IsEndQuestCondition( pUser, nQuest ) )
						vecEndQuest.push_back( nQuest );
					// running
					else
						vecCurrQuest.push_back( nQuest );
				}
			}
			
			// sort
			__QuestSort( vecNewQuest );
			__QuestSort( vecNextQuest );
			__QuestSort( vecEndQuest );
			__QuestSort( vecCurrQuest );
			
			// send
			for( DWORD i = 0; i < vecNewQuest.size(); ++i )
				__AddQuestKey( nPcId, vecNewQuest[ i ], "QUEST_BEGIN", 0, TRUE );
			for( DWORD i = 0; i < vecNextQuest.size(); ++i )
				__AddQuestKey( nPcId, vecNextQuest[ i ], "QUEST_NEXT_LEVEL", 0, TRUE );
			for( DWORD i = 0; i < vecEndQuest.size(); ++i )
				__AddQuestKey( nPcId, vecEndQuest[ i ], "QUEST_END", 0, FALSE );
			for( DWORD i = 0; i < vecCurrQuest.size(); ++i )
				__AddQuestKey( nPcId, vecCurrQuest[ i ], "QUEST_END", 0, FALSE );
		}
#endif // __IMPROVE_QUEST_INTERFACE
		pMover->m_pNpcProperty->RunDialog( "#questBeginYes", NULL, 0, nNpcId, nPcId, nQuestId );
	}

}
void __QuestEnd( int nPcId, int nNpcId, int& nGlobal )
#endif // __IMPROVE_QUEST_INTERFACE
{
#if __VER >= 15 // __IMPROVE_QUEST_INTERFACE
	// 현재 진행 중인 퀘스트 중에서 현재 NPC가 처리해야될 퀘스트를 실행(자신일 수도 있음)
	CMover* pMover = prj.GetMover( nNpcId );
	CUser* pUser = prj.GetUser( nPcId );

	LPQUEST lpQuest;
	BOOL bNewQuest = FALSE;

	__RemoveAllKey( nPcId );
	pMover->m_pNpcProperty->RunDialog( "#addKey", NULL, 0, nNpcId, nPcId, 0 );
	
	// 퀘스트 리스트 send
	vector<int> vecNewQuest;
	vector<int> vecNextQuest;
	vector<int> vecEndQuest;
	vector<int> vecCurrQuest;
	LPCHARACTER lpChar = prj.GetCharacter( pMover->m_szCharacterKey );
	if( lpChar )
	{
		for( int i = 0; i < lpChar->m_awSrcQuest.GetSize(); i++ )
		{
			int nQuest = lpChar->m_awSrcQuest.GetAt( i );
			lpQuest = pUser->GetQuest( nQuest );

			// new quest
			if( lpQuest == NULL && pUser->IsCompleteQuest( nQuest ) == FALSE )
			{
				// now
				if( __IsBeginQuestCondition( pUser, nQuest ) )
				{
					bNewQuest = TRUE;
					vecNewQuest.push_back( nQuest );
				}
				// next
				else if( __IsNextLevelQuest( pUser, nQuest ) )
					vecNextQuest.push_back( nQuest );
			}
			// current quest
			else if( lpQuest && pUser->IsCompleteQuest( nQuest ) == FALSE && lpQuest->m_nState != QS_END )
			{
				// complete
				if( __IsEndQuestCondition( pUser, nQuest ) )
					vecEndQuest.push_back( nQuest );
				// running
				else
					vecCurrQuest.push_back( nQuest );
			}
		}

		// sort
		__QuestSort( vecNewQuest );
		__QuestSort( vecNextQuest );
		__QuestSort( vecEndQuest );
		__QuestSort( vecCurrQuest );

		// send
		for( DWORD i = 0; i < vecNewQuest.size(); ++i )
			__AddQuestKey( nPcId, vecNewQuest[ i ], "QUEST_BEGIN", 0, TRUE );
		for( DWORD i = 0; i < vecNextQuest.size(); ++i )
			__AddQuestKey( nPcId, vecNextQuest[ i ], "QUEST_NEXT_LEVEL", 0, TRUE );
		for( DWORD i = 0; i < vecEndQuest.size(); ++i )
			__AddQuestKey( nPcId, vecEndQuest[ i ], "QUEST_END", 0, FALSE );
		for( DWORD i = 0; i < vecCurrQuest.size(); ++i )
			__AddQuestKey( nPcId, vecCurrQuest[ i ], "QUEST_END", 0, FALSE );
	}
	
	BOOL bDialogText = TRUE;
	BOOL bCompleteCheck = TRUE;
	
	if( nQuestId )
	{
		lpQuest = pUser->GetQuest( nQuestId );
		QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( nQuestId );
		if( lpQuest && lpQuest->m_nState != QS_END && pQuestProp )	// 진행중인 퀘스트 선택 시
		{
			bCompleteCheck = FALSE;
			if( !bButtOK ) // 퀘스트 목록을 선택하고 들어온 경우
			{
				if( strcmpi( pQuestProp->m_szEndCondCharacter, pMover->m_szCharacterKey ) == 0 && __IsEndQuestCondition( pUser, nQuestId ) )
				{
					__SayQuest( nPcId, nQuestId, QSAY_END_COMPLETE1 );
					__SayQuest( nPcId, nQuestId, QSAY_END_COMPLETE2 );
					__SayQuest( nPcId, nQuestId, QSAY_END_COMPLETE3 );
					__AddAnswer( nPcId,"__OK__", "QUEST_END_COMPLETE", 0, nQuestId );
				}
				else
				{
					__SayQuest( nPcId, nQuestId, QSAY_END_FAILURE1 );
					__SayQuest( nPcId, nQuestId, QSAY_END_FAILURE2 );
					__SayQuest( nPcId, nQuestId, QSAY_END_FAILURE3 );
					__AddAnswer( nPcId,"__OK__", "QUEST_END_FAIL", 0, nQuestId );
				}
				bDialogText = FALSE;
			}
		}
	}
	
	// 완료 가능한 퀘스트가 있는지 검사
	if( bCompleteCheck )
	{
		for( int i = 0; i < pUser->m_nQuestSize; ++i )
		{
			lpQuest = &pUser->m_aQuest[i];
			if( lpQuest )
			{
				QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( lpQuest->m_wId );
				if( pQuestProp )
				{
					if( strcmpi( pQuestProp->m_szEndCondCharacter, pMover->m_szCharacterKey ) == 0 && lpQuest->m_nState != QS_END )
					{
						if( __IsEndQuestCondition( pUser, lpQuest->m_wId ) )
						{
							__SayQuest( nPcId, lpQuest->m_wId, QSAY_END_COMPLETE1 );
							__SayQuest( nPcId, lpQuest->m_wId, QSAY_END_COMPLETE2 );
							__SayQuest( nPcId, lpQuest->m_wId, QSAY_END_COMPLETE3 );
							__AddAnswer( nPcId,"__OK__", "QUEST_END_COMPLETE", 0, lpQuest->m_wId );
							bDialogText = FALSE;
							break;
						}
					}
				}
				else	WriteError( "__QuestEnd quest(%d) property null", lpQuest->m_wId );
			}
			else	WriteError( "__QuestEnd : user member quest(%d) null", i  );
		}
	}

	if( bDialogText )
	{
		if( bNewQuest )
		{
			if( vecNewQuest.size() == 1 && bCompleteCheck )	// 진행가능한 퀘스트가 하나면 바로 퀘스트 수락창 표시
				__QuestBegin( nPcId, nNpcId, vecNewQuest[ 0 ] );
			else
				pMover->m_pNpcProperty->RunDialog( "#yesQuest", NULL, 0, nNpcId, nPcId, 0 ); // 준비된 퀘스트가 있을 때의 인사말
		}
		else
			pMover->m_pNpcProperty->RunDialog( "#noQuest", NULL, 0, nNpcId, nPcId, 0 );	// 준비된 퀘스트가 없을 때의 인사말
	}
#else // __IMPROVE_QUEST_INTERFACE
	// 현재 진행 중인 퀘스트 중에서 현재 NPC가 처리해야될 퀘스트를 실행(자신일 수도 있음)
	int nResult = 0;

	CMover* pMover = prj.GetMover( nNpcId );
	CUser* pUser = prj.GetUser( nPcId );

	LPQUEST lpQuest;

	__RemoveAllKey( nPcId );

	while( nGlobal < pUser->m_nQuestSize )
	{
		lpQuest = &pUser->m_aQuest[ nGlobal ];
		nGlobal++;
		if( lpQuest )
		{
			WORD nQuest = lpQuest->m_wId;
			QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( nQuest );
			if( pQuestProp )
			{
				// 대화하고 있는 캐릭터와 현재 실행 중인 퀘스트가 같으면 그놈이 종결 조건을 판정하는 놈이다.
				if( strcmpi( pQuestProp->m_szEndCondCharacter, pMover->m_szCharacterKey ) == 0 )
				{
					if( lpQuest->m_nState != QS_END ) 
					{
						if( __IsEndQuestCondition( pUser, nQuest ) )
						{
							__SayQuest( nPcId, nQuest, QSAY_END_COMPLETE1 );
							__SayQuest( nPcId, nQuest, QSAY_END_COMPLETE2 );
							__SayQuest( nPcId, nQuest, QSAY_END_COMPLETE3 );
							__AddAnswer( nPcId,"__OK__", "QUEST_END_COMPLETE", 0, nQuest );		
						}
						else
						{
							__SayQuest( nPcId, nQuest, QSAY_END_FAILURE1 );
							__SayQuest( nPcId, nQuest, QSAY_END_FAILURE2 );
							__SayQuest( nPcId, nQuest, QSAY_END_FAILURE3 );
							__AddAnswer( nPcId,"__OK__", "QUEST_END", 0, nQuest );
						}
						nResult = 1;
						break;
					}
				}
			}
			else 
			{
				WriteError( "__QuestEnd quest(%d) property null", nQuest );
			}
		}
		else 
		{
			WriteError( "__QuestEnd : user member quest(%d) null", nGlobal-1  );
		}
	} // while( nGlobal < pUser->m_nQuestSize )

	if( nResult == 0 )
	{
		LPCHARACTER lpChar = prj.GetCharacter( pMover->m_szCharacterKey );
		int anQuest[ 32 ];

		for( int i = 0; i < lpChar->m_awSrcQuest.GetSize(); i++ )
		{
			int nQuest = lpChar->m_awSrcQuest.GetAt( i );
			lpQuest = pUser->GetQuest( nQuest );

			if( __IsBeginQuestCondition( pUser, nQuest ) && 
				lpQuest == NULL && 
				pUser->IsCompleteQuest( nQuest ) == FALSE )
			{
				anQuest[ nResult ] = nQuest;
				nResult++;
			}
		}

		// 가능한 퀘스트가 하나일 때는 바로 퀘스트 시작 
		if( nResult == 1 )
			__QuestBegin( nPcId, nNpcId, anQuest[ 0 ] );
		else
		{
			// 여러개일 경우는 키를 추가 
			for( i = 0; i < nResult; i++ )
				__AddQuestKey( nPcId, anQuest[ i ], "QUEST_BEGIN" );

			if ( nResult == 0 )  				
				pMover->m_pNpcProperty->RunDialog( "#noQuest", &nResult, 0, nNpcId, nPcId, 0 );	// 준비된 퀘스트가 없을 때의 인사말 
			else				
				pMover->m_pNpcProperty->RunDialog( "#yesQuest", &nResult, 0, nNpcId, nPcId, 0 ); // 준비된 퀘스트가 있을 때의 인사말 
		}
	}
	// 기타 대화를 위한 키를 추가한다.
	pMover->m_pNpcProperty->RunDialog( "#addKey", NULL, 0, nNpcId, nPcId, 0 );
#endif // __IMPROVE_QUEST_INTERFACE
}