Jump to content

Official Party Update


Recommended Posts

  • Bot

Thanks for the release. I found a bug: when you are at a party and you teleport to a map whose core is different from the map core of the other member of the party, it will show the member as [Offline], that should not happen. Can you look at it, please? : D

Regarding what @Shang says, he means that in the official server, when you create a party, that party is created in all the channels, that is, if you change the channel, the party will be in the channel that was created and in any channel that you change, but still without putting your release, at least in the majority of public sources this does not happen, I suppose the part of creating the party in all the channels at the same time was a recent update of gameforge. So this is not a problem, since it is simply to create the party manually on all channels. xD

Sorry for my bad English.

  • Love 1

english_banner.gif

Link to comment
Share on other sites

On 5/15/2018 at 10:50 PM, WLsj24 said:

Thanks for the release. I found a bug: when you are at a party and you teleport to a map whose core is different from the map core of the other member of the party, it will show the member as [Offline], that should not happen. Can you look at it, please? : D

Regarding what @Shang says, he means that in the official server, when you create a party, that party is created in all the channels, that is, if you change the channel, the party will be in the channel that was created and in any channel that you change, but still without putting your release, at least in the majority of public sources this does not happen, I suppose the part of creating the party in all the channels at the same time was a recent update of gameforge. So this is not a problem, since it is simply to create the party manually on all channels. xD

Sorry for my bad English.

It is working 100% right now?

Link to comment
Share on other sites

  • Bot
3 hours ago, zeimpekis9 said:

It is working 100% right now?

Yes, the only problem is that if "Player1" is in Pyugmoo and "Player2" is in "Spider Dungeon", that is, the members of the party are in different core, (you know, cities are usually in the core1, and maps like Yongbi are usually in the core2) because in that case it will show the one in a different cores as [Offline] (even if both members are online) in the party. If @Mali61 fix that, then one could already speak of a functional version without bugs.

  • Love 1

english_banner.gif

Link to comment
Share on other sites

  • Honorable Member
2 hours ago, WLsj24 said:

Yes, the only problem is that if "Player1" is in Pyugmoo and "Player2" is in "Spider Dungeon", that is, the members of the party are in different core, (you know, cities are usually in the core1, and maps like Yongbi are usually in the core2) because in that case it will show the one in a different cores as [Offline] (even if both members are online) in the party. If @Mali61 fix that, then one could already speak of a functional version without bugs.

Please wait weekend I'm busy

  • Love 3

 

Link to comment
Share on other sites

  • Honorable Member
5 hours ago, zeimpekis9 said:

So, did you fixed it?

Yeah now party will create in all channels but still has some problem with online/offline problem.I don't have enough time but don't worry I will fix it.

  • Love 1

 

Link to comment
Share on other sites

11 minutes ago, Fleon said:

I don't even know why you are taking orders from random people but nice work thanks for the relase.

 

11 minutes ago, Fleon said:

I don't even know why you are taking orders from random people but nice work thanks for the relase.

he is not taking orders. He released a system. We infrom him about the bugs of the system, and we just asked IF he can fix it. Why everyone here is so rude? I dont understand you. You should learn to help RANDOM people and to flame all the time. FFS.

Link to comment
Share on other sites

  • Premium
50 minutes ago, zeimpekis9 said:

 

he is not taking orders. He released a system. We infrom him about the bugs of the system, and we just asked IF he can fix it. Why everyone here is so rude? I dont understand you. You should learn to help RANDOM people and to flame all the time. FFS.

Lul. You are not informing him when you ask "So, did you fix it?" but instead it sounds like a request from somebody who should only be grateful, if you want to help then go for a pull request implementing the feature/bugfix on your own.

I've been helping random people way too much, that's why I understood that random people usually don't deserve anything :].

It's git tho, if you want to know if he updated the code then check the commits instead of asking here, you know.

  • Love 2
Link to comment
Share on other sites

2 hours ago, zeimpekis9 said:

 

he is not taking orders. He released a system. We infrom him about the bugs of the system, and we just asked IF he can fix it. Why everyone here is so rude? I dont understand you. You should learn to help RANDOM people and to flame all the time. FFS.

Ηelping random people is like feeding a snake .. :D

Link to comment
Share on other sites

2 hours ago, Fleon said:

Lul. You are not informing him when you ask "So, did you fix it?" but instead it sounds like a request from somebody who should only be grateful, if you want to help then go for a pull request implementing the feature/bugfix on your own.

I've been helping random people way too much, that's why I understood that random people usually don't deserve anything :].

It's git tho, if you want to know if he updated the code then check the commits instead of asking here, you know.

 

12 minutes ago, BeHappy4Ever said:

Ηelping random people is like feeding a snake .. :D

Whatever. You are so wrong and you dont understand. I will not explain to you anymore.

Link to comment
Share on other sites

  • Forum Moderator
vor 1 Stunde schrieb BeHappy4Ever:

Okay man...

Tρεις και παρ'τα αρχιδια μου!XX

 

vor 1 Stunde schrieb zeimpekis9:

Δεν αναφερόμουν σε σένα αλλά εντάξει.

ENGLISH GUYS!!!!

Rules

§1 Language

(1.1) Language

The language in this board is english. If you want to post something in your own language always add an english translation. The only exception for this rule is this section: Private Servers

Read the rules guys -.-


Best regards
Raylee

Link to comment
Share on other sites

Am 12.5.2018 um 21:53 schrieb Mali61:

giphy.gif

This is the hidden content, please

 

can you create a code methode for vs 2008? The src db part is just for 2011.

ClientManager.cpp: In member function 'void CClientManager::SendPartyOnSetup(CPeer*)':
ClientManager.cpp:424: error: a function-definition is not allowed here before ':' token
ClientManager.cpp:424: error: expected primary-expression before ')' token
ClientManager.cpp:424: error: expected `;' before ')' token
ClientManager.cpp:426: error: 'channels' was not declared in this scope
Spoiler

#ifdef BL_PARTY_UPDATE
	for (auto channels : {1,2,3,4,99})
	{
		TPartyMap & pm = m_map_pkChannelParty[channels];

		for (itertype(pm) it_party = pm.begin(); it_party != pm.end(); ++it_party)
		{
			sys_log(0, "PARTY SendPartyOnSetup Party [%u]", it_party->first);
			pkPeer->EncodeHeader(HEADER_DG_PARTY_CREATE, 0, sizeof(TPacketPartyCreate));
			pkPeer->Encode(&it_party->first, sizeof(DWORD));

			for (itertype(it_party->second) it_member = it_party->second.begin(); it_member != it_party->second.end(); ++it_member)
			{
				sys_log(0, "PARTY SendPartyOnSetup Party [%u] Member [%u]", it_party->first, it_member->first);
				pkPeer->EncodeHeader(HEADER_DG_PARTY_ADD, 0, sizeof(TPacketPartyAdd));
				pkPeer->Encode(&it_party->first, sizeof(DWORD));
				pkPeer->Encode(&it_member->first, sizeof(DWORD));
				pkPeer->Encode(&it_member->second.bRole, sizeof(BYTE));

				pkPeer->EncodeHeader(HEADER_DG_PARTY_SET_MEMBER_LEVEL, 0, sizeof(TPacketPartySetMemberLevel));
				pkPeer->Encode(&it_party->first, sizeof(DWORD));
				pkPeer->Encode(&it_member->first, sizeof(DWORD));
				pkPeer->Encode(&it_member->second.bLevel, sizeof(BYTE));
			}
		}
	}
#else

 

ClientManagerParty.cpp:8: error: function definition does not declare parameters
ClientManagerParty.cpp: In member function 'void CClientManager::QUERY_PARTY_CREATE(CPeer*, TPacketPartyCreate*)':
ClientManagerParty.cpp:13: error: a function-definition is not allowed here before ':' token
ClientManagerParty.cpp:239: error: expected primary-expression at end of input
ClientManagerParty.cpp:239: error: expected `;' at end of input
ClientManagerParty.cpp:239: error: expected primary-expression at end of input
ClientManagerParty.cpp:239: error: expected `)' at end of input
ClientManagerParty.cpp:239: error: expected statement at end of input
ClientManagerParty.cpp:239: error: expected `}' at end of input
Spoiler

#include "stdafx.h"
#include "ClientManager.h"
#include "Config.h"
#include "DBManager.h"
#include "QID.h"

#ifdef BL_PARTY_UPDATE
std::vector <DWORD> channel_info {1,2,3,4,99};
#endif
void CClientManager::QUERY_PARTY_CREATE(CPeer* peer, TPacketPartyCreate* p)
{
#ifdef BL_PARTY_UPDATE
	for (auto channels : channel_info) {
		TPartyMap & pm = m_map_pkChannelParty[channels];

		if (pm.find(p->dwLeaderPID) == pm.end())
		{
			pm.insert(make_pair(p->dwLeaderPID, TPartyMember()));
			ForwardPacket(HEADER_DG_PARTY_CREATE, p, sizeof(TPacketPartyCreate), channels, peer);
			sys_log(0, "PARTY Create [%lu]", p->dwLeaderPID);
		}
	}
#else
	TPartyMap & pm = m_map_pkChannelParty[peer->GetChannel()];

	if (pm.find(p->dwLeaderPID) == pm.end())
	{
		pm.insert(make_pair(p->dwLeaderPID, TPartyMember()));
		ForwardPacket(HEADER_DG_PARTY_CREATE, p, sizeof(TPacketPartyCreate), peer->GetChannel(), peer);
		sys_log(0, "PARTY Create [%lu]", p->dwLeaderPID);
	}
	else
	{
		sys_err("PARTY Create - Already exists [%lu]", p->dwLeaderPID);
	}
#endif
}

void CClientManager::QUERY_PARTY_DELETE(CPeer* peer, TPacketPartyDelete* p)
{
#ifdef BL_PARTY_UPDATE
	for (auto channels : channel_info) {
		TPartyMap& pm = m_map_pkChannelParty[channels];
		itertype(pm) it = pm.find(p->dwLeaderPID);

		if (it == pm.end())
			return;
		pm.erase(it);
		ForwardPacket(HEADER_DG_PARTY_DELETE, p, sizeof(TPacketPartyDelete), channels, peer);
	}
#else
	TPartyMap& pm = m_map_pkChannelParty[peer->GetChannel()];
	itertype(pm) it = pm.find(p->dwLeaderPID);

	if (it == pm.end())
	{
		sys_err("PARTY Delete - Non exists [%lu]", p->dwLeaderPID);
		return;
	}

	pm.erase(it);
	ForwardPacket(HEADER_DG_PARTY_DELETE, p, sizeof(TPacketPartyDelete), peer->GetChannel(), peer);
#endif
	sys_log(0, "PARTY Delete [%lu]", p->dwLeaderPID);
}

