#include "stdafx.h"
#include "gamesrv.h"
#include "PartyManager.h"
#include "Player.h"

cPartyManager* cPartyManager::mpSingleton = NULL;

cPartyManager::cPartyManager()
{
	mpSingleton = this;
}

cPartyManager::~cPartyManager()
{
	Release();
	mpSingleton = 0;
}

bool cPartyManager::Init()
{
	mPartyPool.Reserve( 100, 10 );
	return true;
}

void cPartyManager::Release()
{
	mJoinMap.Clear();
}

void cPartyManager::Process( unsigned long /*elapsedTime*/, unsigned long accumTime )
{
	if( mPartyMap.GetSize() == 0 )
		return;

	/// 일정시간마다 파티의 정보를 send
	cPartyMap::cIterator i = mPartyMap.Begin();
	cPartyMap::cIterator end = mPartyMap.End();
	for( ; i != end; ++i )
	{
		cParty* party = (cParty*)(i->mSecond);
		if( party && accumTime - party->GetLastAccumTime() > PARTY_UPDATETIME )
		{
			SendUpdateParty( party );
			party->SetLastAccumTime( accumTime );
		}
	}
}	

/// 파티 갱신 보내기 - 일정 시간 타임 갱신
/// 근접 그리드에 존재 하지 않는 유저에에 정보를 보내기 위함
void cPartyManager::SendUpdateParty( cParty* party )
{
	if( !party )
		return;

	int count = party->GetCount();
	unsigned long* userArr1 = party->GetUserArr();
	unsigned long* userArr2 = party->GetUserArr();

	typedef tHashSet<unsigned long> cSkillInfluenceSet;

	for( int i = 0; i < count; ++i )
	{
		for( int j = 0; j < count; ++j )
		{
			/// 자기에겐 안보냄.
			if( i == j )
				continue;

			cPlayer* player1 = OBJECTMANAGER->GetPlayer( *(userArr1+i) );
			cPlayer* player2 = OBJECTMANAGER->GetPlayer( *(userArr2+j) );
			if( player1 && player2 )
			{
				/// 1. 맵 위치 검사
				if( player1->GetMapNumber() != player2->GetMapNumber() )
					continue;

				/// 2. 그리드 검사 - 근접 그리드안에 없는 유저에게만 쏘도록 한다
				if( GRIDMANAGER->IsSight( player1, player2 ) == false )
				{
					HANDLE				handle = NULL;
					MSG_SYN_PARTY_DATA*	sendMsg = (MSG_SYN_PARTY_DATA*)NETWORK2->GetMsgRoot( &handle, player2->GetConnectionIdx() );

					sendMsg->Category	= NM_PARTY;
					sendMsg->Protocol	= NM_PARTY_DATA_SYN;
					sendMsg->userIndex	= player1->GetObjectID();
					sendMsg->level		= player1->GetLevel();
					sendMsg->maxHP		= player1->GetMaxHP();
					sendMsg->hp			= player1->GetHP();
					sendMsg->maxMP		= player1->GetMaxMP();
					sendMsg->mp			= player1->GetMP();
					sendMsg->posX		= player1->GetXPos();
					sendMsg->posY		= player1->GetYPos();
					sendMsg->RowCount	= 0;

					/// 버프리스트 담기
					cSkillInfluenceSet* influenceSet = player1->GetInfluenceSet();
					if( influenceSet && influenceSet->GetSize() > 0  )
					{
						cSkillInfluenceSet::cIterator i = influenceSet->Begin();
						cSkillInfluenceSet::cIterator end = influenceSet->End();

						long& buffCount = sendMsg->RowCount;
						cInfluenceObject* pObj = 0;
						for( ; i != end; ++i )
						{
							pObj = SKILLMANAGER->GetInfluence( (unsigned long)(*i) );
							if( !pObj )
							{
								assert(0);
								NETWORK2->PostServerEvent("cPartyManager::SendUpdateParty[%d,%d,%d]", NM_PARTY_DATA_SYN, player2->GetConnectionIdx(), (*userArr1));
								continue;
							}

							sendMsg->mTable[buffCount].mInfluenceClassIdx = pObj->GetInfluenceClassIdx();
							sendMsg->mTable[buffCount].mUniqueIdx = pObj->GetUniqueIdx();
							sendMsg->mTable[buffCount].mRestTime = 0;

							buffCount++;
						}
					}
					
					NETWORK2->SendMsgRoot( handle, sendMsg->GetMsgLength() );
				}
			}
		}
	}
}

