#include "stdafx.h"
#include "gamesrv.h"
#include "TriggerManager.h"
#include "ObjectManager.h"

cTriggerManager* cTriggerManager::mpSingleton = 0;

/////
cTrigger::cTrigger()
: mQuestIndex(0)
, mLowLevel(0)
, mHighLevel(0)
{
	mRace[0] = -1;
	mRace[1] = -1;

	for( unsigned int i = 0; i < QUEST_ITEM_MAX; ++i )
	{
		mHaveItem[i].itemIndex = 0;
		mHaveItem[i].count = 0;
	}

	::memset( mSkillArray, 0, sizeof(mSkillArray) );
}

////////////////
cTriggerManager::cTriggerManager()
{
	assert( mpSingleton == 0 && "bad singleton!" );
	mpSingleton = this;
}

cTriggerManager::~cTriggerManager()
{
	Clear();
}

bool cTriggerManager::Init()
{
	Clear();
	return true;
}

void cTriggerManager::Clear()
{
	cTriggerMap::cIterator i = mTriggerMap.Begin();
	cTriggerMap::cIterator end = mTriggerMap.End();

	for( ; i != end; ++i )
	{
		cTrigger* trigger = (cTrigger*)(i->mSecond);
		SAFE_DELETE( trigger );
	}
	mTriggerMap.Clear();
}

/// 트리거 삽입
bool cTriggerManager::AddTrigger( unsigned long questIdx, cTrigger* trigger )
{
	if( !trigger )
		return false;

	if( mTriggerMap.Insert( questIdx, trigger ) == false )
	{
		assert( 0 && "failed to add trigger" );
		return false;
	}
	return true;
}

/// 트리거삭제
void cTriggerManager::DeleteTrigger( unsigned long questIdx )
{
	cTrigger* trigger = (cTrigger*)mTriggerMap.GetAt( questIdx );
	if( trigger )
	{
		mTriggerMap.Erase( questIdx );
		SAFE_DELETE( trigger );
	}
}

cTrigger* cTriggerManager::GetTrigger( unsigned long questIdx )
{
	return (cTrigger*)mTriggerMap.GetAt( questIdx );
}

/// 퀘스트 조건 체크
bool cTriggerManager::CheckTrigger( unsigned long playerIdx, unsigned long questIdx )
{
	/// 발생조건이 없으면 그냥 true
	cTrigger* trigger = GetTrigger( questIdx );
	if( !trigger )
		return true;

	cPlayer* player = OBJECTMANAGER->GetPlayer( playerIdx );
	if( !player )
		return false;

	/// 레벨 범위 체크
	int level = player->GetLevel();
	if( trigger->mLowLevel > 0 && trigger->mLowLevel > level )
		return false;

	if( trigger->mHighLevel > 0 && trigger->mHighLevel < level )
		return false;

	/// 종족 체크
	char race = player->GetRace();
	if( trigger->mRace[0] != -1 && (trigger->mRace[0] != race && trigger->mRace[1] != race)  )
		return false;

	/// 직업 체크
	unsigned long jobIdx = player->GetJob();
	if( !trigger->mJobSet.IsEmpty() && trigger->mJobSet.Find( jobIdx ) == trigger->mJobSet.End() )
		return false;

	/// 아이템 목록 체크
	sQuestItem* item = trigger->mHaveItem;
	for( unsigned int i = 0; i < QUEST_ITEM_MAX; i++, item++ )
	{
		int			  remainCount = item->count;
		TB_INVENTORY* inven = player->SelectInventory( INVENTORY_CHARACTER_BEGIN );

		/// 인벤토리 +착용정보 아이템 필요갯수 검사
		for( int i = INVENTORY_CHARACTER_BEGIN; i <= INVENTORY_CHARACTER_END; i++, inven++ )
		{
			if( player->IsInventory( inven ) == true )
			{
				if( (long)item->itemIndex == inven->itemDefineIndex )
				{
					/// 남은 체크 갯수 줄이기
					remainCount -= inven->count;

					if( remainCount <= 0 )
						break;
				}
			}
		}
		/// 갯수가 부족하면 조건 불충족
		if( remainCount > 0 )
			return false;
	}

	/// 연계 퀘스트 체크
	typedef tArray<unsigned long> cLinkQuestArr;
	cLinkQuestArr& linkQuest = trigger->mLinkQuestArr;

	for( unsigned int i = 0; i < linkQuest.GetSize(); ++i )
	{
		/// 필요한 연계퀘스트가 모두 완료되었는지 검사
		unsigned long linkIdx = (unsigned long)linkQuest[i];

		if( player->IsCompleteQuest( linkIdx ) == false )
			return false;
	}

	/// 스킬 리스트 검사
	typedef tHashSet<unsigned long> cSkillInfluenceSet;

	for( unsigned int i = 0; i < QUEST_BUFF_MAX; ++i )
	{
		unsigned long skillIndex = trigger->mSkillArray[i];
		if( skillIndex > 0 )
		{
			cSkillInfluenceSet* influenceSet = player->GetInfluenceSet();
			if( !influenceSet )
			{
				assert(0);
				return false;
			}

			/// 해당 효과스킬이 없으면 리턴
			cSkillInfluenceSet::cIterator iter = influenceSet->Find( skillIndex );
			if( iter == influenceSet->End() )
				return false;
		}
	}
	return true;
}