void CClientManager::QUERY_PARTY_ADD(CPeer* peer, TPacketPartyAdd* p)
{
#ifdef BL_PARTY_UPDATE
	for (auto channels : channel_info) {
		TPartyMap & pm = m_map_pkChannelParty[channels];
		itertype(pm) it = pm.find(p->dwLeaderPID);

		if (it == pm.end())
			return;

		if (it->second.find(p->dwPID) == it->second.end())
		{
			it->second.insert(std::make_pair(p->dwPID, TPartyInfo()));
			ForwardPacket(HEADER_DG_PARTY_ADD, p, sizeof(TPacketPartyAdd), channels, peer);
			sys_log(0, "PARTY Add [%lu] to [%lu]", p->dwPID, p->dwLeaderPID);
		}
	}
#else
	TPartyMap & pm = m_map_pkChannelParty[peer->GetChannel()];
	itertype(pm) it = pm.find(p->dwLeaderPID);

	if (it == pm.end())
	{
		sys_err("PARTY Add - Non exists [%lu]", p->dwLeaderPID);
		return;
	}

	if (it->second.find(p->dwPID) == it->second.end())
	{
		it->second.insert(std::make_pair(p->dwPID, TPartyInfo()));
		ForwardPacket(HEADER_DG_PARTY_ADD, p, sizeof(TPacketPartyAdd), peer->GetChannel(), peer);
		sys_log(0, "PARTY Add [%lu] to [%lu]", p->dwPID, p->dwLeaderPID);
	}
	else
		sys_err("PARTY Add - Already [%lu] in party [%lu]", p->dwPID, p->dwLeaderPID);
#endif
}

void CClientManager::QUERY_PARTY_REMOVE(CPeer* peer, TPacketPartyRemove* p)
{
#ifdef BL_PARTY_UPDATE
	for (auto channels : channel_info) {
		TPartyMap & pm = m_map_pkChannelParty[channels];
		itertype(pm) it = pm.find(p->dwLeaderPID);

		if (it == pm.end())
			return;

		itertype(it->second) pit = it->second.find(p->dwPID);

		if (pit != it->second.end())
		{
			it->second.erase(pit);
			ForwardPacket(HEADER_DG_PARTY_REMOVE, p, sizeof(TPacketPartyRemove), channels, peer);
			sys_log(0, "PARTY Remove [%lu] to [%lu]", p->dwPID, p->dwLeaderPID);
		}
	}
#else
	TPartyMap & pm = m_map_pkChannelParty[peer->GetChannel()];
	itertype(pm) it = pm.find(p->dwLeaderPID);

	if (it == pm.end())
	{
		sys_err("PARTY Remove - Non exists [%lu] cannot remove [%lu]",p->dwLeaderPID, p->dwPID);
		return;
	}

	itertype(it->second) pit = it->second.find(p->dwPID);

	if (pit != it->second.end())
	{
		it->second.erase(pit);
		ForwardPacket(HEADER_DG_PARTY_REMOVE, p, sizeof(TPacketPartyRemove), peer->GetChannel(), peer);
		sys_log(0, "PARTY Remove [%lu] to [%lu]", p->dwPID, p->dwLeaderPID);
	}
	else
		sys_err("PARTY Remove - Cannot find [%lu] in party [%lu]", p->dwPID, p->dwLeaderPID);
#endif
}

void CClientManager::QUERY_PARTY_STATE_CHANGE(CPeer* peer, TPacketPartyStateChange* p)
{
#ifdef BL_PARTY_UPDATE
	for (auto channels : channel_info) {
		TPartyMap & pm = m_map_pkChannelParty[channels];
		itertype(pm) it = pm.find(p->dwLeaderPID);

		if (it == pm.end())
			return;

		itertype(it->second) pit = it->second.find(p->dwPID);

		if (pit == it->second.end())
			return;

		if (p->bFlag)
			pit->second.bRole = p->bRole;
		else 
			pit->second.bRole = 0;

		ForwardPacket(HEADER_DG_PARTY_STATE_CHANGE, p, sizeof(TPacketPartyStateChange), channels, peer);
	}
#else
	TPartyMap & pm = m_map_pkChannelParty[peer->GetChannel()];
	itertype(pm) it = pm.find(p->dwLeaderPID);

	if (it == pm.end())
	{
		sys_err("PARTY StateChange - Non exists [%lu] cannot state change [%lu]",p->dwLeaderPID, p->dwPID);
		return;
	}

	itertype(it->second) pit = it->second.find(p->dwPID);

	if (pit == it->second.end())
	{
		sys_err("PARTY StateChange - Cannot find [%lu] in party [%lu]", p->dwPID, p->dwLeaderPID);
		return;
	}

	if (p->bFlag)
		pit->second.bRole = p->bRole;
	else 
		pit->second.bRole = 0;

	ForwardPacket(HEADER_DG_PARTY_STATE_CHANGE, p, sizeof(TPacketPartyStateChange), peer->GetChannel(), peer);
#endif
	sys_log(0, "PARTY StateChange [%lu] at [%lu] from %d %d",p->dwPID, p->dwLeaderPID, p->bRole, p->bFlag);
}

void CClientManager::QUERY_PARTY_SET_MEMBER_LEVEL(CPeer* peer, TPacketPartySetMemberLevel* p)
{
#ifdef BL_PARTY_UPDATE
	for (auto channels : channel_info) {	
		TPartyMap & pm = m_map_pkChannelParty[channels];
		itertype(pm) it = pm.find(p->dwLeaderPID);

		if (it == pm.end())
			return;

		itertype(it->second) pit = it->second.find(p->dwPID);

		if (pit == it->second.end())
			return;

		pit->second.bLevel = p->bLevel;

		ForwardPacket(HEADER_DG_PARTY_SET_MEMBER_LEVEL, p, sizeof(TPacketPartySetMemberLevel), channels);
	}
#else
	TPartyMap & pm = m_map_pkChannelParty[peer->GetChannel()];
	itertype(pm) it = pm.find(p->dwLeaderPID);

	if (it == pm.end())
	{
		sys_err("PARTY SetMemberLevel - Non exists [%lu] cannot level change [%lu]",p->dwLeaderPID, p->dwPID);
		return;
	}

	itertype(it->second) pit = it->second.find(p->dwPID);

	if (pit == it->second.end())
	{
		sys_err("PARTY SetMemberLevel - Cannot find [%lu] in party [%lu]", p->dwPID, p->dwLeaderPID);
		return;
	}

	pit->second.bLevel = p->bLevel;

	ForwardPacket(HEADER_DG_PARTY_SET_MEMBER_LEVEL, p, sizeof(TPacketPartySetMemberLevel), peer->GetChannel());
#endif
	sys_log(0, "PARTY SetMemberLevel pid [%lu] level %d",p->dwPID, p->bLevel);
}

 

 

Edited by Metin2 Dev
Core X - External 2 Internal
  • Metin2 Dev 3
  • Love 1
Link to comment
Share on other sites

  • 2 weeks later...
  • 3 years later...

fix online/offline problem 

fix in " void CParty::SendPartyJoinAllToOne " and " void CParty::SendPartyUnlinkOneToAll " and " void CParty::SendPartyLinkOneToAll " and " void CParty::UpdateOnlineState " and " void CParty::UpdateOfflineState " function compare the file between yours and good luck ❤️

party.cpp

Spoiler

 

#include "stdafx.h"
#include "utils.h"
#include "char.h"
#include "party.h"
#include "char_manager.h"
#include "config.h"
#include "p2p.h"
#include "desc_client.h"
#include "dungeon.h"
#include "unique_item.h"
#ifdef ENABLE_12ZI
#include "zodiac_temple.h"
#endif

CPartyManager::CPartyManager()
{
	Initialize();
}

CPartyManager::~CPartyManager()
{
}

void CPartyManager::Initialize()
{
	m_bEnablePCParty = false;
}

void CPartyManager::DeleteAllParty()
{
	TPCPartySet::iterator it = m_set_pkPCParty.begin();

	while (it != m_set_pkPCParty.end())
	{
		DeleteParty(*it);
		it = m_set_pkPCParty.begin();
	}
}

bool CPartyManager::SetParty(LPCHARACTER ch)	// PC¸¸ »ç؟ëاط¾ك ار´ظ!!
{
	TPartyMap::iterator it = m_map_pkParty.find(ch->GetPlayerID());

	if (it == m_map_pkParty.end())
		return false;

	LPPARTY pParty = it->second;
	pParty->Link(ch);
	return true;
}

#ifdef ENABLE_PARTY_UPDATE
void CPartyManager::P2PLogin(DWORD pid, const char* name, long mapIdx, long channel)
#else
void CPartyManager::P2PLogin(DWORD pid, const char* name)
#endif
{
	TPartyMap::iterator it = m_map_pkParty.find(pid);

	if (it == m_map_pkParty.end())
		return;

#ifdef ENABLE_PARTY_UPDATE
	it->second->UpdateOnlineState(pid, name, mapIdx, channel);
#else
	it->second->UpdateOnlineState(pid, name);
#endif
}

void CPartyManager::P2PLogout(DWORD pid)
{
	TPartyMap::iterator it = m_map_pkParty.find(pid);

	if (it == m_map_pkParty.end())
		return;

	it->second->UpdateOfflineState(pid);
}

void CPartyManager::P2PJoinParty(DWORD leader, DWORD pid, BYTE role)
{
	TPartyMap::iterator it = m_map_pkParty.find(leader);

	if (it != m_map_pkParty.end())
	{
		it->second->P2PJoin(pid);

		if (role >= PARTY_ROLE_MAX_NUM)
			role = PARTY_ROLE_NORMAL;

		it->second->SetRole(pid, role, true);
	}
	else
	{
		sys_err("No such party with leader [%d]", leader);
	}
}

void CPartyManager::P2PQuitParty(DWORD pid)
{
	TPartyMap::iterator it = m_map_pkParty.find(pid);

	if (it != m_map_pkParty.end())
	{
		it->second->P2PQuit(pid);
	}
	else
	{
		sys_err("No such party with member [%d]", pid);
	}
}

LPPARTY CPartyManager::P2PCreateParty(DWORD pid)
{
	TPartyMap::iterator it = m_map_pkParty.find(pid);
	if (it != m_map_pkParty.end())
		return it->second;

	LPPARTY pParty = M2_NEW CParty;

	m_set_pkPCParty.insert(pParty);

	SetPartyMember(pid, pParty);
	pParty->SetPCParty(true);
	pParty->P2PJoin(pid);

	return pParty;
}

void CPartyManager::P2PDeleteParty(DWORD pid)
{
	TPartyMap::iterator it = m_map_pkParty.find(pid);

	if (it != m_map_pkParty.end())
	{
		m_set_pkPCParty.erase(it->second);
		M2_DELETE(it->second);
	}
	else
		sys_err("PARTY P2PDeleteParty Cannot find party [%u]", pid);
}

LPPARTY CPartyManager::CreateParty(LPCHARACTER pLeader)
{
	if (pLeader->GetParty())
		return pLeader->GetParty();

	LPPARTY pParty = M2_NEW CParty;

	if (pLeader->IsPC())
	{
		//TPacketGGParty p;
		//p.header	= HEADER_GG_PARTY;
		//p.subheader	= PARTY_SUBHEADER_GG_CREATE;
		//p.pid		= pLeader->GetPlayerID();
		//P2P_MANAGER::instance().Send(&p, sizeof(p));
		TPacketPartyCreate p;
		p.dwLeaderPID = pLeader->GetPlayerID();

		db_clientdesc->DBPacket(HEADER_GD_PARTY_CREATE, 0, &p, sizeof(TPacketPartyCreate));

		sys_log(0, "PARTY: Create %s pid %u", pLeader->GetName(), pLeader->GetPlayerID());
		pParty->SetPCParty(true);
		pParty->Join(pLeader->GetPlayerID());

		m_set_pkPCParty.insert(pParty);
	}
	else
	{
		pParty->SetPCParty(false);
		pParty->Join(pLeader->GetVID());
	}

	pParty->Link(pLeader);
	return (pParty);
}

