#include "stdafx.h"
#include "gamesrv.h"
#include "DeathMatchObject.h"
#include "PVPManager.h"
#include "Protocol.h"
#include "LevelScript.h"
#include "PvPScript.h"

cDeathMatchObject::cDeathMatchObject()
: mLeaderTimePass(0)
{
}


cDeathMatchObject::~cDeathMatchObject()
{
}


void* cDeathMatchObject::operator new( size_t n )
{
	if( n != sizeof(cDeathMatchObject) ) 
	{
		NETWORK2->PostServerEvent("cDeathMatchObject::operator new %d != sizeof(cDeathMatchObject)", n );
		return NULL;
	}

	return PVPMANAGER->AllocDMObject();
}


void cDeathMatchObject::operator delete( void* ptr, size_t n )
{
	/// NULL 포인터 검사
	if( ptr == 0 )
	{
		NETWORK2->PostServerEvent("cDeathMatchObject::operator delete ptr == 0" );
		return;
	}

	if( n != sizeof(cDeathMatchObject) ) 
	{
		NETWORK2->PostServerEvent("cDeathMatchObject::operator delete n != sizeof(cDeathMatchObject", n );
		return;
	}

	PVPMANAGER->FreeDMObject( static_cast<cDeathMatchObject*>(ptr) );

	return;
}


bool cDeathMatchObject::Init( unsigned char DMIdx, sDMInfo* pDMInfo )
{
	if( pDMInfo == NULL )
		return false;

	mDMIdx = DMIdx;
	mProcess = ePVPDM_PROCESS_WAIT;
	mFirstJoinTeam = ePVPDM_TEAMTYPE_MAX;
	mProcessEndTime = 0;
	mpDMInfo = pDMInfo;
	mScoreEnd = false;

	memset( mTeamInfo, 0 , sizeof( mTeamInfo ) );

	memset( mAMemberInfo, 0, sizeof( mAMemberInfo ) );
	memset( mBMemberInfo, 0, sizeof( mBMemberInfo ) );

	mTeamInfo[ePVPDM_TEAMTYPE_A].mFire = true; 
	mTeamInfo[ePVPDM_TEAMTYPE_A].mWind = false;
	mTeamInfo[ePVPDM_TEAMTYPE_A].mWater = false; 
	mTeamInfo[ePVPDM_TEAMTYPE_A].mEarth = false;

	mTeamInfo[ePVPDM_TEAMTYPE_B].mFire = false; 
	mTeamInfo[ePVPDM_TEAMTYPE_B].mWind = true;
	mTeamInfo[ePVPDM_TEAMTYPE_B].mWater = true; 
	mTeamInfo[ePVPDM_TEAMTYPE_B].mEarth = true;

	return true;
}


void cDeathMatchObject::Process( unsigned long elapsedTime, unsigned long accumTime )
{
	/// 방에 아무도 없으면 객체 소멸
	/// 마지막 유저가 나가는 시점에 삭제 불가능 했던 이유 체크해보자!!
	if( mTeamInfo[ePVPDM_TEAMTYPE_A].mMemberCnt + mTeamInfo[ePVPDM_TEAMTYPE_B].mMemberCnt == 0 && ePVPDM_PROCESS_READY < mProcess )
		mProcess = ePVPDM_PROCESS_END;

	if( mScoreEnd == true )
	{
		mScoreEnd = false;
		Result();
	}

	switch( mProcess )
	{
	case ePVPDM_PROCESS_WAIT:		/// Ready() 호출 기다림
		break;
	case ePVPDM_PROCESS_READY:
		{
			/// PvP 대기시간
			if( mProcessEndTime > accumTime )
				return;

			/// pvp 시작 메세지 발송
			SendFight();

			/// pvp 전투 시작 프로세스로 이동
			mProcess = ePVPDM_PROCESS_FIGHT_MINIMUM;
			mProcessEndTime = accumTime + PVP_DM_TEAM_MINCNT_TIME;


			cTotem* pTotem = NULL;
			NiPoint2 centerPos;
			sStageChangePos* pStagePos = STAGESCRIPT->GetPosScriptInfo( PVP_DM_START_POSIDX_A );
			if( pStagePos != NULL )
			{
				centerPos.x = pStagePos->mPosX;
				centerPos.y = pStagePos->mPosY;
				pTotem = OBJECTMANAGER->PvPAddTotem( ePVPDM_TEAMTYPE_A, 1001, mDMIdx, centerPos, eAPPLYTYPE_BUDDY, eATTRIBUTETYPE_PHYSICAL );
				if( pTotem != NULL )
					GRIDMANAGER->AddTotem( pTotem );
				pTotem = OBJECTMANAGER->PvPAddTotem( ePVPDM_TEAMTYPE_A, 1002, mDMIdx, centerPos, eAPPLYTYPE_ENEMY, eATTRIBUTETYPE_PHYSICAL );
				if( pTotem != NULL )
					GRIDMANAGER->AddTotem( pTotem );
			}
			pStagePos = STAGESCRIPT->GetPosScriptInfo( PVP_DM_START_POSIDX_B );
			{
				centerPos.x = pStagePos->mPosX;
				centerPos.y = pStagePos->mPosY;
				pTotem = OBJECTMANAGER->PvPAddTotem( ePVPDM_TEAMTYPE_B, 1001, mDMIdx, centerPos, eAPPLYTYPE_BUDDY, eATTRIBUTETYPE_PHYSICAL );
				if( pTotem != NULL )
					GRIDMANAGER->AddTotem( pTotem );
				pTotem = OBJECTMANAGER->PvPAddTotem( ePVPDM_TEAMTYPE_B, 1002, mDMIdx, centerPos, eAPPLYTYPE_ENEMY, eATTRIBUTETYPE_PHYSICAL );
				if( pTotem != NULL )
					GRIDMANAGER->AddTotem( pTotem );
			}
		}
		break;
	case ePVPDM_PROCESS_READY_OUT:
		{
			/// pvp out 요청 받는 시간
			if( mProcessEndTime > accumTime )
				return;

			/// 오브젝트 제거
			mProcess = ePVPDM_PROCESS_END;
		}
		break;
	case ePVPDM_PROCESS_FIGHT_MINIMUM:
		{
			LeaderProcess( elapsedTime, accumTime );

			/// 일정 시간동안 인원부족 결투 종료 체크 안함
			if( mProcessEndTime <= accumTime )
			{
				mProcess = ePVPDM_PROCESS_FIGHT;
				mProcessEndTime = accumTime + PVP_DM_FIGHT_TIME - PVP_DM_TEAM_MINCNT_TIME;
			}
		}
		break;
	case ePVPDM_PROCESS_FIGHT:
		{
			LeaderProcess( elapsedTime, accumTime );

			/// 시간 종료
			if( mProcessEndTime <= accumTime )
				Result();
		}
		break;
	case ePVPDM_PROCESS_FIGHTEND:
		{
			/// pvp out 요청 받는 시간
			if( mProcessEndTime <= accumTime )
				mProcess = ePVPDM_PROCESS_END;
		}
		break;
	case ePVPDM_PROCESS_END:
		{
			/// 전체 유저 추방
			SendOut();
			PVPMANAGER->DelAryInsertPVP( mDMIdx );
		}
		break;
	}
}


