#include "stdafx.h"
#include "gamesrv.h"
#include "Gathering.h"
#include "Gathering_Common.h"
#include "GatheringScript.h"
#include "Drop.h"

cGathering::cGathering( void )
: cBaseObject( eOBJECTTYPE_GATHERING )
, mRegenIndex(0)
{
}


cGathering::~cGathering( void )
{
}			


void* cGathering::operator new( size_t n )
{
	if( n != sizeof(cGathering) ) 
	{
		assert(0);
		return NULL;
	}

	return OBJECTMANAGER->AllocGathering();
}


void cGathering::operator delete( void* ptr, size_t n )
{
	/// NULL 포인터 검사
	if( ptr == 0 )
	{
		assert(0);
		return;
	}

	if( n != sizeof(cGathering) ) 
	{
		assert(0);
		return;
	}

	OBJECTMANAGER->FreeGathering( static_cast<cGathering*>(ptr) );

	return;
}


bool cGathering::GatheringInit( unsigned long objectIdx, unsigned long regenIdx )
{
	/// 리젠 그룹 정보
	const sGatheringRegenHeader* pScript = GATHERINGSCRIPT->GetGatheringRegen( regenIdx );
	if( pScript == NULL )
		return false;

	/// 좌표정보중 임의의 위치 선택	
	unsigned long detailSize = pScript->mRegenDetail.GetSize();
	if( detailSize == 0 )
		return false;
	unsigned long selectPos = rand() % detailSize;

	/// 리젠 좌표 세부 정보
	mpRegenDetail = (sGatheringRegen*)pScript->mRegenDetail[selectPos];
	if( mpRegenDetail == NULL )
		return false;

	/// 채집 리스트 정보
	mpGatheringInfo = (sGatheringList*)GATHERINGSCRIPT->GetGatheringInfo( mpRegenDetail->mGatheringIdx );
	if( mpGatheringInfo == NULL )
		return false;

	mMapNumber = mpRegenDetail->mMapNumber;
	mObjectPos.x = mpRegenDetail->mPosX;
	mObjectPos.y = mpRegenDetail->mPosY;

	/// 리젠 지역 체크
	float mapMaxSize = AIMANAGER->GetPathMaxSideSize( mMapNumber );
	if( mObjectPos.x < 0 || mObjectPos.x > mapMaxSize || mObjectPos.y < 0 || mObjectPos.y > mapMaxSize )
		return false;

	//if( AIMANAGER->IsPassible( mMapNumber, mObjectPos.x, mObjectPos.y, GetObject() ) == false )
	//	return false;

	mObject.index = objectIdx;
	mRegenIndex = regenIdx;

	mRangeCheck.SetRadius( 100 + SYNC_MOVE_RANGE );

	return true;
}


void cGathering::Update( unsigned long /*elapsedTime*/, unsigned long accumTime )
{
	cHashMap::cIterator iter = mGatherCharactorMap.Begin();
	for( ; iter != mGatherCharactorMap.End() ; ++iter )
	{
		if( (*iter).mSecond <= accumTime )
			GatheringDie( (*iter).mFirst );
	}
}


unsigned long cGathering::GetClassIdx()
{
	if( mpRegenDetail == NULL )
		return 0;

	return mpRegenDetail->mGatheringIdx; 
}


void cGathering::SendRegenSync()
{
	/// 메세지 발송
	MSG_GATHERING_INFO msg;
	msg.Category = NM_GATHERING;
	msg.Protocol = NM_GATHERING_REGEN_SYN;
	msg.mObjectIdx = mObject.index;
	msg.mPosX = mObjectPos.x;
	msg.mPosY = mObjectPos.y;
	msg.mGatheringIdx = GetClassIdx();
	msg.mDirection = GetDirection();
	msg.mAppendZ   = GetAppendZ();
	NETWORK2->QuickSend( this, (char*)&msg, sizeof(msg) );
}