void CPartyManager::DeleteParty(LPPARTY pParty)
{
	//TPacketGGParty p;
	//p.header = HEADER_GG_PARTY;
	//p.subheader = PARTY_SUBHEADER_GG_DESTROY;
	//p.pid = pParty->GetLeaderPID();
	//P2P_MANAGER::instance().Send(&p, sizeof(p));
	TPacketPartyDelete p;
	p.dwLeaderPID = pParty->GetLeaderPID();

	db_clientdesc->DBPacket(HEADER_GD_PARTY_DELETE, 0, &p, sizeof(TPacketPartyDelete));

	m_set_pkPCParty.erase(pParty);
	M2_DELETE(pParty);
}

void CPartyManager::SetPartyMember(DWORD dwPID, LPPARTY pParty)
{
	TPartyMap::iterator it = m_map_pkParty.find(dwPID);

	if (pParty == NULL)
	{
		if (it != m_map_pkParty.end())
			m_map_pkParty.erase(it);
	}
	else
	{
		if (it != m_map_pkParty.end())
		{
			if (it->second != pParty)
			{
				it->second->Quit(dwPID);
				it->second = pParty;
			}
		}
		else
			m_map_pkParty.insert(TPartyMap::value_type(dwPID, pParty));
	}
}

EVENTINFO(party_update_event_info)
{
	DWORD pid;

	party_update_event_info()
	: pid( 0 )
	{
	}
};

/////////////////////////////////////////////////////////////////////////////
//
// CParty begin!
//
/////////////////////////////////////////////////////////////////////////////
EVENTFUNC(party_update_event)
{
	party_update_event_info* info = dynamic_cast<party_update_event_info*>( event->info );

	if ( info == NULL )
	{
		sys_err( "party_update_event> <Factor> Null pointer" );
		return 0;
	}

	DWORD pid = info->pid;
	LPCHARACTER leader = CHARACTER_MANAGER::instance().FindByPID(pid);

	if (leader && leader->GetDesc())
	{
		LPPARTY pParty = leader->GetParty();

		if (pParty)
			pParty->Update();
	}

	return PASSES_PER_SEC(3);
}

CParty::CParty()
{
	Initialize();
}

CParty::~CParty()
{
	Destroy();
}

void CParty::Initialize()
{
	sys_log(2, "Party::Initialize");

	m_iExpDistributionMode = PARTY_EXP_DISTRIBUTION_NON_PARITY;
	m_pkChrExpCentralize = NULL;

	m_dwLeaderPID = 0;

	m_eventUpdate = NULL;

	memset(&m_anRoleCount, 0, sizeof(m_anRoleCount));
	memset(&m_anMaxRole, 0, sizeof(m_anMaxRole));
	m_anMaxRole[PARTY_ROLE_LEADER] = 1;
	m_anMaxRole[PARTY_ROLE_NORMAL] = 32;

	m_dwPartyStartTime = get_dword_time();
	m_iLongTimeExpBonus = 0;

	m_dwPartyHealTime = get_dword_time();
	m_bPartyHealReady = false;
	m_bCanUsePartyHeal = false;

	m_iLeadership = 0;
	m_iExpBonus = 0;
	m_iAttBonus = 0;
	m_iDefBonus = 0;

	m_itNextOwner = m_memberMap.begin();

	m_iCountNearPartyMember = 0;

	m_pkChrLeader = NULL;
	m_bPCParty = false;
	m_pkDungeon = NULL;
	m_pkDungeon_for_Only_party = NULL;
#ifdef ENABLE_12ZI
	m_pkZodiac = NULL;
	m_pkZodiac_for_Only_party = NULL;
#endif
}


void CParty::Destroy()
{
	sys_log(2, "Party::Destroy");

	// PC°، ¸¸µç ئؤئ¼¸é ئؤئ¼¸إ´دہْ؟، ¸ت؟،¼­ PID¸¦ »èء¦اط¾ك ار´ظ.
	if (m_bPCParty)
	{
		for (TMemberMap::iterator it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
			CPartyManager::instance().SetPartyMember(it->first, NULL);
	}

	event_cancel(&m_eventUpdate); 

	RemoveBonus();

	TMemberMap::iterator it = m_memberMap.begin();

	DWORD dwTime = get_dword_time();

	while (it != m_memberMap.end())
	{
		TMember & rMember = it->second;
		++it;

		if (rMember.pCharacter)
		{
			if (rMember.pCharacter->GetDesc())
			{
				TPacketGCPartyRemove p;
				p.header = HEADER_GC_PARTY_REMOVE;
				p.pid = rMember.pCharacter->GetPlayerID();
				rMember.pCharacter->GetDesc()->Packet(&p, sizeof(p));
				rMember.pCharacter->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ئؤئ¼> ئؤئ¼°، اط»ê µا¾ْ½ہ´د´ظ."));
			}
			else
			{
				// NPCہد °و؟ى ہدء¤ ½أ°£ بؤ ہüإُ ءكہج ¾ئ´ز ¶§ »ç¶َءِ°ش اد´آ ہج؛¥ئ®¸¦ ½أہغ½أإ²´ظ.
				rMember.pCharacter->SetLastAttacked(dwTime);
				rMember.pCharacter->StartDestroyWhenIdleEvent();
			}

			rMember.pCharacter->SetParty(NULL);
		}
	}

	m_memberMap.clear();
	m_itNextOwner = m_memberMap.begin();
	
	if (m_pkDungeon_for_Only_party != NULL)
	{
		m_pkDungeon_for_Only_party->SetPartyNull();
		m_pkDungeon_for_Only_party = NULL;
	}
#ifdef ENABLE_12ZI
	if (m_pkZodiac_for_Only_party != NULL)
	{
		m_pkZodiac_for_Only_party->SetPartyNull();
		m_pkZodiac_for_Only_party = NULL;
	}
#endif
}

void CParty::ChatPacketToAllMember(BYTE type, const char* format, ...)
{
	char chatbuf[CHAT_MAX_LEN + 1];
	va_list args;

	va_start(args, format);
	vsnprintf(chatbuf, sizeof(chatbuf), format, args);
	va_end(args);

	TMemberMap::iterator it;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		TMember & rMember = it->second;

		if (rMember.pCharacter)
		{
			if (rMember.pCharacter->GetDesc())
			{
				rMember.pCharacter->ChatPacket(type, "%s", chatbuf);
			}
		}
	}
}

DWORD CParty::GetLeaderPID()
{
	return m_dwLeaderPID;
}

DWORD CParty::GetMemberCount()
{
	return m_memberMap.size();
}

void CParty::P2PJoin(DWORD dwPID)
{
	TMemberMap::iterator it = m_memberMap.find(dwPID);

	if (it == m_memberMap.end())
	{
		TMember Member;

		Member.pCharacter	= NULL;
		Member.bNear		= false;

		if (m_memberMap.empty())
		{
			Member.bRole = PARTY_ROLE_LEADER;
			m_dwLeaderPID = dwPID;
		}
		else
			Member.bRole = PARTY_ROLE_NORMAL;

		if (m_bPCParty)
		{
			LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(dwPID);

			if (ch)
			{
				sys_log(0, "PARTY: Join %s pid %u leader %u", ch->GetName(), dwPID, m_dwLeaderPID);
				Member.strName = ch->GetName();

				if (Member.bRole == PARTY_ROLE_LEADER)
					m_iLeadership = ch->GetLeadershipSkillLevel();

#ifdef	ENABLE_PARTY_UPDATE
				Member.mapIdx = ch->GetMapIndex();
				Member.channel = g_bChannel;
#endif

			}
			else
			{
				CCI * pcci = P2P_MANAGER::instance().FindByPID(dwPID);

				if (!pcci);
				else if (pcci->bChannel == g_bChannel) {
					Member.strName = pcci->szName;
#ifdef ENABLE_PARTY_UPDATE
					Member.mapIdx = pcci->lMapIndex;
					Member.channel = pcci->bChannel;
#endif
				}
				else
					sys_err("member is not in same channel PID: %u channel %d, this channel %d", dwPID, pcci->bChannel, g_bChannel);
			}
		}

		sys_log(2, "PARTY[%d] MemberCountChange %d -> %d", GetLeaderPID(), GetMemberCount(), GetMemberCount()+1);

		m_memberMap.insert(TMemberMap::value_type(dwPID, Member));

		if (m_memberMap.size() == 1)
			m_itNextOwner = m_memberMap.begin();

		if (m_bPCParty)
		{
			CPartyManager::instance().SetPartyMember(dwPID, this);
			SendPartyJoinOneToAll(dwPID);

			LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(dwPID);

			if (ch)
				SendParameter(ch);
		}
	}

	if (m_pkDungeon)
	{
		m_pkDungeon->QuitParty(this);
	}

#ifdef ENABLE_12ZI
	if (m_pkZodiac)
	{
		m_pkZodiac->QuitParty(this);
	}
#endif
}

void CParty::Join(DWORD dwPID)
{
	P2PJoin(dwPID);

	if (m_bPCParty)
	{
		TPacketPartyAdd p;
		p.dwLeaderPID = GetLeaderPID();
		p.dwPID = dwPID;
		p.bState = PARTY_ROLE_NORMAL; // #0000790: [M2EU] CZ إ©·،½¬ ءُ°،: أت±âب­ ءك؟ن! 
		db_clientdesc->DBPacket(HEADER_GD_PARTY_ADD, 0, &p, sizeof(p));
	}
}

void CParty::P2PQuit(DWORD dwPID)
{
	TMemberMap::iterator it = m_memberMap.find(dwPID);

	if (it == m_memberMap.end())
		return;

	if (m_bPCParty)
		SendPartyRemoveOneToAll(dwPID);

	if (it == m_itNextOwner)
		IncreaseOwnership();

	if (m_bPCParty)
		RemoveBonusForOne(dwPID);

	LPCHARACTER ch = it->second.pCharacter;
	BYTE bRole = it->second.bRole;

	m_memberMap.erase(it);

	sys_log(2, "PARTY[%d] MemberCountChange %d -> %d", GetLeaderPID(), GetMemberCount(), GetMemberCount() - 1);

	if (bRole < PARTY_ROLE_MAX_NUM)
	{
		--m_anRoleCount[bRole];
	}
	else
	{
		sys_err("ROLE_COUNT_QUIT_ERROR: INDEX(%d) > MAX(%d)", bRole, PARTY_ROLE_MAX_NUM);
	}

	if (ch)
	{
		ch->SetParty(NULL);
		ComputeRolePoint(ch, bRole, false);
	}

	if (m_bPCParty)
		CPartyManager::instance().SetPartyMember(dwPID, NULL);

	// ¸®´ُ°، ³ھ°،¸é ئؤئ¼´آ اط»êµا¾î¾ك ار´ظ.
	if (bRole == PARTY_ROLE_LEADER)
		CPartyManager::instance().DeleteParty(this);

	// ہج ¾ئ·،´آ ؤعµه¸¦ أك°،ادءِ ¸» °ح!!! ہ§ DeleteParty اد¸é this´آ ¾ّ´ظ.
}

