2008-10-11 14:16:25 -05:00
/*
2009-02-01 16:38:53 -06:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2010-01-16 20:19:18 +03:00
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
2008-10-11 14:16:25 -05:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
2009-02-01 16:38:53 -06:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-11 14:16:25 -05:00
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
2009-02-01 16:38:53 -06:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-11 14:16:25 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
#include "Common.h"
#include "Opcodes.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Player.h"
#include "World.h"
#include "ObjectMgr.h"
#include "Group.h"
2008-10-26 11:50:07 -05:00
#include "Formulas.h"
2008-10-11 14:16:25 -05:00
#include "ObjectAccessor.h"
2010-08-08 04:37:24 +02:00
#include "Battleground.h"
#include "BattlegroundMgr.h"
2008-10-11 14:16:25 -05:00
#include "MapManager.h"
#include "InstanceSaveMgr.h"
#include "MapInstanced.h"
#include "Util.h"
2010-05-31 20:25:21 +02:00
#include "LFGMgr.h"
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Group :: Group ()
{
m_leaderGuid = 0 ;
2010-05-08 01:58:47 +02:00
m_groupType = GroupType ( 0 );
2008-10-11 14:16:25 -05:00
m_bgGroup = NULL ;
2010-05-08 01:58:47 +02:00
m_lootMethod = LootMethod ( 0 );
2008-10-11 14:16:25 -05:00
m_looterGuid = 0 ;
m_lootThreshold = ITEM_QUALITY_UNCOMMON ;
2009-02-01 16:38:53 -06:00
m_subGroupsCounts = NULL ;
2010-05-21 14:19:47 +02:00
m_guid = 0 ;
m_counter = 0 ;
2010-05-21 22:45:47 +02:00
m_maxEnchantingLevel = 0 ;
2010-08-11 15:20:20 +02:00
m_LfgQueued = false ;
2010-08-11 15:55:27 +02:00
m_LfgStatus = LFG_STATUS_NOT_SAVED ;
2010-08-11 15:20:20 +02:00
m_LfgDungeonEntry = 0 ;
2010-08-13 15:38:10 +02:00
m_Lfgkicks = 0 ;
m_LfgkicksActive = false ;
2009-10-17 15:51:44 -07:00
2010-05-08 01:58:47 +02:00
for ( uint8 i = 0 ; i < TARGETICONCOUNT ; ++ i )
2008-10-11 14:16:25 -05:00
m_targetIcons [ i ] = 0 ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Group ::~ Group ()
{
2010-04-07 19:14:10 +02:00
if ( m_bgGroup )
2008-10-11 14:16:25 -05:00
{
sLog . outDebug ( "Group::~Group: battleground group being deleted." );
2010-04-07 19:14:10 +02:00
if ( m_bgGroup -> GetBgRaid ( ALLIANCE ) == this ) m_bgGroup -> SetBgRaid ( ALLIANCE , NULL );
else if ( m_bgGroup -> GetBgRaid ( HORDE ) == this ) m_bgGroup -> SetBgRaid ( HORDE , NULL );
2008-10-11 14:16:25 -05:00
else sLog . outError ( "Group::~Group: battleground group is not linked to the correct battleground." );
}
Rolls :: iterator itr ;
2010-04-07 19:13:19 +02:00
while ( ! RollId . empty ())
2008-10-11 14:16:25 -05:00
{
itr = RollId . begin ();
Roll * r = * itr ;
RollId . erase ( itr );
delete ( r );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// it is undefined whether objectmgr (which stores the groups) or instancesavemgr
// will be unloaded first so we must be prepared for both cases
// this may unload some instance saves
2009-12-17 11:11:54 +01:00
for ( uint8 i = 0 ; i < MAX_DIFFICULTY ; ++ i )
2009-10-17 16:20:24 -07:00
for ( BoundInstancesMap :: iterator itr2 = m_boundInstances [ i ]. begin (); itr2 != m_boundInstances [ i ]. end (); ++ itr2 )
2009-04-27 18:42:35 -05:00
itr2 -> second . save -> RemoveGroup ( this );
2009-10-17 15:51:44 -07:00
2009-02-01 16:38:53 -06:00
// Sub group counters clean up
2010-06-21 23:20:58 +02:00
delete [] m_subGroupsCounts ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Group :: Create ( const uint64 & guid , const char * name )
{
2010-08-08 05:25:45 +02:00
uint32 lowguid = sObjectMgr . GenerateLowGuid ( HIGHGUID_GROUP );
2010-05-08 01:58:47 +02:00
m_guid = MAKE_NEW_GUID ( lowguid , 0 , HIGHGUID_GROUP );
2008-10-11 14:16:25 -05:00
m_leaderGuid = guid ;
m_leaderName = name ;
2009-10-17 15:51:44 -07:00
2010-04-11 11:22:29 +04:00
m_groupType = isBGGroup () ? GROUPTYPE_BGRAID : GROUPTYPE_NORMAL ;
2009-10-17 15:51:44 -07:00
2010-04-11 11:22:29 +04:00
if ( m_groupType & GROUPTYPE_RAID )
2009-02-01 16:38:53 -06:00
_initRaidSubGroupsCounter ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_lootMethod = GROUP_LOOT ;
m_lootThreshold = ITEM_QUALITY_UNCOMMON ;
m_looterGuid = guid ;
2009-10-17 15:51:44 -07:00
2009-12-17 11:11:54 +01:00
m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL ;
m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL ;
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ())
2008-10-11 14:16:25 -05:00
{
2010-08-08 05:25:45 +02:00
Player * leader = sObjectMgr . GetPlayer ( guid );
2010-04-07 19:14:10 +02:00
if ( leader )
2009-12-17 11:11:54 +01:00
{
m_dungeonDifficulty = leader -> GetDungeonDifficulty ();
m_raidDifficulty = leader -> GetRaidDifficulty ();
}
2009-12-18 13:41:30 -08:00
2008-10-11 14:16:25 -05:00
Player :: ConvertInstancesToGroup ( leader , this , guid );
2009-10-17 15:51:44 -07:00
2010-08-21 03:19:25 +02:00
if ( ! AddMember ( guid , name ))
return false ;
2008-10-11 14:16:25 -05:00
// store group in database
2010-08-21 03:19:25 +02:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
trans -> PAppend ( "DELETE FROM groups WHERE guid ='%u'" , lowguid );
trans -> PAppend ( "DELETE FROM group_member WHERE guid ='%u'" , lowguid );
trans -> PAppend ( "INSERT INTO groups (guid,leaderGuid,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,groupType,difficulty,raiddifficulty) "
2010-05-08 01:58:47 +02:00
"VALUES ('%u','%u','%u','%u','%u','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','%u','%u','%u')" ,
lowguid , GUID_LOPART ( m_leaderGuid ), uint32 ( m_lootMethod ),
2010-04-11 11:22:29 +04:00
GUID_LOPART ( m_looterGuid ), uint32 ( m_lootThreshold ), m_targetIcons [ 0 ], m_targetIcons [ 1 ], m_targetIcons [ 2 ], m_targetIcons [ 3 ], m_targetIcons [ 4 ], m_targetIcons [ 5 ], m_targetIcons [ 6 ], m_targetIcons [ 7 ], uint8 ( m_groupType ), uint32 ( m_dungeonDifficulty ), m_raidDifficulty );
2010-08-21 03:19:25 +02:00
CharacterDatabase . CommitTransaction ( trans );
2008-10-11 14:16:25 -05:00
}
2010-05-08 01:58:47 +02:00
else if ( ! AddMember ( guid , name ))
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2010-08-02 17:28:47 +02:00
bool Group :: LoadGroupFromDB ( const uint32 & groupGuid , QueryResult_AutoPtr result , bool loadMembers )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( isBGGroup ())
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2010-05-08 01:58:47 +02:00
Field * fields = result -> Fetch ();
2010-08-02 17:28:47 +02:00
m_guid = MAKE_NEW_GUID ( groupGuid , 0 , HIGHGUID_GROUP );
2010-05-08 01:58:47 +02:00
m_leaderGuid = MAKE_NEW_GUID ( fields [ 0 ]. GetUInt32 (), 0 , HIGHGUID_PLAYER );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// group leader not exist
2010-08-08 05:25:45 +02:00
if ( ! sObjectMgr . GetPlayerNameByGUID ( fields [ 0 ]. GetUInt32 (), m_leaderName ))
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2010-08-02 17:28:47 +02:00
m_lootMethod = LootMethod ( fields [ 1 ]. GetUInt8 ());
2010-05-08 01:58:47 +02:00
m_looterGuid = MAKE_NEW_GUID ( fields [ 2 ]. GetUInt32 (), 0 , HIGHGUID_PLAYER );
2010-08-02 17:28:47 +02:00
m_lootThreshold = ItemQualities ( fields [ 3 ]. GetUInt16 ());
2010-05-08 01:58:47 +02:00
for ( uint8 i = 0 ; i < TARGETICONCOUNT ; ++ i )
m_targetIcons [ i ] = fields [ 4 + i ]. GetUInt64 ();
2009-10-17 15:51:44 -07:00
2010-05-08 01:58:47 +02:00
m_groupType = GroupType ( fields [ 12 ]. GetUInt8 ());
2010-04-11 11:22:29 +04:00
if ( m_groupType & GROUPTYPE_RAID )
2009-02-01 16:38:53 -06:00
_initRaidSubGroupsCounter ();
2009-10-17 15:51:44 -07:00
2010-05-08 01:58:47 +02:00
uint32 diff = fields [ 13 ]. GetUInt8 ();
2009-12-17 11:11:54 +01:00
if ( diff >= MAX_DUNGEON_DIFFICULTY )
2010-09-10 13:37:33 +02:00
m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL ;
else
m_dungeonDifficulty = Difficulty ( diff );
2009-12-17 11:11:54 +01:00
2010-05-08 01:58:47 +02:00
uint32 r_diff = fields [ 14 ]. GetUInt8 ();
2009-12-17 11:11:54 +01:00
if ( r_diff >= MAX_RAID_DIFFICULTY )
2010-09-10 13:37:33 +02:00
m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL ;
else
m_raidDifficulty = Difficulty ( r_diff );
2009-12-17 11:11:54 +01:00
2010-04-07 19:14:10 +02:00
if ( loadMembers )
2008-10-11 14:16:25 -05:00
{
2010-09-10 13:40:20 +02:00
// 0 1 2 3
result = CharacterDatabase . PQuery ( "SELECT memberGuid, memberFlags, subgroup, roles FROM group_member WHERE guid=%u" , groupGuid );
2010-04-07 19:14:10 +02:00
if ( ! result )
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
do
{
2010-05-08 01:58:47 +02:00
fields = result -> Fetch ();
2010-09-10 13:40:20 +02:00
LoadMemberFromDB ( fields [ 0 ]. GetUInt32 (), fields [ 1 ]. GetUInt8 (), fields [ 2 ]. GetUInt8 (), fields [ 3 ]. GetUInt8 ());
2010-04-07 22:59:46 +02:00
} while ( result -> NextRow ());
2010-05-08 01:58:47 +02:00
if ( GetMembersCount () < 2 ) // group too small
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2010-09-10 13:40:20 +02:00
bool Group :: LoadMemberFromDB ( uint32 guidLow , uint8 memberFlags , uint8 subgroup , uint8 roles )
2008-10-11 14:16:25 -05:00
{
MemberSlot member ;
2010-05-08 01:58:47 +02:00
member . guid = MAKE_NEW_GUID ( guidLow , 0 , HIGHGUID_PLAYER );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// skip non-existed member
2010-08-08 05:25:45 +02:00
if ( ! sObjectMgr . GetPlayerNameByGUID ( member . guid , member . name ))
2010-05-08 01:58:47 +02:00
{
CharacterDatabase . PQuery ( "DELETE FROM group_member WHERE memberGuid=%u" , guidLow );
2008-10-11 14:16:25 -05:00
return false ;
2010-05-08 01:58:47 +02:00
}
2009-10-17 15:51:44 -07:00
2010-03-09 20:33:59 +01:00
member . group = subgroup ;
member . flags = memberFlags ;
2010-09-10 13:40:20 +02:00
member . roles = roles ;
2009-12-22 19:39:02 +01:00
2008-10-11 14:16:25 -05:00
m_memberSlots . push_back ( member );
2009-10-17 15:51:44 -07:00
2009-02-01 16:38:53 -06:00
SubGroupCounterIncrease ( subgroup );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2010-08-11 15:20:20 +02:00
void Group :: ConvertToLFG ()
{
m_groupType = GroupType ( m_groupType | GROUPTYPE_LFG | GROUPTYPE_UNK1 );
m_lootMethod = NEED_BEFORE_GREED ;
if ( ! isBGGroup ())
CharacterDatabase . PExecute ( "UPDATE groups SET groupType='%u' WHERE guid='%u'" , uint8 ( m_groupType ), GUID_LOPART ( m_guid ));
SendUpdate ();
}
2008-10-29 17:09:32 -05:00
void Group :: ConvertToRaid ()
{
2010-04-11 11:22:29 +04:00
m_groupType = GroupType ( m_groupType | GROUPTYPE_RAID );
2009-10-17 15:51:44 -07:00
2009-02-01 16:38:53 -06:00
_initRaidSubGroupsCounter ();
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ())
2010-05-08 01:58:47 +02:00
CharacterDatabase . PExecute ( "UPDATE groups SET groupType='%u' WHERE guid='%u'" , uint8 ( m_groupType ), GUID_LOPART ( m_guid ));
2009-02-01 16:38:53 -06:00
SendUpdate ();
2009-10-17 15:51:44 -07:00
2009-02-01 16:38:53 -06:00
// update quest related GO states (quest activity dependent from raid membership)
2009-10-17 16:20:24 -07:00
for ( member_citerator citr = m_memberSlots . begin (); citr != m_memberSlots . end (); ++ citr )
2010-08-08 05:25:45 +02:00
if ( Player * player = sObjectMgr . GetPlayer ( citr -> guid ))
2009-05-05 16:56:15 -05:00
player -> UpdateForQuestWorldObjects ();
2008-10-29 17:09:32 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Group :: AddInvite ( Player * player )
{
2010-04-07 22:59:46 +02:00
if ( ! player || player -> GetGroupInvite ())
2009-03-14 20:00:02 -06:00
return false ;
Group * group = player -> GetGroup ();
2010-04-07 22:59:46 +02:00
if ( group && group -> isBGGroup ())
2009-03-14 20:00:02 -06:00
group = player -> GetOriginalGroup ();
2010-04-07 22:59:46 +02:00
if ( group )
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
RemoveInvite ( player );
2009-10-17 15:51:44 -07:00
2008-12-12 11:21:28 -06:00
m_invitees . insert ( player );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
player -> SetGroupInvite ( this );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Group :: AddLeaderInvite ( Player * player )
{
2010-04-07 19:14:10 +02:00
if ( ! AddInvite ( player ))
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_leaderGuid = player -> GetGUID ();
m_leaderName = player -> GetName ();
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 Group :: RemoveInvite ( Player * player )
{
2008-12-12 11:21:28 -06:00
m_invitees . erase ( player );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
player -> SetGroupInvite ( NULL );
return GetMembersCount ();
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: RemoveAllInvites ()
{
2010-04-08 08:20:08 +02:00
for ( InvitesList :: iterator itr = m_invitees . begin (); itr != m_invitees . end (); ++ itr )
2008-12-12 11:21:28 -06:00
( * itr ) -> SetGroupInvite ( NULL );
2009-10-17 15:51:44 -07:00
2008-12-12 11:21:28 -06:00
m_invitees . clear ();
}
2009-10-17 15:51:44 -07:00
2008-12-12 11:21:28 -06:00
Player * Group :: GetInvited ( const uint64 & guid ) const
{
2009-10-17 16:20:24 -07:00
for ( InvitesList :: const_iterator itr = m_invitees . begin (); itr != m_invitees . end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if (( * itr ) -> GetGUID () == guid )
2008-12-12 11:21:28 -06:00
return ( * itr );
2008-10-11 14:16:25 -05:00
}
2008-12-12 11:21:28 -06:00
return NULL ;
}
2009-10-17 15:51:44 -07:00
2008-12-12 11:21:28 -06:00
Player * Group :: GetInvited ( const std :: string & name ) const
{
2009-10-17 16:20:24 -07:00
for ( InvitesList :: const_iterator itr = m_invitees . begin (); itr != m_invitees . end (); ++ itr )
2008-12-12 11:21:28 -06:00
{
2010-04-07 19:14:10 +02:00
if (( * itr ) -> GetName () == name )
2008-12-12 11:21:28 -06:00
return ( * itr );
}
return NULL ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Group :: AddMember ( const uint64 & guid , const char * name )
{
2010-08-11 15:20:20 +02:00
if ( isLfgQueued ())
sLFGMgr . Leave ( NULL , this );
2010-04-07 19:14:10 +02:00
if ( ! _addMember ( guid , name ))
2008-10-11 14:16:25 -05:00
return false ;
2010-08-11 15:20:20 +02:00
2008-10-11 14:16:25 -05:00
SendUpdate ();
2009-10-17 15:51:44 -07:00
2010-08-08 05:25:45 +02:00
Player * player = sObjectMgr . GetPlayer ( guid );
2010-04-07 19:14:10 +02:00
if ( player )
2008-10-11 14:16:25 -05:00
{
2010-08-14 15:00:04 +02:00
sLFGMgr . Leave ( player );
2010-04-07 19:14:10 +02:00
if ( ! IsLeader ( player -> GetGUID ()) && ! isBGGroup ())
2008-10-11 14:16:25 -05:00
{
// reset the new member's instances, unless he is currently in one of them
// including raid/heroic instances that they are not permanently bound to!
2009-12-17 11:11:54 +01:00
player -> ResetInstances ( INSTANCE_RESET_GROUP_JOIN , false );
player -> ResetInstances ( INSTANCE_RESET_GROUP_JOIN , true );
2009-10-17 15:51:44 -07:00
2009-12-17 11:11:54 +01:00
if ( player -> getLevel () >= LEVELREQUIREMENT_HEROIC )
2008-10-11 14:16:25 -05:00
{
2009-12-17 11:11:54 +01:00
if ( player -> GetDungeonDifficulty () != GetDungeonDifficulty ())
{
player -> SetDungeonDifficulty ( GetDungeonDifficulty ());
player -> SendDungeonDifficulty ( true );
}
if ( player -> GetRaidDifficulty () != GetRaidDifficulty ())
{
player -> SetRaidDifficulty ( GetRaidDifficulty ());
player -> SendRaidDifficulty ( true );
}
2008-10-11 14:16:25 -05:00
}
}
player -> SetGroupUpdateFlag ( GROUP_UPDATE_FULL );
UpdatePlayerOutOfRange ( player );
2009-10-17 15:51:44 -07:00
2010-09-10 13:37:33 +02:00
// quest related GO state dependent from raid membership
2010-04-07 19:14:10 +02:00
if ( isRaidGroup ())
2009-05-05 16:56:15 -05:00
player -> UpdateForQuestWorldObjects ();
2010-05-21 22:45:47 +02:00
if ( m_maxEnchantingLevel < player -> GetSkillValue ( SKILL_ENCHANTING ))
m_maxEnchantingLevel = player -> GetSkillValue ( SKILL_ENCHANTING );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 Group :: RemoveMember ( const uint64 & guid , const uint8 & method )
{
2009-01-15 21:29:32 -05:00
BroadcastGroupUpdate ();
2009-10-17 15:51:44 -07:00
2010-08-11 15:20:20 +02:00
if ( isLfgQueued ())
2010-05-31 20:25:21 +02:00
sLFGMgr . Leave ( NULL , this );
2010-08-11 15:55:27 +02:00
else if ( isLFGGroup ())
sLFGMgr . OfferContinue ( this );
2010-05-31 20:25:21 +02:00
2008-10-11 14:16:25 -05:00
// remove member and change leader (if need) only if strong more 2 members _before_ member remove
2010-08-26 15:54:56 +06:00
if ( GetMembersCount () > ( isBGGroup () ? 1u : 2u )) // in BG group case allow 1 members group
2008-10-11 14:16:25 -05:00
{
bool leaderChanged = _removeMember ( guid );
2009-10-17 15:51:44 -07:00
2010-08-08 05:25:45 +02:00
if ( Player * player = sObjectMgr . GetPlayer ( guid ))
2008-10-11 14:16:25 -05:00
{
2009-02-01 16:38:53 -06:00
// quest related GO state dependent from raid membership
2010-04-07 19:14:10 +02:00
if ( isRaidGroup ())
2009-05-05 16:56:15 -05:00
player -> UpdateForQuestWorldObjects ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( method == 1 )
2008-10-11 14:16:25 -05:00
{
2010-04-07 22:59:46 +02:00
data . Initialize ( SMSG_GROUP_UNINVITE , 0 );
player -> GetSession () -> SendPacket ( & data );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-08-13 09:24:24 +02:00
player -> GetSession () -> SendLfgUpdateParty ( LFG_UPDATETYPE_LEADER );
if ( isLFGGroup () && player -> GetMap () -> IsDungeon ())
player -> TeleportToBGEntryPoint ();
2009-03-14 20:00:02 -06:00
//we already removed player from group and in player->GetGroup() is his original group!
2010-04-07 22:59:46 +02:00
if ( Group * group = player -> GetGroup ())
2009-03-14 20:00:02 -06:00
{
group -> SendUpdate ();
}
else
{
2010-02-14 19:13:14 -07:00
data . Initialize ( SMSG_GROUP_LIST , 1 + 1 + 1 + 1 + 8 + 4 + 4 + 8 );
data << uint8 ( 0x10 ) << uint8 ( 0 ) << uint8 ( 0 ) << uint8 ( 0 );
2010-05-21 14:19:47 +02:00
data << uint64 ( m_guid ) << uint32 ( m_counter ) << uint32 ( 0 ) << uint64 ( 0 );
2009-03-14 20:00:02 -06:00
player -> GetSession () -> SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_homebindIfInstance ( player );
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( leaderChanged )
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_GROUP_SET_LEADER , ( m_memberSlots . front (). name . size () + 1 ));
data << m_memberSlots . front (). name ;
2009-03-14 20:00:02 -06:00
BroadcastPacket ( & data , true );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SendUpdate ();
2010-05-21 22:45:47 +02:00
ResetMaxEnchantingLevel ();
2008-10-11 14:16:25 -05:00
}
// if group before remove <= 2 disband it
else
2010-05-20 23:35:27 +02:00
Disband ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return m_memberSlots . size ();
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: ChangeLeader ( const uint64 & guid )
{
member_citerator slot = _getMemberCSlot ( guid );
2009-10-17 15:51:44 -07:00
2010-04-07 23:25:02 +02:00
if ( slot == m_memberSlots . end ())
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_setLeader ( guid );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_GROUP_SET_LEADER , slot -> name . size () + 1 );
data << slot -> name ;
2009-03-14 20:00:02 -06:00
BroadcastPacket ( & data , true );
2008-10-11 14:16:25 -05:00
SendUpdate ();
}
2009-10-17 15:51:44 -07:00
2010-09-10 13:37:33 +02:00
void Group :: Disband ( bool hideDestroy /* = false */ )
2008-10-11 14:16:25 -05:00
{
Player * player ;
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( member_citerator citr = m_memberSlots . begin (); citr != m_memberSlots . end (); ++ citr )
2008-10-11 14:16:25 -05:00
{
2010-08-08 05:25:45 +02:00
player = sObjectMgr . GetPlayer ( citr -> guid );
2010-04-07 19:14:10 +02:00
if ( ! player )
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-03-14 20:00:02 -06:00
//we cannot call _removeMember because it would invalidate member iterator
2009-03-14 20:06:00 -06:00
//if we are removing player from battleground raid
2010-04-07 22:59:46 +02:00
if ( isBGGroup ())
2010-08-08 04:37:24 +02:00
player -> RemoveFromBattlegroundRaid ();
2009-03-14 20:06:00 -06:00
else
2009-03-14 20:00:02 -06:00
{
2009-03-14 20:06:00 -06:00
//we can remove player who is in battleground from his original group
2010-04-07 22:59:46 +02:00
if ( player -> GetOriginalGroup () == this )
2009-03-14 20:06:00 -06:00
player -> SetOriginalGroup ( NULL );
2009-03-14 20:00:02 -06:00
else
2009-03-14 20:06:00 -06:00
player -> SetGroup ( NULL );
2010-05-31 20:25:21 +02:00
2010-08-13 09:24:24 +02:00
if ( isLFGGroup () && player -> GetMap () -> IsDungeon ())
player -> TeleportToBGEntryPoint ();
2010-05-20 23:35:27 +02:00
player -> GetSession () -> SendLfgUpdateParty ( LFG_UPDATETYPE_GROUP_DISBAND );
player -> GetSession () -> SendLfgUpdateParty ( LFG_UPDATETYPE_LEADER );
2009-03-14 20:00:02 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-01 16:38:53 -06:00
// quest related GO state dependent from raid membership
2010-04-07 19:14:10 +02:00
if ( isRaidGroup ())
2009-05-05 16:56:15 -05:00
player -> UpdateForQuestWorldObjects ();
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! player -> GetSession ())
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ;
2010-04-07 19:14:10 +02:00
if ( ! hideDestroy )
2008-10-11 14:16:25 -05:00
{
data . Initialize ( SMSG_GROUP_DESTROYED , 0 );
player -> GetSession () -> SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2009-03-14 20:00:02 -06:00
//we already removed player from group and in player->GetGroup() is his original group, send update
2010-04-07 22:59:46 +02:00
if ( Group * group = player -> GetGroup ())
2009-03-14 20:00:02 -06:00
{
group -> SendUpdate ();
}
else
{
2010-02-14 19:13:14 -07:00
data . Initialize ( SMSG_GROUP_LIST , 1 + 1 + 1 + 1 + 8 + 4 + 4 + 8 );
data << uint8 ( 0x10 ) << uint8 ( 0 ) << uint8 ( 0 ) << uint8 ( 0 );
2010-05-21 14:19:47 +02:00
data << uint64 ( m_guid ) << uint32 ( m_counter ) << uint32 ( 0 ) << uint64 ( 0 );
2009-03-14 20:00:02 -06:00
player -> GetSession () -> SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_homebindIfInstance ( player );
}
RollId . clear ();
m_memberSlots . clear ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
RemoveAllInvites ();
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ())
2008-10-11 14:16:25 -05:00
{
2010-05-08 01:58:47 +02:00
uint32 lowguid = GUID_LOPART ( m_guid );
2010-08-21 03:19:25 +02:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
trans -> PAppend ( "DELETE FROM groups WHERE guid=%u" , lowguid );
trans -> PAppend ( "DELETE FROM group_member WHERE guid=%u" , lowguid );
CharacterDatabase . CommitTransaction ( trans );
2009-12-17 11:11:54 +01:00
ResetInstances ( INSTANCE_RESET_GROUP_DISBAND , false , NULL );
ResetInstances ( INSTANCE_RESET_GROUP_DISBAND , true , NULL );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-05-08 01:58:47 +02:00
m_guid = 0 ;
2008-10-11 14:16:25 -05:00
m_leaderGuid = 0 ;
m_leaderName = "" ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/*********************************************************/
/*** LOOT SYSTEM ***/
/*********************************************************/
2009-10-17 15:51:44 -07:00
2010-04-11 11:16:42 +04:00
void Group :: SendLootStartRoll ( uint32 CountDown , uint32 mapid , const Roll & r )
2008-10-11 14:16:25 -05:00
{
2010-02-14 19:13:14 -07:00
WorldPacket data ( SMSG_LOOT_START_ROLL , ( 8 + 4 + 4 + 4 + 4 + 4 + 4 + 1 ));
2008-10-11 14:16:25 -05:00
data << uint64 ( r . itemGUID ); // guid of rolled item
2010-04-11 11:16:42 +04:00
data << uint32 ( mapid ); // 3.3.3 mapid
2008-10-11 14:16:25 -05:00
data << uint32 ( r . totalPlayersRolling ); // maybe the number of players rolling for it???
data << uint32 ( r . itemid ); // the itemEntryId for the item that shall be rolled for
data << uint32 ( r . itemRandomSuffix ); // randomSuffix
data << uint32 ( r . itemRandomPropId ); // item random property ID
2009-12-17 11:11:54 +01:00
data << uint32 ( r . itemCount ); // items in stack
2008-10-11 14:16:25 -05:00
data << uint32 ( CountDown ); // the countdown time to choose "need" or "greed"
2010-05-21 22:45:47 +02:00
data << uint8 ( r . rollVoteMask ); // roll type mask
2009-10-17 15:51:44 -07:00
2010-04-08 08:20:08 +02:00
for ( Roll :: PlayerVote :: const_iterator itr = r . playerVote . begin (); itr != r . playerVote . end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
2010-08-08 05:25:45 +02:00
Player * p = sObjectMgr . GetPlayer ( itr -> first );
2010-04-07 19:14:10 +02:00
if ( ! p || ! p -> GetSession ())
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-04-17 18:55:17 +02:00
if ( itr -> second == NOT_EMITED_YET )
2010-04-07 22:59:46 +02:00
p -> GetSession () -> SendPacket ( & data );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-29 17:09:32 -05:00
void Group :: SendLootRoll ( const uint64 & SourceGuid , const uint64 & TargetGuid , uint8 RollNumber , uint8 RollType , const Roll & r )
2008-10-11 14:16:25 -05:00
{
2009-12-17 11:11:54 +01:00
WorldPacket data ( SMSG_LOOT_ROLL , ( 8 + 4 + 8 + 4 + 4 + 4 + 1 + 1 + 1 ));
2008-10-11 14:16:25 -05:00
data << uint64 ( SourceGuid ); // guid of the item rolled
data << uint32 ( 0 ); // unknown, maybe amount of players
data << uint64 ( TargetGuid );
data << uint32 ( r . itemid ); // the itemEntryId for the item that shall be rolled for
data << uint32 ( r . itemRandomSuffix ); // randomSuffix
data << uint32 ( r . itemRandomPropId ); // Item random property ID
data << uint8 ( RollNumber ); // 0: "Need for: [item name]" > 127: "you passed on: [item name]" Roll number
data << uint8 ( RollType ); // 0: "Need for: [item name]" 0: "You have selected need for [item name] 1: need roll 2: greed roll
2010-04-17 18:55:17 +02:00
data << uint8 ( 0 ); // auto pass on NeedBeforeGreed loot because player cannot use the object
2009-10-17 15:51:44 -07:00
2010-04-08 08:20:08 +02:00
for ( Roll :: PlayerVote :: const_iterator itr = r . playerVote . begin (); itr != r . playerVote . end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
2010-08-08 05:25:45 +02:00
Player * p = sObjectMgr . GetPlayer ( itr -> first );
2010-04-07 19:14:10 +02:00
if ( ! p || ! p -> GetSession ())
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( itr -> second != NOT_VALID )
2010-04-07 22:59:46 +02:00
p -> GetSession () -> SendPacket ( & data );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-29 17:09:32 -05:00
void Group :: SendLootRollWon ( const uint64 & SourceGuid , const uint64 & TargetGuid , uint8 RollNumber , uint8 RollType , const Roll & r )
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_LOOT_ROLL_WON , ( 8 + 4 + 4 + 4 + 4 + 8 + 1 + 1 ));
data << uint64 ( SourceGuid ); // guid of the item rolled
data << uint32 ( 0 ); // unknown, maybe amount of players
data << uint32 ( r . itemid ); // the itemEntryId for the item that shall be rolled for
data << uint32 ( r . itemRandomSuffix ); // randomSuffix
data << uint32 ( r . itemRandomPropId ); // Item random property
data << uint64 ( TargetGuid ); // guid of the player who won.
data << uint8 ( RollNumber ); // rollnumber realted to SMSG_LOOT_ROLL
data << uint8 ( RollType ); // Rolltype related to SMSG_LOOT_ROLL
2009-10-17 15:51:44 -07:00
2010-04-08 08:20:08 +02:00
for ( Roll :: PlayerVote :: const_iterator itr = r . playerVote . begin (); itr != r . playerVote . end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
2010-08-08 05:25:45 +02:00
Player * p = sObjectMgr . GetPlayer ( itr -> first );
2010-04-07 19:14:10 +02:00
if ( ! p || ! p -> GetSession ())
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( itr -> second != NOT_VALID )
2010-04-07 22:59:46 +02:00
p -> GetSession () -> SendPacket ( & data );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: SendLootAllPassed ( uint32 NumberOfPlayers , const Roll & r )
{
WorldPacket data ( SMSG_LOOT_ALL_PASSED , ( 8 + 4 + 4 + 4 + 4 ));
data << uint64 ( r . itemGUID ); // Guid of the item rolled
data << uint32 ( NumberOfPlayers ); // The number of players rolling for it???
data << uint32 ( r . itemid ); // The itemEntryId for the item that shall be rolled for
data << uint32 ( r . itemRandomPropId ); // Item random property ID
data << uint32 ( r . itemRandomSuffix ); // Item random suffix ID
2009-10-17 15:51:44 -07:00
2010-04-08 08:20:08 +02:00
for ( Roll :: PlayerVote :: const_iterator itr = r . playerVote . begin (); itr != r . playerVote . end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
2010-08-08 05:25:45 +02:00
Player * p = sObjectMgr . GetPlayer ( itr -> first );
2010-04-07 19:14:10 +02:00
if ( ! p || ! p -> GetSession ())
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( itr -> second != NOT_VALID )
2010-04-07 22:59:46 +02:00
p -> GetSession () -> SendPacket ( & data );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
// notify group members which player is the allowed looter for the given creature
void Group :: SendLooter ( Creature * pCreature , Player * pLooter )
{
2010-07-30 20:04:28 +02:00
ASSERT ( pCreature );
2010-03-11 22:55:02 +01:00
2010-04-07 18:09:10 +02:00
WorldPacket data ( SMSG_LOOT_LIST , ( 8 + 8 ));
2010-03-11 22:55:02 +01:00
data << uint64 ( pCreature -> GetGUID ());
data << uint8 ( 0 ); // unk1
2010-04-07 18:09:10 +02:00
2010-03-11 22:55:02 +01:00
if ( pLooter )
data . append ( pLooter -> GetPackGUID ());
else
data << uint8 ( 0 );
BroadcastPacket ( & data , false );
}
2010-04-11 14:25:02 +04:00
void Group :: GroupLoot ( Loot * loot , WorldObject * pLootedObject )
2008-10-11 14:16:25 -05:00
{
std :: vector < LootItem >:: iterator i ;
ItemPrototype const * item ;
uint8 itemSlot = 0 ;
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
for ( i = loot -> items . begin (); i != loot -> items . end (); ++ i , ++ itemSlot )
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
if ( i -> freeforall )
continue ;
2010-08-08 05:25:45 +02:00
item = sObjectMgr . GetItemPrototype ( i -> itemid );
2008-10-11 14:16:25 -05:00
if ( ! item )
{
//sLog.outDebug("Group::GroupLoot: missing item prototype for item with id: %d", i->itemid);
continue ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//roll for over-threshold item if it's one-player loot
2010-03-11 22:55:02 +01:00
if ( item -> Quality >= uint32 ( m_lootThreshold ))
2008-10-11 14:16:25 -05:00
{
2010-08-08 05:25:45 +02:00
uint64 newitemGUID = MAKE_NEW_GUID ( sObjectMgr . GenerateLowGuid ( HIGHGUID_ITEM ), 0 , HIGHGUID_ITEM );
2010-03-11 22:55:02 +01:00
Roll * r = new Roll ( newitemGUID , * i );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//a vector is filled with only near party members
2009-10-17 16:20:24 -07:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2008-10-11 14:16:25 -05:00
{
Player * member = itr -> getSource ();
2010-03-11 22:55:02 +01:00
if ( ! member || ! member -> GetSession ())
2008-10-11 14:16:25 -05:00
continue ;
2010-03-11 22:55:02 +01:00
if ( i -> AllowedForPlayer ( member ))
2008-10-11 14:16:25 -05:00
{
2010-08-23 19:56:47 -07:00
if ( member -> IsWithinDistInMap ( pLootedObject , sWorld . getFloatConfig ( CONFIG_GROUP_XP_DISTANCE ), false ))
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
r -> totalPlayersRolling ++ ;
2010-04-17 18:55:17 +02:00
if ( member -> GetPassOnGroupLoot ())
{
r -> playerVote [ member -> GetGUID ()] = PASS ;
r -> totalPass ++ ;
// can't broadcast the pass now. need to wait until all rolling players are known.
}
else
{
r -> playerVote [ member -> GetGUID ()] = NOT_EMITED_YET ;
}
2008-10-11 14:16:25 -05:00
}
}
}
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
if ( r -> totalPlayersRolling > 0 )
{
r -> setLoot ( loot );
r -> itemSlot = itemSlot ;
2010-05-21 22:45:47 +02:00
if ( item -> DisenchantID && m_maxEnchantingLevel >= item -> RequiredDisenchantSkill )
r -> rollVoteMask |= ROLL_FLAG_TYPE_DISENCHANT ;
2010-03-11 22:55:02 +01:00
loot -> items [ itemSlot ]. is_blocked = true ;
2009-10-17 15:51:44 -07:00
2010-04-17 18:55:17 +02:00
// If there is any "auto pass", broadcast the pass now.
if ( r -> totalPass )
{
for ( Roll :: PlayerVote :: const_iterator itr = r -> playerVote . begin (); itr != r -> playerVote . end (); ++ itr )
{
2010-08-08 05:25:45 +02:00
Player * p = sObjectMgr . GetPlayer ( itr -> first );
2010-04-17 18:55:17 +02:00
if ( ! p || ! p -> GetSession ())
continue ;
if ( itr -> second == PASS )
SendLootRoll ( newitemGUID , p -> GetGUID (), 128 , ROLL_PASS , * r );
}
}
2010-04-19 17:13:20 +02:00
2010-04-11 12:57:09 +02:00
SendLootStartRoll ( 60000 , pLootedObject -> GetMapId (), * r );
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
RollId . push_back ( r );
2010-04-07 18:09:10 +02:00
if ( Creature * creature = dynamic_cast < Creature *> ( pLootedObject ))
2010-03-11 22:55:02 +01:00
{
creature -> m_groupLootTimer = 60000 ;
2010-08-02 17:28:47 +02:00
creature -> lootingGroupLowGUID = GetLowGUID ();
2010-03-11 22:55:02 +01:00
}
2010-04-07 18:09:10 +02:00
else if ( GameObject * go = dynamic_cast < GameObject *> ( pLootedObject ))
2010-03-11 22:55:02 +01:00
{
go -> m_groupLootTimer = 60000 ;
2010-08-02 17:28:47 +02:00
go -> lootingGroupLowGUID = GetLowGUID ();
2010-03-11 22:55:02 +01:00
}
}
else
{
delete r ;
}
2008-10-11 14:16:25 -05:00
}
else
i -> is_underthreshold = 1 ;
}
}
2009-10-17 15:51:44 -07:00
2010-04-11 14:25:02 +04:00
void Group :: NeedBeforeGreed ( Loot * loot , WorldObject * pLootedObject )
2008-10-11 14:16:25 -05:00
{
ItemPrototype const * item ;
uint8 itemSlot = 0 ;
2009-10-17 16:20:24 -07:00
for ( std :: vector < LootItem >:: iterator i = loot -> items . begin (); i != loot -> items . end (); ++ i , ++ itemSlot )
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
if ( i -> freeforall )
continue ;
2010-08-08 05:25:45 +02:00
item = sObjectMgr . GetItemPrototype ( i -> itemid );
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
//roll for over-threshold item if it's one-player loot
if ( item -> Quality >= uint32 ( m_lootThreshold ))
2008-10-11 14:16:25 -05:00
{
2010-08-08 05:25:45 +02:00
uint64 newitemGUID = MAKE_NEW_GUID ( sObjectMgr . GenerateLowGuid ( HIGHGUID_ITEM ), 0 , HIGHGUID_ITEM );
2008-10-11 14:16:25 -05:00
Roll * r = new Roll ( newitemGUID , * i );
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2008-10-11 14:16:25 -05:00
{
Player * playerToRoll = itr -> getSource ();
2010-03-11 22:55:02 +01:00
if ( ! playerToRoll || ! playerToRoll -> GetSession ())
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-07-18 04:37:08 -06:00
if ( playerToRoll -> CanUseItem ( item ) == EQUIP_ERR_OK && i -> AllowedForPlayer ( playerToRoll ))
2008-10-11 14:16:25 -05:00
{
2010-08-23 19:56:47 -07:00
if ( playerToRoll -> IsWithinDistInMap ( pLootedObject , sWorld . getFloatConfig ( CONFIG_GROUP_XP_DISTANCE ), false ))
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
r -> totalPlayersRolling ++ ;
2010-04-17 18:55:17 +02:00
if ( playerToRoll -> GetPassOnGroupLoot ())
{
r -> playerVote [ playerToRoll -> GetGUID ()] = PASS ;
r -> totalPass ++ ;
// can't broadcast the pass now. need to wait until all rolling players are known.
}
else
{
r -> playerVote [ playerToRoll -> GetGUID ()] = NOT_EMITED_YET ;
}
2008-10-11 14:16:25 -05:00
}
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( r -> totalPlayersRolling > 0 )
{
r -> setLoot ( loot );
r -> itemSlot = itemSlot ;
2010-05-21 22:45:47 +02:00
if ( item -> DisenchantID && m_maxEnchantingLevel >= item -> RequiredDisenchantSkill )
r -> rollVoteMask |= ROLL_FLAG_TYPE_DISENCHANT ;
if ( item -> Flags2 & ITEM_FLAGS_EXTRA_NEED_ROLL_DISABLED )
r -> rollVoteMask &= ~ ROLL_FLAG_TYPE_NEED ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
loot -> items [ itemSlot ]. is_blocked = true ;
2009-10-17 15:51:44 -07:00
2010-04-17 18:55:17 +02:00
// If there is any "auto pass", broadcast the pass now.
if ( r -> totalPass )
{
for ( Roll :: PlayerVote :: const_iterator itr = r -> playerVote . begin (); itr != r -> playerVote . end (); ++ itr )
{
2010-08-08 05:25:45 +02:00
Player * p = sObjectMgr . GetPlayer ( itr -> first );
2010-04-17 18:55:17 +02:00
if ( ! p || ! p -> GetSession ())
continue ;
if ( itr -> second == PASS )
SendLootRoll ( newitemGUID , p -> GetGUID (), 128 , ROLL_PASS , * r );
}
}
2010-04-11 12:57:09 +02:00
SendLootStartRoll ( 60000 , pLootedObject -> GetMapId (), * r );
2010-03-11 22:55:02 +01:00
2008-10-11 14:16:25 -05:00
RollId . push_back ( r );
2010-03-11 22:55:02 +01:00
2010-04-07 18:09:10 +02:00
if ( Creature * creature = dynamic_cast < Creature *> ( pLootedObject ))
2010-03-11 22:55:02 +01:00
{
creature -> m_groupLootTimer = 60000 ;
2010-08-02 17:28:47 +02:00
creature -> lootingGroupLowGUID = GetLowGUID ();
2010-03-11 22:55:02 +01:00
}
2008-10-11 14:16:25 -05:00
}
else
{
delete r ;
}
}
else
i -> is_underthreshold = 1 ;
}
}
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
void Group :: MasterLoot ( Loot * /*loot*/ , WorldObject * pLootedObject )
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
sLog . outDebug ( "Group::MasterLoot (SMSG_LOOT_MASTER_LIST, 330)" );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 real_count = 0 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_LOOT_MASTER_LIST , 330 );
data << ( uint8 ) GetMembersCount ();
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2008-10-11 14:16:25 -05:00
{
Player * looter = itr -> getSource ();
if ( ! looter -> IsInWorld ())
continue ;
2009-10-17 15:51:44 -07:00
2010-08-23 19:56:47 -07:00
if ( looter -> IsWithinDistInMap ( pLootedObject , sWorld . getFloatConfig ( CONFIG_GROUP_XP_DISTANCE ), false ))
2008-10-11 14:16:25 -05:00
{
2010-04-11 11:16:42 +04:00
data << uint64 ( looter -> GetGUID ());
2008-10-11 14:16:25 -05:00
++ real_count ;
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data . put < uint8 > ( 0 , real_count );
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2008-10-11 14:16:25 -05:00
{
Player * looter = itr -> getSource ();
2010-08-23 19:56:47 -07:00
if ( looter -> IsWithinDistInMap ( pLootedObject , sWorld . getFloatConfig ( CONFIG_GROUP_XP_DISTANCE ), false ))
2008-10-11 14:16:25 -05:00
looter -> GetSession () -> SendPacket ( & data );
}
}
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
void Group :: CountRollVote ( const uint64 & playerGUID , const uint64 & Guid , uint32 NumberOfPlayers , uint8 Choice )
2008-10-11 14:16:25 -05:00
{
Rolls :: iterator rollI = GetRoll ( Guid );
if ( rollI == RollId . end ())
return ;
Roll * roll = * rollI ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Roll :: PlayerVote :: iterator itr = roll -> playerVote . find ( playerGUID );
// this condition means that player joins to the party after roll begins
if ( itr == roll -> playerVote . end ())
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( roll -> getLoot ())
if ( roll -> getLoot () -> items . empty ())
return ;
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
switch ( Choice )
2008-10-11 14:16:25 -05:00
{
2009-12-17 11:11:54 +01:00
case ROLL_PASS : // Player choose pass
2010-01-20 20:42:54 +01:00
SendLootRoll ( 0 , playerGUID , 128 , ROLL_PASS , * roll );
2008-10-11 14:16:25 -05:00
++ roll -> totalPass ;
itr -> second = PASS ;
2010-03-11 22:55:02 +01:00
break ;
2009-12-17 11:11:54 +01:00
case ROLL_NEED : // player choose Need
2010-01-20 20:42:54 +01:00
SendLootRoll ( 0 , playerGUID , 0 , 0 , * roll );
2008-10-11 14:16:25 -05:00
++ roll -> totalNeed ;
itr -> second = NEED ;
2010-03-11 22:55:02 +01:00
break ;
2009-12-17 11:11:54 +01:00
case ROLL_GREED : // player choose Greed
SendLootRoll ( 0 , playerGUID , 128 , ROLL_GREED , * roll );
2008-10-11 14:16:25 -05:00
++ roll -> totalGreed ;
itr -> second = GREED ;
2010-03-11 22:55:02 +01:00
break ;
2010-02-14 19:13:14 -07:00
case ROLL_DISENCHANT : // player choose Disenchant
SendLootRoll ( 0 , playerGUID , 128 , ROLL_DISENCHANT , * roll );
++ roll -> totalGreed ;
itr -> second = DISENCHANT ;
2010-03-11 22:55:02 +01:00
break ;
2008-10-11 14:16:25 -05:00
}
2010-03-11 22:55:02 +01:00
2010-02-14 19:13:14 -07:00
if ( roll -> totalPass + roll -> totalNeed + roll -> totalGreed >= roll -> totalPlayersRolling )
2008-10-11 14:16:25 -05:00
{
CountTheRoll ( rollI , NumberOfPlayers );
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//called when roll timer expires
2010-03-11 22:55:02 +01:00
void Group :: EndRoll ( Loot * pLoot )
2008-10-11 14:16:25 -05:00
{
2010-04-07 22:59:46 +02:00
for ( Rolls :: iterator itr = RollId . begin (); itr != RollId . end ();)
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
if (( * itr ) -> getLoot () == pLoot ) {
CountTheRoll ( itr , GetMembersCount ()); //i don't have to edit player votes, who didn't vote ... he will pass
itr = RollId . begin ();
}
else
itr ++ ;
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: CountTheRoll ( Rolls :: iterator rollI , uint32 NumberOfPlayers )
{
Roll * roll = * rollI ;
2010-03-11 22:55:02 +01:00
if ( ! roll -> isValid ()) // is loot already deleted ?
2008-10-11 14:16:25 -05:00
{
RollId . erase ( rollI );
delete roll ;
return ;
}
//end of the roll
if ( roll -> totalNeed > 0 )
{
2010-03-11 22:55:02 +01:00
if ( ! roll -> playerVote . empty ())
2008-10-11 14:16:25 -05:00
{
uint8 maxresul = 0 ;
uint64 maxguid = ( * roll -> playerVote . begin ()). first ;
Player * player ;
2009-10-17 15:51:44 -07:00
2010-04-08 08:20:08 +02:00
for ( Roll :: PlayerVote :: const_iterator itr = roll -> playerVote . begin (); itr != roll -> playerVote . end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
if ( itr -> second != NEED )
continue ;
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
uint8 randomN = urand ( 1 , 100 );
2009-12-17 11:11:54 +01:00
SendLootRoll ( 0 , itr -> first , randomN , ROLL_NEED , * roll );
2008-10-11 14:16:25 -05:00
if ( maxresul < randomN )
{
maxguid = itr -> first ;
maxresul = randomN ;
}
}
2009-12-17 11:11:54 +01:00
SendLootRollWon ( 0 , maxguid , maxresul , ROLL_NEED , * roll );
2010-08-08 05:25:45 +02:00
player = sObjectMgr . GetPlayer ( maxguid );
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
if ( player && player -> GetSession ())
2008-10-11 14:16:25 -05:00
{
2009-01-02 11:03:43 -06:00
player -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT , roll -> itemid , maxresul );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
ItemPosCountVec dest ;
LootItem * item = & ( roll -> getLoot () -> items [ roll -> itemSlot ]);
2010-03-11 22:55:02 +01:00
uint8 msg = player -> CanStoreNewItem ( NULL_BAG , NULL_SLOT , dest , roll -> itemid , item -> count );
if ( msg == EQUIP_ERR_OK )
2008-10-11 14:16:25 -05:00
{
item -> is_looted = true ;
roll -> getLoot () -> NotifyItemRemoved ( roll -> itemSlot );
2010-03-11 22:55:02 +01:00
roll -> getLoot () -> unlootedCount -- ;
2010-04-07 22:59:46 +02:00
player -> StoreNewItem ( dest , roll -> itemid , true , item -> randomPropertyId );
2008-10-11 14:16:25 -05:00
}
else
{
item -> is_blocked = false ;
2010-08-05 22:08:07 +06:00
player -> SendEquipError ( msg , NULL , NULL , roll -> itemid );
2008-10-11 14:16:25 -05:00
}
}
}
}
else if ( roll -> totalGreed > 0 )
{
2010-03-11 22:55:02 +01:00
if ( ! roll -> playerVote . empty ())
2008-10-11 14:16:25 -05:00
{
uint8 maxresul = 0 ;
uint64 maxguid = ( * roll -> playerVote . begin ()). first ;
Player * player ;
2010-04-19 17:03:10 +02:00
RollVote rollvote = NOT_VALID ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Roll :: PlayerVote :: iterator itr ;
2010-03-11 22:55:02 +01:00
for ( itr = roll -> playerVote . begin (); itr != roll -> playerVote . end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
2010-02-14 19:13:14 -07:00
if ( itr -> second != GREED && itr -> second != DISENCHANT )
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
uint8 randomN = urand ( 1 , 100 );
2010-02-14 19:13:14 -07:00
SendLootRoll ( 0 , itr -> first , randomN , itr -> second , * roll );
2008-10-11 14:16:25 -05:00
if ( maxresul < randomN )
{
maxguid = itr -> first ;
maxresul = randomN ;
2010-02-14 19:13:14 -07:00
rollvote = itr -> second ;
2008-10-11 14:16:25 -05:00
}
}
2010-02-14 19:13:14 -07:00
SendLootRollWon ( 0 , maxguid , maxresul , rollvote , * roll );
2010-08-08 05:25:45 +02:00
player = sObjectMgr . GetPlayer ( maxguid );
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
if ( player && player -> GetSession ())
2008-10-11 14:16:25 -05:00
{
2009-01-02 11:03:43 -06:00
player -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT , roll -> itemid , maxresul );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
LootItem * item = & ( roll -> getLoot () -> items [ roll -> itemSlot ]);
2010-02-14 19:13:14 -07:00
2010-03-11 22:55:02 +01:00
if ( rollvote == GREED )
2010-02-14 19:13:14 -07:00
{
ItemPosCountVec dest ;
2010-03-11 22:55:02 +01:00
uint8 msg = player -> CanStoreNewItem ( NULL_BAG , NULL_SLOT , dest , roll -> itemid , item -> count );
if ( msg == EQUIP_ERR_OK )
2010-02-14 19:13:14 -07:00
{
item -> is_looted = true ;
roll -> getLoot () -> NotifyItemRemoved ( roll -> itemSlot );
2010-03-11 22:55:02 +01:00
roll -> getLoot () -> unlootedCount -- ;
player -> StoreNewItem ( dest , roll -> itemid , true , item -> randomPropertyId );
2010-02-14 19:13:14 -07:00
}
else
{
item -> is_blocked = false ;
2010-08-05 22:08:07 +06:00
player -> SendEquipError ( msg , NULL , NULL , roll -> itemid );
2010-02-14 19:13:14 -07:00
}
}
2010-04-07 19:14:10 +02:00
else if ( rollvote == DISENCHANT )
2008-10-11 14:16:25 -05:00
{
item -> is_looted = true ;
roll -> getLoot () -> NotifyItemRemoved ( roll -> itemSlot );
2010-03-11 22:55:02 +01:00
roll -> getLoot () -> unlootedCount -- ;
2010-02-14 19:13:14 -07:00
ItemPrototype const * pProto = ObjectMgr :: GetItemPrototype ( roll -> itemid );
player -> AutoStoreLoot ( pProto -> DisenchantID , LootTemplates_Disenchant , true );
2008-10-11 14:16:25 -05:00
}
}
}
}
else
{
SendLootAllPassed ( NumberOfPlayers , * roll );
2010-03-11 22:55:02 +01:00
// remove is_blocked so that the item is lootable by all players
2008-10-11 14:16:25 -05:00
LootItem * item = & ( roll -> getLoot () -> items [ roll -> itemSlot ]);
2010-04-07 18:09:10 +02:00
if ( item )
2010-03-11 22:55:02 +01:00
item -> is_blocked = false ;
2008-10-11 14:16:25 -05:00
}
RollId . erase ( rollI );
delete roll ;
}
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
void Group :: SetTargetIcon ( uint8 id , uint64 whoGuid , uint64 targetGuid )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( id >= TARGETICONCOUNT )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// clean other icons
2010-04-07 22:59:46 +02:00
if ( targetGuid != 0 )
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < TARGETICONCOUNT ; ++ i )
2010-04-07 22:59:46 +02:00
if ( m_targetIcons [ i ] == targetGuid )
2010-02-14 19:13:14 -07:00
SetTargetIcon ( i , 0 , 0 );
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
m_targetIcons [ id ] = targetGuid ;
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
WorldPacket data ( MSG_RAID_TARGET_UPDATE , ( 1 + 8 + 1 + 8 ));
data << uint8 ( 0 ); // set targets
data << uint64 ( whoGuid );
data << uint8 ( id );
data << uint64 ( targetGuid );
2009-03-14 20:00:02 -06:00
BroadcastPacket ( & data , true );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-26 11:50:07 -05:00
void Group :: GetDataForXPAtKill ( Unit const * victim , uint32 & count , uint32 & sum_level , Player * & member_with_max_level , Player * & not_gray_member_with_max_level )
2008-10-11 14:16:25 -05:00
{
2009-10-17 16:20:24 -07:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2008-10-11 14:16:25 -05:00
{
Player * member = itr -> getSource ();
2010-04-07 19:14:10 +02:00
if ( ! member || ! member -> isAlive ()) // only for alive
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! member -> IsAtGroupRewardDistance ( victim )) // at req. distance
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
++ count ;
sum_level += member -> getLevel ();
2010-04-07 19:14:10 +02:00
if ( ! member_with_max_level || member_with_max_level -> getLevel () < member -> getLevel ())
2008-10-11 14:16:25 -05:00
member_with_max_level = member ;
2009-10-17 15:51:44 -07:00
2009-12-20 15:20:04 +01:00
uint32 gray_level = Trinity :: XP :: GetGrayLevel ( member -> getLevel ());
2010-04-07 22:59:46 +02:00
if ( victim -> getLevel () > gray_level && ( ! not_gray_member_with_max_level
2008-10-26 11:50:07 -05:00
|| not_gray_member_with_max_level -> getLevel () < member -> getLevel ()))
not_gray_member_with_max_level = member ;
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: SendTargetIconList ( WorldSession * session )
{
2010-04-07 19:14:10 +02:00
if ( ! session )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ( MSG_RAID_TARGET_UPDATE , ( 1 + TARGETICONCOUNT * 9 ));
2010-02-14 19:13:14 -07:00
data << uint8 ( 1 ); // list targets
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < TARGETICONCOUNT ; ++ i )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( m_targetIcons [ i ] == 0 )
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
data << uint8 ( i );
data << uint64 ( m_targetIcons [ i ]);
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
session -> SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: SendUpdate ()
{
Player * player ;
2009-10-17 16:20:24 -07:00
for ( member_citerator citr = m_memberSlots . begin (); citr != m_memberSlots . end (); ++ citr )
2008-10-11 14:16:25 -05:00
{
2010-08-08 05:25:45 +02:00
player = sObjectMgr . GetPlayer ( citr -> guid );
2010-04-07 22:59:46 +02:00
if ( ! player || ! player -> GetSession () || player -> GetGroup () != this )
2008-10-11 14:16:25 -05:00
continue ;
2010-03-09 20:33:59 +01:00
WorldPacket data ( SMSG_GROUP_LIST , ( 1 + 1 + 1 + 1 + 1 + 4 + 8 + 4 + 4 + ( GetMembersCount () - 1 ) * ( 13 + 8 + 1 + 1 + 1 + 1 ) + 8 + 1 + 8 + 1 + 1 + 1 + 1 ));
2010-02-14 19:13:14 -07:00
data << uint8 ( m_groupType ); // group type (flags in 3.3)
2010-03-09 20:33:59 +01:00
data << uint8 ( citr -> group );
data << uint8 ( citr -> flags );
2010-08-11 15:20:20 +02:00
if ( isLFGGroup ())
2010-02-14 19:13:14 -07:00
{
2010-08-11 15:20:20 +02:00
data << uint8 ( 1 );
data << uint8 ( m_LfgStatus );
data << uint32 ( m_LfgDungeonEntry );
2010-02-14 19:13:14 -07:00
}
2010-08-11 15:20:20 +02:00
else
data << uint8 ( isBGGroup () ? 1 : 0 ); // 2.0.x, isBattlegroundGroup?
2010-05-08 01:58:47 +02:00
data << uint64 ( m_guid );
data << uint32 ( m_counter ++ ); // 3.3, value increases every time this packet gets sent
2008-10-11 14:16:25 -05:00
data << uint32 ( GetMembersCount () - 1 );
2009-10-17 16:20:24 -07:00
for ( member_citerator citr2 = m_memberSlots . begin (); citr2 != m_memberSlots . end (); ++ citr2 )
2008-10-11 14:16:25 -05:00
{
2010-03-09 20:33:59 +01:00
if ( citr -> guid == citr2 -> guid )
2008-10-11 14:16:25 -05:00
continue ;
2010-08-08 05:25:45 +02:00
Player * member = sObjectMgr . GetPlayer ( citr2 -> guid );
2010-04-07 18:09:10 +02:00
2009-03-14 20:00:02 -06:00
uint8 onlineState = ( member ) ? MEMBER_STATUS_ONLINE : MEMBER_STATUS_OFFLINE ;
onlineState = onlineState | (( isBGGroup ()) ? MEMBER_STATUS_PVP : 0 );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data << citr2 -> name ;
2009-12-22 19:39:02 +01:00
data << uint64 ( citr2 -> guid ); // guid
data << uint8 ( onlineState ); // online-state
data << uint8 ( citr2 -> group ); // groupid
data << uint8 ( citr2 -> flags ); // See enum GroupMemberFlags
2010-08-11 15:20:20 +02:00
data << uint8 ( citr2 -> roles ); // Lfg Roles
2008-10-11 14:16:25 -05:00
}
data << uint64 ( m_leaderGuid ); // leader guid
2010-03-09 20:33:59 +01:00
if ( GetMembersCount () - 1 )
2008-10-11 14:16:25 -05:00
{
2009-12-22 19:39:02 +01:00
data << uint8 ( m_lootMethod ); // loot method
data << uint64 ( m_looterGuid ); // looter guid
data << uint8 ( m_lootThreshold ); // loot threshold
data << uint8 ( m_dungeonDifficulty ); // Dungeon Difficulty
data << uint8 ( m_raidDifficulty ); // Raid Difficulty
2010-02-14 19:13:14 -07:00
data << uint8 ( 0 ); // 3.3
2008-10-11 14:16:25 -05:00
}
2010-04-07 22:59:46 +02:00
player -> GetSession () -> SendPacket ( & data );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: UpdatePlayerOutOfRange ( Player * pPlayer )
{
2010-04-07 19:14:10 +02:00
if ( ! pPlayer || ! pPlayer -> IsInWorld ())
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Player * player ;
WorldPacket data ;
pPlayer -> GetSession () -> BuildPartyMemberStatsChangedPacket ( pPlayer , & data );
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2008-10-11 14:16:25 -05:00
{
player = itr -> getSource ();
if ( player && player != pPlayer && ! pPlayer -> isVisibleFor ( player ))
player -> GetSession () -> SendPacket ( & data );
}
}
2009-10-17 15:51:44 -07:00
2009-03-14 20:00:02 -06:00
void Group :: BroadcastPacket ( WorldPacket * packet , bool ignorePlayersInBGRaid , int group , uint64 ignore )
2008-10-11 14:16:25 -05:00
{
2009-10-17 16:20:24 -07:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2008-10-11 14:16:25 -05:00
{
Player * pl = itr -> getSource ();
2010-04-07 22:59:46 +02:00
if ( ! pl || ( ignore != 0 && pl -> GetGUID () == ignore ) || ( ignorePlayersInBGRaid && pl -> GetGroup () != this ))
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-04-07 23:25:02 +02:00
if ( pl -> GetSession () && ( group == - 1 || itr -> getSubGroup () == group ))
2008-10-11 14:16:25 -05:00
pl -> GetSession () -> SendPacket ( packet );
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: BroadcastReadyCheck ( WorldPacket * packet )
{
2009-10-17 16:20:24 -07:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2008-10-11 14:16:25 -05:00
{
Player * pl = itr -> getSource ();
2010-04-07 19:14:10 +02:00
if ( pl && pl -> GetSession ())
if ( IsLeader ( pl -> GetGUID ()) || IsAssistant ( pl -> GetGUID ()))
2008-10-11 14:16:25 -05:00
pl -> GetSession () -> SendPacket ( packet );
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: OfflineReadyCheck ()
{
2009-10-17 16:20:24 -07:00
for ( member_citerator citr = m_memberSlots . begin (); citr != m_memberSlots . end (); ++ citr )
2008-10-11 14:16:25 -05:00
{
2010-08-08 05:25:45 +02:00
Player * pl = sObjectMgr . GetPlayer ( citr -> guid );
2008-10-11 14:16:25 -05:00
if ( ! pl || ! pl -> GetSession ())
{
WorldPacket data ( MSG_RAID_READY_CHECK_CONFIRM , 9 );
2010-04-11 11:16:42 +04:00
data << uint64 ( citr -> guid );
data << uint8 ( 0 );
2008-10-11 14:16:25 -05:00
BroadcastReadyCheck ( & data );
}
}
}
2009-10-17 15:51:44 -07:00
2009-12-22 19:39:02 +01:00
bool Group :: _addMember ( const uint64 & guid , const char * name )
2008-10-11 14:16:25 -05:00
{
// get first not-full group
uint8 groupid = 0 ;
2008-10-29 17:09:32 -05:00
if ( m_subGroupsCounts )
2008-10-11 14:16:25 -05:00
{
2008-10-29 17:09:32 -05:00
bool groupFound = false ;
2010-06-22 00:42:31 +02:00
for (; groupid < MAX_RAID_SUBGROUPS ; ++ groupid )
2009-02-01 16:38:53 -06:00
{
if ( m_subGroupsCounts [ groupid ] < MAXGROUPSIZE )
{
groupFound = true ;
break ;
}
}
// We are raid group and no one slot is free
if ( ! groupFound )
return false ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-12-22 19:39:02 +01:00
return _addMember ( guid , name , groupid );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-12-22 19:39:02 +01:00
bool Group :: _addMember ( const uint64 & guid , const char * name , uint8 group )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( IsFull ())
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! guid )
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2010-08-08 05:25:45 +02:00
Player * player = sObjectMgr . GetPlayer ( guid );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
MemberSlot member ;
member . guid = guid ;
member . name = name ;
member . group = group ;
2009-12-22 19:39:02 +01:00
member . flags = 0 ;
2010-08-11 15:20:20 +02:00
member . roles = 0 ;
2008-10-11 14:16:25 -05:00
m_memberSlots . push_back ( member );
2009-10-17 15:51:44 -07:00
2009-02-01 16:38:53 -06:00
SubGroupCounterIncrease ( group );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( player )
2008-10-11 14:16:25 -05:00
{
player -> SetGroupInvite ( NULL );
2010-08-08 04:37:24 +02:00
//if player is in group and he is being added to BG raid group, then call SetBattlegroundRaid()
2010-04-07 22:59:46 +02:00
if ( player -> GetGroup () && isBGGroup ())
2010-08-08 04:37:24 +02:00
player -> SetBattlegroundRaid ( this , group );
2009-03-14 20:00:02 -06:00
//if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup()
2010-04-07 22:59:46 +02:00
else if ( player -> GetGroup ())
2009-03-14 20:00:02 -06:00
player -> SetOriginalGroup ( this , group );
//if player is not in group, then call set group
else
player -> SetGroup ( this , group );
2008-10-11 14:16:25 -05:00
// if the same group invites the player back, cancel the homebind timer
2009-12-17 11:11:54 +01:00
InstanceGroupBind * bind = GetBoundInstance ( player );
2010-04-07 19:14:10 +02:00
if ( bind && bind -> save -> GetInstanceId () == player -> GetInstanceId ())
2008-10-11 14:16:25 -05:00
player -> m_InstanceValid = true ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! isRaidGroup ()) // reset targetIcons for non-raid-groups
2008-10-11 14:16:25 -05:00
{
2010-05-08 01:58:47 +02:00
for ( uint8 i = 0 ; i < TARGETICONCOUNT ; ++ i )
2008-10-11 14:16:25 -05:00
m_targetIcons [ i ] = 0 ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ())
2008-10-11 14:16:25 -05:00
{
// insert into group table
2010-09-10 13:40:20 +02:00
CharacterDatabase . PExecute ( "INSERT INTO group_member (guid, memberGuid, memberFlags, subgroup, roles) VALUES(%u, %u, %u, %u, %u)" , GUID_LOPART ( m_guid ), GUID_LOPART ( member . guid ), member . flags , member . group , member . roles );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Group :: _removeMember ( const uint64 & guid )
{
2010-08-08 05:25:45 +02:00
Player * player = sObjectMgr . GetPlayer ( guid );
2008-10-11 14:16:25 -05:00
if ( player )
{
2009-03-14 20:00:02 -06:00
//if we are removing player from battleground raid
2010-04-07 22:59:46 +02:00
if ( isBGGroup ())
2010-08-08 04:37:24 +02:00
player -> RemoveFromBattlegroundRaid ();
2009-03-14 20:00:02 -06:00
else
{
//we can remove player who is in battleground from his original group
2010-04-07 22:59:46 +02:00
if ( player -> GetOriginalGroup () == this )
2009-03-14 20:00:02 -06:00
player -> SetOriginalGroup ( NULL );
else
player -> SetGroup ( NULL );
2010-05-20 23:35:27 +02:00
player -> GetSession () -> SendLfgUpdateParty ( LFG_UPDATETYPE_LEADER );
2009-03-14 20:00:02 -06:00
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_removeRolls ( guid );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
member_witerator slot = _getMemberWSlot ( guid );
if ( slot != m_memberSlots . end ())
2009-02-01 16:38:53 -06:00
{
SubGroupCounterDecrease ( slot -> group );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_memberSlots . erase ( slot );
2009-02-01 16:38:53 -06:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ())
2010-05-08 01:58:47 +02:00
CharacterDatabase . PExecute ( "DELETE FROM group_member WHERE memberGuid=%u" , GUID_LOPART ( guid ));
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( m_leaderGuid == guid ) // leader was removed
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( GetMembersCount () > 0 )
2008-10-11 14:16:25 -05:00
_setLeader ( m_memberSlots . front (). guid );
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: _setLeader ( const uint64 & guid )
{
2010-03-09 20:33:59 +01:00
member_witerator slot = _getMemberWSlot ( guid );
2010-04-07 23:25:02 +02:00
if ( slot == m_memberSlots . end ())
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ())
2008-10-11 14:16:25 -05:00
{
// TODO: set a time limit to have this function run rarely cause it can be slow
2010-08-21 03:19:25 +02:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// update the group's bound instances when changing leaders
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// remove all permanent binds from the group
// in the DB also remove solo binds that will be replaced with permbinds
// from the new leader
2010-08-21 03:19:25 +02:00
trans -> PAppend (
2010-05-08 01:58:47 +02:00
"DELETE FROM group_instance WHERE guid=%u AND (permanent = 1 OR "
2008-10-11 14:16:25 -05:00
"instance IN (SELECT instance FROM character_instance WHERE guid = '%u')"
2010-05-08 01:58:47 +02:00
")" , GUID_LOPART ( m_guid ), GUID_LOPART ( slot -> guid )
2010-05-03 16:30:53 +02:00
);
2009-10-17 15:51:44 -07:00
2010-08-08 05:25:45 +02:00
Player * player = sObjectMgr . GetPlayer ( slot -> guid );
2010-04-07 19:14:10 +02:00
if ( player )
2008-10-11 14:16:25 -05:00
{
2009-12-17 11:11:54 +01:00
for ( uint8 i = 0 ; i < MAX_DIFFICULTY ; ++ i )
2008-10-11 14:16:25 -05:00
{
2009-11-20 19:11:28 -08:00
for ( BoundInstancesMap :: iterator itr = m_boundInstances [ i ]. begin (); itr != m_boundInstances [ i ]. end ();)
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( itr -> second . perm )
2008-10-11 14:16:25 -05:00
{
itr -> second . save -> RemoveGroup ( this );
m_boundInstances [ i ]. erase ( itr ++ );
}
else
++ itr ;
}
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// copy the permanent binds from the new leader to the group
// overwriting the solo binds with permanent ones if necessary
// in the DB those have been deleted already
Player :: ConvertInstancesToGroup ( player , this , slot -> guid );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// update the group leader
2010-08-21 03:19:25 +02:00
trans -> PAppend ( "UPDATE groups SET leaderGuid='%u' WHERE guid='%u'" , GUID_LOPART ( slot -> guid ), GUID_LOPART ( m_guid ));
CharacterDatabase . CommitTransaction ( trans );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_leaderGuid = slot -> guid ;
m_leaderName = slot -> name ;
2010-03-09 20:33:59 +01:00
ToggleGroupMemberFlag ( slot , MEMBER_FLAG_ASSISTANT , false );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: _removeRolls ( const uint64 & guid )
{
2009-06-04 16:09:01 -05:00
for ( Rolls :: iterator it = RollId . begin (); it != RollId . end (); ++ it )
2008-10-11 14:16:25 -05:00
{
Roll * roll = * it ;
Roll :: PlayerVote :: iterator itr2 = roll -> playerVote . find ( guid );
2010-04-07 19:14:10 +02:00
if ( itr2 == roll -> playerVote . end ())
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
if ( itr2 -> second == GREED || itr2 -> second == DISENCHANT ) -- roll -> totalGreed ;
2008-10-11 14:16:25 -05:00
if ( itr2 -> second == NEED ) -- roll -> totalNeed ;
if ( itr2 -> second == PASS ) -- roll -> totalPass ;
if ( itr2 -> second != NOT_VALID ) -- roll -> totalPlayersRolling ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
roll -> playerVote . erase ( itr2 );
2009-10-17 15:51:44 -07:00
2009-12-17 11:11:54 +01:00
CountRollVote ( guid , roll -> itemGUID , GetMembersCount () - 1 , MAX_ROLL_TYPE );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Group :: _setMembersGroup ( const uint64 & guid , const uint8 & group )
{
member_witerator slot = _getMemberWSlot ( guid );
2010-04-07 23:25:02 +02:00
if ( slot == m_memberSlots . end ())
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
slot -> group = group ;
2009-10-17 15:51:44 -07:00
2009-02-01 16:38:53 -06:00
SubGroupCounterIncrease ( group );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ()) CharacterDatabase . PExecute ( "UPDATE group_member SET subgroup='%u' WHERE memberGuid='%u'" , group , GUID_LOPART ( guid ));
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2009-12-22 19:39:02 +01:00
bool Group :: _setAssistantFlag ( const uint64 & guid , const bool & apply )
2008-10-11 14:16:25 -05:00
{
member_witerator slot = _getMemberWSlot ( guid );
2009-12-22 19:39:02 +01:00
if ( slot == m_memberSlots . end ())
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-12-22 19:39:02 +01:00
ToggleGroupMemberFlag ( slot , MEMBER_FLAG_ASSISTANT , apply );
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ())
2010-03-09 20:33:59 +01:00
CharacterDatabase . PExecute ( "UPDATE group_member SET memberFlags='%u' WHERE memberGuid='%u'" , slot -> flags , GUID_LOPART ( guid ));
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2009-12-22 19:39:02 +01:00
bool Group :: _setMainTank ( const uint64 & guid , const bool & apply )
2008-10-11 14:16:25 -05:00
{
2009-12-22 19:39:02 +01:00
member_witerator slot = _getMemberWSlot ( guid ); // First check member slots to see if the target exists
if ( slot == m_memberSlots . end ())
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-12-22 19:39:02 +01:00
RemoveUniqueGroupMemberFlag ( MEMBER_FLAG_MAINTANK ); // Remove main tank flag from current if any.
ToggleGroupMemberFlag ( slot , MEMBER_FLAG_MAINTANK , apply ); // And apply main tank flag on new main tank.
2010-04-07 18:09:10 +02:00
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ())
2010-03-09 20:33:59 +01:00
CharacterDatabase . PExecute ( "UPDATE group_member SET memberFlags='%u' WHERE memberGuid='%u'" , slot -> flags , GUID_LOPART ( guid ));
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2009-12-22 19:39:02 +01:00
bool Group :: _setMainAssistant ( const uint64 & guid , const bool & apply )
2008-10-11 14:16:25 -05:00
{
member_witerator slot = _getMemberWSlot ( guid );
2009-12-22 19:39:02 +01:00
if ( slot == m_memberSlots . end ())
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-12-22 19:39:02 +01:00
RemoveUniqueGroupMemberFlag ( MEMBER_FLAG_MAINASSIST ); // Remove main assist flag from current if any.
ToggleGroupMemberFlag ( slot , MEMBER_FLAG_MAINASSIST , apply ); // Apply main assist flag on new main assist.
2010-02-14 19:13:14 -07:00
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ())
2010-03-09 20:33:59 +01:00
CharacterDatabase . PExecute ( "UPDATE group_member SET memberFlags='%u' WHERE memberGuid='%u'" , slot -> flags , GUID_LOPART ( guid ));
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Group :: SameSubGroup ( Player const * member1 , Player const * member2 ) const
{
2010-04-07 19:14:10 +02:00
if ( ! member1 || ! member2 ) return false ;
2008-10-11 14:16:25 -05:00
if ( member1 -> GetGroup () != this || member2 -> GetGroup () != this ) return false ;
else return member1 -> GetSubGroup () == member2 -> GetSubGroup ();
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// allows setting subgroup for offline members
void Group :: ChangeMembersGroup ( const uint64 & guid , const uint8 & group )
{
2010-04-07 19:14:10 +02:00
if ( ! isRaidGroup ())
2008-10-11 14:16:25 -05:00
return ;
2010-06-22 00:42:31 +02:00
2010-08-08 05:25:45 +02:00
Player * player = sObjectMgr . GetPlayer ( guid );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( ! player )
{
2010-06-22 00:42:31 +02:00
uint8 prevSubGroup = GetMemberGroup ( guid );
if ( prevSubGroup == group )
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( _setMembersGroup ( guid , group ))
2010-06-22 00:42:31 +02:00
{
SubGroupCounterDecrease ( prevSubGroup );
2008-10-11 14:16:25 -05:00
SendUpdate ();
2010-06-22 00:42:31 +02:00
}
2008-10-11 14:16:25 -05:00
}
2008-10-29 17:09:32 -05:00
else
2009-02-01 16:38:53 -06:00
// This methods handles itself groupcounter decrease
ChangeMembersGroup ( player , group );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// only for online members
void Group :: ChangeMembersGroup ( Player * player , const uint8 & group )
{
2010-04-07 19:14:10 +02:00
if ( ! player || ! isRaidGroup ())
2008-10-11 14:16:25 -05:00
return ;
2010-08-08 19:45:53 +02:00
2010-06-22 00:42:31 +02:00
uint8 prevSubGroup = player -> GetSubGroup ();
if ( prevSubGroup == group )
return ;
2010-04-07 19:14:10 +02:00
if ( _setMembersGroup ( player -> GetGUID (), group ))
2008-10-11 14:16:25 -05:00
{
2010-04-07 22:59:46 +02:00
if ( player -> GetGroup () == this )
2009-03-14 20:00:02 -06:00
player -> GetGroupRef (). setSubGroup ( group );
//if player is in BG raid, it is possible that he is also in normal raid - and that normal raid is stored in m_originalGroup reference
else
{
prevSubGroup = player -> GetOriginalSubGroup ();
player -> GetOriginalGroupRef (). setSubGroup ( group );
}
2009-02-01 16:38:53 -06:00
SubGroupCounterDecrease ( prevSubGroup );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SendUpdate ();
}
}
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
// Retrieve the next Round-Roubin player for the group
//
// No update done if loot method is Master or FFA.
//
// If the RR player is not yet set for the group, the first group member becomes the round-robin player.
// If the RR player is set, the next player in group becomes the round-robin player.
//
2010-04-07 18:09:10 +02:00
// If ifneed is true,
2010-03-11 22:55:02 +01:00
// the current RR player is checked to be near the looted object.
// if yes, no update done.
// if not, he looses his turn.
void Group :: UpdateLooterGuid ( WorldObject * pLootedObject , bool ifneed )
2008-10-11 14:16:25 -05:00
{
switch ( GetLootMethod ())
{
case MASTER_LOOT :
case FREE_FOR_ALL :
return ;
default :
// round robin style looting applies for all low
// quality items in each loot method except free for all and master loot
break ;
}
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
uint64 oldLooterGUID = GetLooterGuid ();
member_citerator guid_itr = _getMemberCSlot ( oldLooterGUID );
if ( guid_itr != m_memberSlots . end ())
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
if ( ifneed )
2008-10-11 14:16:25 -05:00
{
// not update if only update if need and ok
Player * looter = ObjectAccessor :: FindPlayer ( guid_itr -> guid );
2010-08-23 19:56:47 -07:00
if ( looter && looter -> IsWithinDistInMap ( pLootedObject , sWorld . getFloatConfig ( CONFIG_GROUP_XP_DISTANCE ), false ))
2008-10-11 14:16:25 -05:00
return ;
}
++ guid_itr ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// search next after current
2010-03-11 22:55:02 +01:00
Player * pNewLooter = NULL ;
for ( member_citerator itr = guid_itr ; itr != m_memberSlots . end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
if ( Player * pl = ObjectAccessor :: FindPlayer ( itr -> guid ))
2010-08-23 19:56:47 -07:00
if ( pl -> IsWithinDistInMap ( pLootedObject , sWorld . getFloatConfig ( CONFIG_GROUP_XP_DISTANCE ), false ))
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
pNewLooter = pl ;
break ;
}
}
if ( ! pNewLooter )
{
// search from start
for ( member_citerator itr = m_memberSlots . begin (); itr != guid_itr ; ++ itr )
{
if ( Player * pl = ObjectAccessor :: FindPlayer ( itr -> guid ))
2010-08-23 19:56:47 -07:00
if ( pl -> IsWithinDistInMap ( pLootedObject , sWorld . getFloatConfig ( CONFIG_GROUP_XP_DISTANCE ), false ))
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
pNewLooter = pl ;
break ;
2008-10-11 14:16:25 -05:00
}
}
}
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
if ( pNewLooter )
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
if ( oldLooterGUID != pNewLooter -> GetGUID ())
2008-10-11 14:16:25 -05:00
{
2010-03-11 22:55:02 +01:00
SetLooterGuid ( pNewLooter -> GetGUID ());
SendUpdate ();
2008-10-11 14:16:25 -05:00
}
}
2010-03-11 22:55:02 +01:00
else
{
SetLooterGuid ( 0 );
SendUpdate ();
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-08-08 04:37:24 +02:00
GroupJoinBattlegroundResult Group :: CanJoinBattlegroundQueue ( Battleground const * bgOrTemplate , BattlegroundQueueTypeId bgQueueTypeId , uint32 MinPlayerCount , uint32 /*MaxPlayerCount*/ , bool isRated , uint32 arenaSlot )
2008-10-11 14:16:25 -05:00
{
2010-04-11 11:22:29 +04:00
BattlemasterListEntry const * bgEntry = sBattlemasterListStore . LookupEntry ( bgOrTemplate -> GetTypeID ());
2010-04-11 20:20:38 +02:00
if ( ! bgEntry )
return ERR_GROUP_JOIN_BATTLEGROUND_FAIL ; // shouldn't happen
2010-04-11 11:22:29 +04:00
2008-10-11 14:16:25 -05:00
// check for min / max count
uint32 memberscount = GetMembersCount ();
2010-04-11 20:20:38 +02:00
// only check for MinPlayerCount since MinPlayerCount == MaxPlayerCount for arenas...
if ( bgOrTemplate -> isArena () && memberscount != MinPlayerCount )
return ERR_ARENA_TEAM_PARTY_SIZE ;
2010-04-11 11:22:29 +04:00
if ( memberscount > bgEntry -> maxGroupSize ) // no MinPlayerCount for battlegrounds
2010-05-08 01:58:47 +02:00
return ERR_BATTLEGROUND_NONE ; // ERR_GROUP_JOIN_BATTLEGROUND_TOO_MANY handled on client side
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// get a player as reference, to compare other players' stats to (arena team id, queue id based on level, etc.)
Player * reference = GetFirstMember () -> getSource ();
// no reference found, can't join this way
2010-04-07 19:14:10 +02:00
if ( ! reference )
2010-04-11 11:22:29 +04:00
return ERR_BATTLEGROUND_JOIN_FAILED ;
2009-10-17 15:51:44 -07:00
2010-02-15 15:31:27 +01:00
PvPDifficultyEntry const * bracketEntry = GetBattlegroundBracketByLevel ( bgOrTemplate -> GetMapId (), reference -> getLevel ());
2010-04-07 19:14:10 +02:00
if ( ! bracketEntry )
2010-04-11 11:22:29 +04:00
return ERR_BATTLEGROUND_JOIN_FAILED ;
2010-02-15 15:31:27 +01:00
2008-10-11 14:16:25 -05:00
uint32 arenaTeamId = reference -> GetArenaTeamId ( arenaSlot );
uint32 team = reference -> GetTeam ();
2009-10-17 15:51:44 -07:00
2010-08-08 04:37:24 +02:00
BattlegroundQueueTypeId bgQueueTypeIdRandom = BattlegroundMgr :: BGQueueTypeId ( BATTLEGROUND_RB , 0 );
2010-05-26 11:34:37 +02:00
2008-10-11 14:16:25 -05:00
// check every member of the group to be able to join
2009-10-17 16:20:24 -07:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2008-10-11 14:16:25 -05:00
{
Player * member = itr -> getSource ();
// offline member? don't let join
2010-04-07 19:14:10 +02:00
if ( ! member )
2010-04-11 11:22:29 +04:00
return ERR_BATTLEGROUND_JOIN_FAILED ;
2008-10-11 14:16:25 -05:00
// don't allow cross-faction join as group
2010-04-07 19:14:10 +02:00
if ( member -> GetTeam () != team )
2010-04-11 11:22:29 +04:00
return ERR_BATTLEGROUND_JOIN_TIMED_OUT ;
2008-10-11 14:16:25 -05:00
// not in the same battleground level braket, don't let join
2010-02-15 15:31:27 +01:00
PvPDifficultyEntry const * memberBracketEntry = GetBattlegroundBracketByLevel ( bracketEntry -> mapId , member -> getLevel ());
2010-04-07 19:14:10 +02:00
if ( memberBracketEntry != bracketEntry )
2010-04-11 11:22:29 +04:00
return ERR_BATTLEGROUND_JOIN_RANGE_INDEX ;
2008-10-11 14:16:25 -05:00
// don't let join rated matches if the arena team id doesn't match
2010-04-07 19:14:10 +02:00
if ( isRated && member -> GetArenaTeamId ( arenaSlot ) != arenaTeamId )
2010-04-11 11:22:29 +04:00
return ERR_BATTLEGROUND_JOIN_FAILED ;
2008-10-11 14:16:25 -05:00
// don't let join if someone from the group is already in that bg queue
2010-08-08 04:37:24 +02:00
if ( member -> InBattlegroundQueueForBattlegroundQueueType ( bgQueueTypeId ))
2010-04-11 11:22:29 +04:00
return ERR_BATTLEGROUND_JOIN_FAILED ; // not blizz-like
2010-05-26 11:34:37 +02:00
// don't let join if someone from the group is in bg queue random
2010-08-08 04:37:24 +02:00
if ( member -> InBattlegroundQueueForBattlegroundQueueType ( bgQueueTypeIdRandom ))
2010-05-26 11:34:37 +02:00
return ERR_IN_RANDOM_BG ;
// don't let join to bg queue random if someone from the group is already in bg queue
2010-08-08 04:37:24 +02:00
if ( bgOrTemplate -> GetTypeID () == BATTLEGROUND_RB && member -> InBattlegroundQueue ())
2010-05-26 11:34:37 +02:00
return ERR_IN_NON_RANDOM_BG ;
2008-10-11 14:16:25 -05:00
// check for deserter debuff in case not arena queue
2010-04-07 19:14:10 +02:00
if ( bgOrTemplate -> GetTypeID () != BATTLEGROUND_AA && ! member -> CanJoinToBattleground ())
2010-04-11 11:22:29 +04:00
return ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS ;
2008-10-11 14:16:25 -05:00
// check if member can join any more battleground queues
2010-08-08 04:37:24 +02:00
if ( ! member -> HasFreeBattlegroundQueueId ())
2010-04-11 11:22:29 +04:00
return ERR_BATTLEGROUND_TOO_MANY_QUEUES ; // not blizz-like
2008-10-11 14:16:25 -05:00
}
2010-04-11 11:22:29 +04:00
return GroupJoinBattlegroundResult ( bgOrTemplate -> GetTypeID ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//===================================================
2010-04-07 23:56:35 +02:00
//============== Roll ===============================
2008-10-11 14:16:25 -05:00
//===================================================
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Roll :: targetObjectBuildLink ()
{
// called from link()
2009-02-01 16:38:53 -06:00
getTarget () -> addLootValidatorRef ( this );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-12-17 11:11:54 +01:00
void Group :: SetDungeonDifficulty ( Difficulty difficulty )
2008-10-11 14:16:25 -05:00
{
2009-12-17 11:11:54 +01:00
m_dungeonDifficulty = difficulty ;
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ())
2010-05-08 01:58:47 +02:00
CharacterDatabase . PExecute ( "UPDATE groups SET difficulty = %u WHERE guid ='%u'" , m_dungeonDifficulty , GUID_LOPART ( m_guid ));
2009-12-18 13:41:30 -08:00
2009-10-17 16:20:24 -07:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2008-10-11 14:16:25 -05:00
{
Player * player = itr -> getSource ();
2010-04-07 19:14:10 +02:00
if ( ! player -> GetSession () || player -> getLevel () < LEVELREQUIREMENT_HEROIC )
2008-10-11 14:16:25 -05:00
continue ;
2009-12-17 11:11:54 +01:00
player -> SetDungeonDifficulty ( difficulty );
2008-10-11 14:16:25 -05:00
player -> SendDungeonDifficulty ( true );
2009-12-17 11:11:54 +01:00
}
}
void Group :: SetRaidDifficulty ( Difficulty difficulty )
{
m_raidDifficulty = difficulty ;
2010-04-07 19:14:10 +02:00
if ( ! isBGGroup ())
2010-05-08 01:58:47 +02:00
CharacterDatabase . PExecute ( "UPDATE groups SET raiddifficulty = %u WHERE guid ='%u'" , m_raidDifficulty , GUID_LOPART ( m_guid ));
2009-12-17 11:11:54 +01:00
2010-04-07 19:12:44 +02:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2009-12-17 11:11:54 +01:00
{
Player * player = itr -> getSource ();
2010-04-07 19:14:10 +02:00
if ( ! player -> GetSession () || player -> getLevel () < LEVELREQUIREMENT_HEROIC )
2009-12-17 11:11:54 +01:00
continue ;
player -> SetRaidDifficulty ( difficulty );
player -> SendRaidDifficulty ( true );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Group :: InCombatToInstance ( uint32 instanceId )
{
2009-10-17 16:20:24 -07:00
for ( GroupReference * itr = GetFirstMember (); itr != NULL ; itr = itr -> next ())
2008-10-11 14:16:25 -05:00
{
Player * pPlayer = itr -> getSource ();
2010-04-07 19:14:10 +02:00
if ( pPlayer && pPlayer -> getAttackers (). size () && pPlayer -> GetInstanceId () == instanceId && ( pPlayer -> GetMap () -> IsRaidOrHeroicDungeon ()))
2010-04-08 08:20:08 +02:00
for ( std :: set < Unit *>:: const_iterator i = pPlayer -> getAttackers (). begin (); i != pPlayer -> getAttackers (). end (); ++ i )
2010-04-07 19:14:10 +02:00
if (( * i ) && ( * i ) -> GetTypeId () == TYPEID_UNIT && ( * i ) -> ToCreature () -> GetCreatureInfo () -> flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND )
2009-02-13 23:53:06 +01:00
return true ;
2008-10-11 14:16:25 -05:00
}
return false ;
}
2009-10-17 15:51:44 -07:00
2009-12-17 11:11:54 +01:00
void Group :: ResetInstances ( uint8 method , bool isRaid , Player * SendMsgTo )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( isBGGroup ())
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_DISBAND
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// we assume that when the difficulty changes, all instances that can be reset will be
2009-12-17 11:11:54 +01:00
Difficulty diff = GetDifficulty ( isRaid );
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
for ( BoundInstancesMap :: iterator itr = m_boundInstances [ diff ]. begin (); itr != m_boundInstances [ diff ]. end ();)
2008-10-11 14:16:25 -05:00
{
InstanceSave * p = itr -> second . save ;
const MapEntry * entry = sMapStore . LookupEntry ( itr -> first );
2010-08-30 15:25:15 +02:00
if ( ! entry || entry -> IsRaid () != isRaid || ( ! p -> CanReset () && method != INSTANCE_RESET_GROUP_DISBAND ))
2008-10-11 14:16:25 -05:00
{
++ itr ;
continue ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( method == INSTANCE_RESET_ALL )
2008-10-11 14:16:25 -05:00
{
// the "reset all instances" method can only reset normal maps
2009-12-17 11:11:54 +01:00
if ( entry -> map_type == MAP_RAID || diff == DUNGEON_DIFFICULTY_HEROIC )
2008-10-11 14:16:25 -05:00
{
++ itr ;
continue ;
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool isEmpty = true ;
// if the map is loaded, reset it
2010-06-25 00:18:01 +02:00
Map * map = sMapMgr . FindMap ( p -> GetMapId (), p -> GetInstanceId ());
2010-04-07 19:14:10 +02:00
if ( map && map -> IsDungeon () && ! ( method == INSTANCE_RESET_GROUP_DISBAND && ! p -> CanReset ()))
2009-06-18 21:35:34 +02:00
{
2010-04-07 19:14:10 +02:00
if ( p -> CanReset ())
2009-06-18 21:35:34 +02:00
isEmpty = (( InstanceMap * ) map ) -> Reset ( method );
else
isEmpty = ! map -> HavePlayers ();
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( SendMsgTo )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( isEmpty ) SendMsgTo -> SendResetInstanceSuccess ( p -> GetMapId ());
2008-10-11 14:16:25 -05:00
else SendMsgTo -> SendResetInstanceFailed ( 0 , p -> GetMapId ());
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( isEmpty || method == INSTANCE_RESET_GROUP_DISBAND || method == INSTANCE_RESET_CHANGE_DIFFICULTY )
2008-10-11 14:16:25 -05:00
{
// do not reset the instance, just unbind if others are permanently bound to it
2010-04-07 19:14:10 +02:00
if ( p -> CanReset ()) p -> DeleteFromDB ();
2008-10-11 14:16:25 -05:00
else CharacterDatabase . PExecute ( "DELETE FROM group_instance WHERE instance = '%u'" , p -> GetInstanceId ());
// i don't know for sure if hash_map iterators
2009-12-17 11:11:54 +01:00
m_boundInstances [ diff ]. erase ( itr );
itr = m_boundInstances [ diff ]. begin ();
2008-10-11 14:16:25 -05:00
// this unloads the instance save unless online players are bound to it
// (eg. permanent binds or GM solo binds)
p -> RemoveGroup ( this );
}
else
++ itr ;
}
}
2009-10-17 15:51:44 -07:00
2009-12-17 11:11:54 +01:00
InstanceGroupBind * Group :: GetBoundInstance ( Player * player )
2008-10-11 14:16:25 -05:00
{
2009-12-17 11:11:54 +01:00
uint32 mapid = player -> GetMapId ();
MapEntry const * mapEntry = sMapStore . LookupEntry ( mapid );
2010-06-26 17:57:49 +02:00
return GetBoundInstance ( mapEntry );
2010-06-26 13:32:24 +02:00
}
2009-12-17 11:11:54 +01:00
2010-06-26 13:32:24 +02:00
InstanceGroupBind * Group :: GetBoundInstance ( Map * aMap )
{
// Currently spawn numbering not different from map difficulty
Difficulty difficulty = GetDifficulty ( aMap -> IsRaid ());
2009-12-17 11:11:54 +01:00
2008-10-11 14:16:25 -05:00
// some instances only have one difficulty
2010-08-30 15:25:15 +02:00
GetDownscaledMapDifficultyData ( aMap -> GetId (), difficulty );
2009-10-17 15:51:44 -07:00
2010-06-26 13:32:24 +02:00
BoundInstancesMap :: iterator itr = m_boundInstances [ difficulty ]. find ( aMap -> GetId ());
2010-04-07 19:14:10 +02:00
if ( itr != m_boundInstances [ difficulty ]. end ())
2008-10-11 14:16:25 -05:00
return & itr -> second ;
else
return NULL ;
}
2009-10-17 15:51:44 -07:00
2010-06-26 13:32:24 +02:00
InstanceGroupBind * Group :: GetBoundInstance ( MapEntry const * mapEntry )
2009-12-17 11:11:54 +01:00
{
2010-06-26 13:32:24 +02:00
if ( ! mapEntry )
return NULL ;
2010-08-08 19:45:53 +02:00
2010-06-26 13:32:24 +02:00
Difficulty difficulty = GetDifficulty ( mapEntry -> IsRaid ());
2010-08-08 19:45:53 +02:00
2009-12-17 11:11:54 +01:00
// some instances only have one difficulty
2010-08-30 15:25:15 +02:00
GetDownscaledMapDifficultyData ( mapEntry -> MapID , difficulty );
2010-08-08 19:45:53 +02:00
2010-06-26 13:32:24 +02:00
BoundInstancesMap :: iterator itr = m_boundInstances [ difficulty ]. find ( mapEntry -> MapID );
2010-04-07 19:14:10 +02:00
if ( itr != m_boundInstances [ difficulty ]. end ())
2009-12-17 11:11:54 +01:00
return & itr -> second ;
else
return NULL ;
}
2008-10-11 14:16:25 -05:00
InstanceGroupBind * Group :: BindToInstance ( InstanceSave * save , bool permanent , bool load )
{
2010-05-08 01:58:47 +02:00
if ( ! save || isBGGroup ())
return NULL ;
2009-10-17 15:51:44 -07:00
2010-05-08 01:58:47 +02:00
InstanceGroupBind & bind = m_boundInstances [ save -> GetDifficulty ()][ save -> GetMapId ()];
if ( ! load && ( ! bind . save || permanent != bind . perm || save != bind . save ))
CharacterDatabase . PExecute ( "REPLACE INTO group_instance (guid, instance, permanent) VALUES (%u, %u, %u)" , GUID_LOPART ( GetGUID ()), save -> GetInstanceId (), permanent );
2009-10-17 15:51:44 -07:00
2010-05-08 01:58:47 +02:00
if ( bind . save != save )
{
if ( bind . save )
bind . save -> RemoveGroup ( this );
save -> AddGroup ( this );
2008-10-11 14:16:25 -05:00
}
2010-05-08 01:58:47 +02:00
bind . save = save ;
bind . perm = permanent ;
if ( ! load )
sLog . outDebug ( "Group::BindToInstance: %d is now bound to map %d, instance %d, difficulty %d" , GUID_LOPART ( GetGUID ()), save -> GetMapId (), save -> GetInstanceId (), save -> GetDifficulty ());
return & bind ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: UnbindInstance ( uint32 mapid , uint8 difficulty , bool unload )
{
BoundInstancesMap :: iterator itr = m_boundInstances [ difficulty ]. find ( mapid );
2010-04-07 19:14:10 +02:00
if ( itr != m_boundInstances [ difficulty ]. end ())
2008-10-11 14:16:25 -05:00
{
2010-05-08 01:58:47 +02:00
if ( ! unload )
CharacterDatabase . PExecute ( "DELETE FROM group_instance WHERE guid=%u AND instance=%u" , GUID_LOPART ( GetGUID ()), itr -> second . save -> GetInstanceId ());
2008-10-11 14:16:25 -05:00
itr -> second . save -> RemoveGroup ( this ); // save can become invalid
m_boundInstances [ difficulty ]. erase ( itr );
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Group :: _homebindIfInstance ( Player * player )
{
2010-04-07 19:14:10 +02:00
if ( player && ! player -> isGameMaster () && sMapStore . LookupEntry ( player -> GetMapId ()) -> IsDungeon ())
2010-05-04 18:25:30 +02:00
player -> m_InstanceValid = false ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-01-15 21:29:32 -05:00
void Group :: BroadcastGroupUpdate ( void )
{
// FG: HACK: force flags update on group leave - for values update hack
// -- not very efficient but safe
2009-10-17 16:20:24 -07:00
for ( member_citerator citr = m_memberSlots . begin (); citr != m_memberSlots . end (); ++ citr )
2009-01-15 21:29:32 -05:00
{
2009-10-17 15:51:44 -07:00
2010-08-08 05:25:45 +02:00
Player * pp = sObjectMgr . GetPlayer ( citr -> guid );
2010-04-07 19:14:10 +02:00
if ( pp && pp -> IsInWorld ())
2009-01-15 21:29:32 -05:00
{
pp -> ForceValuesUpdateAtIndex ( UNIT_FIELD_BYTES_2 );
pp -> ForceValuesUpdateAtIndex ( UNIT_FIELD_FACTIONTEMPLATE );
2010-08-22 01:57:04 +02:00
sLog . outStaticDebug ( "-- Forced group value update for '%s'" , pp -> GetName ());
2009-01-15 21:29:32 -05:00
}
}
2009-02-01 16:38:53 -06:00
}
2010-05-21 22:45:47 +02:00
void Group :: ResetMaxEnchantingLevel ()
{
m_maxEnchantingLevel = 0 ;
Player * pMember = NULL ;
for ( member_citerator citr = m_memberSlots . begin (); citr != m_memberSlots . end (); ++ citr )
{
2010-08-30 15:25:15 +02:00
pMember = sObjectMgr . GetPlayer ( citr -> guid );
if ( pMember && m_maxEnchantingLevel < pMember -> GetSkillValue ( SKILL_ENCHANTING ))
m_maxEnchantingLevel = pMember -> GetSkillValue ( SKILL_ENCHANTING );
2010-05-21 22:45:47 +02:00
}
}