bool cPartyManager::ResPartyMsgError( unsigned long connectionIdx, char protocol, long error )
{
	HANDLE	   handle  = NULL;
	MSG_ERROR* sendMsg = (MSG_ERROR*)NETWORK2->GetMsgRoot( &handle, connectionIdx );

	if ( sendMsg != NULL )
	{
		sendMsg->Category  = NM_PARTY;
		sendMsg->Protocol  = protocol;
		sendMsg->ErrorCode = error;
		return NETWORK2->SendMsgRoot( handle, sizeof(MSG_ERROR) );
	}
	return false;
}

bool cPartyManager::ResPartyList( cPlayer* player, cParty* party )
{
	HANDLE						handle = NULL;
	MSG_SYN_PARTY_LIST*			sendMsg = (MSG_SYN_PARTY_LIST*)NETWORK2->GetMsgRoot( &handle, player->GetConnectionIdx() );
	unsigned long				length  = sizeof(MSG_SYN_PARTY_LIST) - sizeof(sendMsg->party);

	sendMsg->Category = NM_PARTY;
	sendMsg->Protocol = NM_PARTY_LIST_SYN;
	sendMsg->mIndex = party->GetIndex();
	sendMsg->mLevel = party->GetLevel();
	sendMsg->mLeaderIndex = party->GetLeader();
	sendMsg->mDivideType = party->GetDivideType();
	sendMsg->RowCount = 0;

	long& cnt = sendMsg->RowCount;
	unsigned long* userArr = party->GetUserArr();
	for( unsigned int i = 0; i < party->GetCount(); ++i, ++userArr )
	{
		/// 자기자신 제외
		if( player->GetObjectID() == (*userArr) )
			continue;

		cPlayer* user = OBJECTMANAGER->GetPlayer( (*userArr) );
		if( user )
		{
			sendMsg->party[cnt].UserIndex = (*userArr);
			wcscpy( sendMsg->party[cnt].Name, user->GetName() );

			sendMsg->party[cnt].Job			= user->GetJob();
			sendMsg->party[cnt].Level		= user->GetLevel();
			sendMsg->party[cnt].MapNum		= (user->IsPvPJoin() == true ) ? user->GetPvPMapDataNumber() : user->GetMapNumber();
			sendMsg->party[cnt].InitX		= user->GetXPos();
			sendMsg->party[cnt].InitY		= user->GetYPos();
			sendMsg->party[cnt].HP			= user->GetHP();
			sendMsg->party[cnt].MaxHP		= user->GetMaxHP();
			sendMsg->party[cnt].MP			= user->GetMP();
			sendMsg->party[cnt].MaxMP		= user->GetMaxMP();
			cnt++;
		}
		else
		{
			NETWORK2->PostServerEvent( "Error cPartyManager::ResPartyList : not exist partyuser %d", (*userArr) );
			continue;
		}
	}

	length += (sendMsg->RowCount * sizeof(sendMsg->party));
	return NETWORK2->SendMsgRoot( handle, length );
}