void CParty::Quit(DWORD dwPID)
{
	// Always PC
	P2PQuit(dwPID);

	if (m_bPCParty && dwPID != GetLeaderPID())
	{
		//TPacketGGParty p;
		//p.header = HEADER_GG_PARTY;
		//p.subheader = PARTY_SUBHEADER_GG_QUIT;
		//p.pid = dwPID;
		//p.leaderpid = GetLeaderPID();
		//P2P_MANAGER::instance().Send(&p, sizeof(p));
		TPacketPartyRemove p;
		p.dwPID = dwPID;
		p.dwLeaderPID = GetLeaderPID();
		db_clientdesc->DBPacket(HEADER_GD_PARTY_REMOVE, 0, &p, sizeof(p));
	}
}

void CParty::Link(LPCHARACTER pkChr)
{
	TMemberMap::iterator it;

	if (pkChr->IsPC())
		it = m_memberMap.find(pkChr->GetPlayerID());
	else
		it = m_memberMap.find(pkChr->GetVID());

	if (it == m_memberMap.end())
	{
		sys_err("%s is not member of this party", pkChr->GetName());
		return;
	}

	// اأ·¹ہج¾î ئؤئ¼ہد °و؟ى ¾÷µ¥ہجئ® ہج؛¥ئ® »‎¼؛
	if (m_bPCParty && !m_eventUpdate)
	{
		party_update_event_info* info = AllocEventInfo<party_update_event_info>();
		info->pid = m_dwLeaderPID;
		m_eventUpdate = event_create(party_update_event, info, PASSES_PER_SEC(3));
	}

	if (it->second.bRole == PARTY_ROLE_LEADER)
		m_pkChrLeader = pkChr;

	sys_log(2, "PARTY[%d] %s linked to party", GetLeaderPID(), pkChr->GetName());

	it->second.pCharacter = pkChr;
	pkChr->SetParty(this);

	if (pkChr->IsPC())
	{
		if (it->second.strName.empty())
		{
			it->second.strName = pkChr->GetName();
		}

		SendPartyJoinOneToAll(pkChr->GetPlayerID());

		SendPartyJoinAllToOne(pkChr);
		SendPartyLinkOneToAll(pkChr);
		SendPartyLinkAllToOne(pkChr);
		SendPartyInfoAllToOne(pkChr);
		SendPartyInfoOneToAll(pkChr);

		SendParameter(pkChr);

		if (GetDungeon() && GetDungeon()->GetMapIndex() == pkChr->GetMapIndex())
		{
			pkChr->SetDungeon(GetDungeon());
		}
#ifdef ENABLE_12ZI
		if (GetZodiac() && GetZodiac()->GetMapIndex() == pkChr->GetMapIndex())
		{
			pkChr->SetZodiac(GetZodiac());
		}
#endif
		RequestSetMemberLevel(pkChr->GetPlayerID(), pkChr->GetLevel());
#ifdef ENABLE_PARTY_UPDATE
		RequestSetMemberMapIndex(pkChr->GetPlayerID(), pkChr->GetMapIndex());
		RequestSetMemberChannel(pkChr->GetPlayerID(), g_bChannel);
#endif

	}
}

void CParty::RequestSetMemberLevel(DWORD pid, BYTE level)
{
	TPacketPartySetMemberLevel p;
	p.dwLeaderPID = GetLeaderPID();
	p.dwPID = pid;
	p.bLevel = level;
	db_clientdesc->DBPacket(HEADER_GD_PARTY_SET_MEMBER_LEVEL, 0, &p, sizeof(TPacketPartySetMemberLevel));
}

void CParty::P2PSetMemberLevel(DWORD pid, BYTE level)
{
	if (!m_bPCParty)
		return;

	TMemberMap::iterator it;

	sys_log(0, "PARTY P2PSetMemberLevel leader %d pid %d level %d", GetLeaderPID(), pid, level);

	it = m_memberMap.find(pid);
	if (it != m_memberMap.end())
	{
		it->second.bLevel = level;
	}
}

#ifdef ENABLE_PARTY_UPDATE
void CParty::RequestSetMemberMapIndex(DWORD pid, long mapIdx)
{
	TPacketPartySetMemberMapIndex p;
	p.dwLeaderPID = GetLeaderPID();
	p.dwPID = pid;
	p.mapIdx = mapIdx;
	db_clientdesc->DBPacket(HEADER_GD_PARTY_SET_MEMBER_MAP_INDEX, 0, &p, sizeof(TPacketPartySetMemberMapIndex));
}

void CParty::P2PSetMemberMapIndex(DWORD pid, long mapIdx)
{
	if (!m_bPCParty)
		return;

	TMemberMap::iterator it;

	sys_log(0, "PARTY P2PSetMemberMapIndex leader %d pid %d mapIdx %d", GetLeaderPID(), pid, mapIdx);

	it = m_memberMap.find(pid);
	if (it != m_memberMap.end())
	{
		it->second.mapIdx = mapIdx;
	}
}

void CParty::RequestSetMemberChannel(DWORD pid, long channel)
{
	TPacketPartySetMemberChannel p;
	p.dwLeaderPID = GetLeaderPID();
	p.dwPID = pid;
	p.channel = channel;
	db_clientdesc->DBPacket(HEADER_GD_PARTY_SET_MEMBER_CHANNEL, 0, &p, sizeof(TPacketPartySetMemberChannel));
}

void CParty::P2PSetMemberChannel(DWORD pid, long channel)
{
	if (!m_bPCParty)
		return;

	TMemberMap::iterator it;

	sys_log(0, "PARTY P2PSetMemberChannel leader %d pid %d ch %d", GetLeaderPID(), pid, channel);

	it = m_memberMap.find(pid);
	if (it != m_memberMap.end())
	{
		it->second.channel = channel;
	}
}
#endif

namespace 
{
	struct FExitDungeon
	{
		void operator()(LPCHARACTER ch)
		{
			ch->ExitToSavedLocation();
		}
	};
}

void CParty::Unlink(LPCHARACTER pkChr)
{
	TMemberMap::iterator it;

	if (pkChr->IsPC())
		it = m_memberMap.find(pkChr->GetPlayerID());
	else
		it = m_memberMap.find(pkChr->GetVID());

	if (it == m_memberMap.end())
	{
		sys_err("%s is not member of this party", pkChr->GetName());
		return;
	}

	if (pkChr->IsPC())
	{
		SendPartyUnlinkOneToAll(pkChr);

		if (it->second.bRole == PARTY_ROLE_LEADER)
		{
			RemoveBonus();

#ifdef ENABLE_12ZI
			if (it->second.pCharacter->GetDungeon() || it->second.pCharacter->GetZodiac())
#else
			if (it->second.pCharacter->GetDungeon())
#endif
			{
				FExitDungeon f;
				ForEachNearMember(f);
			}
		}
	}

	if (it->second.bRole == PARTY_ROLE_LEADER)
		m_pkChrLeader = NULL;

	it->second.pCharacter = NULL;
	pkChr->SetParty(NULL);
}

void CParty::SendPartyRemoveOneToAll(DWORD pid)
{
	TMemberMap::iterator it;

	TPacketGCPartyRemove p;
	p.header = HEADER_GC_PARTY_REMOVE;
	p.pid = pid;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		if (it->second.pCharacter && it->second.pCharacter->GetDesc())
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
	}
}

void CParty::SendPartyJoinOneToAll(DWORD pid)
{
	const TMember& r = m_memberMap[pid];

	TPacketGCPartyAdd p;

	p.header = HEADER_GC_PARTY_ADD;
	p.pid = pid;
	strlcpy(p.name, r.strName.c_str(), sizeof(p.name));
#ifdef ENABLE_PARTY_UPDATE
	p.mapIdx = r.mapIdx;
	p.channel = r.channel;
#endif

	for (TMemberMap::iterator it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		if (it->second.pCharacter && it->second.pCharacter->GetDesc())
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
	}
}

void CParty::SendPartyJoinAllToOne(LPCHARACTER ch)
{
	if (!ch->GetDesc())
		return;
	for (TMemberMap::iterator it = m_memberMap.begin();it!= m_memberMap.end(); ++it)
	{
		CCI *pCCI = P2P_MANAGER::instance().Find(it->second.strName.c_str());
		if (it->second.pCharacter || pCCI)
			UpdateOnlineState(it->first, it->second.strName.c_str(), it->second.channel, it->second.mapIdx);
		else
			UpdateOfflineState(it->first);
	}

}

void CParty::SendPartyUnlinkOneToAll(LPCHARACTER ch)
{
	if (!ch->GetDesc())
		return;

	TMemberMap::iterator it;

	TPacketGCPartyLink p;
	p.header = HEADER_GC_PARTY_UNLINK;
	p.pid = ch->GetPlayerID();
	p.vid = (DWORD)ch->GetVID();

	for (it = m_memberMap.begin();it!= m_memberMap.end(); ++it)
	{
		#ifdef ENABLE_PARTY_UPDATE
		CCI *pCCI = P2P_MANAGER::instance().Find(it->second.strName.c_str());
		if (it->second.pCharacter && it->second.pCharacter->GetDesc())
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
		else if (pCCI)
			pCCI->pkDesc->Packet(&p, sizeof(p));
		#else
		if (it->second.pCharacter && it->second.pCharacter->GetDesc())
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
		#endif
	}
}

void CParty::SendPartyLinkOneToAll(LPCHARACTER ch)
{
	if (!ch->GetDesc())
		return;

	TMemberMap::iterator it;

	TPacketGCPartyLink p;
	p.header = HEADER_GC_PARTY_LINK;
	p.vid = ch->GetVID();
	p.pid = ch->GetPlayerID();
#ifdef ENABLE_PARTY_UPDATE
	p.mapIdx = ch->GetMapIndex();
	p.channel = g_bChannel;
#endif

	for (it = m_memberMap.begin();it!= m_memberMap.end(); ++it)
	{
		#ifdef ENABLE_PARTY_UPDATE
		CCI *pCCI = P2P_MANAGER::instance().Find(it->second.strName.c_str());
		if (it->second.pCharacter && it->second.pCharacter->GetDesc())
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
		else if (pCCI)
			pCCI->pkDesc->Packet(&p, sizeof(p));
		#else
		if (it->second.pCharacter && it->second.pCharacter->GetDesc())
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
		#endif
	}
}

void CParty::SendPartyLinkAllToOne(LPCHARACTER ch)
{
	if (!ch->GetDesc())
		return;

	TMemberMap::iterator it;

	TPacketGCPartyLink p;
	p.header = HEADER_GC_PARTY_LINK;

	for (it = m_memberMap.begin();it!= m_memberMap.end(); ++it)
	{
		if (it->second.pCharacter)
		{
			p.vid = it->second.pCharacter->GetVID();
			p.pid = it->second.pCharacter->GetPlayerID();
#ifdef ENABLE_PARTY_UPDATE
			p.mapIdx = it->second.pCharacter->GetMapIndex();
			p.channel = g_bChannel;
#endif
			ch->GetDesc()->Packet(&p, sizeof(p));
		}
	}
}

