#include "gamesrv.h"
#include "stdafx.h"
#include "Totem.h"
#include "Totem_Common.h"
#include "TotemScript.h"

cTotem::cTotem( void ) : cBaseObject( eOBJECTTYPE_TOTEM )
, mpInfScript(NULL)
{
}


cTotem::~cTotem( void )
{
}			


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

	return OBJECTMANAGER->AllocTotem();
}


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

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

	OBJECTMANAGER->FreeTotem( static_cast<cTotem*>(ptr) );

	return;
}


bool cTotem::TotemInit( sObject attacker, unsigned long objectIdx, unsigned long classIdx, unsigned long partyIdx, 
					   NiPoint2 pos, eAPPLYTYPE applyType, eATTRIBUTETYPE attributeType )
{
	/// 토템 스크립트
	mpTotemScript = TOTEMSCRIPT->GetTotemInfo( classIdx );
	if( mpTotemScript == NULL )
		return false;

	/// 적용 효과 스크립트
	mpInfScript = SKILLSCRIPT->GetInfluenceInfo( mpTotemScript->mInfluenceIdx );
	if( mpInfScript == NULL )
	{
        NETWORK2->PostServerEvent("cTotem::TotemInit mpInfScript[%d] != NULL", mpTotemScript->mInfluenceIdx );
		return false;
	}

	if( AIMANAGER->IsPassible( GetMapNumber(), pos.x, pos.y, GetObject() ) == false )
		return false;

	cBaseObject* pObject = OBJECTMANAGER->GetObject( attacker.type, attacker.index );
	if( pObject == NULL )
		return false;

	mMapNumber = pObject->GetMapNumber();
	mTeamType = ePVPDM_TEAMTYPE_MAX;
	mObjectPos = pos;
	mObject.index = objectIdx;
	mAttacker = attacker;
	mApplytype = applyType;
	mAttriButeType = attributeType;
	mNextCheckTime = NETWORK2->GetAccumTime() + mpTotemScript->mApplyTime;
	mEndTime = NETWORK2->GetAccumTime() + mpTotemScript->mContinuanceTime;
	mPartyIdx = partyIdx;

	return true;
}


bool cTotem::PvPTotemInit( ePVPDM_TEAM_TYPE teamType, unsigned long objectIdx, unsigned long classIdx,
					   unsigned short pvpIdx, NiPoint2 pos, eAPPLYTYPE applyType, eATTRIBUTETYPE attributeType )
{
	/// 토템 스크립트
	mpTotemScript = TOTEMSCRIPT->GetTotemInfo( classIdx );
	if( mpTotemScript == NULL )
		return false;

	/// 적용 효과 스크립트
	mpInfScript = SKILLSCRIPT->GetInfluenceInfo( mpTotemScript->mInfluenceIdx );
	if( mpInfScript == NULL )
	{
		NETWORK2->PostServerEvent("cTotem::PvPTotemInit mpInfScript[%d] != NULL", mpTotemScript->mInfluenceIdx );
		return false;
	}

	mMapNumber = pvpIdx;		/// pvp 방번호
	mTeamType = teamType;
	mObjectPos = pos;
	mObject.index = objectIdx;
	mAttacker = mObject;
	mApplytype = applyType;
	mAttriButeType = attributeType;
	mNextCheckTime = NETWORK2->GetAccumTime() + mpTotemScript->mApplyTime;
	mEndTime = NETWORK2->GetAccumTime() + PVP_DM_TEAM_MINCNT_TIME + PVP_DM_FIGHT_TIME;
	mPartyIdx = 0;

	return true;
}


void cTotem::TotemProcess( unsigned long /*elapsedTime*/, unsigned long accumTime )
{
	/// 체크시간 확인
	if( mNextCheckTime > accumTime )
		return;

	/// 다음 체크 시간 설정
	mNextCheckTime = mNextCheckTime + mpTotemScript->mApplyTime;

	/// 객체 유지 체크
	if( CheckTotem( accumTime ) == true )
	{
		/// 한프레임 타겟 선정 갯수 초기화
		mTargetCnt = 0;

		switch( mTeamType )
		{
		case ePVPDM_TEAMTYPE_A:
			ATeamSelectTarget();
			break;
		case ePVPDM_TEAMTYPE_B:
			BTeamSelectTarget();
			break;
		case ePVPDM_TEAMTYPE_MAX:	/// 플레이어/몬스터가 사용한 일반 토템
			{
				/// 범위안에 들어온 타겟을 목록에 추가
				if( mAttacker.type == eOBJECTTYPE_PLAYER )
					PlayerSelectTarget();
				else if( mAttacker.type == eOBJECTTYPE_MONSTER )
					MonsterSelectTarget();
			}
			break;
		}
	}
}


