bool Group::AddMember(ObjectGuid guid, const char* name) { if (!_addMember(guid, name)) return false; SendUpdate(); if (Player* player = sObjectMgr.GetPlayer(guid)) { if (!IsLeader(player->GetObjectGuid()) && !isBGGroup()) { // reset the new member's instances, unless he is currently in one of them // including raid instances that they are not permanently bound to! player->ResetInstances(INSTANCE_RESET_GROUP_JOIN); } player->SetGroupUpdateFlag(GROUP_UPDATE_FULL); UpdatePlayerOutOfRange(player); // quest related GO state dependent from raid membership if (isRaidGroup()) player->UpdateForQuestWorldObjects(); } return true; }
bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, uint8 group) { if(IsFull()) return false; MemberSlot member; member.guid = guid; member.name = name; member.group = group; member.assistant = isAssistant; m_members.push_back(member); Player *player = objmgr.GetPlayer(guid); if(player) { player->groupInfo.invite = NULL; player->groupInfo.group = this; } if(!isRaidGroup()) // reset targetIcons for non-raid-groups { for(int i=0; i<TARGETICONCOUNT; i++) m_targetIcons[i] = 0; } // insert into group table sDatabase.PExecute("INSERT INTO `group_member`(`leaderGuid`,`memberGuid`,`assistant`,`subgroup`) VALUES('%u','%u','%u','%u')", GUID_LOPART(m_leaderGuid), GUID_LOPART(member.guid), ((member.assistant==1)?1:0), member.group); return true; }
bool Group::AddMember(ObjectGuid guid, const char* name) { if (!_addMember(guid, name)) return false; SendUpdate(); if (Player* player = sObjectMgr.GetPlayer(guid)) { if (!IsLeader(player->GetObjectGuid()) && !isBGGroup()) { // 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! player->ResetInstances(INSTANCE_RESET_GROUP_JOIN); if (player->getLevel() >= LEVELREQUIREMENT_HEROIC && player->GetDifficulty() != GetDifficulty()) { player->SetDifficulty(GetDifficulty()); player->SendDungeonDifficulty(true); } } player->SetGroupUpdateFlag(GROUP_UPDATE_FULL); UpdatePlayerOutOfRange(player); // used by eluna GlobalEluna(OnAddMember(this, player->GetObjectGuid())); // quest related GO state dependent from raid membership if (isRaidGroup()) player->UpdateForQuestWorldObjects(); } return true; }
uint32 Group::RemoveMember(ObjectGuid guid, uint8 method) { //Playerbot mod - if master leaves group, all bots leave group { Player* const player = sObjectMgr.GetPlayer(guid); if (player && player->GetPlayerbotMgr()) player->GetPlayerbotMgr()->RemoveAllBotsFromGroup(); } //END Playerbot mod // remove member and change leader (if need) only if strong more 2 members _before_ member remove if (GetMembersCount() > uint32(isBGGroup() ? 1 : 2)) // in BG group case allow 1 members group { bool leaderChanged = _removeMember(guid); if (Player* player = sObjectMgr.GetPlayer(guid)) { // quest related GO state dependent from raid membership if (isRaidGroup()) player->UpdateForQuestWorldObjects(); WorldPacket data; if (method == 1) { data.Initialize(SMSG_GROUP_UNINVITE, 0); player->GetSession()->SendPacket(&data); } // we already removed player from group and in player->GetGroup() is his original group! if (Group* group = player->GetGroup()) { group->SendUpdate(); } else { data.Initialize(SMSG_GROUP_LIST, 24); data << uint64(0) << uint64(0) << uint64(0); player->GetSession()->SendPacket(&data); } _homebindIfInstance(player); } if (leaderChanged) { WorldPacket data(SMSG_GROUP_SET_LEADER, (m_memberSlots.front().name.size() + 1)); data << m_memberSlots.front().name; BroadcastPacket(&data, true); } SendUpdate(); } // if group before remove <= 2 disband it else Disband(true); return m_memberSlots.size(); }
bool Group::_addMember(ObjectGuid guid, const char* name, bool isAssistant, uint8 group) { if (IsFull()) return false; if (!guid) return false; Player* player = sObjectMgr.GetPlayer(guid, false); MemberSlot member; member.guid = guid; member.name = name; member.group = group; member.assistant = isAssistant; m_memberSlots.push_back(member); SubGroupCounterIncrease(group); if (player) { player->SetGroupInvite(NULL); // if player is in group and he is being added to BG raid group, then call SetBattleGroundRaid() if (player->GetGroup() && isBGGroup()) player->SetBattleGroundRaid(this, group); // if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup() else if (player->GetGroup()) player->SetOriginalGroup(this, group); // if player is not in group, then call set group else player->SetGroup(this, group); if (player->IsInWorld()) { // if the same group invites the player back, cancel the homebind timer if (InstanceGroupBind* bind = GetBoundInstance(player->GetMapId())) if (bind->state->GetInstanceId() == player->GetInstanceId()) player->m_InstanceValid = true; } } if (!isRaidGroup()) // reset targetIcons for non-raid-groups { for (int i = 0; i < TARGET_ICON_COUNT; ++i) m_targetIcons[i].Clear(); } if (!isBGGroup()) { // insert into group table CharacterDatabase.PExecute("INSERT INTO group_member(groupId,memberGuid,assistant,subgroup) VALUES('%u','%u','%u','%u')", m_Id, member.guid.GetCounter(), ((member.assistant == 1) ? 1 : 0), member.group); } return true; }
bool Group::Create(ObjectGuid guid, const char* name) { m_leaderGuid = guid; m_leaderName = name; m_groupType = isBGGroup() ? GROUPTYPE_RAID : GROUPTYPE_NORMAL; if (m_groupType == GROUPTYPE_RAID) _initRaidSubGroupsCounter(); m_lootMethod = GROUP_LOOT; m_lootThreshold = ITEM_QUALITY_UNCOMMON; m_masterLooterGuid = guid; m_currentLooterGuid = guid; // used for round robin looter m_difficulty = DUNGEON_DIFFICULTY_NORMAL; if (!isBGGroup()) { m_Id = sObjectMgr.GenerateGroupLowGuid(); Player* leader = sObjectMgr.GetPlayer(guid); if (leader) m_difficulty = leader->GetDifficulty(); Player::ConvertInstancesToGroup(leader, this, guid); // store group in database CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("DELETE FROM groups WHERE groupId ='%u'", m_Id); CharacterDatabase.PExecute("DELETE FROM group_member WHERE groupId ='%u'", m_Id); CharacterDatabase.PExecute("INSERT INTO groups(groupId,leaderGuid,mainTank,mainAssistant,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,isRaid,difficulty) " "VALUES('%u','%u','%u','%u','%u','%u','%u','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','%u','%u')", m_Id, m_leaderGuid.GetCounter(), m_mainTankGuid.GetCounter(), m_mainAssistantGuid.GetCounter(), uint32(m_lootMethod), m_masterLooterGuid.GetCounter(), uint32(m_lootThreshold), m_targetIcons[0].GetRawValue(), m_targetIcons[1].GetRawValue(), m_targetIcons[2].GetRawValue(), m_targetIcons[3].GetRawValue(), m_targetIcons[4].GetRawValue(), m_targetIcons[5].GetRawValue(), m_targetIcons[6].GetRawValue(), m_targetIcons[7].GetRawValue(), isRaidGroup(), m_difficulty); } if (!AddMember(guid, name)) return false; if (!isBGGroup()) CharacterDatabase.CommitTransaction(); // used by eluna GlobalEluna(OnCreate(this, m_leaderGuid, m_groupType)); return true; }
void Group::_setLeader(const uint64 &guid) { int8 id = _getMemberIndex(guid); if(id < 0) return; if(isRaidGroup()) { sDatabase.BeginTransaction(); sDatabase.PExecute("UPDATE `raidgroup` SET `leaderGuid`='%u' WHERE `leaderGuid`='%u'", GUID_LOPART(m_members[id].guid), GUID_LOPART(m_leaderGuid)); sDatabase.PExecute("UPDATE `raidgroup_member` SET `leaderGuid`='%u' WHERE `leaderGuid`='%u'", GUID_LOPART(m_members[id].guid), GUID_LOPART(m_leaderGuid)); sDatabase.CommitTransaction(); } m_leaderGuid = m_members[id].guid; m_leaderName = m_members[id].name; }
void Group::Disband(bool hideDestroy) { Player *player; for(vector<MemberSlot>::const_iterator citr=m_members.begin(); citr!=m_members.end(); citr++) { player = objmgr.GetPlayer(citr->guid); if(!player || !player->GetSession()) continue; player->RemoveAreaAurasByOthers(); player->RemoveAreaAurasFromGroup(); player->groupInfo.group = NULL; WorldPacket data; if(!hideDestroy) { data.Initialize(SMSG_GROUP_DESTROYED, 0); player->GetSession()->SendPacket(&data); } data.Initialize(SMSG_GROUP_LIST, 14); data<<(uint16)0<<(uint32)0<<(uint64)0; player->GetSession()->SendPacket(&data); } RollId.clear(); m_members.clear(); for(vector<uint64>::iterator itr=m_invitees.begin(); itr!=m_invitees.end(); itr++) { Player *invitee = objmgr.GetPlayer((*itr)); if(invitee) invitee->groupInfo.invite = NULL; } m_invitees.clear(); if(isRaidGroup()) { sDatabase.BeginTransaction(); sDatabase.PExecute("DELETE FROM `raidgroup` WHERE `leaderGuid`='%u'", GUID_LOPART(m_leaderGuid)); sDatabase.PExecute("DELETE FROM `raidgroup_member` WHERE `leaderGuid`='%u'", GUID_LOPART(m_leaderGuid)); sDatabase.CommitTransaction(); } m_leaderGuid = 0; m_leaderName = ""; }
void Group::_chooseLeader(bool offline /*= false*/) { if (GetMembersCount() < GetMembersMinCount()) return; ObjectGuid first = ObjectGuid(); // First available: if no suitable canditates are found ObjectGuid chosen = ObjectGuid(); // Player matching prio creteria for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) { if (citr->guid == m_leaderGuid) continue; // Prioritize online players Player* player = sObjectMgr.GetPlayer(citr->guid); if (!player || !player->GetSession() || player->GetGroup() != this) continue; // Prioritize assistants for raids if (isRaidGroup() && !citr->assistant) { if (first.IsEmpty()) first = citr->guid; continue; } chosen = citr->guid; break; } if (chosen.IsEmpty()) chosen = first; // If we are choosing a new leader due to inactivity, check if everyone is offline first if (offline && chosen.IsEmpty()) return; // Still nobody online... if (chosen.IsEmpty()) chosen = m_memberSlots.front().guid; // Do announce if we are choosing a new leader due to old one being offline return (offline ? ChangeLeader(chosen) : _setLeader(chosen)); }
bool Group::IsMember(uint64 guid) { Player *player = objmgr.GetPlayer(guid); if(player) return (player->groupInfo.group == this); else { if(!isRaidGroup()) return false; QueryResult *result = sDatabase.PQuery("SELECT `leaderGuid` FROM `raidgroup_member` WHERE `memberGuid`='%u' AND `leaderGuid`='%u'", GUID_LOPART(guid), GUID_LOPART(GetLeaderGUID())); if(result) { delete result; return true; } else return false; } }
// allows setting subgroup for offline members void Group::ChangeMembersGroup(ObjectGuid guid, uint8 group) { if (!isRaidGroup()) return; Player* player = sObjectMgr.GetPlayer(guid); if (!player) { uint8 prevSubGroup = GetMemberGroup(guid); if (prevSubGroup == group) return; if (_setMembersGroup(guid, group)) { SubGroupCounterDecrease(prevSubGroup); SendUpdate(); } } else // This methods handles itself groupcounter decrease ChangeMembersGroup(player, group); }
bool Group::_removeMember(const uint64 &guid) { Player *player = objmgr.GetPlayer(guid); if (player) { player->RemoveAreaAurasByOthers(); player->RemoveAreaAurasFromGroup(); player->groupInfo.group = NULL; } _removeRolls(guid); m_members.erase(m_members.begin()+_getMemberIndex(guid)); if(isRaidGroup()) sDatabase.PExecute("DELETE FROM `raidgroup_member` WHERE `memberGuid`='%u'", GUID_LOPART(guid)); if(m_leaderGuid == guid) // leader was removed { if(m_members.size() > 0) _setLeader(m_members[0].guid); return true; } return false; }
// only for online members void Group::ChangeMembersGroup(Player* player, uint8 group) { if (!player || !isRaidGroup()) return; uint8 prevSubGroup = player->GetSubGroup(); if (prevSubGroup == group) return; if (_setMembersGroup(player->GetObjectGuid(), group)) { if (player->GetGroup() == this) 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); } SubGroupCounterDecrease(prevSubGroup); SendUpdate(); } }
uint32 Group::RemoveMember(ObjectGuid guid, uint8 method) { Player* player = sObjectMgr.GetPlayer(guid); #ifdef BUILD_PLAYERBOT // if master leaves group, all bots leave group if (player && player->GetPlayerbotMgr()) player->GetPlayerbotMgr()->RemoveAllBotsFromGroup(); #endif for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) { if (Player* groupMember = itr->getSource()) { if (groupMember->GetObjectGuid() == guid) continue; groupMember->RemoveAllGroupBuffsFromCaster(guid); if (player) player->RemoveAllGroupBuffsFromCaster(groupMember->GetObjectGuid()); } } // remove member and change leader (if need) only if strong more 2 members _before_ member remove if (GetMembersCount() > GetMembersMinCount()) { bool leaderChanged = _removeMember(guid); if (player) { // quest related GO state dependent from raid membership if (isRaidGroup()) player->UpdateForQuestWorldObjects(); WorldPacket data; if (method == 1) { data.Initialize(SMSG_GROUP_UNINVITE, 0); player->GetSession()->SendPacket(data); } // we already removed player from group and in player->GetGroup() is his original group! if (Group* group = player->GetGroup()) { group->SendUpdate(); } else { data.Initialize(SMSG_GROUP_LIST, 24); data << uint64(0) << uint64(0) << uint64(0); player->GetSession()->SendPacket(data); } _homebindIfInstance(player); } if (leaderChanged) { WorldPacket data(SMSG_GROUP_SET_LEADER, (m_leaderName.size() + 1)); data << m_leaderName; BroadcastPacket(data, true); } SendUpdate(); } // if group before remove <= 2 disband it else Disband(true); return m_memberSlots.size(); }
/** Provide rewards to group members at unit kill * * @param pVictim Killed unit * @param player_tap Player who tap unit if online, it can be group member or can be not if leaved after tap but before kill target * * Rewards received by group members and player_tap */ void Group::RewardGroupAtKill(Unit* pVictim, Player* player_tap) { bool PvP = pVictim->isCharmedOwnedByPlayerOrPlayer(); // prepare data for near group iteration (PvP and !PvP cases) uint32 xp = 0; uint32 count = 0; uint32 sum_level = 0; Player* member_with_max_level = NULL; Player* not_gray_member_with_max_level = NULL; GetDataForXPAtKill(pVictim, count, sum_level, member_with_max_level, not_gray_member_with_max_level, player_tap); if (member_with_max_level) { /// not get Xp in PvP or no not gray players in group xp = (PvP || !not_gray_member_with_max_level) ? 0 : MaNGOS::XP::Gain(not_gray_member_with_max_level, pVictim); /// skip in check PvP case (for speed, not used) bool is_raid = PvP ? false : sMapStore.LookupEntry(pVictim->GetMapId())->IsRaid() && isRaidGroup(); bool is_dungeon = PvP ? false : sMapStore.LookupEntry(pVictim->GetMapId())->IsDungeon(); float group_rate = MaNGOS::XP::xp_in_group_rate(count, is_raid); for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { Player* pGroupGuy = itr->getSource(); if (!pGroupGuy) continue; // will proccessed later if (pGroupGuy == player_tap) continue; if (!pGroupGuy->IsAtGroupRewardDistance(pVictim)) continue; // member (alive or dead) or his corpse at req. distance RewardGroupAtKill_helper(pGroupGuy, pVictim, count, PvP, group_rate, sum_level, is_dungeon, not_gray_member_with_max_level, member_with_max_level, xp); } if (player_tap) { // member (alive or dead) or his corpse at req. distance if (player_tap->IsAtGroupRewardDistance(pVictim)) RewardGroupAtKill_helper(player_tap, pVictim, count, PvP, group_rate, sum_level, is_dungeon, not_gray_member_with_max_level, member_with_max_level, xp); } } }
bool Group::_addMember(ObjectGuid guid, const char* name, bool isAssistant, uint8 group) { if (IsFull()) return false; if (!guid) return false; Player* player = sObjectMgr.GetPlayer(guid, false); uint32 lastMap = 0; if (player && player->IsInWorld()) lastMap = player->GetMapId(); else if (player && player->IsBeingTeleported()) lastMap = player->GetTeleportDest().mapid; MemberSlot member; member.guid = guid; member.name = name; member.group = group; member.assistant = isAssistant; member.lastMap = lastMap; m_memberSlots.push_back(member); SubGroupCounterIncrease(group); if (player) { player->SetGroupInvite(nullptr); // if player is in group and he is being added to BG raid group, then call SetBattleGroundRaid() if (player->GetGroup() && isBattleGroup()) player->SetBattleGroundRaid(this, group); // if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup() else if (player->GetGroup()) player->SetOriginalGroup(this, group); // if player is not in group, then call set group else player->SetGroup(this, group); if (player->IsInWorld()) { // if the same group invites the player back, cancel the homebind timer if (InstanceGroupBind* bind = GetBoundInstance(player->GetMapId())) if (bind->state->GetInstanceId() == player->GetInstanceId()) player->m_InstanceValid = true; } if (player->IsPvPFreeForAll()) { player->ForceHealthAndPowerUpdate(); for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* groupMember = itr->getSource(); if (groupMember && groupMember->GetSession()) groupMember->ForceHealthAndPowerUpdate(); } } } if (!isRaidGroup()) // reset targetIcons for non-raid-groups { for (auto& m_targetIcon : m_targetIcons) m_targetIcon.Clear(); } if (!isBattleGroup()) { // insert into group table CharacterDatabase.PExecute("INSERT INTO group_member(groupId,memberGuid,assistant,subgroup) VALUES('%u','%u','%u','%u')", m_Id, member.guid.GetCounter(), ((member.assistant == 1) ? 1 : 0), member.group); } return true; }
void Group::Disband(bool hideDestroy) { Player* player; for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) { player = sObjectMgr.GetPlayer(citr->guid); if (!player) continue; // we cannot call _removeMember because it would invalidate member iterator // if we are removing player from battleground raid if (isBGGroup()) player->RemoveFromBattleGroundRaid(); else { // we can remove player who is in battleground from his original group if (player->GetOriginalGroup() == this) player->SetOriginalGroup(NULL); else player->SetGroup(NULL); } // quest related GO state dependent from raid membership if (isRaidGroup()) player->UpdateForQuestWorldObjects(); if (!player->GetSession()) continue; WorldPacket data; if (!hideDestroy) { data.Initialize(SMSG_GROUP_DESTROYED, 0); player->GetSession()->SendPacket(&data); } // we already removed player from group and in player->GetGroup() is his original group, send update if (Group* group = player->GetGroup()) { group->SendUpdate(); } else { data.Initialize(SMSG_GROUP_LIST, 24); data << uint64(0) << uint64(0) << uint64(0); player->GetSession()->SendPacket(&data); } _homebindIfInstance(player); } m_memberSlots.clear(); RemoveAllInvites(); if (!isBGGroup()) { CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("DELETE FROM groups WHERE groupId='%u'", m_Id); CharacterDatabase.PExecute("DELETE FROM group_member WHERE groupId='%u'", m_Id); CharacterDatabase.CommitTransaction(); ResetInstances(INSTANCE_RESET_GROUP_DISBAND, NULL); } m_leaderGuid.Clear(); m_leaderName.clear(); }