void cDeathMatchObject::LeaderProcess( unsigned long /*elapsedTime*/, unsigned long accumTime )
{
	if( mLeaderTimePass < accumTime )
		mLeaderTimePass = accumTime + 200;

	/// 리더 선정
	for( int teamType = ePVPDM_TEAMTYPE_A ; teamType < ePVPDM_TEAMTYPE_MAX ; ++teamType )
	{
		/// 시간 체크
		if( mTeamInfo[teamType].mLeaderChangeTime >= accumTime )
			continue;

		/// 팀포인터
		sPvPDMMemberInfo* pMember = NULL;
		if( teamType == ePVPDM_TEAMTYPE_A )
			pMember = mAMemberInfo;
		else
			pMember = mBMemberInfo;

		unsigned long memberIdx[PVP_DM_TEAM_CNT];
		unsigned long cnt = 0;
		cPlayer* pPlayer = NULL;
		for( int i = 0 ; i < PVP_DM_TEAM_CNT ; ++i )
		{

			unsigned long playerIdx = pMember[i].mPlayerIdx;
			if( playerIdx == 0 )
				continue;

			pPlayer = OBJECTMANAGER->GetPlayer( playerIdx );
			if( pPlayer == NULL || pPlayer->GetStateDie() == true )
				continue;

			/// 현재 수장은 제외
			if( mTeamInfo[teamType].mLeaderIdx == playerIdx )
				continue;

			/// 리더 선정이 가능한 목록을 담는다.
			memberIdx[cnt] = playerIdx;
			++cnt;
		}

		if( cnt == 0 )
			continue;

		/// 기존 수장 권한 반납
		sObject leader = { eOBJECTTYPE_PLAYER, mTeamInfo[teamType].mLeaderIdx };
		SKILLMANAGER->DeleteInfluenceClassIdx( leader, PVP_DM_LEADER_INFLUENCE );
		SKILLMANAGER->DeleteInfluenceClassIdx( leader, PVP_DM_LEADER_INFLUENCE2 );

		/// 선정된 목록중 랜덤 선택
		unsigned long selectCnt = rand() % cnt;

		sPlayerSkillBaseInfo* pSkill = SKILLSCRIPT->GetPlayerSkillInfo( PVP_DM_LEADER_SKILL );
		if( pSkill == NULL )
			return;

		sObject object = { eOBJECTTYPE_PLAYER, memberIdx[selectCnt] };
        if( SKILLMANAGER->AddInfSwitch( object, object, pSkill->mpSetpInfoArray[0].mInfulenceIdx, PVP_DM_LEADER_SKILL, true ) == 0 )
			return;

		mTeamInfo[teamType].mLeaderIdx = memberIdx[selectCnt];
		/// 다음 변경 시간 설정
		mTeamInfo[teamType].mLeaderChangeTime = accumTime + PVP_DM_LEADER_CHANGETIME;

		/// 수장 설정 메세지 발송
		MSG_SYN_PVP_DM_LEADERCHANGE synMsg;
		synMsg.Category = NM_PVP;
		synMsg.Protocol = NM_PVP_DM_LEADERSELECT_SYN;
		synMsg.mCharacterIdx = mTeamInfo[teamType].mLeaderIdx;
		TeamQuickSend( (ePVPDM_TEAM_TYPE)teamType, (char*)&synMsg, sizeof(synMsg) );
	}
}