void cTotem::PlayerSelectTarget()
{
	/// 오라 타입 체크
	bool addInfAura = false;
	if( mpInfScript != NULL && mpInfScript->mTypeDetail == eINFLUENCETYPEDETAIL_AURA )
		addInfAura = true;

	/// 공통 처리
	switch( mApplytype )
	{
	case eAPPLYTYPE_SELF:
	case eAPPLYTYPE_BUDDY:
	case eAPPLYTYPE_PARTY:
		{
			/// 공격자가 보유 목록에 이미 들어 있는지 체크
			if( mPlayerTargetSet.Find( mAttacker.index ) != mPlayerTargetSet.End() )
				break;;

			if( addInfAura == true )
			{
				cPlayer* pAttacker = OBJECTMANAGER->GetPlayer( mAttacker.index );
				if( pAttacker != NULL )
					CopyTotemInfluence( pAttacker );	/// 오라 타입 효과 생성
			}
			else
				SKILLMANAGER->AddInfChildTotem( mAttacker, mAttacker, mpTotemScript->mInfluenceIdx, 0, mObject.index, true );
		}
		break;
	}

	/// 개별 처리
	switch( mApplytype )
	{
	case eAPPLYTYPE_ENEMY:
		{
			/// 몬스터 타겟
			cBaseObject* pMonsterTarget = GRIDMANAGER->FindFirstMonster( this );
			while( pMonsterTarget != NULL )
			{
				if( pMonsterTarget->GetObjectID() == mAttacker.index )
				{
					pMonsterTarget = GRIDMANAGER->FindNextMonster();
					continue;		/// 자신 통과
				}

				/// 타겟 보유 목록에 이미 들어 있는지 체크
				if( mMonsterTargetSet.Find( pMonsterTarget->GetObjectID() ) != mMonsterTargetSet.End() )
				{
					pMonsterTarget = GRIDMANAGER->FindNextMonster();
					continue;
				}

				if( addInfAura == true )
				{
					/// 오라 타입 효과 생성
					if( CopyTotemInfluence( pMonsterTarget ) == true )
						++mTargetCnt;
				}
				else
				{
					/// 일반 효과 생성
					if( SKILLMANAGER->AddInfluence( mAttacker, pMonsterTarget->GetObject(), mpTotemScript->mInfluenceIdx, 0, true ) == true )
						++mTargetCnt;
				}

				/// 타겟 수가 꽉차면 리턴
				if( mTargetCnt == TOTEM_APPLY_LIST_MAX )
					return;

				/// 다음 몬스터 검색
				pMonsterTarget = GRIDMANAGER->FindNextMonster();
			}


			/// 플레이어 타겟
			cPlayer* pPlayerTarget = GRIDMANAGER->FindFirstPlayer( this );
			while( pPlayerTarget != NULL )
			{
				if( pPlayerTarget->GetObjectID() == mAttacker.index )
				{
					pPlayerTarget = GRIDMANAGER->FindNextPlayer();
					continue;		/// 자신 통과
				}

				/// 타겟 보유 목록에 이미 들어 있는지 체크
				if( mPlayerTargetSet.Find( pPlayerTarget->GetObjectID() ) != mPlayerTargetSet.End() )
				{
					pPlayerTarget = GRIDMANAGER->FindNextPlayer();
					continue;
				}

				/// 1:1 공격대상 체크
				if( DUELMANAGER->IsAttack( pPlayerTarget->GetDuelIdx(), mAttacker.index, pPlayerTarget->GetObjectID() ) == false )
				{
					pPlayerTarget = GRIDMANAGER->FindNextPlayer();
					continue;
				}

				if( addInfAura == true )
				{
					/// 오라 타입 효과 생성
					if( CopyTotemInfluence( pPlayerTarget ) == true )
						++mTargetCnt;
				}
				else
				{
					/// 효과 생성
					if( SKILLMANAGER->AddInfluence( mAttacker, pPlayerTarget->GetObject(), mpTotemScript->mInfluenceIdx, 0, true ) == true )
						++mTargetCnt;
				}

				/// 타겟 수가 꽉차면 리턴
				if( mTargetCnt == TOTEM_APPLY_LIST_MAX )
					return;

				pPlayerTarget = GRIDMANAGER->FindNextPlayer();
			}
		}

		break;
	case eAPPLYTYPE_BUDDY:
		{
			/// 플레이어 타겟
			cPlayer* pPlayerTarget = GRIDMANAGER->FindFirstPlayer( this );
			while( pPlayerTarget != NULL )
			{
				if( pPlayerTarget->GetObjectID() == mAttacker.index )
				{
					pPlayerTarget = GRIDMANAGER->FindNextPlayer();
					continue;		/// 자신 통과
				}

				/// 타겟 보유 목록에 이미 들어 있는지 체크
				if( mPlayerTargetSet.Find( pPlayerTarget->GetObjectID() ) != mPlayerTargetSet.End() )
				{
					pPlayerTarget = GRIDMANAGER->FindNextPlayer();
					continue;
				}

				/// 1:1 공격대상 체크
				if( DUELMANAGER->IsAttack( pPlayerTarget->GetDuelIdx(), mAttacker.index, pPlayerTarget->GetObjectID() ) == true )
				{
					pPlayerTarget = GRIDMANAGER->FindNextPlayer();
					continue;
				}

				if( addInfAura == true )
				{
					/// 오라 타입 효과 생성
					if( CopyTotemInfluence( pPlayerTarget ) == true )
						++mTargetCnt;
				}
				else
				{
					/// 효과 생성
					if( SKILLMANAGER->AddInfSwitch( mAttacker, pPlayerTarget->GetObject(), mpTotemScript->mInfluenceIdx, 0, true ) != 0 )
						++mTargetCnt;
				}

				/// 타겟 수가 꽉차면 리턴
				if( mTargetCnt == TOTEM_APPLY_LIST_MAX )
					return;

				pPlayerTarget = GRIDMANAGER->FindNextPlayer();
			}
		}
		break;
	case eAPPLYTYPE_DIEBUDDY:
		{
			/// 플레이어 타겟
			cPlayer* pPlayerTarget = GRIDMANAGER->FindFirstPlayer( this );
			while( pPlayerTarget != NULL )
			{
				if( pPlayerTarget->GetObjectID() == mAttacker.index )
				{
					pPlayerTarget = GRIDMANAGER->FindNextPlayer();
					continue;		/// 자신 통과
				}

				/// 타겟 보유 목록에 이미 들어 있는지 체크
				if( mPlayerTargetSet.Find( pPlayerTarget->GetObjectID() ) != mPlayerTargetSet.End() )
				{
					pPlayerTarget = GRIDMANAGER->FindNextPlayer();
					continue;
				}

				/// 죽지 않은 유저 제외
				if( pPlayerTarget->GetStateDie() == false )
				{
					pPlayerTarget = GRIDMANAGER->FindNextPlayer();
					continue;
				}

				/// 1:1 공격대상 체크
				if( DUELMANAGER->IsAttack( pPlayerTarget->GetDuelIdx(), mAttacker.index, pPlayerTarget->GetObjectID() ) == true )
				{
					pPlayerTarget = GRIDMANAGER->FindNextPlayer();
					continue;
				}

				if( addInfAura == true )
				{
					/// 오라 타입 효과 생성
					if( CopyTotemInfluence( pPlayerTarget ) == true )
						++mTargetCnt;
				}
				else
				{
					/// 효과 생성
					if( SKILLMANAGER->AddInfSwitch( mAttacker, pPlayerTarget->GetObject(), mpTotemScript->mInfluenceIdx, 0, true ) != 0 )
						++mTargetCnt;
				}

				/// 타겟 수가 꽉차면 리턴
				if( mTargetCnt == TOTEM_APPLY_LIST_MAX )
					return;

				pPlayerTarget = GRIDMANAGER->FindNextPlayer();
			}
		}
		break;
	case eAPPLYTYPE_PARTY:
		{
			/// 파티가 없으면 공격자에게만 적용
			cParty* pParty = PARTYMAN->GetParty( mPartyIdx );
			if( pParty == NULL )
				return;

			/// 파티 목록 비교
			unsigned long* userArr = pParty->GetUserArr();
			unsigned int partyCount = pParty->GetCount();

			for( unsigned int i = 0 ; i < partyCount ; ++i )
			{
				cPlayer* pPlayerTarget = GRIDMANAGER->GetPlayer( userArr[i] );
				if( pPlayerTarget != NULL )
				{
					if( pPlayerTarget->GetObjectID() == mAttacker.index )
					{
						pPlayerTarget = GRIDMANAGER->FindNextPlayer();
						continue;		/// 자신 통과
					}

					/// 타겟 보유 목록에 이미 들어 있는지 체크
					if( mPlayerTargetSet.Find( pPlayerTarget->GetObjectID() ) != mPlayerTargetSet.End() )
					{
						pPlayerTarget = GRIDMANAGER->FindNextPlayer();
						continue;
					}

					if( addInfAura == true )
					{
						/// 오라 타입 효과 생성
						if( CopyTotemInfluence( pPlayerTarget ) == true )
							++mTargetCnt;
					}
					else
					{
						/// 효과 생성
						if( SKILLMANAGER->AddInfSwitch( mAttacker, pPlayerTarget->GetObject(), mpTotemScript->mInfluenceIdx, 0, true ) != 0 )
							++mTargetCnt;
					}
				}
			}
		}
		break;
	}
}