/// 파티원 추가 정보 보내기
bool cPartyManager::ResPartyAddOne( unsigned long characterIdx, cParty* party )
{
	HANDLE		handle = NULL;

	cPlayer*	partyUser = 0;
	cPlayer*	addUser = OBJECTMANAGER->GetPlayer( characterIdx );
	if( !addUser )
	{
		NETWORK2->PostServerEvent( "Error cPartyManager::ResPartyAddOne : not exist add user(%d)", characterIdx );
		return false;
	}

	unsigned long*  userArr    = party->GetUserArr();
	unsigned int	partyCount = party->GetCount();

	/// 추가된 유저를 제외한 나머지 파티원에게 보내기
	for( unsigned int i = 0; i < partyCount; ++i, ++userArr )
	{
		if( characterIdx == (*userArr) )
			continue;

		partyUser = OBJECTMANAGER->GetPlayer( (*userArr));
		if( !partyUser )
		{
			NETWORK2->PostServerEvent( "Error cPartyManager::ResPartyAddOne : not exist partyuser %d", (*userArr) );
			continue;
		}

		MSG_SYN_PARTY_ADDONE*		sendMsg = (MSG_SYN_PARTY_ADDONE*)NETWORK2->GetMsgRoot( &handle, partyUser->GetConnectionIdx() );
		sendMsg->Category = NM_PARTY;
		sendMsg->Protocol = NM_PARTY_ADDONE_SYN;

		sendMsg->mPartyLevel	= party->GetLevel();
		sendMsg->UserIndex		= characterIdx;
		wcscpy( sendMsg->Name, addUser->GetName() );
		sendMsg->Level			= addUser->GetLevel();
		sendMsg->Job			= addUser->GetJob();
		sendMsg->HP				= addUser->GetHP();
		sendMsg->MaxHP			= addUser->GetMaxHP();
		sendMsg->MP				= addUser->GetMP();
		sendMsg->MaxMP			= addUser->GetMaxMP();
		sendMsg->MapNum			= (addUser->IsPvPJoin() == true ) ? addUser->GetPvPMapDataNumber() : addUser->GetMapNumber();
		sendMsg->InitX			= addUser->GetXPos();
		sendMsg->InitY			= addUser->GetYPos();

		NETWORK2->SendMsgRoot( handle, sizeof(MSG_SYN_PARTY_ADDONE) );
	}

	return true;
}

///// 파티 강제 해체
//void cPartyManager::PartyBreak( cPlayer* player )
//{
//	if( !player )
//	{
//		NETWORK2->PostServerEvent( "Error cPartyManager::PartyBreak : not exist party out user" );
//		assert(0);
//		return;
//	}
//
//	ePLAYER_PARTYSTATE state = player->GetPartyState();
//	if( state == ePARTY_NONE )
//		return;
//
//	/// 파티신청을 받는중이었으면 신청자에게 알려줌	
//	if( state == ePARTY_RECVJOIN )
//	{
//		/// 파티 신청정보 삭제
//		DelRequest( player->GetObjectID() );
//
//		///
//		unsigned long fromIndex = GetRequest( player->GetObjectID() );
//		cPlayer* fromPlayer = OBJECTMANAGER->GetPlayer( fromIndex );
//		if( fromPlayer )
//		{
//			HANDLE				handle = NULL;
//			MSG_RES_PARTY_ADD*	sendMsg = (MSG_RES_PARTY_ADD*)NETWORK2->GetMsgRoot( &handle, fromPlayer->GetConnectionIdx(), NM_PARTY, NM_PARTY_ADD_RES );
//			if( sendMsg != NULL )
//			{
//				sendMsg->ErrorCode = ERROR_PARTY_ADD_USEROUT;
//				NETWORK2->SendMsgRoot( handle, sizeof(MSG_RES_PARTY_ADD) );
//			}
//		}
//	}
//	else
//	{
//		/// 실제 파티 해산
//		unsigned long partyIndex = player->GetPartyIndex();
//		cParty* party = GetParty( partyIndex );
//		if( party )
//		{
//			/// 파티 해산
//			HANDLE			handle = NULL;
//			cPlayer*		partyUser = 0;
//			unsigned long*  userArr = party->GetUserArr();
//			unsigned int	partyCount = party->GetCount();
//
//			for( unsigned int i = 0; i < partyCount; ++i, ++userArr )
//			{
//				partyUser = OBJECTMANAGER->GetPlayer( (*userArr) );
//				if( partyUser )
//				{
//					/// 모든 파티원의 파티상태 초기화 
//					partyUser->SetPartyIndex( 0 );
//					partyUser->SetPartyState( ePARTY_NONE );
//
//					if( NETWORK2->GetMsgRoot( &handle, partyUser->GetConnectionIdx(), NM_PARTY, NM_PARTY_BREAK_SYN ) != NULL )
//					{
//						NETWORK2->SendMsgRoot( handle, sizeof(MSG_SYN_PARTY_BREAK) );
//					}
//				}
//				else
//				{
//					NETWORK2->PostServerEvent( "Error cPartyManager::PartyOutPlayer : not exist party out user" );
//					continue;
//				}
//			}
//
//			/// 파티 삭제
//			DeleteParty( partyIndex );
//		}
//		else
//		{
//			assert(0);
//			return;
//		}
//	}
//}

