int __AddQuestKey( int nPcId, int nQuestId, LPCTSTR lpKey, int nParam )
#endif // __IMPROVE_QUEST_INTERFACE
{
	CHAR szWord[ 128 ], szKey[ 128 ];
	QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( nQuestId );
	if( pQuestProp )
		strcpy( szWord, pQuestProp->m_szTitle );
	if( lpKey[0] == '\0' ) 
		strcpy( szKey, szWord );
	else
		strcpy( szKey, lpKey );

	CUser* pUser	= prj.GetUser( nPcId );
	RunScriptFunc rsf;
#if __VER >= 15 // __IMPROVE_QUEST_INTERFACE
	if( bNew )
		rsf.wFuncType		= FUNCTYPE_NEWQUEST;
	else
		rsf.wFuncType		= FUNCTYPE_CURRQUEST;
#else // __IMPROVE_QUEST_INTERFACE
	rsf.wFuncType		= FUNCTYPE_ADDKEY;
#endif // __IMPROVE_QUEST_INTERFACE
	lstrcpy( rsf.lpszVal1, szWord );
	lstrcpy( rsf.lpszVal2, szKey );
	rsf.dwVal1	= nParam;
	rsf.dwVal2 = nQuestId;
	pUser->AddRunScriptFunc( rsf );
	return 1;
}
int __RemoveAllKey( int nPcId )
{
	CUser* pUser	= prj.GetUser( nPcId );
	RunScriptFunc rsf;
	rsf.wFuncType		= FUNCTYPE_REMOVEALLKEY;
	pUser->AddRunScriptFunc( rsf );

	return 1;
}
int __SayQuest( int nPcId,int nQuestId, int nIdx )
{
	CString strToken;

	QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( nQuestId );
	if( pQuestProp && pQuestProp->m_apQuestDialog[ nIdx ] )
		strToken = pQuestProp->m_apQuestDialog[ nIdx ];
	if( strToken.IsEmpty() == TRUE )
		return FALSE;

	CUser* pUser = prj.GetUser( nPcId );
	RunScriptFunc rsf;
	rsf.wFuncType		= FUNCTYPE_SAY;//QUEST;
	lstrcpy( rsf.lpszVal1, strToken );
	rsf.dwVal2 = nQuestId;
	pUser->AddRunScriptFunc( rsf );
	return 1;
}
int __AddAnswer( int nPcId, LPCTSTR lpszWord, LPCTSTR lpszKey, DWORD dwParam1, int nQuest )
{
	CHAR szKey[ 128 ], szWord[ 128 ];

	strcpy( szWord, lpszWord );

	if( lpszKey[0] == '\0' ) 
		strcpy( szKey, szWord );
	else
		strcpy( szKey, lpszKey );

	CUser* pUser = prj.GetUser( nPcId );
	RunScriptFunc rsf;
	rsf.wFuncType		= FUNCTYPE_ADDANSWER;
	lstrcpy( rsf.lpszVal1, szWord );
	lstrcpy( rsf.lpszVal2, szKey );
	rsf.dwVal1 = (DWORD)dwParam1;
	rsf.dwVal2 = nQuest;
	pUser->AddRunScriptFunc( rsf );
	return 1;
}
int __AddKey( int nPcId, LPCTSTR lpszWord, LPCTSTR lpszKey, DWORD dwParam )
{
	CHAR szKey[ 128 ], szWord[ 128 ];

	strcpy( szWord, lpszWord );

	if( lpszKey[0] == '\0' ) 
		strcpy( szKey, szWord );
	else
		strcpy( szKey, lpszKey );

	CUser* pUser	= prj.GetUser( nPcId );
	RunScriptFunc rsf;
	rsf.wFuncType		= FUNCTYPE_ADDKEY;
	lstrcpy( rsf.lpszVal1, szWord );
	lstrcpy( rsf.lpszVal2, szKey );
	rsf.dwVal1	= dwParam;
	rsf.dwVal2 = 0;
	pUser->AddRunScriptFunc( rsf );
	return 1;
}
//int __EndQuest( int nPcId, int nQuestId, BOOL IsEndQuestCondition = TRUE )
int __EndQuest( int nPcId, int nQuestId, BOOL IsEndQuestCondition )
{
	int nNum;
	QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( nQuestId );

	if( pQuestProp )
	{
		CUser* pUser = prj.GetUser( nPcId );
		if( IsEndQuestCondition )
		{
			if( __IsEndQuestCondition( pUser, nQuestId ) == 0 )
				return FALSE;
		}
		// 보상 아이템 갯수 만큼, 인벤토리 여유가 있는가?
		int nItemNum = 0;
		for( int i = 0; i < pQuestProp->m_nEndRewardItemNum; i++ )
		{
			QuestPropItem* pEndRewardItem = &pQuestProp->m_paEndRewardItem[ i ];
			if( pEndRewardItem->m_nSex == -1 || pEndRewardItem->m_nSex == pUser->GetSex() )
			{
				if( pEndRewardItem->m_nType == 0 )
				{
					if( pEndRewardItem->m_nJobOrItem == -1 || pEndRewardItem->m_nJobOrItem == pUser->GetJob() )
					{
						if( pEndRewardItem->m_nItemIdx )
						{
							ItemProp* pItemProp = prj.GetItemProp(  pEndRewardItem->m_nItemIdx );
							int nDiv = pEndRewardItem->m_nItemNum / pItemProp->dwPackMax;
							int nSur = pEndRewardItem->m_nItemNum % pItemProp->dwPackMax;
							if( nSur ) nDiv++;
							nItemNum += nDiv;
						}
					}
				}
				else
				if( pEndRewardItem->m_nType == 1 )
				{
					if( pEndRewardItem->m_nJobOrItem == -1 || pUser->GetItemNum( pEndRewardItem->m_nJobOrItem ) )
					{
						if( pEndRewardItem->m_nItemIdx )
						{
							ItemProp* pItemProp = prj.GetItemProp(  pEndRewardItem->m_nItemIdx );
							int nDiv = pEndRewardItem->m_nItemNum / pItemProp->dwPackMax;
							int nSur = pEndRewardItem->m_nItemNum % pItemProp->dwPackMax;
							if( nSur ) nDiv++;
							nItemNum += nDiv;
						}
					}
				}
			}
		}
		if( nItemNum > pUser->m_Inventory.GetEmptyCount() ) 
		{
			pUser->AddDefinedText( TID_QUEST_NOINVENTORYSPACE ); // 인벤토리 공간이 없어서 퀘스트를 완료할 수 없습니다.
			RunScriptFunc rsf;
			rsf.wFuncType		= FUNCTYPE_EXIT;
			pUser->AddRunScriptFunc( rsf );
			return FALSE;
		}
		////////////////////////////
		// 보상 지급 
		////////////////////////////
		for( i = 0; i < pQuestProp->m_nEndRewardItemNum; i++ )
		{
			QuestPropItem* pEndRewardItem = &pQuestProp->m_paEndRewardItem[ i ];
			if( pEndRewardItem->m_nSex == -1 || pEndRewardItem->m_nSex == pUser->GetSex() )
			{
				if( pEndRewardItem->m_nType == 0 )
				{
					if( pEndRewardItem->m_nJobOrItem == -1 || pEndRewardItem->m_nJobOrItem == pUser->GetJob() )
					{
						if( pEndRewardItem->m_nItemIdx )
						{
							int nItemNum = pEndRewardItem->m_nItemNum;
#ifdef __JEFF_11
#if __VER >= 13 // __CHIPI_QUESTITEM_FLAG
							__CreateItem( nPcId, pEndRewardItem->m_nItemIdx, nItemNum, pEndRewardItem->m_nAbilityOption, pEndRewardItem->m_byFlag );
#else // __CHIPI_QUESTITEM_FLAG
							__CreateItem( nPcId, pEndRewardItem->m_nItemIdx, nItemNum, pEndRewardItem->m_nAbilityOption );
#endif // __CHIPI_QUESTITEM_FLAG
#else	// __JEFF_11
							__CreateItem( nPcId, pEndRewardItem->m_nItemIdx, nItemNum );
#endif	// __JEFF_11
						}
					}
				}
				else
				if( pEndRewardItem->m_nType == 1 )
				{
					if( pEndRewardItem->m_nJobOrItem == -1 || pUser->GetItemNum( pEndRewardItem->m_nJobOrItem ) )
					{
						if( pEndRewardItem->m_nItemIdx )
						{
							int nItemNum = pEndRewardItem->m_nItemNum;
#ifdef __JEFF_11
#if __VER >= 13 // __CHIPI_QUESTITEM_FLAG
							__CreateItem( nPcId, pEndRewardItem->m_nItemIdx, nItemNum, pEndRewardItem->m_nAbilityOption, pEndRewardItem->m_byFlag );
#else // __CHIPI_QUESTITEM_FLAG
							__CreateItem( nPcId, pEndRewardItem->m_nItemIdx, nItemNum, pEndRewardItem->m_nAbilityOption );
#endif // __CHIPI_QUESTITEM_FLAG
#else	// __JEFF_11
							__CreateItem( nPcId, pEndRewardItem->m_nItemIdx, nItemNum );
#endif	// __JEFF_11
						}
					}
				}
			}
		}
#if __VER >= 9	// __PET_0410
		if( pQuestProp->m_bEndRewardPetLevelup )
			pUser->PetLevelup();
#endif	// __PET_0410
		if(	pQuestProp->m_nEndRewardGoldMin )
		{
			nNum = pQuestProp->m_nEndRewardGoldMax - pQuestProp->m_nEndRewardGoldMin + 1; 
			int nGold = pQuestProp->m_nEndRewardGoldMin + xRandom( nNum ); 
			pUser->AddGold( nGold );
			pUser->AddGoldText( nGold );
		}
		if(	pQuestProp->m_nEndRewardExpMin )
		{
			nNum = pQuestProp->m_nEndRewardExpMax - pQuestProp->m_nEndRewardExpMin + 1; 
			int nExp = pQuestProp->m_nEndRewardExpMin + xRandom( nNum ); 
			if( pUser->AddExperience( nExp, TRUE, FALSE ) )
				pUser->LevelUpSetting();
			else
				pUser->ExpUpSetting();
			
			pUser->AddSetExperience( pUser->GetExp1(), (WORD)pUser->m_nLevel, pUser->m_nSkillPoint, pUser->m_nSkillLevel );
			pUser->AddDefinedText( TID_GAME_REAPEXP );
		}
		if( pQuestProp->m_nEndRewardSkillPoint )
		{
			pUser->AddSkillPoint( pQuestProp->m_nEndRewardSkillPoint );
			pUser->AddSetExperience( pUser->GetExp1(), (WORD)pUser->m_nLevel, pUser->m_nSkillPoint, pUser->m_nSkillLevel );
			g_dpDBClient.SendLogSkillPoint( LOG_SKILLPOINT_GET_QUEST, pQuestProp->m_nEndRewardSkillPoint, (CMover*)pUser, NULL );
		}

#if __VER >= 8 // __S8_PK
		if( pQuestProp->m_nEndRewardPKValueMin || pQuestProp->m_nEndRewardPKValueMax )
		{
			if( pQuestProp->m_nEndRewardPKValueMin <= pQuestProp->m_nEndRewardPKValueMax )
			{
				int nPKValue = pUser->GetPKValue() - xRandom( pQuestProp->m_nEndRewardPKValueMin, pQuestProp->m_nEndRewardPKValueMax + 1 );
				if( nPKValue < 0 )
					nPKValue = 0;
				pUser->SetPKValue( nPKValue );
				pUser->AddPKValue();
				g_dpDBClient.SendLogPkPvp( (CMover*)pUser, NULL, 0, 'P' );
#if __VER >= 13 // __HONORABLE_TITLE			// 달인
				pUser->CheckHonorStat();
				g_UserMng.AddHonorTitleChange( pUser, pUser->m_nHonor);
#endif	// __HONORABLE_TITLE			// 달인
			}
		}
#else // __VER >= 8 // __S8_PK
		if( pQuestProp->m_nEndRewardKarmaStyle )
		{
			if( pQuestProp->m_nEndRewardKarmaStyle == 1 )
				pUser->ChangeSlaughter( CHANGE_SLAUGHTER_SET, NULL, pQuestProp->m_nEndRewardKarmaPoint );
			else
			if( pQuestProp->m_nEndRewardKarmaStyle == 2 )
			{
				int nKarma = pUser->GetKarma();
				pUser->ChangeSlaughter( CHANGE_SLAUGHTER_SET, NULL, nKarma + pQuestProp->m_nEndRewardKarmaPoint ); 
			}
		}
#endif // __VER >= 8 // __S8_PK
#if __VER >= 9 // __S_9_ADD
		if( pQuestProp->m_nEndRewardTeleport != 0 )
			pUser->REPLACE( g_uIdofMulti, pQuestProp->m_nEndRewardTeleport, pQuestProp->m_nEndRewardTeleportPos, REPLACE_NORMAL, nTempLayer );
#endif // __S_9_ADD
		// 시작시 변신을 했으면 종료시 변신 해제시킨다.
		if( pQuestProp->m_nBeginSetDisguiseMoverIndex )
		{
			CUser* pUser = prj.GetUser( nPcId );
			pUser->NoDisguise( NULL );
			g_UserMng.AddNoDisguise( pUser );
		}
#if __VER >= 15 // __CAMPUS
		if( pQuestProp->m_nEndRewardTSP )
			g_dpDBClient.SendUpdateCampusPoint( pUser->m_idPlayer, pQuestProp->m_nEndRewardTSP, TRUE, 'Q' );

		if( pQuestProp->m_nEndRemoveTSP )
			g_dpDBClient.SendUpdateCampusPoint( pUser->m_idPlayer, pQuestProp->m_nEndRemoveTSP, FALSE, 'Q' );
#endif // __CAMPUS
		////////////////////////////
		// 아이템 제거 
		////////////////////////////
		for( i = 0; i < 8; i++ )
		{
			if( pQuestProp->m_nEndRemoveItemIdx[ i ] )
			{
				int nItemNum = pQuestProp->m_nEndRemoveItemNum[ i ];
				if( nItemNum > 0x7fff )		// 삭제될 아이템 개수가 short의 MAX를 넘으면..
				{
					for( ; nItemNum > 0x7fff; )
					{
						pUser->RemoveItemA( pQuestProp->m_nEndRemoveItemIdx[ i ], 0x7fff );
						nItemNum -= 0x7fff;
					}
				}
				pUser->RemoveItemA( pQuestProp->m_nEndRemoveItemIdx[ i ], nItemNum );
			}
		}
		if( pQuestProp->m_nEndRemoveGold )
			__RemoveGold( nPcId, pQuestProp->m_nEndRemoveGold );
		////////////////////////////
		// 퀘스트 제거 (완료,진행 모두 제거함)
		////////////////////////////
		for( i = 0; i < MAX_QUESTREMOVE; i++ )
		{
			if( pQuestProp->m_anEndRemoveQuest[ i ] )
			{
				__RemoveQuest( nPcId, pQuestProp->m_anEndRemoveQuest[ i ] );
			}
		}
		// 퀘스트 종료 
		__SetQuestState( nPcId, nQuestId, QS_END );
	}
	return 1;
}