void cTotem::MonsterSelectTarget()
{
	/// 오라 타입 체크
	bool addInfAura = false;
	if( mpInfScript != NULL && mpInfScript->mTypeDetail == eINFLUENCETYPEDETAIL_AURA )
		addInfAura = true;

	/// 공통 처리
	switch( mApplytype )
	{
	case eAPPLYTYPE_SELF:
	case eAPPLYTYPE_BUDDY:
	case eAPPLYTYPE_PARTY:
		{
			/// 공격자가 보유 목록에 이미 들어 있는지 체크
			if( mMonsterTargetSet.Find( mAttacker.index ) == mMonsterTargetSet.End() )
				return;

			if( addInfAura == true )
			{
				cMonster* pAttacker = OBJECTMANAGER->GetMonster( mAttacker.index );
				if( pAttacker != NULL )
					CopyTotemInfluence( pAttacker );	/// 오라 타입 효과 생성
			}
			else
				SKILLMANAGER->AddInfSwitch( mAttacker, mAttacker, mpTotemScript->mInfluenceIdx, 0, true );
		}
		break;
	}

	/// 개별 처리
	switch( mApplytype )
	{
	case eAPPLYTYPE_BUDDY:
		{
			/// 몬스터 타겟
			cBaseObject* pMonsterTarget = GRIDMANAGER->FindFirstMonster( this );
			while( pMonsterTarget != NULL )
			{
				if( pMonsterTarget->GetObjectID() == mAttacker.index )
				{
					pMonsterTarget = GRIDMANAGER->FindNextMonster();
					continue;		/// 자신 통과
				}

				/// 타겟 보유 목록에 이미 들어 있는지 체크
				if( mMonsterTargetSet.Find( pMonsterTarget->GetObjectID() ) != mMonsterTargetSet.End() )
				{
					pMonsterTarget = GRIDMANAGER->FindNextMonster();
					continue;
				}

				if( addInfAura == true )
				{
					/// 오라 타입 효과 생성
					if( CopyTotemInfluence( pMonsterTarget ) == true )
						++mTargetCnt;
				}
				else
				{
					/// 일반 효과 생성
					if( SKILLMANAGER->AddInfluence( mAttacker, pMonsterTarget->GetObject(), mpTotemScript->mInfluenceIdx, 0, true ) == true )
						++mTargetCnt;
				}

				/// 타겟 수가 꽉차면 리턴
				if( mTargetCnt == TOTEM_APPLY_LIST_MAX )
					return;

				/// 다음 몬스터 검색
				pMonsterTarget = GRIDMANAGER->FindNextMonster();
			}
		}
		break;
	case eAPPLYTYPE_ENEMY:
		{
			cBaseObject* pPlayerTarget = GRIDMANAGER->FindFirstPlayer( this );
			while( pPlayerTarget != NULL )
			{
				/// 타겟 보유 목록에 이미 들어 있는지 체크
				if( mPlayerTargetSet.Find( pPlayerTarget->GetObjectType() ) != mPlayerTargetSet.End() )
				{
					pPlayerTarget = GRIDMANAGER->FindNextPlayer();
					continue;
				}

				if( addInfAura == true )
				{
					/// 효과 생성
					if( CopyTotemInfluence( pPlayerTarget ) == true )
						++mTargetCnt;
				}
				else
				{
					/// 효과 생성
					if( SKILLMANAGER->AddInfluence( mAttacker, pPlayerTarget->GetObject(), mpTotemScript->mInfluenceIdx, 0, true ) == true )
						++mTargetCnt;
				}

				/// 타겟 수가 꽉차면 리턴
				if( mTargetCnt == TOTEM_APPLY_LIST_MAX )
					return;

				pPlayerTarget = GRIDMANAGER->FindNextPlayer();
			}
		}
		break;
	}
}