// 신청을 받는경우와 파티중인경우를 분류해서 처리
// 신청을 하는경우에는 따로 처리하지않아도 됨 ( 신청자가 응답을 주었을경우 자동으로 처리됨 )
void cPartyManager::PartyOutPlayer( cPlayer* player )
{
	if( !player )
	{
		NETWORK2->PostServerEvent( "Error cPartyManager::PartyOutPlayer : not exist party out user" );
		assert(0);
		return;
	}
	
	ePLAYER_PARTYSTATE state = player->GetPartyState();
	if( state == ePARTY_NONE )
		return;

	// 신청을 받는 경우
	if( state == ePARTY_RECVJOIN )
	{
		/// 신청한 유저에게 거절메세지 보내기
		unsigned long reqIdx = GetRequest( player->GetObjectID() );
		if( reqIdx > 0 )
		{
			cPlayer* requester = OBJECTMANAGER->GetPlayer( reqIdx );
			if( requester )
			{
				ePLAYER_PARTYSTATE state = ( requester->GetPartyIndex() > 0 ) ? ePARTY_COMPLETE : ePARTY_NONE;
				requester->SetPartyState( state );

				HANDLE     handle  = NULL;
				MSG_RES_PARTY_ADD* sendMsg = (MSG_RES_PARTY_ADD*)NETWORK2->GetMsgRoot( &handle, requester->GetConnectionIdx(), NM_PARTY, NM_PARTY_ADD_RES );
				if( sendMsg != NULL )
				{
					sendMsg->ErrorCode = ERROR_PARTY_ADD_REFUSE;
					NETWORK2->SendMsgRoot( handle, sizeof(MSG_RES_PARTY_ADD) );
				}
			}

			/// 유저의 상태 변경
			player->SetPartyState( ePARTY_NONE );

			/// 리퀘스트 삭제
			DelRequest( player->GetObjectID() );

			player->EndRequestRejection( eREQREJCT_PARTY );
		}
		else
		{
			NETWORK2->PostServerEvent("cPartyManager::PartyOutPlayer[%d]", player->GetObjectID() );
		}
	}
	else
	{
		/// 파티탈퇴 혹은 파티해산 처리 
		unsigned long partyIndex = player->GetPartyIndex();
		cParty* party = GetParty( partyIndex );
		if( party )
		{
			/// 3명이면 한명빠져도 유지가능
			/// 남은유저에게 파티탈퇴 알리기
			if( party->GetCount() > 2 )
			{
				HANDLE			handle = NULL;
				cPlayer*		partyUser = 0;
				unsigned long*  userArr = party->GetUserArr();
				unsigned int	partyCount = party->GetCount();

				for( unsigned int i = 0; i < partyCount; ++i, ++userArr )
				{
					/// 탈퇴본인은 제외
					if( (*userArr) == player->GetObjectID() )
						continue;

					partyUser = OBJECTMANAGER->GetPlayer( (*userArr) );
					if( partyUser )
					{
						MSG_SYN_PARTY_OUT*	sendMsg = (MSG_SYN_PARTY_OUT*)NETWORK2->GetMsgRoot( &handle, partyUser->GetConnectionIdx(), NM_PARTY, NM_PARTY_OUT_SYN );
						if( sendMsg != NULL )
						{
							sendMsg->UserIndex = player->GetObjectID();
							NETWORK2->SendMsgRoot( handle, sizeof(MSG_SYN_PARTY_OUT) );
						}
					}
					else
					{
						NETWORK2->PostServerEvent( "Error cPartyManager::PartyOutPlayer : not exist party out user" );
						continue;
					}
				}
				
				/// 탈퇴자가 파티장이었으면 리더 체인지 처리
				if( party->GetLeader() == player->GetObjectID() )
				{
					/// 파티장이면 다음 유저 인덱스 찾기
					unsigned long nextIndex = FindNext( party, player->GetObjectID() );
					PartyChangeLeader( player, nextIndex );
				}

				/// 파티탈퇴 요청한 사람을 탈퇴
				if ( NETWORK2->GetMsgRoot( &handle, player->GetConnectionIdx(), NM_PARTY, NM_PARTY_OUT_RES ) != NULL )
				{
					NETWORK2->SendMsgRoot( handle, sizeof(MSG_RES_PARTY_OUT) );
				}

				/// 파티탈퇴 요청한 유저를 삭제.
				party->DeleteUser( player->GetObjectID() );

				player->SetPartyIndex( 0 );
				player->SetPartyState( ePARTY_NONE );
			}
			/// 2명이하면 파티 해산
			else
			{
				/// 파티 해산
				HANDLE			handle = NULL;
				cPlayer*		partyUser = 0;
				unsigned long*  userArr = party->GetUserArr();
				unsigned int	partyCount = party->GetCount();

				for( unsigned int i = 0; i < partyCount; ++i, ++userArr )
				{
					partyUser = OBJECTMANAGER->GetPlayer( (*userArr) );
					if( !partyUser )
					{
						NETWORK2->PostServerEvent( "Error cPartyManager::PartyOutPlayer : not exist party out user" );
						continue;
					}

					/// 모든 파티원의 파티상태 초기화 
					partyUser->SetPartyIndex( 0 );
					partyUser->SetPartyState( ePARTY_NONE );

					/// 파티탈퇴를 요청한 유저에게는 파티 해산메세지를 쏘지 않는다
					if( player != partyUser )
					{
						if ( NETWORK2->GetMsgRoot( &handle, partyUser->GetConnectionIdx(), NM_PARTY, NM_PARTY_DELETE_SYN ) != NULL )
						{
							NETWORK2->SendMsgRoot( handle, sizeof(MSG_SYN_PARTY_DELETE) );
						}
					}
				}

				/// 파티탈퇴 요청한 사람을 탈퇴
				if ( NETWORK2->GetMsgRoot( &handle, player->GetConnectionIdx(), NM_PARTY, NM_PARTY_OUT_RES ) != NULL )
				{
					NETWORK2->SendMsgRoot( handle, sizeof(MSG_RES_PARTY_OUT) );
				}

				/// 파티 삭제
				DeleteParty( partyIndex );
			}
		}
	}
}