void cGathering::AddGatherPlayer( cPlayer* pPlayer )
{
	try
	{
		if( pPlayer == NULL )
			throw ERROR_GATHERING_FAIL;

		pPlayer->MoveStop();

		sGatheringList* pInfo = GATHERINGSCRIPT->GetGatheringInfo( mpRegenDetail->mGatheringIdx );
		if( pInfo == NULL )
			throw ERROR_GATHERING_FAIL;

		/// 거리 체크
		if( mRangeCheck.IsRange( pPlayer->GetPos(), mObjectPos ) == false )
			throw ERROR_GATHERING_RANGE;

		/// 레벨 체크
		if( pPlayer->GetLevel() < pInfo->mNeedLevel )
			throw ERROR_GATHERING_LEVEL;

		/// 장비 체크
		if( pInfo->mNeedItemIdx != 0 && pPlayer->IsItem( pInfo->mNeedItemIdx ) == false )
			throw ERROR_GATHERING_ITEM;
				
		/// 퀘스트 체크
        if( pInfo->mNeedQuestIdx != 0 && pPlayer->IsCompleteGathering( pInfo->mNeedQuestIdx ) == true )
			throw ERROR_GATHERING_QUEST;
        
		/// 전문기술 체크
		if( pInfo->mNeedMakeIdx != 0 && pPlayer->IsMakeSkill( pInfo->mNeedMakeIdx ) == false )
			throw ERROR_GATHERING_MAKESKILL;

		/// 플레이어 상태 변경
		if( pPlayer->ChangeState( ePLAYER_STATE_GATHERING ) == false )
			throw ERROR_GATHERING_FAIL;

		throw ERROR_GATHERING_SUCCESS;
	}
	catch (int e)
	{
		HANDLE handle  = NULL;
		
		/// 성공/실패 메세지 발송
		MSG_ERROR* sendMsg = (MSG_ERROR*)NETWORK2->GetMsgRoot( &handle, pPlayer->GetConnectionIdx(), 
			NM_GATHERING, NM_GATHERING_START_RES );
		if ( sendMsg != NULL )
		{
			sendMsg->ErrorCode = e;
			NETWORK2->SendMsgRoot( handle, sizeof(MSG_ERROR) );
		}

		/// 성공시 부가 처리
		if( e == ERROR_GATHERING_SUCCESS )
		{
			pPlayer->SetGatheringIdx( mObject.index );

			if( mGatherCharactorMap.Insert( pPlayer->GetObjectID(), NETWORK2->GetAccumTime() + GATHER_CASTING_TIME ) == false )
				NETWORK2->PostServerEvent("cGathering::AddGatherPlayer duplicate(%d)", pPlayer->GetObjectID() );

			MSG_SYN_GATHERING_START msg;
			msg.Category = NM_GATHERING;
			msg.Protocol = NM_GATHERING_START_SYN;
			msg.mObjectIdx = mObject.index;
			msg.mClassIdx = mpGatheringInfo->mGatheringIdx;
			msg.mCharacterIdx = pPlayer->GetObjectID();
			NETWORK2->QuickSendExcept( pPlayer, (char*)&msg, sizeof(msg) );
		}
	}
}


void cGathering::ReqEraseGatherPlayer( cPlayer* pPlayer )
{
	/// 플레이어 상태 변경
	if( pPlayer->ChangeState( eOBJECT_STATE_IDLE ) == false )
		return;

	/// 플레이어와 채집중인 인덱스 변경
	pPlayer->SetGatheringIdx( 0 );

	mGatherCharactorMap.Erase( pPlayer->GetObjectID() );

	/// 성공
	HANDLE handle  = NULL;
	MSG_ERROR* sendMsg = (MSG_ERROR*)NETWORK2->GetMsgRoot( &handle, pPlayer->GetConnectionIdx(), 
		NM_GATHERING, NM_GATHERING_CANCEL_SUCCESS_RES );
	if ( sendMsg != NULL )
		NETWORK2->SendMsgRoot( handle, sizeof(MSG_ERROR) );

	MSG_SYN_GATHERING_CANCEL msg;
	msg.Category = NM_GATHERING;
	msg.Protocol = NM_GATHERING_CANCEL_SYN;
	msg.mCharacterIdx = pPlayer->GetObjectID();
	NETWORK2->QuickSendExcept( this, (char*)&msg, sizeof(msg) );
}