void CParty::SendPartyInfoOneToAll(DWORD pid)
{
	TMemberMap::iterator it = m_memberMap.find(pid);

	if (it == m_memberMap.end())
		return;

	if (it->second.pCharacter)
	{
		SendPartyInfoOneToAll(it->second.pCharacter);
		return;
	}

	// Data Building
	TPacketGCPartyUpdate p;
	memset(&p, 0, sizeof(p));
	p.header = HEADER_GC_PARTY_UPDATE;
	p.pid = pid;
	p.percent_hp = 255;
	p.role = it->second.bRole;

	for (it = m_memberMap.begin();it!= m_memberMap.end(); ++it)
	{
		if ((it->second.pCharacter) && (it->second.pCharacter->GetDesc()))
		{
			//sys_log(2, "PARTY send info %s[%d] to %s[%d]", ch->GetName(), (DWORD)ch->GetVID(), it->second.pCharacter->GetName(), (DWORD)it->second.pCharacter->GetVID());
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
		}
	}
}

void CParty::SendPartyInfoOneToAll(LPCHARACTER ch)
{
	if (!ch->GetDesc())
		return;

	TMemberMap::iterator it;

	// Data Building
	TPacketGCPartyUpdate p;
	ch->BuildUpdatePartyPacket(p);

	for (it = m_memberMap.begin();it!= m_memberMap.end(); ++it)
	{
		if ((it->second.pCharacter) && (it->second.pCharacter->GetDesc()))
		{
			sys_log(2, "PARTY send info %s[%d] to %s[%d]", ch->GetName(), (DWORD)ch->GetVID(), it->second.pCharacter->GetName(), (DWORD)it->second.pCharacter->GetVID());
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
		}
	}
}

void CParty::SendPartyInfoAllToOne(LPCHARACTER ch)
{
	TMemberMap::iterator it;

	TPacketGCPartyUpdate p;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		if (!it->second.pCharacter)
		{
			DWORD pid = it->first;
			memset(&p, 0, sizeof(p));
			p.header = HEADER_GC_PARTY_UPDATE;
			p.pid = pid;
			p.percent_hp = 255;
			p.role = it->second.bRole;
			ch->GetDesc()->Packet(&p, sizeof(p));
			continue;
		}

		it->second.pCharacter->BuildUpdatePartyPacket(p);
		sys_log(2, "PARTY send info %s[%d] to %s[%d]", it->second.pCharacter->GetName(), (DWORD)it->second.pCharacter->GetVID(), ch->GetName(), (DWORD)ch->GetVID());
		ch->GetDesc()->Packet(&p, sizeof(p));
	}
}

void CParty::SendMessage(LPCHARACTER ch, BYTE bMsg, DWORD dwArg1, DWORD dwArg2)
{
	if (ch->GetParty() != this)
	{
		sys_err("%s is not member of this party %p", ch->GetName(), this);
		return;
	}

	switch (bMsg)
	{
		case PM_ATTACK:
			break;

		case PM_RETURN:
			{
				TMemberMap::iterator it = m_memberMap.begin();

				while (it != m_memberMap.end())
				{
					TMember & rMember = it->second;
					++it;

					LPCHARACTER pkChr;

					if ((pkChr = rMember.pCharacter) && ch != pkChr)
					{
						DWORD x = dwArg1 + number(-500, 500);
						DWORD y = dwArg2 + number(-500, 500);

						pkChr->SetVictim(NULL);
						pkChr->SetRotationToXY(x, y);

						if (pkChr->Goto(x, y))
						{
							LPCHARACTER victim = pkChr->GetVictim();
							sys_log(0, "%s %p RETURN victim %p", pkChr->GetName(), get_pointer(pkChr), get_pointer(victim));
							pkChr->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
						}
					}
				}
			}
			break;

		case PM_ATTACKED_BY:	// °ّ°ف ¹ق¾زہ½, ¸®´ُ؟،°ش µµ؟ٍہ» ؟نأ»
			{
				// ¸®´ُ°، ¾ّہ» ¶§
				LPCHARACTER pkChrVictim = ch->GetVictim();

				if (!pkChrVictim)
					return;

				TMemberMap::iterator it = m_memberMap.begin();

				while (it != m_memberMap.end())
				{
					TMember & rMember = it->second;
					++it;

					LPCHARACTER pkChr;

					if ((pkChr = rMember.pCharacter) && ch != pkChr)
					{
						if (pkChr->CanBeginFight())
							pkChr->BeginFight(pkChrVictim);
					}
				}
			}
			break;

		case PM_AGGRO_INCREASE:
			{
				LPCHARACTER victim = CHARACTER_MANAGER::instance().Find(dwArg2);

				if (!victim)
					return;

				TMemberMap::iterator it = m_memberMap.begin();

				while (it != m_memberMap.end())
				{
					TMember & rMember = it->second;
					++it;

					LPCHARACTER pkChr;

					if ((pkChr = rMember.pCharacter) && ch != pkChr)
					{
						pkChr->UpdateAggrPoint(victim, DAMAGE_TYPE_SPECIAL, dwArg1);
					}
				}
			}
			break;
	}
}

LPCHARACTER CParty::GetLeaderCharacter()
{
	return m_memberMap[GetLeaderPID()].pCharacter;
}

bool CParty::SetRole(DWORD dwPID, BYTE bRole, bool bSet)
{
	TMemberMap::iterator it = m_memberMap.find(dwPID);

	if (it == m_memberMap.end())
	{
		return false;
	}

	LPCHARACTER ch = it->second.pCharacter;

	if (bSet)
	{
		if (m_anRoleCount[bRole] >= m_anMaxRole[bRole])
			return false;

		if (it->second.bRole != PARTY_ROLE_NORMAL)
			return false;

		it->second.bRole = bRole;

		if (ch && GetLeader())
			ComputeRolePoint(ch, bRole, true);

		if (bRole < PARTY_ROLE_MAX_NUM)
		{
			++m_anRoleCount[bRole];
		}
		else
		{
			sys_err("ROLE_COUNT_INC_ERROR: INDEX(%d) > MAX(%d)", bRole, PARTY_ROLE_MAX_NUM);
		}
	}
	else
	{
		if (it->second.bRole == PARTY_ROLE_LEADER)
			return false;

		if (it->second.bRole == PARTY_ROLE_NORMAL)
			return false;

		it->second.bRole = PARTY_ROLE_NORMAL;

		if (ch && GetLeader())
			ComputeRolePoint(ch, PARTY_ROLE_NORMAL, false);

		if (bRole < PARTY_ROLE_MAX_NUM)
		{
			--m_anRoleCount[bRole];
		}
		else
		{
			sys_err("ROLE_COUNT_DEC_ERROR: INDEX(%d) > MAX(%d)", bRole, PARTY_ROLE_MAX_NUM);
		}
	}

	SendPartyInfoOneToAll(dwPID);
	return true;
}

BYTE CParty::GetRole(DWORD pid)
{
	TMemberMap::iterator it = m_memberMap.find(pid);

	if (it == m_memberMap.end())
		return PARTY_ROLE_NORMAL;
	else
		return it->second.bRole;
}

bool CParty::IsRole(DWORD pid, BYTE bRole)
{
	TMemberMap::iterator it = m_memberMap.find(pid);

	if (it == m_memberMap.end())
		return false;

	return it->second.bRole == bRole;
}

void CParty::RemoveBonus()
{
	TMemberMap::iterator it;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		LPCHARACTER ch;

		if ((ch = it->second.pCharacter))
		{
			ComputeRolePoint(ch, it->second.bRole, false);
		}

		it->second.bNear = false;
	}
}

void CParty::RemoveBonusForOne(DWORD pid)
{
	TMemberMap::iterator it = m_memberMap.find(pid);

	if (it == m_memberMap.end())
		return;

	LPCHARACTER ch;

	if ((ch = it->second.pCharacter))
		ComputeRolePoint(ch, it->second.bRole, false);
}

void CParty::HealParty()
{
	// XXX DELETEME إ¬¶َہج¾ًئ® ؟د·لµة¶§±îءِ
	{
		return;
	}
	if (!m_bPartyHealReady)
		return;

	TMemberMap::iterator it;
	LPCHARACTER l = GetLeaderCharacter();

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		if (!it->second.pCharacter)
			continue;

		LPCHARACTER ch = it->second.pCharacter;

		if (DISTANCE_APPROX(l->GetX()-ch->GetX(), l->GetY()-ch->GetY()) < PARTY_DEFAULT_RANGE)
		{
			ch->PointChange(POINT_HP, ch->GetMaxHP()-ch->GetHP());
			ch->PointChange(POINT_SP, ch->GetMaxSP()-ch->GetSP());
		}
	}

	m_bPartyHealReady = false;
	m_dwPartyHealTime = get_dword_time();
}

void CParty::SummonToLeader(DWORD pid)
{
	int xy[12][2] = 
	{
		{	250,	0		},
		{	216,	125		},
		{	125,	216		},
		{	0,		250		},
		{	-125,	216		},
		{	-216,	125		},
		{	-250,	0		},
		{	-216,	-125	},
		{	-125,	-216	},
		{	0,		-250	},
		{	125,	-216	},
		{	216,	-125	},
	};

	int n = 0;
	int x[12], y[12];

	SECTREE_MANAGER & s = SECTREE_MANAGER::instance();
	LPCHARACTER l = GetLeaderCharacter();

	if (m_memberMap.find(pid) == m_memberMap.end())
	{
		l->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ئؤئ¼> ¼زب¯اد·ء´آ ´ë»َہ» أ£ہ» ¼ِ ¾ّ½ہ´د´ظ."));
		return;
	}

	LPCHARACTER ch = m_memberMap[pid].pCharacter;

	if (!ch)
	{
		l->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ئؤئ¼> ¼زب¯اد·ء´آ ´ë»َہ» أ£ہ» ¼ِ ¾ّ½ہ´د´ظ."));
		return;
	}

	if (ch->IsDead())
	{
		l->ChatPacket(CHAT_TYPE_INFO, " <مجموعة> لا تستطيع سحب شخص ميت ");
		return;
	}

	if (!ch->CanSummon(m_iLeadership))
	{
		l->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ئؤئ¼> ´ë»َہ» ¼زب¯از ¼ِ ¾ّ½ہ´د´ظ."));
		return;
	}

	for (int i = 0; i < 12; ++i)
	{
		PIXEL_POSITION p;

		if (s.GetMovablePosition(l->GetMapIndex(), l->GetX() + xy [i][0], l->GetY() + xy[i][1], p))
		{
			x[n] = p.x;
			y[n] = p.y;
			n++;
		}
	}

	if (n == 0)
		l->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ئؤئ¼> ئؤئ¼؟ّہ» اِہç ہ§ؤ،·خ ¼زب¯از ¼ِ ¾ّ½ہ´د´ظ."));
	else
	{
		int i = number(0, n - 1);
		ch->Show(l->GetMapIndex(), x[i], y[i]);
		ch->Stop();
	}
}

void CParty::IncreaseOwnership()
{
	if (m_memberMap.empty())
	{
		m_itNextOwner = m_memberMap.begin();
		return;
	}

	if (m_itNextOwner == m_memberMap.end())
		m_itNextOwner = m_memberMap.begin();
	else
	{
		m_itNextOwner++;

		if (m_itNextOwner == m_memberMap.end())
			m_itNextOwner = m_memberMap.begin();
	}
}