/// 파티장 변경 
void cPartyManager::PartyChangeLeader( cPlayer* fromPlayer, unsigned long toUserIdx )
{
	cPlayer* toPlayer = OBJECTMANAGER->GetPlayer( toUserIdx );

	try
	{
		if( fromPlayer && toPlayer )
		{
			if( fromPlayer == toPlayer )
				throw ERROR_PARTY_CHANGELEADER_FAIL;

			/// 파티가 없거나, 같은 파티가 아니라면 
			if( (fromPlayer->GetPartyIndex() == 0 || toPlayer->GetPartyIndex() == 0) )
				throw ERROR_PARTY_CHANGELEADER_FAIL;

			if( fromPlayer->GetPartyIndex() != toPlayer->GetPartyIndex() )
				throw ERROR_PARTY_CHANGELEADER_FAIL;

			/// 파티 세팅
			cParty* party = GetParty( fromPlayer->GetPartyIndex() );
			if( party )
			{
				/// 권한없음.
				if( party->GetLeader() != fromPlayer->GetObjectID() )						
					throw ERROR_PARTY_CHANGELEADER_LEADER;

				/// 파티장 정보 재세팅
				party->SetLeader( toUserIdx );

				/// 파티장 변경 요청 완료 res
				ResPartyMsgError( fromPlayer->GetConnectionIdx(), NM_PARTY_CHANGELEADER_RES, ERROR_PARTY_CHANGELEADER_SUCESS );

				/// 파티장 위임 알림 
				HANDLE			handle = NULL;
				cPlayer*		partyUser = 0;
				unsigned long*  userArr = party->GetUserArr();
				unsigned int	partyCount = party->GetCount();

				for( unsigned int i = 0; i < partyCount; ++i, ++userArr )
				{
					partyUser = OBJECTMANAGER->GetPlayer( (*userArr) );
					if( partyUser )
					{
						MSG_SYN_PARTY_CHANGELEADER*	sendMsg = (MSG_SYN_PARTY_CHANGELEADER*)NETWORK2->GetMsgRoot( &handle, partyUser->GetConnectionIdx(), NM_PARTY, NM_PARTY_CHANGELEADER_SYN );
						if( sendMsg != NULL )
						{
							sendMsg->UserIndex = toUserIdx;
							NETWORK2->SendMsgRoot( handle, sizeof(MSG_SYN_PARTY_CHANGELEADER) );
						}
					}
					else
					{
						NETWORK2->PostServerEvent( "Error cPartyManager::PartyChangeLeader : not exist party out user" );
						continue;
					}
				}
			}
			else
				throw ERROR_PARTY_CHANGELEADER_FAIL;
		}
	}
	catch ( int error )
	{
		ResPartyMsgError( fromPlayer->GetConnectionIdx(), NM_PARTY_CHANGELEADER_RES, error );
	}
}