void cTotem::ATeamSelectTarget()
{
	switch( mApplytype )
	{
	case eAPPLYTYPE_BUDDY:
		{
			cDeathMatchObject* pDM = PVPMANAGER->GetPvPDMObject( mMapNumber );
			if( pDM != NULL )
			{
				unsigned char teamCnt = pDM->TeamCnt( ePVPDM_TEAMTYPE_A );
				sPvPDMMemberInfo* pMember = pDM->TeamMember( ePVPDM_TEAMTYPE_A );
				if( pMember == NULL )
					return;

				for( unsigned char i = 0 ; i < teamCnt ; ++i )
				{
					cPlayer* pPlayerTarget = GRIDMANAGER->GetPlayer( pMember[i].mPlayerIdx );
					if( pPlayerTarget != NULL )
					{
						/// 타겟 보유 목록에 이미 들어 있는지 체크
						if( mPlayerTargetSet.Find( pPlayerTarget->GetObjectID() ) != mPlayerTargetSet.End() )
							continue;

						/// 오라 타입 효과 생성
						if( CopyTotemInfluence( pPlayerTarget ) == true )
							++mTargetCnt;

						/// 타겟 수가 꽉차면 리턴
						if( mTargetCnt == TOTEM_APPLY_LIST_MAX )
							return;
					}
				}
			}
		}
		break;
	case eAPPLYTYPE_ENEMY:
		{
			cDeathMatchObject* pDM = PVPMANAGER->GetPvPDMObject( mMapNumber );
			if( pDM != NULL )
			{
				unsigned char teamCnt = pDM->TeamCnt( ePVPDM_TEAMTYPE_B );
				sPvPDMMemberInfo* pMember = pDM->TeamMember( ePVPDM_TEAMTYPE_B );
				if( pMember == NULL )
					return;

				for( unsigned char i = 0 ; i < teamCnt ; ++i )
				{
					cPlayer* pPlayerTarget = GRIDMANAGER->GetPlayer( pMember[i].mPlayerIdx );
					if( pPlayerTarget != NULL )
					{
						/// 타겟 보유 목록에 이미 들어 있는지 체크
						if( mPlayerTargetSet.Find( pPlayerTarget->GetObjectID() ) != mPlayerTargetSet.End() )
							continue;

						/// 오라 타입 효과 생성
						if( CopyTotemInfluence( pPlayerTarget ) == true )
							++mTargetCnt;

						/// 타겟 수가 꽉차면 리턴
						if( mTargetCnt == TOTEM_APPLY_LIST_MAX )
							return;
					}
				}
			}
		}
		break;	
	}
}