LPCHARACTER CParty::GetNextOwnership(LPCHARACTER ch, long x, long y)
{
	if (m_itNextOwner == m_memberMap.end())
		return ch;

	int size = m_memberMap.size();

	while (size-- > 0)
	{
		LPCHARACTER pkMember = m_itNextOwner->second.pCharacter;

		if (pkMember && DISTANCE_APPROX(pkMember->GetX() - x, pkMember->GetY() - y) < 3000)
		{
			IncreaseOwnership();
			return pkMember;
		}

		IncreaseOwnership();
	}

	return ch;
}

void CParty::ComputeRolePoint(LPCHARACTER ch, BYTE bRole, bool bAdd)
{
	if (!bAdd)
	{
		bool state = false;
		const DWORD Bonuslar[] =
		{
			POINT_PARTY_ATTACKER_BONUS,
			POINT_PARTY_TANKER_BONUS,
			POINT_PARTY_BUFFER_BONUS,
			POINT_PARTY_SKILL_MASTER_BONUS,
			POINT_PARTY_DEFENDER_BONUS,
			POINT_PARTY_HASTE_BONUS
		};

		for (size_t i = 0; i < sizeof(Bonuslar) / sizeof(DWORD); ++i)
		{
			if (ch->GetPoint(Bonuslar[i]))
			{
				ch->PointChange(Bonuslar[i], -ch->GetPoint(Bonuslar[i]));
				state = true;
			}
		}

		if (state)
		{
			ch->ComputeBattlePoints();
			ch->ComputePoints();
		}
		return;
	}

	float k = (float) ch->GetSkillPowerByLevel( MIN(SKILL_MAX_LEVEL, m_iLeadership ) )/ 100.0f;

	switch (bRole)
	{
		case PARTY_ROLE_ATTACKER:
			{
				int iBonus = (int) (10 + 60 * k);

				if (ch->GetPoint(POINT_PARTY_ATTACKER_BONUS) != iBonus)
				{
					ch->PointChange(POINT_PARTY_ATTACKER_BONUS, iBonus - ch->GetPoint(POINT_PARTY_ATTACKER_BONUS));
					ch->ComputePoints();
				}
			}
			break;

		case PARTY_ROLE_TANKER:
			{
				int iBonus = (int) (50 + 1450 * k);

				if (ch->GetPoint(POINT_PARTY_TANKER_BONUS) != iBonus)
				{
					ch->PointChange(POINT_PARTY_TANKER_BONUS, iBonus - ch->GetPoint(POINT_PARTY_TANKER_BONUS));
					ch->ComputePoints();
				}
			}
			break;

		case PARTY_ROLE_BUFFER:
			{
				int iBonus = (int) (5 + 45 * k);

				if (ch->GetPoint(POINT_PARTY_BUFFER_BONUS) != iBonus)
				{
					ch->PointChange(POINT_PARTY_BUFFER_BONUS, iBonus - ch->GetPoint(POINT_PARTY_BUFFER_BONUS));
				}
			}
			break;

		case PARTY_ROLE_SKILL_MASTER:
			{
				int iBonus = (int) (25 + 600 * k);

				if (ch->GetPoint(POINT_PARTY_SKILL_MASTER_BONUS) != iBonus)
				{
					ch->PointChange(POINT_PARTY_SKILL_MASTER_BONUS, iBonus - ch->GetPoint(POINT_PARTY_SKILL_MASTER_BONUS));
					ch->ComputePoints();
				}
			}
			break;
		case PARTY_ROLE_HASTE:
			{
				int iBonus = (int) (1+5*k);
				if (ch->GetPoint(POINT_PARTY_HASTE_BONUS) != iBonus)
				{
					ch->PointChange(POINT_PARTY_HASTE_BONUS, iBonus - ch->GetPoint(POINT_PARTY_HASTE_BONUS));
					ch->ComputePoints();
				}
			}
			break;
		case PARTY_ROLE_DEFENDER:
			{
				int iBonus = (int) (5+30*k);
				if (ch->GetPoint(POINT_PARTY_DEFENDER_BONUS) != iBonus)
				{
					ch->PointChange(POINT_PARTY_DEFENDER_BONUS, iBonus - ch->GetPoint(POINT_PARTY_DEFENDER_BONUS));
					ch->ComputePoints();
				}
			}
			break;
	}
}

void CParty::Update()
{
	sys_log(1, "PARTY::Update");

	LPCHARACTER l = GetLeaderCharacter();

	if (!l)
		return;

	TMemberMap::iterator it;

	int iNearMember = 0;
	bool bResendAll = false;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		LPCHARACTER ch = it->second.pCharacter;

		it->second.bNear = false;

		if (!ch)
			continue;

		if (l->GetDungeon())
			it->second.bNear = l->GetDungeon() == ch->GetDungeon();
#ifdef ENABLE_12ZI
		else if (l->GetZodiac())
			it->second.bNear = l->GetZodiac() == ch->GetZodiac();
#endif
		else
			it->second.bNear = (DISTANCE_APPROX(l->GetX()-ch->GetX(), l->GetY()-ch->GetY()) < PARTY_DEFAULT_RANGE);

		if (it->second.bNear)
		{
			++iNearMember;
		}
	}

	if (iNearMember <= 1 && !l->GetDungeon())
	{
		for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
			it->second.bNear = false;

		iNearMember = 0;
	}

#ifdef ENABLE_12ZI
	if (iNearMember <= 1 && !l->GetZodiac())
	{
		for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
			it->second.bNear = false;

		iNearMember = 0;
	}
#endif

	if (iNearMember != m_iCountNearPartyMember)
	{
		m_iCountNearPartyMember = iNearMember;
		bResendAll = true;
	}

	m_iLeadership = l->GetLeadershipSkillLevel();
	int iNewExpBonus = ComputePartyBonusExpPercent();
	m_iAttBonus = ComputePartyBonusAttackGrade();
	m_iDefBonus = ComputePartyBonusDefenseGrade();

	if (m_iExpBonus != iNewExpBonus)
	{
		bResendAll = true;
		m_iExpBonus = iNewExpBonus;
	}

	bool bLongTimeExpBonusChanged = false;

	// ئؤئ¼ °ل¼؛ بؤ أو؛ذار ½أ°£ہج ءِ³ھ¸é °واèؤ، ؛¸³ت½؛¸¦ ¹ق´آ´ظ.
	if (!m_iLongTimeExpBonus && (get_dword_time() - m_dwPartyStartTime > PARTY_ENOUGH_MINUTE_FOR_EXP_BONUS * 60 * 1000 / (g_iUseLocale?1:2)))
	{
		bLongTimeExpBonusChanged = true;
		m_iLongTimeExpBonus = 5;
		bResendAll = true;
	}

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		LPCHARACTER ch = it->second.pCharacter;

		if (!ch)
			continue;

		if (bLongTimeExpBonusChanged && ch->GetDesc())
			ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ئؤئ¼ہا اùµ؟·آہج ³ô¾ئء® ءِ±ف؛خإح أك°، °واèؤ، ؛¸³ت½؛¸¦ ¹ق½ہ´د´ظ."));

		bool bNear = it->second.bNear;

		ComputeRolePoint(ch, it->second.bRole, bNear);

		if (bNear)
		{
			if (!bResendAll)
				SendPartyInfoOneToAll(ch);
		}
	}

	// PARTY_ROLE_LIMIT_LEVEL_BUG_FIX
	m_anMaxRole[PARTY_ROLE_ATTACKER]	 = m_iLeadership >= 10 ? 1 : 0;
	m_anMaxRole[PARTY_ROLE_HASTE]	 = m_iLeadership >= 20 ? 1 : 0;
	m_anMaxRole[PARTY_ROLE_TANKER]	 = m_iLeadership >= 20 ? 1 : 0;
	m_anMaxRole[PARTY_ROLE_BUFFER]	 = m_iLeadership >= 25 ? 1 : 0;
	m_anMaxRole[PARTY_ROLE_SKILL_MASTER] = m_iLeadership >= 35 ? 1 : 0;
	m_anMaxRole[PARTY_ROLE_DEFENDER] 	 = m_iLeadership >= 40 ? 1 : 0;
	m_anMaxRole[PARTY_ROLE_ATTACKER]	+= m_iLeadership >= 40 ? 1 : 0;
	// END_OF_PARTY_ROLE_LIMIT_LEVEL_BUG_FIX

	// Party Heal Update
	if (!m_bPartyHealReady)
	{
		if (!m_bCanUsePartyHeal && m_iLeadership >= 18)
			m_dwPartyHealTime = get_dword_time();

		m_bCanUsePartyHeal = m_iLeadership >= 18; // إë¼ض·آ 18 ہج»َہ؛ بْہ» »ç؟ëاز ¼ِ ہضہ½.

		// إë¼ض·آ 40ہج»َہ؛ ئؤئ¼ بْ ؤًإ¸ہسہج ہû´ظ.
		DWORD PartyHealCoolTime = (m_iLeadership >= 40) ? PARTY_HEAL_COOLTIME_SHORT * 60 * 1000 : PARTY_HEAL_COOLTIME_LONG * 60 * 1000;

		if (m_bCanUsePartyHeal)
		{
			if (get_dword_time() > m_dwPartyHealTime + PartyHealCoolTime)
			{
				m_bPartyHealReady = true;

				// send heal ready
				if (0) // XXX  DELETEME إ¬¶َہج¾ًئ® ؟د·لµة¶§±îءِ
					if (GetLeaderCharacter())
						GetLeaderCharacter()->ChatPacket(CHAT_TYPE_COMMAND, "PartyHealReady");
			}
		}
	}

	if (bResendAll)
	{
		for (TMemberMap::iterator it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
			if (it->second.pCharacter)
				SendPartyInfoOneToAll(it->second.pCharacter);
	}
}

#ifdef ENABLE_PARTY_UPDATE
void CParty::UpdateOnlineState(DWORD dwPID, const char* name, long mapIdx, long channel)
#else
void CParty::UpdateOnlineState(DWORD dwPID, const char* name)
#endif
{
	TMember& r = m_memberMap[dwPID];

	TPacketGCPartyAdd p;

	p.header = HEADER_GC_PARTY_ADD;
	p.pid = dwPID;
	r.strName = name;
	strlcpy(p.name, name, sizeof(p.name));
#ifdef ENABLE_PARTY_UPDATE
	p.mapIdx = mapIdx;
	p.channel = channel;
#endif

	for (TMemberMap::iterator it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		#ifdef ENABLE_PARTY_UPDATE
		CCI *pCCI = P2P_MANAGER::instance().Find(it->second.strName.c_str());
		if (it->second.pCharacter && it->second.pCharacter->GetDesc())
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
		else if (pCCI)
			pCCI->pkDesc->Packet(&p, sizeof(p));
		#else	
		if (it->second.pCharacter && it->second.pCharacter->GetDesc())
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
		#endif
	}
}

void CParty::UpdateOfflineState(DWORD dwPID)
{
	//const TMember& r = m_memberMap[dwPID];

	TPacketGCPartyAdd p;
	p.header = HEADER_GC_PARTY_ADD;
	p.pid = dwPID;
	memset(p.name, 0, CHARACTER_NAME_MAX_LEN+1);
#ifdef ENABLE_PARTY_UPDATE
	p.mapIdx = 0;
	p.channel = 0;
#endif

	for (TMemberMap::iterator it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		#ifdef ENABLE_PARTY_UPDATE
		CCI *pCCI = P2P_MANAGER::instance().Find(it->second.strName.c_str());
		if (it->second.pCharacter && it->second.pCharacter->GetDesc())
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
		else if (pCCI)
			pCCI->pkDesc->Packet(&p, sizeof(p));
		#else	
		if (it->second.pCharacter && it->second.pCharacter->GetDesc())
			it->second.pCharacter->GetDesc()->Packet(&p, sizeof(p));
		#endif
	}
}