/// 파티분배방식 변경
void cPartyManager::PartyChangeDivide( cPlayer* fromPlayer, PARTY_DIVIDE_TYPE type )
{
	try
	{
		if( fromPlayer )
		{
			cParty* party = GetParty( fromPlayer->GetPartyIndex() );
			if( party )
			{
				if( party->GetDivideType() == type )
					throw ERROR_PARTY_CHANGEDIVIDE_LEADER;

				/// 권한없음.
				if( party->GetLeader() != fromPlayer->GetObjectID() )						
					throw ERROR_PARTY_CHANGEDIVIDE_LEADER;

				party->SetDivideType( type );

				/// 파티장에게 분배 성공 알림
				ResPartyMsgError( fromPlayer->GetConnectionIdx(), NM_PARTY_CHANGEDIVIDE_RES, ERROR_PARTY_CHANGEDIVIDE_SUCESS );

				/// 분배방식 변경 알림
				HANDLE			handle = NULL;
				cPlayer*		partyUser = 0;
				unsigned long*  userArr = party->GetUserArr();
				unsigned int	partyCount = party->GetCount();

				for( unsigned int i = 0; i < partyCount; ++i, ++userArr )
				{
					partyUser = OBJECTMANAGER->GetPlayer( (*userArr) );
					if( partyUser )
					{
						MSG_SYN_PARTY_CHANGEDIVDE*	sendMsg = (MSG_SYN_PARTY_CHANGEDIVDE*)NETWORK2->GetMsgRoot( &handle, partyUser->GetConnectionIdx(), NM_PARTY, NM_PARTY_CHANGEDIVIDE_SYN );
						if( sendMsg != NULL )
						{
							sendMsg->type = type;
							NETWORK2->SendMsgRoot( handle, sizeof(MSG_SYN_PARTY_CHANGEDIVDE) );
						}
					}
					else
					{
						NETWORK2->PostServerEvent( "Error cPartyManager::PartyChangeDivide : not exist party out user" );
						continue;
					}
				}
			}
			else
				throw ERROR_PARTY_CHANGEDIVIDE_FAIL;
		}
	}
	catch ( int error )
	{
		ResPartyMsgError( fromPlayer->GetConnectionIdx(), NM_PARTY_CHANGEDIVIDE_RES, error );
	}
}

// 신청자 : 게임종료시 파티로부터 탈퇴처리
// 신청받는유저 : 맵아웃, 게임종료시 자동 거절 처리한다
void cPartyManager::PartyMapOut( cPlayer* hero )
{
	ePLAYER_PARTYSTATE state = hero->GetPartyState();

	/// 파티초대를 받는중이었다면
	if( state == ePARTY_RECVJOIN )
	{
		/// 신청한 유저에게 거절메세지 보내기
		unsigned long reqIdx = GetRequest( hero->GetObjectID() );
		if( reqIdx > 0 )
		{
			cPlayer* requester = OBJECTMANAGER->GetPlayer( reqIdx );
			if( requester )
			{
				ePLAYER_PARTYSTATE state = ( requester->GetPartyIndex() > 0 ) ? ePARTY_COMPLETE : ePARTY_NONE;
				requester->SetPartyState( state );

				HANDLE     handle  = NULL;
				MSG_RES_PARTY_ADD* sendMsg = (MSG_RES_PARTY_ADD*)NETWORK2->GetMsgRoot( &handle, requester->GetConnectionIdx(), NM_PARTY, NM_PARTY_ADD_RES );
				if( sendMsg != NULL )
				{
					sendMsg->ErrorCode = ERROR_PARTY_ADD_REFUSE;
					NETWORK2->SendMsgRoot( handle, sizeof(MSG_RES_PARTY_ADD) );
				}
			}

			/// 맵체인지한 유저의 상태 변경
			hero->SetPartyState( ePARTY_NONE );
			
			/// 리퀘스트 삭제
			DelRequest( hero->GetObjectID() );

			hero->EndRequestRejection( eREQREJCT_PARTY );
		}
		else
		{
			NETWORK2->PostServerEvent("cPartyManager::PartyMapOut[%d]", hero->GetObjectID() );
		}
	} 
}

