Jump to content

Hysteria

Inactive Member
  • Posts

    22
  • Joined

  • Last visited

  • Feedback

    0%

Posts posted by Hysteria

  1. this is the best fix if someone need it

    	void CQuestManager::CancelServerTimers(DWORD arg)
    	{
    		itertype(m_mapServerTimer) it = m_mapServerTimer.begin();
       
    		for (; it != m_mapServerTimer.end(); )
    		{
    			if (it->first.second == arg)
    			{
    				LPEVENT event = it->second;
    				event_cancel(&event);
    				m_mapServerTimer.erase(it++);
    			}
    			else
    				++it;
    		}
    	}

     

    • Love 1
  2. fix highlight system : find 

    			AutoGiveItem(getitem->GetVnum(), getitem->GetCount(), -1, false);
    			M2_DESTROY_ITEM(getitem);
    		}
    		else
    			AutoGiveItem(getitem);

    change with 

    #ifdef ENABLE_HIGHLIGHT_SYSTEM
    				AutoGiveItem(getitem->GetVnum(), getitem->GetCount(), -1, false, false);
    				M2_DESTROY_ITEM(getitem);
    #else
    				AutoGiveItem(getitem->GetVnum(), getitem->GetCount(), -1, false);
    				M2_DESTROY_ITEM(getitem);
    #endif		}
    			else
    #ifdef ENABLE_HIGHLIGHT_SYSTEM
    				AutoGiveItem(getitem, false, false);
    #else
    				AutoGiveItem(getitem, false);
    #endif

    not tested

  3. 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
×
×
  • 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.