int CParty::GetFlag(const std::string& name)
{
	TFlagMap::iterator it = m_map_iFlag.find(name);

	if (it != m_map_iFlag.end())
	{
		//sys_log(0,"PARTY GetFlag %s %d", name.c_str(), it->second);
		return it->second;
	}

	//sys_log(0,"PARTY GetFlag %s 0", name.c_str());
	return 0;
}

void CParty::SetFlag(const std::string& name, int value)
{
	TFlagMap::iterator it = m_map_iFlag.find(name);

	//sys_log(0,"PARTY SetFlag %s %d", name.c_str(), value);
	if (it == m_map_iFlag.end())
	{
		m_map_iFlag.insert(make_pair(name, value));
	}
	else if (it->second != value)
	{
		it->second = value;
	}
}

void CParty::SetDungeon(LPDUNGEON pDungeon)
{
	m_pkDungeon = pDungeon;
	m_map_iFlag.clear();
}

LPDUNGEON CParty::GetDungeon()
{
	return m_pkDungeon;
}

void CParty::SetDungeon_for_Only_party(LPDUNGEON pDungeon)
{
	m_pkDungeon_for_Only_party = pDungeon;
}

LPDUNGEON CParty::GetDungeon_for_Only_party()
{
	return m_pkDungeon_for_Only_party;
}

#ifdef ENABLE_12ZI
void CParty::SetZodiac(LPZODIAC pZodiac)
{
	m_pkZodiac = pZodiac;
	m_map_iFlag.clear();
}

LPZODIAC CParty::GetZodiac()
{
	return m_pkZodiac;
}

void CParty::SetZodiac_for_Only_party(LPZODIAC pZodiac)
{
	m_pkZodiac_for_Only_party = pZodiac;
}

LPZODIAC CParty::GetZodiac_for_Only_party()
{
	return m_pkZodiac_for_Only_party;
}
#endif

bool CParty::IsPositionNearLeader(LPCHARACTER ch)
{
	if (!m_pkChrLeader)
		return false;

	if (DISTANCE_APPROX(ch->GetX() - m_pkChrLeader->GetX(), ch->GetY() - m_pkChrLeader->GetY()) >= PARTY_DEFAULT_RANGE)
		return false;

	return true;
}


int CParty::GetExpBonusPercent()
{
	if (GetNearMemberCount() <= 1)
		return 0;

	return m_iExpBonus + m_iLongTimeExpBonus;
}

bool CParty::IsNearLeader(DWORD pid)
{
	TMemberMap::iterator it = m_memberMap.find(pid);

	if (it == m_memberMap.end())
		return false;    

	return it->second.bNear;
}

BYTE CParty::CountMemberByVnum(DWORD dwVnum)
{
	if (m_bPCParty)
		return 0;

	LPCHARACTER tch;
	BYTE bCount = 0;

	TMemberMap::iterator it;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		if (!(tch = it->second.pCharacter))
			continue;

		if (tch->IsPC())
			continue;

		if (tch->GetMobTable().dwVnum == dwVnum)
			++bCount;
	}

	return bCount;
}

void CParty::SendParameter(LPCHARACTER ch)
{
	TPacketGCPartyParameter p;

	p.bHeader = HEADER_GC_PARTY_PARAMETER;
	p.bDistributeMode = m_iExpDistributionMode;

	LPDESC d = ch->GetDesc();

	if (d)
	{
		d->Packet(&p, sizeof(TPacketGCPartyParameter));
	}
}

void CParty::SendParameterToAll()
{
	if (!m_bPCParty)
		return;

	TMemberMap::iterator it;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
		if (it->second.pCharacter)
			SendParameter(it->second.pCharacter);
}

void CParty::SetParameter(int iMode)
{
	if (iMode >= PARTY_EXP_DISTRIBUTION_MAX_NUM)
	{
		sys_err("Invalid exp distribution mode %d", iMode);
		return;
	}

	m_iExpDistributionMode = iMode;
	SendParameterToAll();
}

int CParty::GetExpDistributionMode()
{
	return m_iExpDistributionMode;
}

void CParty::SetExpCentralizeCharacter(DWORD dwPID)
{
	TMemberMap::iterator it = m_memberMap.find(dwPID);

	if (it == m_memberMap.end())
		return;

	m_pkChrExpCentralize = it->second.pCharacter;
}

LPCHARACTER CParty::GetExpCentralizeCharacter()
{
	return m_pkChrExpCentralize;
}

BYTE CParty::GetMemberMaxLevel()
{
	BYTE bMax = 0;

	itertype(m_memberMap) it = m_memberMap.begin();
	while (it!=m_memberMap.end())
	{
		if (!it->second.bLevel)
		{
			++it;
			continue;
		}

		if (!bMax)
			bMax = it->second.bLevel;
		else if (it->second.bLevel)
			bMax = MAX(bMax, it->second.bLevel);
		++it;
	}
	return bMax;
}

BYTE CParty::GetMemberMinLevel()
{
	BYTE bMin = PLAYER_MAX_LEVEL_CONST;

	itertype(m_memberMap) it = m_memberMap.begin();
	while (it!=m_memberMap.end())
	{
		if (!it->second.bLevel)
		{
			++it;
			continue;
		}

		if (!bMin)
			bMin = it->second.bLevel;
		else if (it->second.bLevel)
			bMin = MIN(bMin, it->second.bLevel);
		++it;
	}
	return bMin;
}

int CParty::ComputePartyBonusExpPercent()
{
	if (GetNearMemberCount() <= 1)
		return 0;

	LPCHARACTER leader = GetLeaderCharacter();

	int iBonusPartyExpFromItem = 0;

	// UPGRADE_PARTY_BONUS
	int iMemberCount=MIN(8, GetNearMemberCount());

	if (leader && (leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP) || leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP_MALL)
		|| leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP_GIFT) || leader->IsEquipUniqueGroup(10010)))
	{
		// ءك±¹أّ ہ°µµ ہû؟ëہ» ب®ہخاط¾كار´ظ.
		if (g_iUseLocale)
		{
			iBonusPartyExpFromItem = 30;
		}
		else
		{
			iBonusPartyExpFromItem = KOR_aiUniqueItemPartyBonusExpPercentByMemberCount[iMemberCount];
		}
	}

	if (g_iUseLocale)
		return iBonusPartyExpFromItem + CHN_aiPartyBonusExpPercentByMemberCount[iMemberCount];
	else
		return iBonusPartyExpFromItem + KOR_aiPartyBonusExpPercentByMemberCount[iMemberCount];
	// END_OF_UPGRADE_PARTY_BONUS
}

party.h

Spoiler
#ifndef __INC_METIN_II_GAME_PARTY_H__
#define __INC_METIN_II_GAME_PARTY_H__

#include "char.h"

enum // unit : minute
{
	PARTY_ENOUGH_MINUTE_FOR_EXP_BONUS = 60, // ئؤئ¼ °ل¼؛ بؤ 60؛ذ بؤ ؛خإح أك°، °واèؤ، ؛¸³ت½؛
	PARTY_HEAL_COOLTIME_LONG = 60,
	PARTY_HEAL_COOLTIME_SHORT = 30,
	PARTY_MAX_MEMBER = 8,
	PARTY_DEFAULT_RANGE = 5000,
};

enum EPartyRole
{   
	PARTY_ROLE_NORMAL,  
	PARTY_ROLE_LEADER,
	PARTY_ROLE_ATTACKER,
	PARTY_ROLE_TANKER,
	PARTY_ROLE_BUFFER,  
	PARTY_ROLE_SKILL_MASTER,
	PARTY_ROLE_HASTE,   
	PARTY_ROLE_DEFENDER,
	PARTY_ROLE_MAX_NUM, 
};  

enum EPartyExpDistributionModes
{
	PARTY_EXP_DISTRIBUTION_NON_PARITY,
	PARTY_EXP_DISTRIBUTION_PARITY,
	PARTY_EXP_DISTRIBUTION_MAX_NUM
};

class CParty;
class CDungeon;
#ifdef ENABLE_12ZI
class CZodiac;
#endif

class CPartyManager : public singleton<CPartyManager>
{
	public:
		typedef std::map<DWORD, LPPARTY> TPartyMap;
		typedef std::set<LPPARTY> TPCPartySet;

	public:
		CPartyManager();
		virtual ~CPartyManager();

		void		Initialize();

		//void		SendPartyToDB();

		void		EnablePCParty() { m_bEnablePCParty = true; sys_log(0,"PARTY Enable"); }
		void		DisablePCParty() { m_bEnablePCParty = false; sys_log(0,"PARTY Disable"); }
		bool		IsEnablePCParty() { return m_bEnablePCParty; }

		LPPARTY		CreateParty(LPCHARACTER pkLeader);
		void		DeleteParty(LPPARTY pParty);
		void		DeleteAllParty();
		bool		SetParty(LPCHARACTER pkChr);

		void		SetPartyMember(DWORD dwPID, LPPARTY pParty);

#ifdef ENABLE_PARTY_UPDATE
		void		P2PLogin(DWORD pid, const char* name, long mapIdx, long channel);
#else
		void		P2PLogin(DWORD pid, const char* name);	
#endif
		void		P2PLogout(DWORD pid);

		LPPARTY		P2PCreateParty(DWORD pid);
		void		P2PDeleteParty(DWORD pid);
		void		P2PJoinParty(DWORD leader, DWORD pid, BYTE role = 0);
		void		P2PQuitParty(DWORD pid);

	private:
		TPartyMap	m_map_pkParty;		// PID·خ ¾î´ہ ئؤئ¼؟، ہض³ھ °ث»ِاد±â ہ§ار ؤءإ×ہج³ت
		TPartyMap	m_map_pkMobParty;	// Mob ئؤئ¼´آ PID ´ë½إ VID ·خ µû·خ °ü¸®ار´ظ.

		TPCPartySet	m_set_pkPCParty;	// »ç¶÷µéہا ئؤئ¼ ہüأ¼ ء‎اص

		bool		m_bEnablePCParty;	// µً؛ٌ°، ؤرء®ہضءِ ¾تہ¸¸é »ç¶÷µéہا ئؤئ¼ »َإآ°، ؛¯°و؛ز°،
};

enum EPartyMessages
{
	PM_ATTACK,		// Attack him
	PM_RETURN,		// Return back to position
	PM_ATTACKED_BY,	// I was attacked by someone
	PM_AGGRO_INCREASE,	// My aggro is increased
};

class CParty
{
	public:
		typedef struct SMember
		{
			LPCHARACTER	pCharacter;
			bool	bNear;
			BYTE	bRole;
			BYTE	bLevel;
			std::string strName;
#ifdef ENABLE_PARTY_UPDATE
			long	mapIdx;
			long	channel;
#endif
		} TMember;

		typedef std::map<DWORD, TMember> TMemberMap;