/// 파티원 맵체인지
void cPartyManager::PartyMapIn( cPlayer* player )
{
	ePLAYER_PARTYSTATE state = player->GetPartyState();
	
	/// 파티중이라면
	if( state == ePARTY_COMPLETE )
	{
		cParty* party = GetParty( player->GetPartyIndex() );
		if( party )
		{
			/// 다른유저들에게 맵 체인지 알리기
			HANDLE			handle = NULL;
			cPlayer*		partyUser = 0;
			unsigned long*  userArr = party->GetUserArr();
			unsigned int partyCount = party->GetCount();

			for( unsigned int i = 0; i < partyCount; ++i, ++userArr )
			{
				/// 맵 체인지한 유저는 빼고 보냄.
				if( (*userArr) == player->GetObjectID() )
					continue;

				partyUser = OBJECTMANAGER->GetPlayer( (*userArr) );
				if( partyUser )
				{
					MSG_SYN_PARTY_MAPCHANGE* sendMsg = (MSG_SYN_PARTY_MAPCHANGE*)NETWORK2->GetMsgRoot( &handle, partyUser->GetConnectionIdx(), NM_PARTY, NM_PARTY_MAPCHANGE_SYN );
					if( sendMsg != NULL )
					{
						sendMsg->UserIndex = player->GetObjectID();
						sendMsg->MapNum = player->GetMapNumber();
						NETWORK2->SendMsgRoot( handle, sizeof(MSG_SYN_PARTY_MAPCHANGE) );
					}
				}
				else
				{
					NETWORK2->PostServerEvent( "Error cPartyManager::PartyMapIn : not exist party out user" );
					continue;
				}
			}

			/// 이동한유저들에겐 파티 정보 새로 보내기
			ResPartyList( player, party );
		}
		else
		{
			NETWORK2->PostServerEvent( "Error cPartyManager::PartyMapIn : not exist party" );
		}
	}
}

/// 전직 정보 보내기
void cPartyManager::SendToPartyChangeJob( cPlayer* player )
{
	cParty* party = GetParty( player->GetPartyIndex() );
	if( player && party )
	{
		cPlayer*	 partyUser = 0;
		unsigned long* userArr = party->GetUserArr();
		unsigned int partyCount = party->GetCount();

		for( unsigned int i = 0; i < partyCount; ++i, ++userArr )
		{
			if( (*userArr) == player->GetObjectID() )
				continue;

			partyUser = OBJECTMANAGER->GetPlayer( (*userArr) );
			if( partyUser )
			{
				HANDLE					 handle = NULL;
				MSG_SYN_PARTY_CHANGEJOB* sendMsg = (MSG_SYN_PARTY_CHANGEJOB*)NETWORK2->GetMsgRoot( &handle, partyUser->GetConnectionIdx(), NM_PARTY, NM_PARTY_JOBCHANGE_SYN );
				if( sendMsg != NULL )
				{
					sendMsg->userIndex = player->GetObjectID();
					sendMsg->job = player->GetJob();
					NETWORK2->SendMsgRoot( handle, sizeof(NM_PARTY_JOBCHANGE_SYN) );
				}
			}
			else
			{
				NETWORK2->PostServerEvent( "Error cPartyManager::SendToPartyChangeJob : not exist party user" );
				continue;
			}
		}
	}
}

