void CGuildWarManager::SurrenderNotifyToMap( void* pMsg )
{
	const MSG_GUILD_WAR_RESULT*	pmsg				= ( MSG_GUILD_WAR_RESULT* )pMsg;
	const DWORD					winnnerGuildIndex	= pmsg->mWinner.mGuildIndex;
	const DWORD					loserGuildIndex		= pmsg->mLoser.mGuildIndex;

	MSG_DWORD4					message;
	{
		message.Category = MP_GUILD_WAR;
		message.Protocol = MP_GUILD_WAR_SURRENDER;
	}

	// 승리 길드에게 메시지 전달
	{
		CGuild* guild	= GUILDMGR->GetGuild( winnnerGuildIndex );

		if( guild )
		{
			const MSG_GUILD_WAR_RESULT::Data& data = pmsg->mWinner;

			message.dwData1 = 1;	// 1 = win
			message.dwData2 = loserGuildIndex;
			message.dwData3	= data.mScoreValue;
			message.dwData4	= DWORD( data.mScoreVariation );

			guild->SendMsgToAll( &message, sizeof( message ) );
		}
	}

	// 패배 길드에게 전달
	{
		CGuild* guild	= GUILDMGR->GetGuild( loserGuildIndex );

		if( guild )
		{
			const MSG_GUILD_WAR_RESULT::Data& data = pmsg->mLoser;

			message.dwData1 = 0;	// 0 = surrender, 
			message.dwData2 = winnnerGuildIndex;
			message.dwData3	= data.mScoreValue;
			message.dwData4	= DWORD( data.mScoreVariation );

			guild->SendMsgToAll( &message, sizeof( message ) );
		}
	}

	UnregistGuildWar( winnnerGuildIndex, loserGuildIndex );
//	PenaltyForEndNotifyToMap( 1, loserGuildIndex );

	UpdateGuildWarRecord( FALSE, 0, loserGuildIndex );
	UpdateGuildWarRecord( FALSE, 1, winnnerGuildIndex );
}
void CGuildWarManager::NetworkMsgParse( BYTE Protocol, void* pMsg )
{
	switch( Protocol )
	{
	case MP_GUILD_WAR_NACK:
		{
			MSG_BYTE* pmsg = (MSG_BYTE*)pMsg;

			CObject* object = g_pUserTable->FindUser( pmsg->dwObjectID );
			
			if( object )
			{
				object->SendMsg( pmsg, sizeof( MSG_BYTE ) );
			}

			break;
		}
	case MP_GUILD_WAR_DECLARE:
		{
			Declare( pMsg );
			break;
		}
	case MP_GUILD_WAR_DECLARE_NACK:
		{
			break;
		}
	case MP_GUILD_WAR_DECLARE_ACCEPT:
		{
			DeclareAccept( pMsg );
			break;
		}
	case MP_GUILD_WAR_DECLARE_DENY:
		{
			DeclareDeny( pMsg );
			break;
		}
	case MP_GUILD_WAR_DECLARE_DENY_NOTIFY_TOMAP:
		{
			DeclareDenyNotifyToMap( pMsg );
			break;
		}
	case MP_GUILD_WAR_START:
		{
			break;
		}
	case MP_GUILD_WAR_START_NOTIFY_TOMAP:
		{
			StartNotifyToMap( pMsg );
			break;
		}
	case MP_GUILD_WAR_PROC:
		{
			break;
		}
	case MP_GUILD_WAR_END:
		{
			break;
		}
	case MP_GUILD_WAR_END_NOTIFY_TOMAP:
		{
			MSG_DWORD2* pmsg = (MSG_DWORD2*)pMsg;

			DWORD dwGuildIdxWinner = pmsg->dwData1;
			DWORD dwGuildIdxLoser = pmsg->dwData2;
			if( dwGuildIdxWinner == 0 || dwGuildIdxLoser == 0 )	return;

			CGuild* pGuildWinner = GUILDMGR->GetGuild( dwGuildIdxWinner );
			CGuild* pGuildLoser = GUILDMGR->GetGuild( dwGuildIdxLoser );

			if( pGuildWinner == NULL || pGuildLoser == NULL )	return;

			MSG_DWORD2 Msg;
			Msg.Category = MP_GUILD_WAR;
			Msg.Protocol = MP_GUILD_WAR_END;

			// send guildwinner
			Msg.dwData1 = 1;	// 0 = lose, 1 = win
			Msg.dwData2 = dwGuildIdxLoser; 
			pGuildWinner->SendMsgToAll( &Msg, sizeof(Msg) );

			// send guildloser
			Msg.dwData1 = 0;
			Msg.dwData2 = dwGuildIdxWinner; 
			pGuildLoser->SendMsgToAll( &Msg, sizeof(Msg) );

			// unregist
			UnregistGuildWar( dwGuildIdxWinner, dwGuildIdxLoser );
			//	PenaltyForEndNotifyToMap( 0, dwGuildIdxLoser );

			// guildfieldwarrecord
			UpdateGuildWarRecord( FALSE, 0, dwGuildIdxLoser );
			UpdateGuildWarRecord( FALSE, 1, dwGuildIdxWinner );

			// registend
			//RegistEnd( dwGuildIdxWinner, dwGuildIdxLoser );
			break;
		}
	case MP_GUILD_WAR_SUGGESTEND:
		{
			SuggestEnd( pMsg );
			break;
		}
	case MP_GUILD_WAR_SUGGESTEND_NOTIFY_TOMAP:
		{
			const MSG_DWORD2*	pmsg	= (MSG_DWORD2*)pMsg;
			CObject*			object	= g_pUserTable->FindUser( pmsg->dwData1 );
			if( object )
			{
				MSG_DWORD message;
				message.Category	= MP_GUILD_WAR;
				message.Protocol	= MP_GUILD_WAR_SUGGESTEND;
				message.dwData		= pmsg->dwData2;

				object->SendMsg( &message, sizeof(message) );
			}

			break;
		}
	case MP_GUILD_WAR_SUGGESTEND_NACK:
		{
			break;
		}
	case MP_GUILD_WAR_SUGGESTEND_ACCEPT:
		{
			SuggestEndAccept( pMsg );
			break;
		}
	case MP_GUILD_WAR_SUGGESTEND_ACCEPT_NOTIFY_TOMAP:
		{
			SuggestEndAcceptNotifyToMap( pMsg );
			break;
		}
	case MP_GUILD_WAR_SUGGESTEND_DENY:
		{
			SuggestEndDeny( pMsg );
			break;
		}
	case MP_GUILD_WAR_SUGGESTEND_DENY_NOTIFY_TOMAP:
		{
			SuggestEndDenyNotifyToMap( pMsg );
			break;
		}
	case MP_GUILD_WAR_SURRENDER:
		{
			Surrender( pMsg );
			break;
		}
	case MP_GUILD_WAR_SURRENDER_NACK:
		{
			break;
		}
	case MP_GUILD_WAR_SURRENDER_NOTIFY_TOMAP:
		{
			SurrenderNotifyToMap( pMsg );
			break;
		}
	case MP_GUILD_WAR_ADDMONEY_TOMAP:
		{
			AddMoneyToMap( pMsg );
			break;
		}
	default:
		{
			ASSERT( 0 && "It is not defined" );
			break;
		}
	}
}
void CGuildWarManager::RemoveUnionEnemyFromGuild( CGuildUnion* friendlyUnion, CGuild* friendlyGuild )
{
	std::list< sGFWENEMY* > enemeyList;
	GetEnemy( friendlyUnion->GetMasterGuildIdx(), enemeyList );

	const DWORD	friendlyGuildIndex = friendlyGuild->GetIdx();

	MSG_DWORD2 messageToFriendy;
	{
		messageToFriendy.Category	= MP_GUILD_WAR;
		messageToFriendy.Protocol	= MP_GUILD_WAR_END;
		messageToFriendy.dwData1	= 2;
	}

	MSG_DWORD2 messageToEnemy;
	{
		messageToEnemy.Category	= MP_GUILD_WAR;
		messageToEnemy.Protocol	= MP_GUILD_WAR_END;
		messageToEnemy.dwData1	= 2;	// draw
		messageToEnemy.dwData2	= friendlyGuildIndex;
	}

	// 모든 적 목록에서 해당 길드를 적에서 제거하도록 한다.
	for( std::list< sGFWENEMY* >::const_iterator it = enemeyList.begin(); enemeyList.end() != it; ++it )
	{
		const sGFWENEMY*	enemyData		= *it;
		const DWORD			enemyGuildIndex = enemyData->dwEnemyGuildIdx;
		CGuild*				enemyGuild		= GUILDMGR->GetGuild( enemyGuildIndex );

		if( ! enemyGuild )
		{
			ASSERT( 0 );
			continue;
		}

		// 적 길드에게 해당 길드와의 싸움을 끝낼 것을 알린다
		{
			enemyGuild->SendMsgToAll( &messageToEnemy, sizeof( messageToEnemy ) );
		}

		// 아군에게도 알리자
		{
			messageToFriendy.dwData2 = enemyGuildIndex;

			friendlyGuild->SendMsgToAll( &messageToFriendy, sizeof( messageToFriendy ) );
		}

		// 다른 맵에도 알린다(종전으로 표시될 것이다
		{
			MSG_DWORD2 message;
			message.Category	= MP_GUILD_WAR;
			message.Protocol	= MP_GUILD_WAR_SUGGESTEND_ACCEPT_NOTIFY_TOMAP;
			message.dwData1		= friendlyGuildIndex;
			message.dwData2		= enemyGuildIndex;

			g_Network.Send2AgentServer( (char*)&message, sizeof( message ) );
		}

		// DB 및 메모리 갱신
		{
			DeleteGuildWar( friendlyGuildIndex, enemyGuildIndex );
			UnregistGuildWar( friendlyGuildIndex, enemyGuildIndex );

			UpdateGuildWarRecord( TRUE, 2, enemyGuildIndex );
			UpdateGuildWarRecord( TRUE, 2, friendlyGuildIndex );
		}

		//SendToAllUser( 1, friendlyGuild->GetGuildName(), enemyGuild->GetGuildName() );
	}
}
void CGuildWarManager::AddUnionEnemyToGuild( CGuildUnion* friendlyUnion, CGuild* friendlyGuild )
{
	MSG_GUILD_LIST	messageToFriendly;
	MSG_GUILD_LIST	messageToEnemey;
	{
		messageToFriendly.Category	= MP_GUILD_WAR;
		messageToFriendly.Protocol	= MP_GUILD_WAR_START;
		messageToFriendly.mSize		= 0;

		messageToEnemey.Category	= MP_GUILD_WAR;
		messageToEnemey.Protocol	= MP_GUILD_WAR_START;
		messageToEnemey.mSize		= 1;

		MSG_GUILD_LIST::Data&	dest	= messageToEnemey.mData[ 0 ];
		const GUILDINFO&		source	= friendlyGuild->GetInfo();

		// 올바로 복사되는지 꼭 검사할 것
		memcpy( &dest, &source, sizeof( source ) );

		// 중간에 참전했으므로 선포금이 없다
		dest.MarkName = 0;

		CGuildUnion* alliance = GUILDUNIONMGR->GetUnion( source.UnionIdx );

		if( alliance )
		{
			SafeStrCpy( dest.mUnionName, alliance->GetName(), sizeof( dest.mUnionName ) );
		}
		else
		{
			dest.mUnionName[ 0 ] = 0;
		}
	}	

	const DWORD				friendlyGuildIndex = friendlyGuild->GetIdx();
	std::list< sGFWENEMY* > enemeyList;

	GetEnemy( friendlyUnion->GetMasterGuildIdx(), enemeyList );

	// 적대 길드 목록을 메시지에 담고, 신입 길드 또한 적 길드로 하여금 등록하게 한다.
	for( std::list< sGFWENEMY* >::const_iterator it = enemeyList.begin(); enemeyList.end() != it; ++it )
	{
		const sGFWENEMY*	enemyData		= *it;
		const DWORD			enemyGuildIndex = enemyData->dwEnemyGuildIdx;
		CGuild*				enemyGuild		= GUILDMGR->GetGuild( enemyGuildIndex );

		if( ! enemyGuild )
		{
			ASSERT( 0 );
			continue;
		}

		// 적대 길드 정보를 담는다
		// 신입 길드를 적으로 등록하도록 모든 적대 길드에게 보낸다.
		{
			MSG_GUILD_LIST::Data&	dest	= messageToFriendly.mData[ messageToFriendly.mSize++ ];
			const GUILDINFO&		source	= enemyGuild->GetInfo();

			// 제대로 복사되나 테스트할 것
			memcpy( &dest, &source, sizeof( source ) );

			// 중간에 참전하여 선포금이 없다
			dest.MarkName = 0;

			CGuildUnion* alliance = GUILDUNIONMGR->GetUnion( source.UnionIdx );

			if( alliance )
			{
				SafeStrCpy( dest.mUnionName, alliance->GetName(), sizeof( dest.mUnionName ) );
			}
			else
			{
				dest.mUnionName[ 0 ] = 0;
			}

			enemyGuild->SendMsgToAll( &messageToEnemey, messageToEnemey.GetSize() );
		}

		// DB와 메모리에도 저장한다
		{
			InsertGuildWar( friendlyGuildIndex, enemyGuildIndex, 0 );
			RegistGuildWar( friendlyGuildIndex, enemyGuildIndex, 0 );
		}
		
		// 다른 맵에도 등록하게 한다.
		{
			MSG_DWORD3 message;
			message.Category	= MP_GUILD_WAR;
			message.Protocol	= MP_GUILD_WAR_START_NOTIFY_TOMAP;
			message.dwData1		= friendlyGuildIndex;
			message.dwData2		= enemyGuildIndex;
			message.dwData3		= 0;

			g_Network.Send2AgentServer( ( char* )&message, sizeof( message ) );	
		}
	}

	if( messageToFriendly.mSize )
	{
		// 적대 길드 목록을 다 담은 후 신입 길드에게도 보낸다
		friendlyGuild->SendMsgToAll( &messageToFriendly, messageToFriendly.GetSize() );
	}
}
void CGuildWarManager::AddEnemyToFriendly( Alliance& friendlyMap, Alliance& enemyMap )
{
	MSG_GUILD_LIST	messageToClient;
	messageToClient.Category	= MP_GUILD_WAR;
	messageToClient.Protocol	= MP_GUILD_WAR_START;
	messageToClient.mSize		= 0;

	// 길드 1의 적(길드2) 전체 정보를 넣는다
	for( Alliance::iterator it = enemyMap.begin(); enemyMap.end() != it; ++it )
	{
		CGuild*			enemy = it->first;
		const MONEYTYPE	money = it->second;

		if( ! enemy )
		{
			ASSERT( 0 );
			continue;
		}

		MSG_GUILD_LIST::Data&	dest	= messageToClient.mData[ messageToClient.mSize++ ];
		const GUILDINFO&		source	= enemy->GetInfo();
		
		// 제대로 복사되나 꼭 확인하자. 좀 위험한 코드
		memcpy( &dest, &source, sizeof( source ) );

		dest.MarkName = money;

		CGuildUnion* allianace = GUILDUNIONMGR->GetUnion( source.UnionIdx );

		if( allianace )
		{
			SafeStrCpy( dest.mUnionName, allianace->GetName(), sizeof( dest.mUnionName ) );
		}
		else
		{
			dest.mUnionName[ 0 ] = 0;
		}
	}

	MSG_DWORD3 messageToAgent;
	messageToAgent.Category	= MP_GUILD_WAR;
	messageToAgent.Protocol	= MP_GUILD_WAR_START_NOTIFY_TOMAP;

	// 길드 2의 적, 즉 길드 1의 편 전부에게 보낸다.
	for( Alliance::iterator it = friendlyMap.begin(); friendlyMap.end() != it; ++it )
	{
		CGuild*			friendly		= it->first;
		const MONEYTYPE	friendlyMoney	= it->second;
		
		if( ! friendly )
		{
			ASSERT( 0 );
			continue;
		}
		
		friendly->SendMsgToAll( &messageToClient, messageToClient.GetSize() );

		// 아군 길드 각각이 상대 길드들을 적으로 등록하게 한다.
		for( Alliance::iterator inner = enemyMap.begin(); enemyMap.end() != inner; ++inner )
		{
			CGuild*			enemy		= inner->first;
			const MONEYTYPE	enemyMoney	= inner->second;

			if( ! enemy )
			{
				ASSERT( 0 );
				continue;
			}

			// 두 길드 모두 선포금을 지니고 있을때만 돈을 업데이트해야한다. 그렇지 않은 길드는 선포금을 건 당사자가 아니다.
			const MONEYTYPE money = ( friendlyMoney && enemyMoney ? friendlyMoney : 0 ) ;

			InsertGuildWar( friendly->GetIdx(), enemy->GetIdx(), money );
			RegistGuildWar( friendly->GetIdx(), enemy->GetIdx(), money );

			// 다른 맵에도 등록하게 한다.
			{
				messageToAgent.dwData1		= friendly->GetIdx();
				messageToAgent.dwData2		= enemy->GetIdx();
				messageToAgent.dwData3		= money;

				g_Network.Send2AgentServer( (char*)&messageToAgent, sizeof( messageToAgent ) );	
			}
		}
	}
}
void CGuildWarManager::SuggestEndAccept( void* pMsg )
{
	// 편의상 제안한 쪽은 아군, 받아들이는 쪽은 적군이라 하자

	MSG_DWORD*	pmsg				= ( MSG_DWORD* )pMsg;
	CPlayer*	friendlyGuildMaster	= ( CPlayer* )	g_pUserTable->FindUser( pmsg->dwObjectID );

	if( !	friendlyGuildMaster ||
			friendlyGuildMaster->GetGuildMemberRank() != GUILD_MASTER )
	{
		return;	
	}

	const DWORD friendlyGuildIndex	= friendlyGuildMaster->GetGuildIdx();
	const DWORD enemyGuildIndex		= pmsg->dwData;
	CGuild*		friendlyGuild		= GUILDMGR->GetGuild( friendlyGuildIndex );
	CGuild*		enemyGuild			= GUILDMGR->GetGuild( enemyGuildIndex );

	if( !	friendlyGuild	||
		!	enemyGuild		||
		!	IsGuildWar( friendlyGuildIndex, enemyGuildIndex ) )
	{
		return;
	}

	// 동맹인데 마스터 길드가 아닐 경우 해킹 또는 클라이언트 검사 실패
	{
		CGuildUnion* friendlyAlliance	= GUILDUNIONMGR->GetUnion( friendlyGuild->GetUnionIndex() );
		CGuildUnion* enemyAlliance		= GUILDUNIONMGR->GetUnion( enemyGuild->GetUnionIndex() );

		if( ( friendlyAlliance	&& friendlyAlliance->GetMasterGuild()	!= friendlyGuild	)	||
			( enemyAlliance		&& enemyAlliance->GetMasterGuild()		!= enemyGuild		)	)
		{
			return;
		}
	}

	// 편의상 종전을 요청한 측을 아군, 요청받은 측을 적군으로 하자
	Alliance friendlyAlliance;
	Alliance enemyAlliance;

	// 연합인 경우 해당 길드를 모두 자료구조에 담는다. 
	{
		// 아군
		{
			CGuildUnion* alliance = GUILDUNIONMGR->GetUnion( friendlyGuild->GetUnionIndex() );

			if( alliance )
			{
				// 연합이 있는데도 마스터 길드가 아닌 경우 오류
				if( alliance->GetMasterGuild() != friendlyGuild )
				{
					return;
				}

				AddGuildToGroup( alliance, friendlyAlliance );
			}

			friendlyAlliance[ friendlyGuild ] = GetWarMoney( friendlyGuildIndex, enemyGuildIndex );
		}

		// 적군
		{
			CGuildUnion* alliance = GUILDUNIONMGR->GetUnion( enemyGuild->GetUnionIndex() );

			if( alliance )
			{
				// 연합이 있는데도 마스터 길드가 아닌 경우 오류
				if( alliance->GetMasterGuild() != enemyGuild )
				{
					return;
				}

				AddGuildToGroup( alliance, enemyAlliance );
			}

			enemyAlliance[ enemyGuild ] = GetWarMoney( friendlyGuildIndex, enemyGuildIndex );
		}
	}
	
	// 선포금이 있다면 반환해주자
	{
		const DWORD money = GetWarMoney( friendlyGuildIndex, enemyGuildIndex );

		if( money )
		{
			SendMoneyMsg( friendlyGuildMaster, NULL, money, MP_GUILD_WAR_ADDMONEY );

			CPlayer* enemyGuildMaster = ( CPlayer* )g_pUserTable->FindUser( enemyGuild->GetMasterIdx() );

			if( enemyGuildMaster )
			{
				SendMoneyMsg( enemyGuildMaster, NULL, money, MP_GUILD_WAR_ADDMONEY );
			}
			else
			{
				SendToAgentAddMoneyMsg( enemyGuild->GetMasterIdx(), money );
			}
		}
	}
	
	// 자료구조를 순환하며, 각각의 전쟁을 종료시킨다.
	for( Alliance::const_iterator it = friendlyAlliance.begin(); friendlyAlliance.end() != it; ++it )
	{
		// 전쟁 종료
		CGuild* friendly = it->first;

		if( ! friendly )
		{
			ASSERT( 0 );
			continue;
		}

		const DWORD friendlyGuildIndex = friendly->GetIdx();

		for( Alliance::const_iterator inner = enemyAlliance.begin(); enemyAlliance.end() != inner; ++inner )
		{
			CGuild* enemy = inner->first;

			if( ! enemy )
			{
				ASSERT( 0 );
				continue;
			}

			const DWORD enemyGuildIndex = enemy->GetIdx();

			// 길드전 중지를 해당 맵에 알린다
			{
				MSG_DWORD2 message;
				message.Category	= MP_GUILD_WAR;
				message.Protocol	= MP_GUILD_WAR_END;
				message.dwData1		= 2;		// 2 = draw

				message.dwData2		= enemyGuildIndex;
				friendly->SendMsgToAll( &message, sizeof( message ) );

				message.dwData2		= friendlyGuildIndex;
				enemy->SendMsgToAll( &message, sizeof( message ) );
			}

			// 에이전트를 통해 다른 맵에게도 보낸다
			{
				MSG_DWORD2 message;
				message.Category	= MP_GUILD_WAR;
				message.Protocol	= MP_GUILD_WAR_SUGGESTEND_ACCEPT_NOTIFY_TOMAP;
				message.dwData1		= friendlyGuildIndex;
				message.dwData2		= enemyGuildIndex;

				g_Network.Send2AgentServer( (char*)&message, sizeof( message ) );
			}

			DeleteGuildWar( friendlyGuildIndex, enemyGuildIndex );
			UnregistGuildWar( friendlyGuildIndex, enemyGuildIndex );

			UpdateGuildWarRecord( TRUE, 2, friendlyGuildIndex );
			UpdateGuildWarRecord( TRUE, 2, enemyGuildIndex );
		}
	}

	//SendToAllUser( 1, friendlyGuild->GetGuildName(), enemyGuild->GetGuildName() );
}