void cTotem::BTeamSelectTarget()
{
	switch( mApplytype )
	{
	case eAPPLYTYPE_BUDDY:
		{
			cDeathMatchObject* pDM = PVPMANAGER->GetPvPDMObject( mMapNumber );
			if( pDM != NULL )
			{
				unsigned char teamCnt = pDM->TeamCnt( ePVPDM_TEAMTYPE_B );
				sPvPDMMemberInfo* pMember = pDM->TeamMember( ePVPDM_TEAMTYPE_B );
				if( pMember == NULL )
					return;

				for( unsigned char i = 0 ; i < teamCnt ; ++i )
				{
					cPlayer* pPlayerTarget = GRIDMANAGER->GetPlayer( pMember[i].mPlayerIdx );
					if( pPlayerTarget != NULL )
					{
						/// 타겟 보유 목록에 이미 들어 있는지 체크
						if( mPlayerTargetSet.Find( pPlayerTarget->GetObjectID() ) != mPlayerTargetSet.End() )
							continue;

						/// 오라 타입 효과 생성
						if( CopyTotemInfluence( pPlayerTarget ) == true )
							++mTargetCnt;

						/// 타겟 수가 꽉차면 리턴
						if( mTargetCnt == TOTEM_APPLY_LIST_MAX )
							return;
					}
				}
			}
		}
		break;
	case eAPPLYTYPE_ENEMY:
		{
			cDeathMatchObject* pDM = PVPMANAGER->GetPvPDMObject( mMapNumber );
			if( pDM != NULL )
			{
				unsigned char teamCnt = pDM->TeamCnt( ePVPDM_TEAMTYPE_A );
				sPvPDMMemberInfo* pMember = pDM->TeamMember( ePVPDM_TEAMTYPE_A );
				if( pMember == NULL )
					return;

				for( unsigned char i = 0 ; i < teamCnt ; ++i )
				{
					cPlayer* pPlayerTarget = GRIDMANAGER->GetPlayer( pMember[i].mPlayerIdx );
					if( pPlayerTarget != NULL )
					{
						/// 타겟 보유 목록에 이미 들어 있는지 체크
						if( mPlayerTargetSet.Find( pPlayerTarget->GetObjectID() ) != mPlayerTargetSet.End() )
							continue;

						/// 오라 타입 효과 생성
						if( CopyTotemInfluence( pPlayerTarget ) == true )
							++mTargetCnt;

						/// 타겟 수가 꽉차면 리턴
						if( mTargetCnt == TOTEM_APPLY_LIST_MAX )
							return;
					}
				}
			}
		}
		break;	
	}
}