/// 파티원이 몬스터 사냥한 정보를 보낸다 (퀘스트 업데이트용)
void cPartyManager::SendToPartyHunt( cMonster* monster, cPlayer* hero, unsigned int racegender )
{
	cParty* party = GetParty( hero->GetPartyIndex() );
	if( party )
	{
		cPlayer*	 partyUser = 0;
		unsigned long* userArr = party->GetUserArr();
		unsigned int partyCount = party->GetCount();

		for( unsigned int i = 0; i < partyCount; ++i, ++userArr )
		{
			partyUser = OBJECTMANAGER->GetPlayer( (*userArr) );
			if( partyUser )
			{
				/// 거리 체크
				if( monster->GetMapNumber() == partyUser->GetMapNumber() )
				{
					NiPoint2 monPos = monster->GetPos();
					NiPoint2 userPos = partyUser->GetPos();

					/// 일정 범위안에 있으면 퀘스트 정보 갱신
					cRangeCheck range( PARTY_RANGE );
					if( range.IsRange( monPos, userPos ) == true )
					{
						/// 파티원 퀘스트 정보 갱신
						partyUser->UpdateDutyHunt( racegender );
					}
				}
			}
			else
			{
				NETWORK2->PostServerEvent( "Error cPartyManager::SendToPartyHunt : not exist party user" );
				continue;
			}
		}
	}
}

///
unsigned long cPartyManager::AddParty( unsigned long leaderIdx, unsigned long userIdex )
{
	/// 파티 생성
	cParty* pParty = new cParty;
	if( !pParty )
	{
		SAFE_DELETE( pParty );
		NETWORK2->PostServerEvent( "Error cPartyManager::AddParty : failed to create party" );

		assert(0);
		return 0;
	}

	/// 파티 기본정보 세팅
	unsigned long index = mPartyIndexGen.GeneratIdx();
	pParty->SetIndex( index );
	pParty->SetLevel( 0 );
	pParty->SetDivideType( PARTY_DIVIDE_TURN );
	pParty->SetLastAccumTime( NETWORK2->GetAccumTime() );

	/// 파티원 세팅
	pParty->AddUser( leaderIdx );
	pParty->AddUser( userIdex );

	/// 파티장 세팅
	pParty->SetLeader( leaderIdx );

	/// 파티 삽입 
	if( mPartyMap.Insert( index, pParty ) == false )
	{
		SAFE_DELETE( pParty );
		NETWORK2->PostServerEvent( "Error cPartyManager::AddParty : failed to insert party map" );
		assert(0);
		return 0;
	}
	
	return index;
}

bool cPartyManager::DeleteParty( unsigned long partyIdx )
{
	cParty* party = (cParty*)mPartyMap.GetAt( partyIdx );
	if( party )
	{
		mPartyMap.Erase( partyIdx );
		mPartyIndexGen.DelIdx( partyIdx );
		SAFE_DELETE( party );
	}
	else
	{
		NETWORK2->PostServerEvent( "Error cPartyManager::DeleteParty : failed to find party" );
		return false;
	}

	return true;
}

unsigned long cPartyManager::FindNext( cParty* party, unsigned long userIndex )
{
	unsigned long*  userArr = party->GetUserArr();
	unsigned int arrIndex = 0;
	unsigned int count = party->GetCount();
	for( unsigned int i = 0; i < count; ++i )
	{
		if( userIndex == userArr[i] )
		{
			arrIndex = i + 1;
			break;
		}
	}

	/// 인원수를 넘어가면 첫번째 유저로 바굼
	arrIndex = arrIndex % count;
	return userArr[arrIndex];
}

cParty*	cPartyManager::GetParty( unsigned int partyIdx )
{
	return ( partyIdx > 0 ) ? (cParty*)mPartyMap.GetAt( partyIdx ) : NULL;
}

bool cPartyManager::AddRequest( unsigned long recvIdx, unsigned long reqIdx )
{
	/// 신청받은 유저인덱스를 키로 넣는다.
	return mJoinMap.Insert( recvIdx, reqIdx );
}

void cPartyManager::DelRequest( unsigned long recvIdx )
{
	mJoinMap.Erase( recvIdx );
}

/// 파티를 신청한 유저의 인덱스를 검색
unsigned long cPartyManager::GetRequest( unsigned long recvIdx )
{
	cJoinMap::cIterator i = mJoinMap.Find( recvIdx );
	return ( i != mJoinMap.End() ) ? (unsigned long)(*i).mSecond : 0;
}