void cGathering::EraseGatherPlayer( cPlayer* pPlayer )
{
	mGatherCharactorMap.Erase( pPlayer->GetObjectID() );
}


void cGathering::GatheringDie( unsigned long playerIdx )
{
	/// 드롭 처리
	DROP->GatherDrop( this, playerIdx );

	MSG_SYN_GATHERING_END msg;
	msg.Category = NM_GATHERING;
	msg.mObjectIdx = mObject.index;

	/// 기존 유저들 상태 복구
	cHashMap::cIterator iter = mGatherCharactorMap.Begin();
	for( ; iter != mGatherCharactorMap.End() ; ++iter )
	{
		cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( (*iter).mFirst );
		if( pPlayer != NULL )
		{
			if( pPlayer->GetState() == ePLAYER_STATE_GATHERING )
				pPlayer->ChangeState( eOBJECT_STATE_IDLE );
			
			if( playerIdx == (*iter).mFirst )
				msg.Protocol = NM_GATHERING_END_SUCCESS_SYN;
			else
				msg.Protocol = NM_GATHERING_END_FAILE_SYN;

			msg.mCharacterIdx = (*iter).mFirst;

			/// 메세지 발송
			NETWORK2->QuickSend( pPlayer, (char*)&msg, sizeof(msg) );
		}
	}

	/// 객체 삭제 메세지...
	MSG_GATHERINGIDX delMsg;
	delMsg.Category = NM_GATHERING;
	delMsg.Protocol = NM_GATHERING_DEL_SYN;
	delMsg.mObjectIdx = mObject.index;
	NETWORK2->QuickSend( this, (char*)&delMsg, sizeof(delMsg) );

	/// 객체 삭제 대기열에 등록
	GRIDMANAGER->RemoveGathering( this );
	OBJECTMANAGER->InsertDeleteGathering( mObject.index );
	AIMANAGER->InsertReadyGathering( mObject.index, mRegenIndex );
}

// SendSightIn Method
bool cGathering::SendSightIn(char category, char protocol, unsigned long connectionIdx)
{
	HANDLE          handle  = NULL;
	MSG_GATHERING_INFO* sendMsg = (MSG_GATHERING_INFO*)NETWORK2->GetMsgRoot( &handle, connectionIdx );
	if ( sendMsg != NULL )
	{
		sendMsg->Category = category;
		sendMsg->Protocol = protocol;

		sendMsg->mObjectIdx         = mObject.index;
		sendMsg->mPosX              = mObjectPos.x;
		sendMsg->mPosY              = mObjectPos.y;
		sendMsg->mGatheringIdx      = GetClassIdx();
		sendMsg->mDirection			= GetDirection();
		sendMsg->mAppendZ			= GetAppendZ();

		return NETWORK2->SendMsgRoot( handle, sizeof(MSG_GATHERING_INFO) );
	}
	return false;
}


// SendSightOut Method
bool cGathering::SendSightOut(char category, char protocol, unsigned long connectionIdx)
{
	HANDLE            handle  = NULL;
	MSG_GATHERINGIDX* sendMsg = (MSG_GATHERINGIDX*)NETWORK2->GetMsgRoot( &handle, connectionIdx );
	if ( sendMsg != NULL )
	{
		sendMsg->Category   = category;
		sendMsg->Protocol   = protocol;
		sendMsg->mObjectIdx = mObject.index;
		return NETWORK2->SendMsgRoot( handle, sizeof(MSG_GATHERINGIDX) );
	}
	return false;
}