bool cDeathMatchObject::IsFight()
{
	if( mProcess == ePVPDM_PROCESS_FIGHT_MINIMUM )
		return true;

	if( mProcess == ePVPDM_PROCESS_FIGHT )
		return true;

	return false;
}


sPvPDMMemberInfo* cDeathMatchObject::TeamMember( ePVPDM_TEAM_TYPE teamType )
{
	if( teamType == ePVPDM_TEAMTYPE_A )
		return mAMemberInfo;
	else if( teamType == ePVPDM_TEAMTYPE_B )
		return mBMemberInfo;
	else
		return NULL;
}


unsigned char cDeathMatchObject::JoinTeam( unsigned long playerIdx, ePVPDM_TEAM_TYPE teamType, sDMInfo* pDMInfo )
{
	cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( playerIdx );
	if( pPlayer == NULL )
		return 0;

	if( pDMInfo == NULL )
		return 0;

	/// 최대 인원 체크
	if( mTeamInfo[teamType].mMemberCnt > PVP_DM_TEAM_CNT )
		return 0;

	if( mpDMInfo != pDMInfo )
		return 0;

	/// 프로세스 상태 확인
	if( mProcess != ePVPDM_PROCESS_WAIT )
		return 0;

	sPvPDMMemberInfo* pMemberInfo;
	/// 같은 팀
	if( teamType == ePVPDM_TEAMTYPE_A )
		pMemberInfo = mAMemberInfo;
	else
		pMemberInfo = mBMemberInfo;

	/// 가장 먼저 입장 기록
	if( mFirstJoinTeam == ePVPDM_TEAMTYPE_MAX )
		mFirstJoinTeam = teamType;

	/// 빈자리에 넣는다.
	for( int i = 0 ; i < PVP_DM_TEAM_CNT ; ++i )
	{
		if( pMemberInfo[i].mPlayerIdx == 0 )
		{
			/// 다른 팀원 들에게 접속을 알림
			MSG_SYN_PVP_DM_MEMBERIN syncMsg;
			syncMsg.Category = NM_PVP;
			syncMsg.Protocol = NM_PVP_DM_MEMBERIN_SYN;
			syncMsg.mMemberInfo.mCharacterIdx = pPlayer->GetObjectID();
			::wcsncpy( syncMsg.mMemberInfo.mName, pPlayer->GetName(), MAX_NAME_SIZE ); 
			syncMsg.mMemberInfo.mForceType = pPlayer->GetForceType();
			TeamQuickSend( teamType, (char*)&syncMsg, sizeof(syncMsg) );	

			/// 자신을 팀에 등록
			pMemberInfo[i].mPlayerIdx = pPlayer->GetObjectID();
			++mTeamInfo[teamType].mMemberCnt;
			return mDMIdx;
		}
	}

	NETWORK2->PostServerEvent("cDeathMatchObject::JoinTeam i > PVP_DM_TEAM_CNT");
	return 0;
}