bool cTotem::CheckTotem( unsigned long accumTime )
{
	/// 시간 확인
	if( mEndTime <= accumTime )
	{
		OBJECTMANAGER->InsertDeleteTotem( mObject.index );
		return false;
	}

	/// 공격자와 종속 관계 처리
	cBaseObject* pAttacker = NULL;
	if( mpTotemScript->mDependent == true )
	{
		/// 종속 적일 경우 공격자가 없으면 제거
		pAttacker = OBJECTMANAGER->GetObject( mAttacker.type, mAttacker.index );
		if( pAttacker == NULL || pAttacker->GetStateDie() == true )
		{
			OBJECTMANAGER->InsertDeleteTotem( mObject.index );
			return false;
		}

		/// 거리 밖으로 나간 경우 제거
        mRangeCheck.SetRadius( mpTotemScript->mAttackerRange );
		if( mRangeCheck.IsNotRange( pAttacker->GetPos(), mObjectPos ) == true )
		{
			OBJECTMANAGER->InsertDeleteTotem( mObject.index );
			return false;
		}
	}

	return true;
}


// SendSightIn Method
bool cTotem::SendSightIn(char category, char protocol, unsigned long connectionIdx)
{
	HANDLE          handle  = NULL;
	MSG_TOTEM_INFO* sendMsg = (MSG_TOTEM_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->mCreateInfClassIdx = GetClassIdx();

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

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


bool cTotem::CopyTotemInfluence( cBaseObject* pTarget )
{
	if( mpTotemScript == NULL )
		return false;

	/// 오라의 효과가 범위거리가 없으면 안된다.
	if( mpTotemScript->mApplyRange == 0.0f )
	{
		NETWORK2->PostServerEvent("cSkillManager::CopyAuraInfluence auraRange == 0.0f" );
		return false;
	}

	if( pTarget == NULL )
		return false;

	/// 거리 체크
	NiPoint3 childPos( pTarget->GetXPos(), pTarget->GetYPos(), pTarget->Height() );
	NiPoint3 parentPos( mObjectPos.x, mObjectPos.y, Height() );
	mRangeCheck.SetRadius( mpTotemScript->mApplyRange );
	if( mRangeCheck.IsNotRange( mObjectPos, pTarget->GetPos() ) == true )
		return false;

	/// 효과 생성
	if( SKILLMANAGER->AddInfChildTotem( mAttacker, pTarget->GetObject(), mpTotemScript->mInfluenceIdx, 0, mObject.index, true ) == true )
	{
		if( pTarget->GetObjectType() == eOBJECTTYPE_PLAYER )
			mPlayerTargetSet.Insert( pTarget->GetObjectID() );
		else if( pTarget->GetObjectType() == eOBJECTTYPE_MONSTER )
			mMonsterTargetSet.Insert( pTarget->GetObjectID() );
	}

	return true;
}


void cTotem::EraseTarget( sObject target )
{
	if( target.type == eOBJECTTYPE_MONSTER )
		mMonsterTargetSet.Erase( target.index );
	else if( target.type == eOBJECTTYPE_PLAYER )
		mPlayerTargetSet.Erase( target.index );
}