		typedef std::map<std::string, int> TFlagMap;

	public:
		CParty();
		virtual ~CParty();

		void		P2PJoin(DWORD dwPID);
		void		P2PQuit(DWORD dwPID);
		virtual void	Join(DWORD dwPID);
		void		Quit(DWORD dwPID);
		void		Link(LPCHARACTER pkChr);
		void		Unlink(LPCHARACTER pkChr);

		void		ChatPacketToAllMember(BYTE type, const char* format, ...);

#ifdef ENABLE_PARTY_UPDATE
		void		UpdateOnlineState(DWORD dwPID, const char* name, long mapIdx, long channel);
#else
		void		UpdateOnlineState(DWORD dwPID, const char* name);
#endif
		void		UpdateOfflineState(DWORD dwPID);

		DWORD		GetLeaderPID();
		LPCHARACTER	GetLeaderCharacter();
		LPCHARACTER	GetLeader() { return m_pkChrLeader; }

		DWORD		GetMemberCount();
		DWORD		GetNearMemberCount()	{ return m_iCountNearPartyMember; }

		bool		IsMember(DWORD pid) { return m_memberMap.find(pid) != m_memberMap.end(); }

		bool		IsNearLeader(DWORD pid);

		bool		IsPositionNearLeader(LPCHARACTER ch);

		void		SendMessage(LPCHARACTER ch, BYTE bMsg, DWORD dwArg1, DWORD dwArg2);

		void		SendPartyJoinOneToAll(DWORD dwPID);
		void		SendPartyJoinAllToOne(LPCHARACTER ch);
		void		SendPartyRemoveOneToAll(DWORD dwPID);

		void		SendPartyInfoOneToAll(DWORD pid);
		void		SendPartyInfoOneToAll(LPCHARACTER ch);
		void		SendPartyInfoAllToOne(LPCHARACTER ch);

		void		SendPartyLinkOneToAll(LPCHARACTER ch);
		void		SendPartyLinkAllToOne(LPCHARACTER ch);
		void		SendPartyUnlinkOneToAll(LPCHARACTER ch);

		int		GetPartyBonusExpPercent()	{ return m_iExpBonus; }
		int		GetPartyBonusAttackGrade()	{ return m_iAttBonus; }
		int		GetPartyBonusDefenseGrade()	{ return m_iDefBonus; }

		int	ComputePartyBonusExpPercent();
		inline int	ComputePartyBonusAttackGrade();
		inline int	ComputePartyBonusDefenseGrade();

		template <class Func> void ForEachMember(Func & f);
		template <class Func> void ForEachMemberPtr(Func & f);
		template <class Func> void ForEachOnlineMember(Func & f);
		template <class Func> void ForEachNearMember(Func & f);
		template <class Func> void ForEachOnMapMember (Func & f, long lMapIndex);
		template <class Func> bool ForEachOnMapMemberBool (Func & f, long lMapIndex);

		void		Update();

		int		GetExpBonusPercent();

		bool		SetRole(DWORD pid, BYTE bRole, bool on);
		BYTE		GetRole(DWORD pid);
		bool		IsRole(DWORD pid, BYTE bRole);

		BYTE		GetMemberMaxLevel();
		BYTE		GetMemberMinLevel();

		void		ComputeRolePoint(LPCHARACTER ch, BYTE bRole, bool bAdd);

		void		HealParty();
		void		SummonToLeader(DWORD pid);

		void		SetPCParty(bool b) { m_bPCParty = b; }

		LPCHARACTER	GetNextOwnership(LPCHARACTER ch, long x, long y);

		void		SetFlag(const std::string& name, int value);
		int		GetFlag(const std::string& name);

		void		SetDungeon(LPDUNGEON pDungeon);
		LPDUNGEON	GetDungeon();
#ifdef ENABLE_12ZI
		void		SetZodiac(LPZODIAC pZodiac);
		LPZODIAC	GetZodiac();
#endif
		BYTE		CountMemberByVnum(DWORD dwVnum);

		void		SetParameter(int iMode);
		int		GetExpDistributionMode();

		void		SetExpCentralizeCharacter(DWORD pid);
		LPCHARACTER	GetExpCentralizeCharacter();

		void		RequestSetMemberLevel(DWORD pid, BYTE level);
		void		P2PSetMemberLevel(DWORD pid, BYTE level);

#ifdef ENABLE_PARTY_UPDATE
		void		RequestSetMemberMapIndex(DWORD pid, long mapIdx);
		void		P2PSetMemberMapIndex(DWORD pid, long mapIdx);
		
		void		RequestSetMemberChannel(DWORD pid, long channel);
		void		P2PSetMemberChannel(DWORD pid, long channel);
#endif

	protected:
		void		IncreaseOwnership();

		virtual void	Initialize();
		void		Destroy();
		void		RemovePartyBonus();

		void		RemoveBonus();
		void		RemoveBonusForOne(DWORD pid);

		void		SendParameter(LPCHARACTER ch);
		void		SendParameterToAll();

		TMemberMap	m_memberMap;
		DWORD		m_dwLeaderPID;
		LPCHARACTER	m_pkChrLeader;

		LPEVENT		m_eventUpdate;

		TMemberMap::iterator m_itNextOwner;

	private:
		int		m_iExpDistributionMode;
		LPCHARACTER	m_pkChrExpCentralize;

		DWORD		m_dwPartyStartTime;

		DWORD		m_dwPartyHealTime;
		bool		m_bPartyHealReady;
		bool		m_bCanUsePartyHeal;

		int		m_anRoleCount[PARTY_ROLE_MAX_NUM];
		int		m_anMaxRole[PARTY_ROLE_MAX_NUM];

		int		m_iLongTimeExpBonus;

		// used in Update
		int		m_iLeadership;
		int		m_iExpBonus;
		int		m_iAttBonus;
		int		m_iDefBonus;

		int		m_iCountNearPartyMember;

		bool		m_bPCParty;

		TFlagMap	m_map_iFlag;

		LPDUNGEON	m_pkDungeon;

		LPDUNGEON	m_pkDungeon_for_Only_party;
#ifdef ENABLE_12ZI
		LPZODIAC	m_pkZodiac;
		LPZODIAC	m_pkZodiac_for_Only_party;
#endif
	public:
		void SetDungeon_for_Only_party(LPDUNGEON pDungeon);
		LPDUNGEON GetDungeon_for_Only_party();
#ifdef ENABLE_12ZI
		void SetZodiac_for_Only_party(LPZODIAC pZodiac);
		LPZODIAC GetZodiac_for_Only_party();
#endif
};

template <class Func> void CParty::ForEachMember(Func & f)
{
	TMemberMap::iterator it;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
		f(it->first);
}

template <class Func> void CParty::ForEachMemberPtr(Func & f)
{
	TMemberMap::iterator it;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
		f(it->second.pCharacter);
}

template <class Func> void CParty::ForEachOnlineMember(Func & f)
{
	TMemberMap::iterator it;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
		if (it->second.pCharacter)
			f(it->second.pCharacter);
}

template <class Func> void CParty::ForEachNearMember(Func & f)
{
	TMemberMap::iterator it;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
		if (it->second.pCharacter && it->second.bNear)
			f(it->second.pCharacter);
}

template <class Func> void CParty::ForEachOnMapMember (Func & f, long lMapIndex)
{
	TMemberMap::iterator it;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		LPCHARACTER ch = it->second.pCharacter;
		if (ch)
		{
			if (ch->GetMapIndex () == lMapIndex)
				f(ch);
		}
	}
}

template <class Func> bool CParty::ForEachOnMapMemberBool(Func & f, long lMapIndex)
{
	TMemberMap::iterator it;

	for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
	{
		LPCHARACTER ch = it->second.pCharacter;
		if (ch)
		{
			if (ch->GetMapIndex () == lMapIndex)
			{
				if(f(ch) == false)
				{
					return false;
			
				}
			}
		}
	}
	return true;
}

inline int CParty::ComputePartyBonusAttackGrade()
{
	/*
	   if (GetNearMemberCount() <= 1)
	   return 0;

	   int leadership = GetLeaderCharacter()->GetLeadershipSkillLevel();
	   int n = GetNearMemberCount();

	   if (n >= 3 && leadership >= 10)
	   return 2;

	   if (n >= 2 && leadership >= 4)
	   return 1;
	 */
	return 0;
}

inline int CParty::ComputePartyBonusDefenseGrade()
{
	/*
	   if (GetNearMemberCount() <= 1)
	   return 0;

	   int leadership = GetLeaderCharacter()->GetLeadershipSkillLevel();
	   int n = GetNearMemberCount();

	   if (n >= 5 && leadership >= 24)
	   return 2;

	   if (n >= 4 && leadership >= 16)
	   return 1;
	 */
	return 0;
}
#endif

#ifdef ENABLE_ENABLE_DICE_SYSTEM
#include "item.h"

struct FPartyDropDiceRoll
{
	const LPITEM m_itemDrop;
	LPCHARACTER m_itemOwner;
	int m_lastNumber;

	FPartyDropDiceRoll(const LPITEM itemDrop, LPCHARACTER itemOwner) : m_itemDrop(itemDrop), m_itemOwner(itemOwner), m_lastNumber(0)
	{
	};

	void Process(const LPCHARACTER mobVictim)
	{
		if ((!mobVictim || (mobVictim->GetMobRank() >= MOB_RANK_BOSS && mobVictim->GetMobRank() <= MOB_RANK_KING)) && m_itemOwner->GetParty() && m_itemOwner->GetParty()->GetNearMemberCount() > 1)
		{
			LPPARTY pParty = m_itemOwner->GetParty();
			pParty->ChatPacketToAllMember(CHAT_TYPE_DICE_INFO, LC_TEXT("*** Rolling for the following item: %16s ***"), m_itemDrop->GetName());

			pParty->ForEachNearMember(*this);
			if (m_itemOwner)
			{
				m_itemDrop->SetOwnership(m_itemOwner);
				pParty->ChatPacketToAllMember(CHAT_TYPE_DICE_INFO, LC_TEXT("*** Rolling of %s: %16s ***"), m_itemDrop->GetName(), m_itemOwner->GetName());
			}
		}
		else
			m_itemDrop->SetOwnership(m_itemOwner);
	}
	LPCHARACTER GetItemOwner()
	{
		return m_itemOwner;
	}
	const LPITEM GetItemDrop()
	{
		return m_itemDrop;
	}
	void operator () (LPCHARACTER ch)
	{
		if (!ch)
			return;

		LPPARTY pParty = ch->GetParty();
		if (!pParty)
			return;

		while (true)
		{
			int pickedNumber = number(10000, 99999);
			if (pickedNumber > m_lastNumber)
			{
				m_lastNumber = pickedNumber;
				m_itemOwner = ch;
			}
			else if (pickedNumber == m_lastNumber)
			{
				continue;
			}
			else // if (pickedNumber < m_lastNumber)
			{
			}
			pParty->ChatPacketToAllMember(CHAT_TYPE_DICE_INFO, LC_TEXT("*** -> %16s - Dice score: %05d ***"), ch->GetName(), pickedNumber);
			break;
		}
	}
};
#endif

 

 

  • Metin2 Dev 1
  • Not Good 1
  • Good 1
  • Love 2
Link to comment
Share on other sites

Announcements



×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.