void cDeathMatchObject::SendTeamList( cPlayer* pPlayer )
{
	HANDLE          handle  = NULL;
	MSG_RES_PVP_DM_MEMBERIN* sendMsg = (MSG_RES_PVP_DM_MEMBERIN*)NETWORK2->GetMsgRoot( &handle, pPlayer->GetConnectionIdx(), 
		NM_PVP, NM_PVP_DM_MEMBERIN_RES );
	if ( sendMsg != NULL )
	{
		sPvPDMMemberInfo* pMemberInfo = NULL;

		/// 팀별 정보 설정
		if( pPlayer->GetPvPDMTeam() == ePVPDM_TEAMTYPE_A )
		{
			sendMsg->mFireForce = true;
			sendMsg->mWaterForce = false;
			sendMsg->mWindForce = false;
			sendMsg->mEarthForce = false;

			sendMsg->mMemberCnt = mTeamInfo[ePVPDM_TEAMTYPE_A].mMemberCnt;
			pMemberInfo = mAMemberInfo;
		}
		else if( pPlayer->GetPvPDMTeam() == ePVPDM_TEAMTYPE_B )
		{
			sendMsg->mFireForce = false;
			sendMsg->mWaterForce = true;
			sendMsg->mWindForce = true;
			sendMsg->mEarthForce = true;

			sendMsg->mMemberCnt = mTeamInfo[ePVPDM_TEAMTYPE_B].mMemberCnt;
			pMemberInfo = mBMemberInfo;
		}

		if( pMemberInfo != NULL )
		{
			/// 같은 팀 맴버 정보 발송
			for( int i = 0 ; i < sendMsg->mMemberCnt ; ++i )
			{
				unsigned long teamPlayer = pMemberInfo[i].mPlayerIdx;

				sendMsg->mMemberInfo[i].mCharacterIdx = teamPlayer;
				cPlayer* pTeamPlayer = OBJECTMANAGER->GetPlayer( teamPlayer );
				if( pTeamPlayer != NULL )
				{
					::wcsncpy( sendMsg->mMemberInfo[i].mName, pTeamPlayer->GetName(), MAX_NAME_SIZE ); 
					sendMsg->mMemberInfo[i].mForceType = pTeamPlayer->GetForceType();
				}
				else
					NETWORK2->PostServerEvent(" cDeathMatchObject::SendTeamList pTeamPlayer[%d] != NULL ", teamPlayer );
			}
		}

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

}


void cDeathMatchObject::OutMember( unsigned long playerIdx, ePVPDM_TEAM_TYPE teamType )
{
	cPlayer* pPlayer = NULL;

	sPvPDMMemberInfo* pMember = NULL;

	/// 팀원 목록에서 자신 제거
	if( ePVPDM_TEAMTYPE_A == teamType )
		pMember = mAMemberInfo;
	else
		pMember = mBMemberInfo;

	/// 팀원 목록에서 자신 제거
	for( int i = 0 ; i < PVP_DM_TEAM_CNT ; ++i )
	{
		if( pMember[i].mPlayerIdx == playerIdx )
		{
			pPlayer = OBJECTMANAGER->GetPlayer( playerIdx );
			if( pPlayer != NULL )
			{
				pPlayer->PvPResurrection( false );	/// 죽어 있으면 부활

				/// pvp 나감 처리
				pPlayer->PvPOut();

				/// pvp 다시 진입 불가 효과 생성
				sObject object = { pPlayer->GetObjectType(), pPlayer->GetObjectID() };
				SKILLMANAGER->AddInfluence( object, object, PVP_DM_CANTPVP_INFLUENCE, 0, true );

			}

			pMember[i].Init();
			--mTeamInfo[teamType].mMemberCnt;	/// 팀인원 감소

			break;
		}
	}

	if( mTeamInfo[teamType].mLeaderIdx == playerIdx )
	{
		mTeamInfo[teamType].mLeaderIdx = 0;
		mTeamInfo[teamType].mLeaderChangeTime = NETWORK2->GetAccumTime() + PVP_DM_LEADER_DIECHANGETIME;
	}

	/// 팀원들에게 나감 알림
	MSG_SYN_PVP_DM_MEMBEROUT synMsg;
	synMsg.Category = NM_PVP;
	synMsg.Protocol = NM_PVP_DM_MEMBEROUT_SYN;
	synMsg.mCharacterIdx = playerIdx;
	TeamQuickSend( teamType, (char*)&synMsg, sizeof( synMsg ) );

	/// 인원 패배 조건에 해당하는지 확인
	if( mTeamInfo[teamType].mMemberCnt < PVP_DM_TEAM_MINCNT && ePVPDM_PROCESS_FIGHT == mProcess )
	{
		mProcess = ePVPDM_PROCESS_END;
		Result();
	}
}


void cDeathMatchObject::Ready()
{
	unsigned long accumTime = NETWORK2->GetAccumTime();

	bool isReady = true;

	for( int i = 0 ; i < ePVPDM_TEAMTYPE_MAX ; ++i )
	{
		/// 최소 인원 체크
		if( mTeamInfo[i].mMemberCnt < PVP_DM_TEAM_MINCNT )
		{
			isReady = false;
			break;
		}
	}

	if( isReady == true )
	{
		MSGROOT msg;
		msg.Category = NM_PVP;
		msg.Protocol = NM_PVP_DM_READY_SYN;
		DMQuickSend( (char*)&msg, sizeof( msg ) );

		mProcess = ePVPDM_PROCESS_READY;
		mProcessEndTime = accumTime + PVP_DM_READY_TIME;
		return;
	}
	else
	{
		MSGROOT msg;
		msg.Category = NM_PVP;
		msg.Protocol = NM_PVP_DM_NOTREADY_SYN;
		DMQuickSend( (char*)&msg, sizeof( msg ) );

		mProcess = ePVPDM_PROCESS_READY_OUT;
		mProcessEndTime = accumTime + PVP_DM_READY_OUT_TIME;
		return;
	}
}


void cDeathMatchObject::SendFight()
{
	MSG_SYN_PVP_FIGHT msg;
	msg.Category = NM_PVP;
	msg.Protocol = NM_PVP_DM_FIGHT_SYN;
	msg.mFightTime = PVP_DM_READY_TIME;
	DMQuickSend( (char*)&msg, sizeof( msg ) );
}


void cDeathMatchObject::ScoreUpdate( unsigned long killIdx, ePVPDM_TEAM_TYPE killerTeam, 
									unsigned long deadIdx, ePVPDM_TEAM_TYPE deadTeam )
{
	/// 수장 죽음 체크
	bool isLeader = false;

	unsigned long plusPoint;
	/// 죽은 수장 처리
	if( mTeamInfo[deadTeam].mLeaderIdx == deadIdx )
	{
		isLeader = true;

		/// 수장 없음 설정
		++mTeamInfo[deadTeam].mLeaderDieCnt;
		mTeamInfo[deadTeam].mLeaderIdx = 0;
		mTeamInfo[deadTeam].mLeaderChangeTime = NETWORK2->GetAccumTime() + PVP_DM_LEADER_DIECHANGETIME;

		/// 수장 죽음 메세지 발송
		MSGROOT synMsg;
		synMsg.Category = NM_PVP;

		synMsg.Protocol = NM_PVP_DM_LEADERDIE_SYN;
		TeamQuickSend( deadTeam, (char*)&synMsg, sizeof( synMsg ) );

		synMsg.Protocol = NM_PVP_DM_ENEMYLEADERDIE_SYN;
		TeamQuickSend( killerTeam, (char*)&synMsg, sizeof( synMsg ) );

		/// 죽은 자가 수장이면 5포인트를 줌
		plusPoint = PVP_DM_LEADER_DIE_POINT;
	}
	else
	{
		/// 죽인자가 수장이면 2포인트를 줌
		if( killIdx == mTeamInfo[killerTeam].mLeaderIdx )
			plusPoint = PVP_DM_LEADER_MEMBER_KILL_POINT;
		else
			plusPoint = PVP_DM_MEMBER_DIE_POINT;
	}

	/// 죽인자 팀에 점수 증가
	mTeamInfo[killerTeam].mPoint += plusPoint;

	/// 팀원 죽인수/죽은수 변경
	sPvPDMMemberInfo* killerMember = NULL;
	sPvPDMMemberInfo* deathMember = NULL;
	if( ePVPDM_TEAMTYPE_A == killerTeam )
	{
		killerMember = mAMemberInfo;
		deathMember = mBMemberInfo;
	}
	else
	{
		killerMember = mBMemberInfo;
		deathMember = mAMemberInfo;
	}

	/// 죽인자 kill 증가
	for( int i = 0 ; i < PVP_DM_TEAM_CNT ; ++i )
	{
		if( killerMember[i].mPlayerIdx == killIdx )
		{
			if( isLeader == true )
				++killerMember[i].mLeaderKillCnt;
			else
				++killerMember[i].mKillCnt;

			/// 점수 메세지 발송
			MSG_SYN_PVP_DM_SCORE msg;
			msg.Category = NM_PVP;
			msg.Protocol = NM_PVP_DM_SCORE_SYN;
			msg.mTeamType = (unsigned char)killerTeam;
			msg.mPlusScore = plusPoint;
			msg.mTotalScore = mTeamInfo[killerTeam].mPoint;
			msg.mPlayerIdx = killIdx;
			msg.mPlayerScore = killerMember[i].mKillCnt + killerMember[i].mLeaderKillCnt;
			TeamQuickSend( killerTeam, (char*)&msg, sizeof( MSG_SYN_PVP_DM_SCORE ) );

			break;
		}
	}

	/// 죽은자 death 증가
	for( int i = 0 ; i < PVP_DM_TEAM_CNT ; ++i )
	{
		if( deathMember[i].mPlayerIdx == deadIdx )
		{
			++deathMember[i].mDeathCnt;

			/// 점수 메세지 발송
			MSG_SYN_PVP_DM_SCORE msg;
			msg.Category = NM_PVP;
			msg.Protocol = NM_PVP_DM_SCORE_SYN;
			msg.mTeamType = (unsigned char)killerTeam;
			msg.mPlusScore = plusPoint;
			msg.mTotalScore = mTeamInfo[killerTeam].mPoint;
			msg.mPlayerIdx = deadIdx;
			msg.mPlayerScore = deathMember[i].mDeathCnt;
			TeamQuickSend( deadTeam, (char*)&msg, sizeof( MSG_SYN_PVP_DM_SCORE ) );

			break;
		}
	}

	/// 점수 승리조건 체크
	if( mTeamInfo[killerTeam].mPoint >= PVP_DM_DEST_POINT )
		mScoreEnd = true; 
}

void cDeathMatchObject::Result()
{

	mProcess = ePVPDM_PROCESS_FIGHTEND;
	mProcessEndTime = NETWORK2->GetAccumTime() + PVP_DM_OUTWAIT_TIME;

	///포인트 달성 체크
	if( mTeamInfo[ePVPDM_TEAMTYPE_A].mPoint >= PVP_DM_DEST_POINT )
	{
		SendResult( ePVPDM_TEAMTYPE_A, ePVPDM_ENDTYPE_POINT );
		return;
	}
	if( mTeamInfo[ePVPDM_TEAMTYPE_B].mPoint >= PVP_DM_DEST_POINT )
	{
		SendResult( ePVPDM_TEAMTYPE_B, ePVPDM_ENDTYPE_POINT );
		return;
	}

	/// 포인트 우위 체크
	if( mTeamInfo[ePVPDM_TEAMTYPE_A].mPoint > mTeamInfo[ePVPDM_TEAMTYPE_B].mPoint )
	{
		SendResult( ePVPDM_TEAMTYPE_A, ePVPDM_ENDTYPE_TIME );
		return;
	}
	else if( mTeamInfo[ePVPDM_TEAMTYPE_A].mPoint < mTeamInfo[ePVPDM_TEAMTYPE_B].mPoint )
	{
		SendResult( ePVPDM_TEAMTYPE_B, ePVPDM_ENDTYPE_TIME );
		return;
	}

	/// 인원수 체크
	if( mTeamInfo[ePVPDM_TEAMTYPE_A].mMemberCnt > mTeamInfo[ePVPDM_TEAMTYPE_B].mMemberCnt )
	{
		SendResult( ePVPDM_TEAMTYPE_B, ePVPDM_ENDTYPE_MEMBER );
		return;
	}
	if( mTeamInfo[ePVPDM_TEAMTYPE_A].mMemberCnt < mTeamInfo[ePVPDM_TEAMTYPE_B].mMemberCnt )
	{
		SendResult( ePVPDM_TEAMTYPE_A, ePVPDM_ENDTYPE_MEMBER );
		return;
	}

	/// 수장 사망 횟수 체크
	if( mTeamInfo[ePVPDM_TEAMTYPE_A].mLeaderDieCnt > mTeamInfo[ePVPDM_TEAMTYPE_B].mLeaderDieCnt )
	{
		SendResult( ePVPDM_TEAMTYPE_A, ePVPDM_ENDTYPE_LEADERDIE );
		return;
	}
	if( mTeamInfo[ePVPDM_TEAMTYPE_A].mLeaderDieCnt < mTeamInfo[ePVPDM_TEAMTYPE_B].mLeaderDieCnt )
	{
		SendResult( ePVPDM_TEAMTYPE_B, ePVPDM_ENDTYPE_LEADERDIE );
		return;
	}

	/// 맵 입장 순서 체크
	if( mFirstJoinTeam == ePVPDM_TEAMTYPE_A )
	{
		SendResult( ePVPDM_TEAMTYPE_A, ePVPDM_ENDTYPE_FASTJOIN );
		return;
	}
	else
	{
		SendResult( ePVPDM_TEAMTYPE_B, ePVPDM_ENDTYPE_FASTJOIN );
		return;
	}

}


void cDeathMatchObject::SendResult( ePVPDM_TEAM_TYPE winTeam, ePVPDM_END_TYPE endType )
{
	/// 승리/패배 포인터 설정
	sPvPDMMemberInfo* pWinInfo = NULL;
	sPvPDMMemberInfo* pLoseInfo = NULL;
	sPvPDMTeamInfo* pTeam = NULL;
	if( winTeam == ePVPDM_TEAMTYPE_A )
	{
		pWinInfo = mAMemberInfo;
		pLoseInfo = mBMemberInfo;
		pTeam = &mTeamInfo[ePVPDM_TEAMTYPE_A];
	}
	else
	{
		pWinInfo = mBMemberInfo;
		pLoseInfo = mAMemberInfo;
		pTeam = &mTeamInfo[ePVPDM_TEAMTYPE_B];
	}

	SendTeamResult( pTeam, pWinInfo, endType, NM_PVP_DM_WIN_SYN );
	SendTeamResult( pTeam, pLoseInfo, endType, NM_PVP_DM_LOSE_SYN );
}


void cDeathMatchObject::SendTeamResult( sPvPDMTeamInfo* pTeam, sPvPDMMemberInfo* pMember, ePVPDM_END_TYPE endType, char protocol )
{
	/// 승/패 메세지 발송
	PerIoContext* perIoContext = NETWORK2->GetIoContext( IOCP_REQUEST_WRITE );
	MSG_SYN_PVP_DM_FIGHTEND* pSyn = (MSG_SYN_PVP_DM_FIGHTEND*)perIoContext->buffer;
	pSyn->Category = NM_PVP;
	pSyn->Protocol = protocol;
	pSyn->mEndType = (unsigned char)endType;

	/// 팀 목록 취합
	cPlayer* pPlayer = NULL;
	sPvPDMTeamScore member[PVP_DM_TEAM_CNT];
	unsigned long memberCnt = 0;
	long memberScore;
	for( int i = 0 ; i < PVP_DM_TEAM_CNT ; ++i )
	{
		if( pMember[i].mPlayerIdx == 0 )
			continue;

		pPlayer = OBJECTMANAGER->GetPlayer( pMember[i].mPlayerIdx );
		if( pPlayer == NULL )
			continue;

		if( pPlayer->GetGameIn() == false )
			continue;

		memberScore = pMember[i].mLeaderKillCnt * mpDMInfo->mLeaderKillPoint +
			pMember[i].mKillCnt * mpDMInfo->mKillPoint - pMember[i].mDeathCnt * mpDMInfo->mDeathPoint;

		member[memberCnt].mCharacterIdx = pMember[i].mPlayerIdx;
		member[memberCnt].mScore = memberScore > 0 ? memberScore : 0;
		pPlayer->PvPScorePlus( member[memberCnt].mScore );
		++memberCnt;
	}

	unsigned long myFriendly = 0;
	unsigned long teamFriendly = 0;
	unsigned long myPoint = 0;
	unsigned long teamPoint = 0;

	/// 승리 패배 부여 점수
	if( protocol == NM_PVP_DM_WIN_SYN )
	{
		myFriendly = mpDMInfo->mWinMyForceFriendly;
		teamFriendly = mpDMInfo->mWinFamilyForceFriendly;
		myPoint = mpDMInfo->mWinMyForcePoint;
		teamPoint = mpDMInfo->mWinFamilyForcePoint;
	}
	else
	{
		if( mpDMInfo->mLoseCheckFriendly < pTeam->mPoint )
			myFriendly = mpDMInfo->mLoseMyForceFriendly;
		teamFriendly = 0;

		if( mpDMInfo->mLoseCheckPoint < pTeam->mPoint )
			myPoint = mpDMInfo->mLoseMyForcePoint;
		teamPoint = 0;
	}

	unsigned long firePoint = 0;
	unsigned long waterPoint = 0;
	unsigned long windPoint = 0;
	unsigned long earthPoint = 0;
	unsigned long fireFriendly = 0;
	unsigned long waterFriendly = 0;
	unsigned long windFriendly = 0;
	unsigned long earthFriendly = 0;

	if( pTeam->mFire == true )
	{
		firePoint = teamPoint;
		fireFriendly = teamFriendly;
	}
	if( pTeam->mWater == true )
	{
		waterPoint = teamPoint;
		waterFriendly = teamFriendly;
	}
	if( pTeam->mWind == true  )
	{
		windPoint = teamPoint;
		windFriendly = teamFriendly;
	}
	if( pTeam->mEarth == true  )
	{
		earthPoint = teamPoint; 
		earthFriendly = teamFriendly;
	}

	unsigned long addExp = 0;
	unsigned long addSxp = 0;
	sExpTable* expTable;
	sSxpTable* sxpTable;
	unsigned long money = 0;
	unsigned long expPer = 0;
	unsigned long sxpPer = 0;
	sDMMemberGive* pGive = NULL;
	unsigned long infIdx;

	/// 팀원에게 개별 전송
	for( unsigned long i = 0 ; i < memberCnt ; ++i )
	{
		money = 0;
		expPer = 0;
		sxpPer = 0;

		pPlayer = OBJECTMANAGER->GetPlayer( member[i].mCharacterIdx );
		if( pPlayer == NULL )
			continue;
		/// 죽어 있으면 부활
		pPlayer->PvPResurrection( false );

		/// 승리 패배 부여 점수
		if( protocol == NM_PVP_DM_WIN_SYN )
		{
			pGive = PVPSCRIPT->GetMemberGive( pPlayer->GetLevel() );
			if( pGive != NULL )
			{
				money = pGive->mWinMoney;
				expPer = pGive->mWinExp;
				sxpPer = pGive->mWinSxp;
			}
			infIdx = PVP_DM_WIN_INFLUENCE;
		}
		else
		{
			pGive = PVPSCRIPT->GetMemberGive( pPlayer->GetLevel() );
			if( pGive != NULL )
			{
				money = pGive->mLoseMoney;
				expPer = pGive->mLoseExp;
				sxpPer = pGive->mLoseSxp;
			}
			infIdx = PVP_DM_LOSE_INFLUENCE;
		}

		expTable = LEVELSCRIPT->GetExpTable( pPlayer->GetLevel() );
		if( expTable != NULL )
			addExp = (unsigned long)( expTable->mExp * expPer * 0.01f);
		else
			addExp = 0;
		sxpTable = LEVELSCRIPT->GetSxpTable( pPlayer->GetSkillLevel() );
		if( sxpTable != NULL )
			addSxp = (unsigned long)( sxpTable->mSxp * sxpPer * 0.01f );
		else
			addSxp = 0;

		switch( pPlayer->GetForceType() )
		{
		case eFORCETYPE_FIRE:
			{
				fireFriendly = fireFriendly + ( myFriendly - teamFriendly );
				firePoint = firePoint + ( myPoint - teamPoint );
			}
			break;
		case eFORCETYPE_WATER:
			{
				waterFriendly = waterFriendly + ( myFriendly - teamFriendly );
				waterPoint = waterPoint + ( myPoint - teamPoint );
			}
			break;
		case eFORCETYPE_WIND:
			{
				windFriendly = windFriendly + ( myFriendly - teamFriendly );
				windPoint = windPoint + ( myPoint - teamPoint );
			}
			break;
		case eFORCETYPE_EARTH:
			{
				earthFriendly = earthFriendly + ( myFriendly - teamFriendly );
				earthPoint = earthPoint + ( myPoint - teamPoint );
			}
			break;
		}

		pSyn->mFireFriendly = fireFriendly;
		pSyn->mFirePoint = firePoint;
		pSyn->mWaterFriendly = waterFriendly;
		pSyn->mWaterPoint = waterPoint;
		pSyn->mWindFriendly = windFriendly;
		pSyn->mWindPoint = windPoint;
		pSyn->mEarthFriendly = earthFriendly;
		pSyn->mEarthPoint = earthPoint;
		pSyn->mExp = addExp;
		pSyn->mSxp = addSxp;
		pSyn->mMoney = money;

		pPlayer->FireFriendlyPlus( fireFriendly );
		pPlayer->FirePointPlus( firePoint );
		pPlayer->WaterFriendlyPlus( waterFriendly );
		pPlayer->WaterPointPlus( waterPoint );
		pPlayer->WindFriendlyPlus( windFriendly );
		pPlayer->WindPointPlus( windPoint );
		pPlayer->EarthFriendlyPlus( earthFriendly );
		pPlayer->EarthPointPlus( earthPoint );
		pPlayer->AddExpSxpNoPer( addExp, addSxp );
		/// 시스템이 money를 넣주는 형태로 바꿔야 함
		pPlayer->AddMoney( pPlayer->GetObject(), money );
		SKILLMANAGER->AddInfluence( pPlayer->GetObject(), pPlayer->GetObject(), infIdx, 0, true );

		memcpy( pSyn->mTeam, member, sizeof( sPvPDMTeamScore ) * memberCnt );
		pSyn->mTeamCnt = memberCnt;
		NETWORK2->SendToUser( pPlayer->GetConnectionIdx(), (char*)pSyn, pSyn->GetMsgLength() );

	}

	perIoContext->offset = pSyn->GetMsgLength();
	NETWORK2->ReleaseIoContext( perIoContext, "cDeathMatchObject::SendTeamResult:MSG_SYN_PVP_DM_FIGHTEND" );	
}


void cDeathMatchObject::SendOut()
{
	cPlayer* pPlayer = NULL;
	bool leader = false;
	for( int i = 0 ; PVP_DM_TEAM_CNT > i ; ++i )
	{
		pPlayer = OBJECTMANAGER->GetPlayer( mAMemberInfo[i].mPlayerIdx );
		if( pPlayer == NULL )
			continue;

		mAMemberInfo[i].Init();

		if( mTeamInfo[ePVPDM_TEAMTYPE_A].mLeaderIdx == mAMemberInfo[i].mPlayerIdx )
			leader = true;
		else
			leader = false;

		pPlayer->AutoPvPOut();
	}

	for( int i = 0 ; PVP_DM_TEAM_CNT > i ; ++i )
	{
		pPlayer = OBJECTMANAGER->GetPlayer( mBMemberInfo[i].mPlayerIdx );
		if( pPlayer == NULL )
			continue;

		mBMemberInfo[i].Init();

		if( mTeamInfo[ePVPDM_TEAMTYPE_B].mLeaderIdx == mBMemberInfo[i].mPlayerIdx )
			leader = true;
		else
			leader = false;

		pPlayer->AutoPvPOut();
	}
}


void cDeathMatchObject::SendOut( unsigned long playerIdx, unsigned long teamType )
{
	cPlayer* pPlayer;
	bool leader = false;

	if( teamType == ePVPDM_TEAMTYPE_A )
	{
		for( int i = 0 ; PVP_DM_TEAM_CNT > i ; ++i )
		{
			if( playerIdx != mAMemberInfo[i].mPlayerIdx )
				continue;

			pPlayer = OBJECTMANAGER->GetPlayer( playerIdx );
			if( pPlayer == NULL )
				return;

			mAMemberInfo[i].Init();

			if( mTeamInfo[ePVPDM_TEAMTYPE_A].mLeaderIdx == playerIdx )
				leader = true;

			pPlayer->PvPOut();

			return;
		}
	}

	if( teamType == ePVPDM_TEAMTYPE_B )
	{
		for( int i = 0 ; PVP_DM_TEAM_CNT > i ; ++i )
		{
			if( playerIdx != mBMemberInfo[i].mPlayerIdx )
				continue;

			pPlayer = OBJECTMANAGER->GetPlayer( playerIdx );
			if( pPlayer == NULL )
				return;

			mBMemberInfo[i].Init();

			if( mTeamInfo[ePVPDM_TEAMTYPE_B].mLeaderIdx == playerIdx )
				leader = true;

			pPlayer->PvPOut();

			return;
		}
	}
}

void cDeathMatchObject::DMQuickSend( char* msg, unsigned long length )
{
	TeamQuickSend( ePVPDM_TEAMTYPE_A, msg, length );
	TeamQuickSend( ePVPDM_TEAMTYPE_B, msg, length );
}


void cDeathMatchObject::TeamQuickSend( ePVPDM_TEAM_TYPE teamType, char* msg, unsigned long length )
{
	sPvPDMMemberInfo* pMemberInfo = NULL;
	if( teamType == ePVPDM_TEAMTYPE_A )
		pMemberInfo = mAMemberInfo;
	else if( teamType == ePVPDM_TEAMTYPE_B )
		pMemberInfo = mBMemberInfo;

	if( pMemberInfo == NULL )
	{
		NETWORK2->PostServerEvent(" cDeathMatchObject::TeamQuickSend pMemberInfo[%d] == NULL", teamType );
		return;
	}

	cPlayer* pPlayer = NULL;
	for( int i = 0 ; i < PVP_DM_TEAM_CNT ; ++i )
	{
		if( pMemberInfo[i].mPlayerIdx == 0 )
			continue;

		pPlayer = OBJECTMANAGER->GetPlayer( pMemberInfo[i].mPlayerIdx );
		if( pPlayer == NULL || pPlayer->GetGameIn() == false )
			continue;

		NETWORK2->SendToUser( pPlayer->GetConnectionIdx(), msg, length );
	}
}
