TrinityCore
Loading...
Searching...
No Matches
Group.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Group.h"
19#include "Battleground.h"
20#include "BattlegroundMgr.h"
21#include "Common.h"
22#include "CharacterCache.h"
23#include "DatabaseEnv.h"
24#include "Formulas.h"
25#include "GameObject.h"
26#include "GroupMgr.h"
27#include "InstanceSaveMgr.h"
28#include "LootMgr.h"
29#include "ObjectAccessor.h"
30#include "ObjectMgr.h"
31#include "Opcodes.h"
32#include "Player.h"
33#include "MapManager.h"
34#include "Log.h"
35#include "LFGMgr.h"
36#include "Random.h"
37#include "SpellAuras.h"
38#include "UpdateData.h"
39#include "UpdateFieldFlags.h"
40#include "Util.h"
41#include "World.h"
42#include "WorldPacket.h"
43#include "WorldSession.h"
44
45Roll::Roll(ObjectGuid _guid, LootItem const& li) : itemGUID(_guid), itemid(li.itemid),
46itemRandomPropId(li.randomPropertyId), itemRandomPropertySeed(li.randomPropertySeed), itemCount(li.count),
47totalPlayersRolling(0), totalNeed(0), totalGreed(0), totalPass(0), itemSlot(0),
48rollVoteMask(ROLL_ALL_TYPE_NO_DISENCHANT) { }
49
51
52void Roll::setLoot(Loot* pLoot)
53{
54 link(pLoot, this);
55}
56
58{
59 return getTarget();
60}
61
62Group::Group() : m_leaderGuid(), m_leaderName(""), m_groupType(GROUPTYPE_NORMAL),
63m_dungeonDifficulty(DUNGEON_DIFFICULTY_NORMAL), m_raidDifficulty(RAID_DIFFICULTY_10MAN_NORMAL),
64m_bgGroup(nullptr), m_bfGroup(nullptr), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(),
65m_masterLooterGuid(), m_subGroupsCounts(nullptr), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0), m_isLeaderOffline(false),
66m_scriptRef(this, NoopGroupDeleter())
67{
68 for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i)
69 m_targetIcons[i].Clear();
70}
71
73{
74 if (m_bgGroup)
75 {
76 TC_LOG_DEBUG("bg.battleground", "Group::~Group: battleground group being deleted.");
77 if (m_bgGroup->GetBgRaid(ALLIANCE) == this)
78 m_bgGroup->SetBgRaid(ALLIANCE, nullptr);
79 else if (m_bgGroup->GetBgRaid(HORDE) == this)
80 m_bgGroup->SetBgRaid(HORDE, nullptr);
81 else
82 TC_LOG_ERROR("misc", "Group::~Group: battleground group is not linked to the correct battleground.");
83 }
84 Rolls::iterator itr;
85 while (!RollId.empty())
86 {
87 itr = RollId.begin();
88 Roll *r = *itr;
89 RollId.erase(itr);
90 delete(r);
91 }
92
93 // this may unload some instance saves
94 for (uint8 i = 0; i < MAX_DIFFICULTY; ++i)
95 for (BoundInstancesMap::iterator itr2 = m_boundInstances[i].begin(); itr2 != m_boundInstances[i].end(); ++itr2)
96 itr2->second.save->RemoveGroup(this);
97
98 // Sub group counters clean up
99 delete[] m_subGroupsCounts;
100}
101
114
116{
117 Player* newLeader = nullptr;
118
119 // Attempt to give leadership to main assistant first
121 {
122 for (auto memberSlot : m_memberSlots)
123 {
124 if ((memberSlot.flags & MEMBER_FLAG_ASSISTANT) == MEMBER_FLAG_ASSISTANT)
125 if (Player* player = ObjectAccessor::FindPlayer(memberSlot.guid))
126 {
127 newLeader = player;
128 break;
129 }
130 }
131 }
132
133 // If there aren't assistants in raid, or if the group is not a raid, pick the first available member
134 if (!newLeader)
135 {
136 for (auto memberSlot : m_memberSlots)
137 if (Player* player = ObjectAccessor::FindPlayer(memberSlot.guid))
138 {
139 newLeader = player;
140 break;
141 }
142 }
143
144 if (newLeader)
145 {
146 ChangeLeader(newLeader->GetGUID());
147 SendUpdate();
148 }
149}
150
152{
153 ObjectGuid leaderGuid = leader->GetGUID();
154
155 m_guid = ObjectGuid::Create<HighGuid::Group>(sGroupMgr->GenerateGroupId());
156 m_leaderGuid = leaderGuid;
157 m_leaderName = leader->GetName();
159
160 if (isBGGroup() || isBFGroup())
162
165
166 if (!isLFGGroup())
168
170 m_looterGuid = leaderGuid;
172
175
176 if (!isBGGroup() && !isBFGroup())
177 {
180
181 m_dbStoreId = sGroupMgr->GenerateNewGroupDbStoreId();
182
183 sGroupMgr->RegisterGroupDbStoreId(m_dbStoreId, this);
184
185 // Store group in database
187
188 uint8 index = 0;
189
190 stmt->setUInt32(index++, m_dbStoreId);
191 stmt->setUInt32(index++, m_leaderGuid.GetCounter());
192 stmt->setUInt8(index++, uint8(m_lootMethod));
193 stmt->setUInt32(index++, m_looterGuid.GetCounter());
194 stmt->setUInt8(index++, uint8(m_lootThreshold));
195 stmt->setUInt64(index++, m_targetIcons[0].GetRawValue());
196 stmt->setUInt64(index++, m_targetIcons[1].GetRawValue());
197 stmt->setUInt64(index++, m_targetIcons[2].GetRawValue());
198 stmt->setUInt64(index++, m_targetIcons[3].GetRawValue());
199 stmt->setUInt64(index++, m_targetIcons[4].GetRawValue());
200 stmt->setUInt64(index++, m_targetIcons[5].GetRawValue());
201 stmt->setUInt64(index++, m_targetIcons[6].GetRawValue());
202 stmt->setUInt64(index++, m_targetIcons[7].GetRawValue());
203 stmt->setUInt8(index++, uint8(m_groupType));
204 stmt->setUInt32(index++, uint8(m_dungeonDifficulty));
205 stmt->setUInt32(index++, uint8(m_raidDifficulty));
206 stmt->setUInt32(index++, m_masterLooterGuid.GetCounter());
207
208 CharacterDatabase.Execute(stmt);
209
210 Group::ConvertLeaderInstancesToGroup(leader, this, false);
211
212 bool addMemberResult = AddMember(leader);
213 ASSERT(addMemberResult); // If the leader can't be added to a new group because it appears full, something is clearly wrong.
214 }
215 else if (!AddMember(leader))
216 return false;
217
218 return true;
219}
220
222{
223 m_dbStoreId = fields[16].GetUInt32();
224 m_guid = ObjectGuid::Create<HighGuid::Group>(sGroupMgr->GenerateGroupId());
225 m_leaderGuid = ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt32());
226
227 // group leader not exist
228 if (!sCharacterCache->GetCharacterNameByGuid(m_leaderGuid, m_leaderName))
229 return;
230
231 m_lootMethod = LootMethod(fields[1].GetUInt8());
232 m_looterGuid = ObjectGuid::Create<HighGuid::Player>(fields[2].GetUInt32());
233 m_lootThreshold = ItemQualities(fields[3].GetUInt8());
234
235 for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i)
236 m_targetIcons[i].SetRawValue(fields[4 + i].GetUInt64());
237
238 m_groupType = GroupType(fields[12].GetUInt8());
241
244
245 m_masterLooterGuid = fields[15].GetUInt32() ? ObjectGuid::Create<HighGuid::Player>(fields[15].GetUInt32()) : ObjectGuid::Empty;
246
248 sLFGMgr->_LoadFromDB(fields, GetGUID());
249}
250
251void Group::LoadMemberFromDB(ObjectGuid::LowType guidLow, uint8 memberFlags, uint8 subgroup, uint8 roles)
252{
253 MemberSlot member;
254 member.guid = ObjectGuid::Create<HighGuid::Player>(guidLow);
255
256 // skip non-existed member
257 if (!sCharacterCache->GetCharacterNameByGuid(member.guid, member.name))
258 {
260 stmt->setUInt32(0, guidLow);
261 CharacterDatabase.Execute(stmt);
262 return;
263 }
264
265 member.group = subgroup;
266 member.flags = memberFlags;
267 member.roles = roles;
268
269 m_memberSlots.push_back(member);
270
271 SubGroupCounterIncrease(subgroup);
272
273 sLFGMgr->SetupGroupMember(member.guid, GetGUID());
274}
275
277{
280 if (!isBGGroup() && !isBFGroup())
281 {
283
284 stmt->setUInt8(0, uint8(m_groupType));
285 stmt->setUInt32(1, m_dbStoreId);
286
287 CharacterDatabase.Execute(stmt);
288 }
289
290 SendUpdate();
291}
292
294{
296
298
299 if (!isBGGroup() && !isBFGroup())
300 {
302
303 stmt->setUInt8(0, uint8(m_groupType));
304 stmt->setUInt32(1, m_dbStoreId);
305
306 CharacterDatabase.Execute(stmt);
307 }
308
309 SendUpdate();
310
311 // update quest related GO states (quest activity dependent from raid membership)
312 for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
313 if (Player* player = ObjectAccessor::FindPlayer(citr->guid))
314 player->UpdateVisibleGameobjectsOrSpellClicks();
315}
316
318{
319 if (!player || player->GetGroupInvite())
320 return false;
321 Group* group = player->GetGroup();
322 if (group && (group->isBGGroup() || group->isBFGroup()))
323 group = player->GetOriginalGroup();
324 if (group)
325 return false;
326
327 RemoveInvite(player);
328
329 m_invitees.insert(player);
330
331 player->SetGroupInvite(this);
332
333 sScriptMgr->OnGroupInviteMember(this, player->GetGUID());
334
335 return true;
336}
337
339{
340 if (!AddInvite(player))
341 return false;
342
343 m_leaderGuid = player->GetGUID();
344 m_leaderName = player->GetName();
345 return true;
346}
347
349{
350 if (player)
351 {
352 m_invitees.erase(player);
353 player->SetGroupInvite(nullptr);
354 }
355}
356
358{
359 for (InvitesList::iterator itr = m_invitees.begin(); itr != m_invitees.end(); ++itr)
360 if (*itr)
361 (*itr)->SetGroupInvite(nullptr);
362
363 m_invitees.clear();
364}
365
367{
368 for (InvitesList::const_iterator itr = m_invitees.begin(); itr != m_invitees.end(); ++itr)
369 {
370 if ((*itr) && (*itr)->GetGUID() == guid)
371 return (*itr);
372 }
373 return nullptr;
374}
375
376Player* Group::GetInvited(const std::string& name) const
377{
378 for (InvitesList::const_iterator itr = m_invitees.begin(); itr != m_invitees.end(); ++itr)
379 {
380 if ((*itr) && (*itr)->GetName() == name)
381 return (*itr);
382 }
383 return nullptr;
384}
385
387{
388 // Get first not-full group
389 uint8 subGroup = 0;
391 {
392 bool groupFound = false;
393 for (; subGroup < MAX_RAID_SUBGROUPS; ++subGroup)
394 {
395 if (m_subGroupsCounts[subGroup] < MAX_GROUP_SIZE)
396 {
397 groupFound = true;
398 break;
399 }
400 }
401 // We are raid group and no one slot is free
402 if (!groupFound)
403 return false;
404 }
405
406 MemberSlot member;
407 member.guid = player->GetGUID();
408 member.name = player->GetName();
409 member.group = subGroup;
410 member.flags = 0;
411 member.roles = 0;
412 m_memberSlots.push_back(member);
413
414 SubGroupCounterIncrease(subGroup);
415
416 player->SetGroupInvite(nullptr);
417 if (player->GetGroup())
418 {
419 if (isBGGroup() || isBFGroup()) // if player is in group and he is being added to BG raid group, then call SetBattlegroundRaid()
420 player->SetBattlegroundOrBattlefieldRaid(this, subGroup);
421 else //if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup()
422 player->SetOriginalGroup(this, subGroup);
423 }
424 else //if player is not in group, then call set group
425 player->SetGroup(this, subGroup);
426
427 // if the same group invites the player back, cancel the homebind timer
428 player->m_InstanceValid = player->CheckInstanceValidity(false);
429
430 if (!isRaidGroup()) // reset targetIcons for non-raid-groups
431 {
432 for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i)
433 m_targetIcons[i].Clear();
434 }
435
436 // insert into the table if we're not a battleground group
437 if (!isBGGroup() && !isBFGroup())
438 {
440
441 stmt->setUInt32(0, m_dbStoreId);
442 stmt->setUInt32(1, member.guid.GetCounter());
443 stmt->setUInt8(2, member.flags);
444 stmt->setUInt8(3, member.group);
445 stmt->setUInt8(4, member.roles);
446
447 CharacterDatabase.Execute(stmt);
448 }
449
450 SendUpdate();
451 sScriptMgr->OnGroupAddMember(this, player->GetGUID());
452
453 if (!IsLeader(player->GetGUID()) && !isBGGroup() && !isBFGroup())
454 {
455 // reset the new member's instances, unless he is currently in one of them
456 // including raid/heroic instances that they are not permanently bound to!
459 }
462
463 // quest related GO state dependent from raid membership
464 if (isRaidGroup())
466
467 {
468 // Broadcast new player group member fields to rest of the group
470
471 UpdateData groupData;
472 WorldPacket groupDataPacket;
473
474 // Broadcast group members' fields to player
475 for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
476 {
477 if (itr->GetSource() == player)
478 continue;
479
480 if (Player* existingMember = itr->GetSource())
481 {
482 if (player->HaveAtClient(existingMember))
483 {
484 existingMember->SetFieldNotifyFlag(UF_FLAG_PARTY_MEMBER);
485 existingMember->BuildValuesUpdateBlockForPlayer(&groupData, player);
486 existingMember->RemoveFieldNotifyFlag(UF_FLAG_PARTY_MEMBER);
487 }
488
489 if (existingMember->HaveAtClient(player))
490 {
491 UpdateData newData;
492 WorldPacket newDataPacket;
493 player->BuildValuesUpdateBlockForPlayer(&newData, existingMember);
494 if (newData.HasData())
495 {
496 newData.BuildPacket(&newDataPacket);
497 existingMember->SendDirectMessage(&newDataPacket);
498 }
499 }
500 }
501 }
502
503 if (groupData.HasData())
504 {
505 groupData.BuildPacket(&groupDataPacket);
506 player->SendDirectMessage(&groupDataPacket);
507 }
508
510 }
511
512 if (m_maxEnchantingLevel < player->GetSkillValue(SKILL_ENCHANTING))
514
515 return true;
516}
517
518bool Group::RemoveMember(ObjectGuid guid, RemoveMethod const& method /*= GROUP_REMOVEMETHOD_DEFAULT*/, ObjectGuid kicker /*= ObjectGuid::Empty*/, char const* reason /*= nullptr*/)
519{
521
522 sScriptMgr->OnGroupRemoveMember(this, guid, method, kicker, reason);
523
525 if (player)
526 {
527 for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
528 {
529 if (Player* groupMember = itr->GetSource())
530 {
531 if (groupMember->GetGUID() == guid)
532 continue;
533
534 groupMember->RemoveAllGroupBuffsFromCaster(guid);
535 player->RemoveAllGroupBuffsFromCaster(groupMember->GetGUID());
536 }
537 }
538 }
539
540 // LFG group vote kick handled in scripts
541 if (isLFGGroup() && method == GROUP_REMOVEMETHOD_KICK)
542 return !m_memberSlots.empty();
543
544 // remove member and change leader (if need) only if strong more 2 members _before_ member remove (BG/BF allow 1 member group)
545 if (GetMembersCount() > ((isBGGroup() || isLFGGroup() || isBFGroup()) ? 1u : 2u))
546 {
547 if (player)
548 {
549 bool isOriginalGroup = false;
550
551 // Battleground group handling
552 if (isBGGroup() || isBFGroup())
554 else
555 // Regular group
556 {
557 if (player->GetOriginalGroup() == this)
558 {
559 player->SetOriginalGroup(nullptr);
560 isOriginalGroup = true;
561 }
562 else
563 player->SetGroup(nullptr);
564
565 // quest related GO state dependent from raid membership
567 }
568
569 WorldPacket data;
570
571 if (method == GROUP_REMOVEMETHOD_KICK || method == GROUP_REMOVEMETHOD_KICK_LFG)
572 {
574 player->SendDirectMessage(&data);
575 }
576
577 // if we had OriginalGroup (now in Group slot after removal) we need to notify the client to replace group data
578 if (Group* group = player->GetGroup())
579 group->SendUpdateToPlayer(player);
580 else
581 {
582 data.Initialize(SMSG_GROUP_LIST, 1 + 1 + 1 + 1 + 8 + 4 + 4 + 8);
583 data << uint8(0x10) << uint8(0) << uint8(0) << uint8(0);
584 data << m_guid << uint32(m_counter) << uint32(0) << ObjectGuid::Empty;
585 player->SendDirectMessage(&data);
586 }
587
588 // if player left his original group but not bg/lfg group then we need to update values reported by Lua_GetReal** functions
589 if (isOriginalGroup)
590 {
591 data.Initialize(SMSG_REAL_GROUP_UPDATE, 1 + 4 + 8);
592 data << uint8(0x10);
593 data << uint32(0);
594 data << ObjectGuid::Empty;
595 player->SendDirectMessage(&data);
596 }
597
598 _homebindIfInstance(player);
599 }
600
601 // Remove player from group in DB
602 if (!isBGGroup() && !isBFGroup())
603 {
605 stmt->setUInt32(0, guid.GetCounter());
606 CharacterDatabase.Execute(stmt);
607 DelinkMember(guid);
608 }
609
610 // Reevaluate group enchanter if the leaving player had enchanting skill or the player is offline
611 if (!player || player->GetSkillValue(SKILL_ENCHANTING))
613
614 // Remove player from loot rolls
615 for (Rolls::iterator it = RollId.begin(); it != RollId.end(); ++it)
616 {
617 Roll* roll = *it;
618 Roll::PlayerVote::iterator itr2 = roll->playerVote.find(guid);
619 if (itr2 == roll->playerVote.end())
620 continue;
621
622 if (itr2->second == GREED || itr2->second == DISENCHANT)
623 --roll->totalGreed;
624 else if (itr2->second == NEED)
625 --roll->totalNeed;
626 else if (itr2->second == PASS)
627 --roll->totalPass;
628
629 if (itr2->second != NOT_VALID)
630 --roll->totalPlayersRolling;
631
632 roll->playerVote.erase(itr2);
633
635 }
636
637 // Update subgroups
639 if (slot != m_memberSlots.end())
640 {
641 SubGroupCounterDecrease(slot->group);
642 m_memberSlots.erase(slot);
643 }
644
645 // Pick new leader if necessary
646 if (m_leaderGuid == guid)
647 {
648 for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
649 {
651 {
652 ChangeLeader(itr->guid);
653 break;
654 }
655 }
656 }
657
658 SendUpdate();
659
660 if (isLFGGroup() && GetMembersCount() == 1)
661 {
663 uint32 mapId = sLFGMgr->GetDungeonMapId(GetGUID());
664 if (!mapId || !leader || (leader->IsAlive() && leader->GetMapId() != mapId))
665 {
666 Disband();
667 return false;
668 }
669 }
670
671 if (m_memberMgr.getSize() < ((isLFGGroup() || isBGGroup()) ? 1u : 2u))
672 Disband();
673
674 return true;
675 }
676 // If group size before player removal <= 2 then disband it
677 else
678 {
679 Disband();
680 return false;
681 }
682}
683
685{
686 member_witerator slot = _getMemberWSlot(newLeaderGuid);
687
688 if (slot == m_memberSlots.end())
689 return;
690
691 Player* newLeader = ObjectAccessor::FindConnectedPlayer(slot->guid);
692
693 // Don't allow switching leader to offline players
694 if (!newLeader)
695 return;
696
697 sScriptMgr->OnGroupChangeLeader(this, newLeaderGuid, m_leaderGuid);
698
699 if (!isBGGroup() && !isBFGroup())
700 {
701 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
702
703 // Remove the groups permanent instance bindings
704 for (uint8 i = 0; i < MAX_DIFFICULTY; ++i)
705 {
706 for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end();)
707 {
708 // Do not unbind saves of instances that already had map created (a newLeader entered)
709 // forcing a new instance with another leader requires group disbanding (confirmed on retail)
710 if (itr->second.perm && !sMapMgr->FindMap(itr->first, itr->second.save->GetInstanceId()))
711 {
713 stmt->setUInt32(0, m_dbStoreId);
714 stmt->setUInt32(1, itr->second.save->GetInstanceId());
715 trans->Append(stmt);
716
717 itr->second.save->RemoveGroup(this);
718 m_boundInstances[i].erase(itr++);
719 }
720 else
721 ++itr;
722 }
723 }
724
725 // Copy the permanent binds from the new leader to the group
726 Group::ConvertLeaderInstancesToGroup(newLeader, this, true);
727
728 // Update the group leader
730
731 stmt->setUInt32(0, newLeader->GetGUID().GetCounter());
732 stmt->setUInt32(1, m_dbStoreId);
733
734 trans->Append(stmt);
735
736 CharacterDatabase.CommitTransaction(trans);
737 }
738
740 oldLeader->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GROUP_LEADER);
741
743 m_leaderGuid = newLeader->GetGUID();
744 m_leaderName = newLeader->GetName();
746
748 data << slot->name;
749 BroadcastPacket(&data, true);
750}
751
753void Group::ConvertLeaderInstancesToGroup(Player* player, Group* group, bool switchLeader)
754{
755 // copy all binds to the group, when changing leader it's assumed the character
756 // will not have any solo binds
757 for (uint8 i = 0; i < MAX_DIFFICULTY; ++i)
758 {
759 for (Player::BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();)
760 {
761 if (!switchLeader || !group->GetBoundInstance(itr->second.save->GetDifficultyID(), itr->first))
762 if (itr->second.extendState) // not expired
763 group->BindToInstance(itr->second.save, itr->second.perm, false);
764
765 // permanent binds are not removed
766 if (switchLeader && !itr->second.perm)
767 {
768 // increments itr in call
769 player->UnbindInstance(itr, Difficulty(i), false);
770 }
771 else
772 ++itr;
773 }
774 }
775
776 /* if group leader is in a non-raid dungeon map and nobody is actually bound to this map then the group can "take over" the instance *
777 * (example: two-player group disbanded by disconnect where the player reconnects within 60 seconds and the group is reformed) */
778 if (Map* playerMap = player->FindMap())
779 if (!switchLeader && playerMap->IsNonRaidDungeon())
780 if (InstanceSave* save = sInstanceSaveMgr->GetInstanceSave(playerMap->GetInstanceId()))
781 if (save->GetGroupCount() == 0 && save->GetPlayerCount() == 0)
782 {
783 TC_LOG_DEBUG("maps", "Group::ConvertLeaderInstancesToGroup: Group for player {} is taking over unbound instance map {} with Id {}", player->GetName(), playerMap->GetId(), playerMap->GetInstanceId());
784 // if nobody is saved to this, then the save wasn't permanent
785 group->BindToInstance(save, false, false);
786 }
787}
788
789void Group::Disband(bool hideDestroy /* = false */)
790{
791 sScriptMgr->OnGroupDisband(this);
792
793 Player* player;
794 for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
795 {
796 player = ObjectAccessor::FindConnectedPlayer(citr->guid);
797 if (!player)
798 continue;
799
800 bool isOriginalGroup = false;
801
802 //we cannot call _removeMember because it would invalidate member iterator
803 //if we are removing player from battleground raid
804 if (isBGGroup() || isBFGroup())
806 else
807 {
808 //we can remove player who is in battleground from his original group
809 if (player->GetOriginalGroup() == this)
810 {
811 player->SetOriginalGroup(nullptr);
812 isOriginalGroup = true;
813 }
814 else
815 player->SetGroup(nullptr);
816 }
817
818 // quest related GO state dependent from raid membership
819 if (isRaidGroup())
821
822 if (!player->GetSession())
823 continue;
824
825 WorldPacket data;
826 if (!hideDestroy)
827 {
829 player->SendDirectMessage(&data);
830 }
831
832 //we already removed player from group and in player->GetGroup() is his original group, send update
833 if (Group* group = player->GetGroup())
834 {
835 group->SendUpdate();
836 }
837 else
838 {
839 data.Initialize(SMSG_GROUP_LIST, 1+1+1+1+8+4+4+8);
840 data << uint8(0x10) << uint8(0) << uint8(0) << uint8(0);
841 data << m_guid << uint32(m_counter) << uint32(0) << ObjectGuid::Empty;
842 player->SendDirectMessage(&data);
843 }
844
845 // if player left his original group but not bg/lfg group then we need to update values reported by Lua_GetReal** functions
846 if (isOriginalGroup)
847 {
848 data.Initialize(SMSG_REAL_GROUP_UPDATE, 1 + 4 + 8);
849 data << uint8(0x10);
850 data << uint32(0);
851 data << ObjectGuid::Empty;
852 player->SendDirectMessage(&data);
853 }
854
855 _homebindIfInstance(player);
856 }
857
858 m_memberSlots.clear();
859
861
862 if (!isBGGroup() && !isBFGroup())
863 {
864 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
865
867 stmt->setUInt32(0, m_dbStoreId);
868 trans->Append(stmt);
869
870 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER_ALL);
871 stmt->setUInt32(0, m_dbStoreId);
872 trans->Append(stmt);
873
874 CharacterDatabase.CommitTransaction(trans);
875
878
879 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_LFG_DATA);
880 stmt->setUInt32(0, m_dbStoreId);
881 CharacterDatabase.Execute(stmt);
882
883 sGroupMgr->FreeGroupDbStoreId(this);
884 }
885
886 sGroupMgr->RemoveGroup(this);
887 delete this;
888}
889
890/*********************************************************/
891/*** LOOT SYSTEM ***/
892/*********************************************************/
893
894void Group::SendLootStartRoll(uint32 countDown, uint32 mapid, Roll const& r)
895{
896 WorldPacket data(SMSG_LOOT_START_ROLL, (8+4+4+4+4+4+4+1));
897 data << r.itemGUID; // guid of rolled item
898 data << uint32(mapid); // 3.3.3 mapid
899 data << uint32(r.itemSlot); // itemslot
900 data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for
901 data << uint32(r.itemRandomPropertySeed); // randomSuffix
902 data << uint32(r.itemRandomPropId); // item random property ID
903 data << uint32(r.itemCount); // items in stack
904 data << uint32(countDown); // the countdown time to choose "need" or "greed"
905 data << uint8(r.rollVoteMask); // roll type mask
906
907 for (Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr != r.playerVote.end(); ++itr)
908 {
910 if (!p || !p->GetSession())
911 continue;
912
913 if (itr->second == NOT_EMITED_YET)
914 p->SendDirectMessage(&data);
915 }
916}
917
918void Group::SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, bool canNeed, Roll const& r)
919{
920 if (!p || !p->GetSession())
921 return;
922
923 WorldPacket data(SMSG_LOOT_START_ROLL, (8 + 4 + 4 + 4 + 4 + 4 + 4 + 1));
924 data << r.itemGUID; // guid of rolled item
925 data << uint32(mapId); // 3.3.3 mapid
926 data << uint32(r.itemSlot); // itemslot
927 data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for
928 data << uint32(r.itemRandomPropertySeed); // randomSuffix
929 data << uint32(r.itemRandomPropId); // item random property ID
930 data << uint32(r.itemCount); // items in stack
931 data << uint32(countDown); // the countdown time to choose "need" or "greed"
932 uint8 voteMask = r.rollVoteMask;
933 if (!canNeed)
934 voteMask &= ~ROLL_FLAG_TYPE_NEED;
935 data << uint8(voteMask); // roll type mask
936
937 p->SendDirectMessage(&data);
938}
939
940void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rollNumber, uint8 rollType, Roll const& roll, bool autoPass)
941{
942 WorldPacket data(SMSG_LOOT_ROLL, (8+4+8+4+4+4+1+1+1));
943 data << sourceGuid; // guid of the item rolled
944 data << uint32(roll.itemSlot); // slot
945 data << targetGuid;
946 data << uint32(roll.itemid); // the itemEntryId for the item that shall be rolled for
947 data << uint32(roll.itemRandomPropertySeed); // randomSuffix
948 data << uint32(roll.itemRandomPropId); // Item random property ID
949 data << uint8(rollNumber); // 0: "Need for: [item name]" > 127: "you passed on: [item name]" Roll number
950 data << uint8(rollType); // 0: "Need for: [item name]" 0: "You have selected need for [item name] 1: need roll 2: greed roll
951 data << uint8(autoPass); // 1: "You automatically passed on: %s because you cannot loot that item."
952
953 for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr)
954 {
956 if (!p || !p->GetSession())
957 continue;
958
959 if (itr->second != NOT_VALID)
960 p->SendDirectMessage(&data);
961 }
962}
963
964void Group::SendLootRollWon(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rollNumber, uint8 rollType, Roll const& roll)
965{
966 WorldPacket data(SMSG_LOOT_ROLL_WON, (8+4+4+4+4+8+1+1));
967 data << sourceGuid; // guid of the item rolled
968 data << uint32(roll.itemSlot); // slot
969 data << uint32(roll.itemid); // the itemEntryId for the item that shall be rolled for
970 data << uint32(roll.itemRandomPropertySeed); // randomSuffix
971 data << uint32(roll.itemRandomPropId); // Item random property
972 data << targetGuid; // guid of the player who won.
973 data << uint8(rollNumber); // rollnumber realted to SMSG_LOOT_ROLL
974 data << uint8(rollType); // rollType related to SMSG_LOOT_ROLL
975
976 for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr)
977 {
979 if (!p || !p->GetSession())
980 continue;
981
982 if (itr->second != NOT_VALID)
983 p->SendDirectMessage(&data);
984 }
985}
986
988{
989 WorldPacket data(SMSG_LOOT_ALL_PASSED, (8+4+4+4+4));
990 data << roll.itemGUID; // Guid of the item rolled
991 data << uint32(roll.itemSlot); // Item loot slot
992 data << uint32(roll.itemid); // The itemEntryId for the item that shall be rolled for
993 data << uint32(roll.itemRandomPropId); // Item random property ID
994 data << uint32(roll.itemRandomPropertySeed); // Item random suffix ID
995
996 for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr)
997 {
998 Player* player = ObjectAccessor::FindConnectedPlayer(itr->first);
999 if (!player || !player->GetSession())
1000 continue;
1001
1002 if (itr->second != NOT_VALID)
1003 player->SendDirectMessage(&data);
1004 }
1005}
1006
1007// notify group members which player is the allowed looter for the given creature
1008void Group::SendLooter(Creature* creature, Player* groupLooter)
1009{
1010 ASSERT(creature);
1011
1012 WorldPacket data(SMSG_LOOT_LIST, (8+8));
1013 data << creature->GetGUID();
1014
1015 if (GetLootMethod() == MASTER_LOOT && creature->loot.hasOverThresholdItem())
1017 else
1018 data << uint8(0);
1019
1020 if (groupLooter)
1021 data << groupLooter->GetPackGUID();
1022 else
1023 data << uint8(0);
1024
1025 BroadcastPacket(&data, false);
1026}
1027
1028bool CanRollOnItem(const LootItem& item, Player const* player)
1029{
1030 // Players can't roll on unique items if they already reached the maximum quantity of that item
1031 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid);
1032 if (!proto)
1033 return false;
1034
1035 uint32 itemCount = player->GetItemCount(item.itemid, true);
1036 if (proto->GetMaxCount() > 0 && static_cast<int32>(itemCount) >= proto->GetMaxCount())
1037 return false;
1038
1039 if (!item.AllowedForPlayer(player))
1040 return false;
1041
1042 return true;
1043}
1044
1045void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
1046{
1047 std::vector<LootItem>::iterator i;
1048 ItemTemplate const* item;
1049 uint8 itemSlot = 0;
1050
1051 for (i = loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
1052 {
1053 if (i->freeforall)
1054 continue;
1055
1056 item = sObjectMgr->GetItemTemplate(i->itemid);
1057 if (!item)
1058 {
1059 //TC_LOG_DEBUG("misc", "Group::GroupLoot: missing item prototype for item with id: {}", i->itemid);
1060 continue;
1061 }
1062
1063 //roll for over-threshold item if it's one-player loot
1064 if (item->GetQuality() >= uint32(m_lootThreshold))
1065 {
1066 ObjectGuid newitemGUID = ObjectGuid::Create<HighGuid::Item>(sObjectMgr->GetGenerator<HighGuid::Item>().Generate());
1067 Roll* r = new Roll(newitemGUID, *i);
1068
1069 //a vector is filled with only near party members
1070 for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
1071 {
1072 Player* member = itr->GetSource();
1073 if (!member || !member->GetSession())
1074 continue;
1075 if (member->IsAtGroupRewardDistance(pLootedObject))
1076 {
1078 RollVote vote = member->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET;
1079 if (!CanRollOnItem(*i, member))
1080 {
1081 vote = PASS;
1082 ++r->totalPass;
1083 }
1084 r->playerVote[member->GetGUID()] = vote;
1085 }
1086 }
1087
1088 if (r->totalPlayersRolling > 0)
1089 {
1090 r->setLoot(loot);
1091 r->itemSlot = itemSlot;
1094
1095 loot->items[itemSlot].is_blocked = true;
1096
1097 // If there are any "auto pass", broadcast them now
1098 if (r->totalPass)
1099 {
1100 for (Roll::PlayerVote::const_iterator itr=r->playerVote.begin(); itr != r->playerVote.end(); ++itr)
1101 {
1103 if (!p || !p->GetSession())
1104 continue;
1105
1106 if (itr->second == PASS)
1107 SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r, true);
1108 }
1109 }
1110
1111 if (r->totalPass == r->totalPlayersRolling)
1112 delete r;
1113 else
1114 {
1115 SendLootStartRoll(60000, pLootedObject->GetMapId(), *r);
1116
1117 RollId.push_back(r);
1118
1119 if (Creature* creature = pLootedObject->ToCreature())
1120 {
1121 creature->m_groupLootTimer = 60000;
1122 creature->lootingGroupLowGUID = GetGUID();
1123 }
1124 else if (GameObject* go = pLootedObject->ToGameObject())
1125 {
1126 go->m_groupLootTimer = 60000;
1127 go->lootingGroupLowGUID = GetGUID();
1128 }
1129 }
1130 }
1131 else
1132 delete r;
1133 }
1134 else
1135 i->is_underthreshold = true;
1136 }
1137
1138 for (i = loot->quest_items.begin(); i != loot->quest_items.end(); ++i, ++itemSlot)
1139 {
1140 if (!i->follow_loot_rules)
1141 continue;
1142
1143 item = sObjectMgr->GetItemTemplate(i->itemid);
1144 if (!item)
1145 {
1146 //TC_LOG_DEBUG("misc", "Group::GroupLoot: missing item prototype for item with id: {}", i->itemid);
1147 continue;
1148 }
1149
1150 ObjectGuid newitemGUID = ObjectGuid::Create<HighGuid::Item>(sObjectMgr->GetGenerator<HighGuid::Item>().Generate());
1151 Roll* r = new Roll(newitemGUID, *i);
1152
1153 //a vector is filled with only near party members
1154 for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
1155 {
1156 Player* member = itr->GetSource();
1157 if (!member || !member->GetSession())
1158 continue;
1159
1160 if (member->IsAtGroupRewardDistance(pLootedObject))
1161 {
1163 RollVote vote = NOT_EMITED_YET;
1164 if (!CanRollOnItem(*i, member))
1165 {
1166 vote = PASS;
1167 ++r->totalPass;
1168 }
1169 r->playerVote[member->GetGUID()] = vote;
1170 }
1171 }
1172
1173 if (r->totalPlayersRolling > 0)
1174 {
1175 r->setLoot(loot);
1176 r->itemSlot = itemSlot;
1177
1178 loot->quest_items[itemSlot - loot->items.size()].is_blocked = true;
1179
1180 SendLootStartRoll(60000, pLootedObject->GetMapId(), *r);
1181
1182 RollId.push_back(r);
1183
1184 if (Creature* creature = pLootedObject->ToCreature())
1185 {
1186 creature->m_groupLootTimer = 60000;
1187 creature->lootingGroupLowGUID = GetGUID();
1188 }
1189 else if (GameObject* go = pLootedObject->ToGameObject())
1190 {
1191 go->m_groupLootTimer = 60000;
1192 go->lootingGroupLowGUID = GetGUID();
1193 }
1194 }
1195 else
1196 delete r;
1197 }
1198}
1199
1200void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject)
1201{
1202 ItemTemplate const* item;
1203 uint8 itemSlot = 0;
1204 for (std::vector<LootItem>::iterator i = loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
1205 {
1206 if (i->freeforall)
1207 continue;
1208
1209 item = sObjectMgr->GetItemTemplate(i->itemid);
1210 ASSERT(item);
1211
1212 //roll for over-threshold item if it's one-player loot
1213 if (item->GetQuality() >= uint32(m_lootThreshold))
1214 {
1215 ObjectGuid newitemGUID = ObjectGuid::Create<HighGuid::Item>(sObjectMgr->GetGenerator<HighGuid::Item>().Generate());
1216 Roll* r = new Roll(newitemGUID, *i);
1217
1218 for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
1219 {
1220 Player* playerToRoll = itr->GetSource();
1221 if (!playerToRoll || !playerToRoll->GetSession())
1222 continue;
1223
1224 if (playerToRoll->IsAtGroupRewardDistance(lootedObject))
1225 {
1227 RollVote vote = playerToRoll->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET;
1228 if (!CanRollOnItem(*i, playerToRoll))
1229 {
1230 vote = PASS;
1231 r->totalPass++; // Can't broadcast the pass now. need to wait until all rolling players are known
1232 }
1233 r->playerVote[playerToRoll->GetGUID()] = vote;
1234 }
1235 }
1236
1237 if (r->totalPlayersRolling > 0)
1238 {
1239 r->setLoot(loot);
1240 r->itemSlot = itemSlot;
1243
1245 r->rollVoteMask &= ~ROLL_FLAG_TYPE_NEED;
1246
1247 loot->items[itemSlot].is_blocked = true;
1248
1249 //Broadcast Pass and Send Rollstart
1250 for (Roll::PlayerVote::const_iterator itr = r->playerVote.begin(); itr != r->playerVote.end(); ++itr)
1251 {
1253 if (!p || !p->GetSession())
1254 continue;
1255
1256 if (itr->second == PASS)
1257 SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r);
1258 else
1259 SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, p->CanRollForItemInLFG(item, lootedObject) == EQUIP_ERR_OK, *r);
1260 }
1261
1262 RollId.push_back(r);
1263
1264 if (Creature* creature = lootedObject->ToCreature())
1265 {
1266 creature->m_groupLootTimer = 60000;
1267 creature->lootingGroupLowGUID = GetGUID();
1268 }
1269 else if (GameObject* go = lootedObject->ToGameObject())
1270 {
1271 go->m_groupLootTimer = 60000;
1272 go->lootingGroupLowGUID = GetGUID();
1273 }
1274 }
1275 else
1276 delete r;
1277 }
1278 else
1279 i->is_underthreshold = true;
1280 }
1281
1282 for (std::vector<LootItem>::iterator i = loot->quest_items.begin(); i != loot->quest_items.end(); ++i, ++itemSlot)
1283 {
1284 if (!i->follow_loot_rules)
1285 continue;
1286
1287 item = sObjectMgr->GetItemTemplate(i->itemid);
1288 ObjectGuid newitemGUID = ObjectGuid::Create<HighGuid::Item>(sObjectMgr->GetGenerator<HighGuid::Item>().Generate());
1289 Roll* r = new Roll(newitemGUID, *i);
1290
1291 for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
1292 {
1293 Player* playerToRoll = itr->GetSource();
1294 if (!playerToRoll || !playerToRoll->GetSession())
1295 continue;
1296
1297 if (playerToRoll->IsAtGroupRewardDistance(lootedObject))
1298 {
1300 RollVote vote = NOT_EMITED_YET;
1301 if (!CanRollOnItem(*i, playerToRoll))
1302 {
1303 vote = PASS;
1304 ++r->totalPass;
1305 }
1306 r->playerVote[playerToRoll->GetGUID()] = vote;
1307 }
1308 }
1309
1310 if (r->totalPlayersRolling > 0)
1311 {
1312 r->setLoot(loot);
1313 r->itemSlot = itemSlot;
1314
1315 loot->quest_items[itemSlot - loot->items.size()].is_blocked = true;
1316
1317 //Broadcast Pass and Send Rollstart
1318 for (Roll::PlayerVote::const_iterator itr = r->playerVote.begin(); itr != r->playerVote.end(); ++itr)
1319 {
1321 if (!p || !p->GetSession())
1322 continue;
1323
1324 if (itr->second == PASS)
1325 SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r);
1326 else
1327 SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, p->CanRollForItemInLFG(item, lootedObject) == EQUIP_ERR_OK, *r);
1328 }
1329
1330 RollId.push_back(r);
1331
1332 if (Creature* creature = lootedObject->ToCreature())
1333 {
1334 creature->m_groupLootTimer = 60000;
1335 creature->lootingGroupLowGUID = GetGUID();
1336 }
1337 else if (GameObject* go = lootedObject->ToGameObject())
1338 {
1339 go->m_groupLootTimer = 60000;
1340 go->lootingGroupLowGUID = GetGUID();
1341 }
1342 }
1343 else
1344 delete r;
1345 }
1346}
1347
1348void Group::MasterLoot(Loot* loot, WorldObject* pLootedObject)
1349{
1350 TC_LOG_DEBUG("network", "Group::MasterLoot (SMSG_LOOT_MASTER_LIST)");
1351
1352 for (std::vector<LootItem>::iterator i = loot->items.begin(); i != loot->items.end(); ++i)
1353 {
1354 if (i->freeforall)
1355 continue;
1356
1357 i->is_blocked = !i->is_underthreshold;
1358 }
1359
1360 for (std::vector<LootItem>::iterator i = loot->quest_items.begin(); i != loot->quest_items.end(); ++i)
1361 {
1362 if (!i->follow_loot_rules)
1363 continue;
1364
1365 i->is_blocked = !i->is_underthreshold;
1366 }
1367
1368 uint32 real_count = 0;
1369
1371 data << uint8(GetMembersCount());
1372
1373 for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
1374 {
1375 Player* looter = itr->GetSource();
1376 if (!looter->IsInWorld())
1377 continue;
1378
1379 if (looter->IsAtGroupRewardDistance(pLootedObject))
1380 {
1381 data << looter->GetGUID();
1382 ++real_count;
1383 }
1384 }
1385
1386 data.put<uint8>(0, real_count);
1387
1388 for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
1389 {
1390 Player* looter = itr->GetSource();
1391 if (looter->IsAtGroupRewardDistance(pLootedObject))
1392 looter->SendDirectMessage(&data);
1393 }
1394}
1395
1396bool Group::CountRollVote(ObjectGuid playerGUID, ObjectGuid Guid, uint8 Choice)
1397{
1398 Rolls::iterator rollI = GetRoll(Guid);
1399 if (rollI == RollId.end())
1400 return false;
1401 Roll* roll = *rollI;
1402
1403 Roll::PlayerVote::iterator itr = roll->playerVote.find(playerGUID);
1404 // this condition means that player joins to the party after roll begins
1405 if (itr == roll->playerVote.end() || itr->second != NOT_EMITED_YET)
1406 return false;
1407
1408 if (roll->getLoot())
1409 if (roll->getLoot()->items.empty())
1410 return false;
1411
1412 switch (Choice)
1413 {
1414 case ROLL_PASS: // Player choose pass
1415 SendLootRoll(ObjectGuid::Empty, playerGUID, 128, ROLL_PASS, *roll);
1416 ++roll->totalPass;
1417 itr->second = PASS;
1418 break;
1419 case ROLL_NEED: // player choose Need
1420 SendLootRoll(ObjectGuid::Empty, playerGUID, 0, 0, *roll);
1421 ++roll->totalNeed;
1422 itr->second = NEED;
1423 break;
1424 case ROLL_GREED: // player choose Greed
1425 SendLootRoll(ObjectGuid::Empty, playerGUID, 128, ROLL_GREED, *roll);
1426 ++roll->totalGreed;
1427 itr->second = GREED;
1428 break;
1429 case ROLL_DISENCHANT: // player choose Disenchant
1430 SendLootRoll(ObjectGuid::Empty, playerGUID, 128, ROLL_DISENCHANT, *roll);
1431 ++roll->totalGreed;
1432 itr->second = DISENCHANT;
1433 break;
1434 }
1435
1436 if (roll->totalPass + roll->totalNeed + roll->totalGreed >= roll->totalPlayersRolling)
1437 CountTheRoll(rollI, nullptr);
1438
1439 return true;
1440}
1441
1442//called when roll timer expires
1443void Group::EndRoll(Loot* pLoot, Map* allowedMap)
1444{
1445 for (Rolls::iterator itr = RollId.begin(); itr != RollId.end();)
1446 {
1447 if ((*itr)->getLoot() == pLoot) {
1448 CountTheRoll(itr, allowedMap); //i don't have to edit player votes, who didn't vote ... he will pass
1449 itr = RollId.begin();
1450 }
1451 else
1452 ++itr;
1453 }
1454}
1455
1456void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
1457{
1458 Roll* roll = *rollI;
1459 if (!roll->isValid()) // is loot already deleted ?
1460 {
1461 RollId.erase(rollI);
1462 delete roll;
1463 return;
1464 }
1465
1466 //end of the roll
1467 if (roll->totalNeed > 0)
1468 {
1469 if (!roll->playerVote.empty())
1470 {
1471 uint8 maxresul = 0;
1472 ObjectGuid maxguid = ObjectGuid::Empty;
1473 Player* player = nullptr;
1474
1475 for (Roll::PlayerVote::const_iterator itr = roll->playerVote.begin(); itr != roll->playerVote.end(); ++itr)
1476 {
1477 if (itr->second != NEED)
1478 continue;
1479
1480 player = ObjectAccessor::FindPlayer(itr->first);
1481 if (!player || (allowedMap != nullptr && player->FindMap() != allowedMap))
1482 {
1483 --roll->totalNeed;
1484 continue;
1485 }
1486
1487 uint8 randomN = urand(1, 100);
1488 SendLootRoll(ObjectGuid::Empty, itr->first, randomN, ROLL_NEED, *roll);
1489 if (maxresul < randomN)
1490 {
1491 maxguid = itr->first;
1492 maxresul = randomN;
1493 }
1494 }
1495
1496 if (!maxguid.IsEmpty())
1497 {
1498 SendLootRollWon(ObjectGuid::Empty, maxguid, maxresul, ROLL_NEED, *roll);
1499 player = ObjectAccessor::FindConnectedPlayer(maxguid);
1500
1501 if (player && player->GetSession())
1502 {
1504
1505 ItemPosCountVec dest;
1506 LootItem* item = &(roll->itemSlot >= roll->getLoot()->items.size() ? roll->getLoot()->quest_items[roll->itemSlot - roll->getLoot()->items.size()] : roll->getLoot()->items[roll->itemSlot]);
1507 InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count);
1508 if (msg == EQUIP_ERR_OK)
1509 {
1510 item->is_looted = true;
1511 roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
1512 roll->getLoot()->unlootedCount--;
1513 player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, item->GetAllowedLooters());
1514 }
1515 else
1516 {
1517 item->is_blocked = false;
1518 item->rollWinnerGUID = player->GetGUID();
1519 player->SendEquipError(msg, nullptr, nullptr, roll->itemid);
1520 }
1521 }
1522 }
1523 else
1524 roll->totalNeed = 0;
1525 }
1526 }
1527
1528 if (roll->totalNeed == 0 && roll->totalGreed > 0) // if (roll->totalNeed == 0 && ...), not else if, because numbers can be modified above if player is on a different map
1529 {
1530 if (!roll->playerVote.empty())
1531 {
1532 uint8 maxresul = 0;
1533 ObjectGuid maxguid = ObjectGuid::Empty;
1534 Player* player = nullptr;
1535 RollVote rollvote = NOT_VALID;
1536
1537 Roll::PlayerVote::iterator itr;
1538 for (itr = roll->playerVote.begin(); itr != roll->playerVote.end(); ++itr)
1539 {
1540 if (itr->second != GREED && itr->second != DISENCHANT)
1541 continue;
1542
1543 player = ObjectAccessor::FindPlayer(itr->first);
1544 if (!player || (allowedMap != nullptr && player->FindMap() != allowedMap))
1545 {
1546 --roll->totalGreed;
1547 continue;
1548 }
1549
1550 uint8 randomN = urand(1, 100);
1551 SendLootRoll(ObjectGuid::Empty, itr->first, randomN, itr->second, *roll);
1552 if (maxresul < randomN)
1553 {
1554 maxguid = itr->first;
1555 maxresul = randomN;
1556 rollvote = itr->second;
1557 }
1558 }
1559
1560 if (!maxguid.IsEmpty())
1561 {
1562 SendLootRollWon(ObjectGuid::Empty, maxguid, maxresul, rollvote, *roll);
1563 player = ObjectAccessor::FindConnectedPlayer(maxguid);
1564
1565 if (player && player->GetSession())
1566 {
1568
1569 LootItem* item = &(roll->itemSlot >= roll->getLoot()->items.size() ? roll->getLoot()->quest_items[roll->itemSlot - roll->getLoot()->items.size()] : roll->getLoot()->items[roll->itemSlot]);
1570
1571 if (rollvote == GREED)
1572 {
1573 ItemPosCountVec dest;
1574 InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count);
1575 if (msg == EQUIP_ERR_OK)
1576 {
1577 item->is_looted = true;
1578 roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
1579 roll->getLoot()->unlootedCount--;
1580 player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, item->GetAllowedLooters());
1581 }
1582 else
1583 {
1584 item->is_blocked = false;
1585 item->rollWinnerGUID = player->GetGUID();
1586 player->SendEquipError(msg, nullptr, nullptr, roll->itemid);
1587 }
1588 }
1589 else if (rollvote == DISENCHANT)
1590 {
1591 item->is_looted = true;
1592 roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
1593 roll->getLoot()->unlootedCount--;
1594 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(roll->itemid);
1595 ASSERT(pProto);
1597
1598 ItemPosCountVec dest;
1599 InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count);
1600 if (msg == EQUIP_ERR_OK)
1601 player->AutoStoreLoot(pProto->DisenchantID, LootTemplates_Disenchant, true);
1602 else // If the player's inventory is full, send the disenchant result in a mail.
1603 {
1604 Loot loot;
1605 loot.FillLoot(pProto->DisenchantID, LootTemplates_Disenchant, player, true);
1606
1607 uint32 max_slot = loot.GetMaxSlotInLootFor(player);
1608 for (uint32 i = 0; i < max_slot; ++i)
1609 {
1610 LootItem* lootItem = loot.LootItemInSlot(i, player);
1611 player->SendEquipError(msg, nullptr, nullptr, lootItem->itemid);
1612 player->SendItemRetrievalMail(lootItem->itemid, lootItem->count);
1613 }
1614 }
1615 }
1616 }
1617 }
1618 else
1619 roll->totalGreed = 0;
1620 }
1621 }
1622
1623 if (roll->totalNeed == 0 && roll->totalGreed == 0) // if, not else, because numbers can be modified above if player is on a different map
1624 {
1625 SendLootAllPassed(*roll);
1626
1627 // remove is_blocked so that the item is lootable by all players
1628 LootItem* item = &(roll->itemSlot >= roll->getLoot()->items.size() ? roll->getLoot()->quest_items[roll->itemSlot - roll->getLoot()->items.size()] : roll->getLoot()->items[roll->itemSlot]);
1629 item->is_blocked = false;
1630 }
1631
1632 RollId.erase(rollI);
1633 delete roll;
1634}
1635
1637{
1638 if (id >= TARGET_ICONS_COUNT)
1639 return;
1640
1641 // clean other icons
1642 if (!targetGuid.IsEmpty())
1643 for (int i = 0; i < TARGET_ICONS_COUNT; ++i)
1644 if (m_targetIcons[i] == targetGuid)
1646
1647 m_targetIcons[id] = targetGuid;
1648
1649 WorldPacket data(MSG_RAID_TARGET_UPDATE, (1+8+1+8));
1650 data << uint8(0); // set targets
1651 data << whoGuid;
1652 data << uint8(id);
1653 data << targetGuid;
1654 BroadcastPacket(&data, true);
1655}
1656
1658{
1659 if (!session)
1660 return;
1661
1663 data << uint8(1); // list targets
1664
1665 for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i)
1666 {
1667 if (m_targetIcons[i].IsEmpty())
1668 continue;
1669
1670 data << uint8(i);
1671 data << m_targetIcons[i];
1672 }
1673
1674 session->SendPacket(&data);
1675}
1676
1678{
1679 for (member_witerator witr = m_memberSlots.begin(); witr != m_memberSlots.end(); ++witr)
1680 {
1681 Player* player = ObjectAccessor::FindConnectedPlayer(witr->guid);
1682 if (!player)
1683 continue;
1684
1685 SendUpdateToPlayer(player, &(*witr));
1686 }
1687}
1688
1689void Group::SendUpdateToPlayer(Player const* player, MemberSlot const* slot /*= nullptr*/)
1690{
1691 if (player->GetGroup() != this)
1692 {
1693 if (player->GetOriginalGroup() == this)
1695
1696 return;
1697 }
1698
1699 // if MemberSlot wasn't provided
1700 if (!slot)
1701 {
1702 member_citerator citr = _getMemberCSlot(player->GetGUID());
1703
1704 if (citr == m_memberSlots.end()) // if there is no MemberSlot for such a player
1705 return;
1706
1707 slot = &(*citr);
1708 }
1709
1710 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));
1711 data << uint8(m_groupType); // group type (flags in 3.3)
1712 data << uint8(slot->group);
1713 data << uint8(slot->flags);
1714 data << uint8(slot->roles);
1715 if (isLFGGroup())
1716 {
1717 data << uint8(sLFGMgr->GetState(m_guid) == lfg::LFG_STATE_FINISHED_DUNGEON ? 2 : 0); // FIXME - Dungeon save status? 2 = done
1718 data << uint32(sLFGMgr->GetDungeon(m_guid));
1719 }
1720
1721 data << m_guid;
1722 data << uint32(m_counter++); // 3.3, value increases every time this packet gets sent
1723 data << uint32(GetMembersCount()-1);
1724 for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
1725 {
1726 if (slot->guid == citr->guid)
1727 continue;
1728
1729 Player* member = ObjectAccessor::FindConnectedPlayer(citr->guid);
1730
1731 uint8 onlineState = (member && !member->GetSession()->PlayerLogout()) ? MEMBER_STATUS_ONLINE : MEMBER_STATUS_OFFLINE;
1732 onlineState = onlineState | ((isBGGroup() || isBFGroup()) ? MEMBER_STATUS_PVP : 0);
1733
1734 data << citr->name;
1735 data << citr->guid; // guid
1736 data << uint8(onlineState); // online-state
1737 data << uint8(citr->group); // groupid
1738 data << uint8(citr->flags); // See enum GroupMemberFlags
1739 data << uint8(citr->roles); // Lfg Roles
1740 }
1741
1742 data << m_leaderGuid; // leader guid
1743
1744 if (GetMembersCount() - 1)
1745 {
1746 data << uint8(m_lootMethod); // loot method
1747
1749 data << m_masterLooterGuid; // master looter guid
1750 else
1751 data << ObjectGuid::Empty;
1752
1753 data << uint8(m_lootThreshold); // loot threshold
1754 data << uint8(m_dungeonDifficulty); // Dungeon Difficulty
1755 data << uint8(m_raidDifficulty); // Raid Difficulty
1756 data << uint8(m_raidDifficulty >= RAID_DIFFICULTY_10MAN_HEROIC); // 3.3 Dynamic Raid Difficulty - 0 normal/1 heroic
1757 }
1758
1759 player->SendDirectMessage(&data);
1760}
1761
1763{
1764 WorldPacket data(SMSG_REAL_GROUP_UPDATE, 1 + 4 + 8);
1765 data << uint8(m_groupType);
1766 data << uint32(GetMembersCount() - 1);
1767 data << m_leaderGuid;
1768 player->SendDirectMessage(&data);
1769}
1770
1772{
1773 if (!player || !player->IsInWorld())
1774 return;
1775
1776 WorldPacket data;
1777 player->GetSession()->BuildPartyMemberStatsChangedPacket(player, &data);
1778
1779 Player* member;
1780 for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
1781 {
1782 member = itr->GetSource();
1783 if (member && member != player && (!member->IsInMap(player) || !member->IsWithinDist(player, member->GetSightRange(), false)))
1784 member->SendDirectMessage(&data);
1785 }
1786}
1787
1788void Group::BroadcastPacket(WorldPacket const* packet, bool ignorePlayersInBGRaid, int group /*= -1*/, ObjectGuid ignoredPlayer /*= ObjectGuid::Empty*/)
1789{
1790 for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
1791 {
1792 Player* player = itr->GetSource();
1793 if (!player || (!ignoredPlayer.IsEmpty() && player->GetGUID() == ignoredPlayer) || (ignorePlayersInBGRaid && player->GetGroup() != this))
1794 continue;
1795
1796 if (player->GetSession() && (group == -1 || itr->getSubGroup() == group))
1797 player->SendDirectMessage(packet);
1798 }
1799}
1800
1802{
1803 for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
1804 {
1805 Player* player = itr->GetSource();
1806 if (player && player->GetSession())
1807 if (IsLeader(player->GetGUID()) || IsAssistant(player->GetGUID()))
1808 player->SendDirectMessage(packet);
1809 }
1810}
1811
1813{
1814 for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
1815 {
1816 Player* player = ObjectAccessor::FindConnectedPlayer(citr->guid);
1817 if (!player || !player->GetSession())
1818 {
1820 data << citr->guid;
1821 data << uint8(0);
1822 BroadcastReadyCheck(&data);
1823 }
1824 }
1825}
1826
1828{
1829 member_witerator slot = _getMemberWSlot(guid);
1830 if (slot == m_memberSlots.end())
1831 return false;
1832
1833 slot->group = group;
1834
1836
1837 if (!isBGGroup() && !isBFGroup())
1838 {
1840
1841 stmt->setUInt8(0, group);
1842 stmt->setUInt32(1, guid.GetCounter());
1843
1844 CharacterDatabase.Execute(stmt);
1845 }
1846
1847 return true;
1848}
1849
1850bool Group::SameSubGroup(Player const* member1, Player const* member2) const
1851{
1852 if (!member1 || !member2)
1853 return false;
1854
1855 if (member1->GetGroup() != this || member2->GetGroup() != this)
1856 return false;
1857 else
1858 return member1->GetSubGroup() == member2->GetSubGroup();
1859}
1860
1861// Allows setting sub groups both for online or offline members
1863{
1864 // Only raid groups have sub groups
1865 if (!isRaidGroup())
1866 return;
1867
1868 // Check if player is really in the raid
1869 member_witerator slot = _getMemberWSlot(guid);
1870 if (slot == m_memberSlots.end())
1871 return;
1872
1873 // Abort if the player is already in the target sub group
1874 uint8 prevSubGroup = GetMemberGroup(guid);
1875 if (prevSubGroup == group)
1876 return;
1877
1878 // Update the player slot with the new sub group setting
1879 slot->group = group;
1880
1881 // Increase the counter of the new sub group..
1883
1884 // ..and decrease the counter of the previous one
1885 SubGroupCounterDecrease(prevSubGroup);
1886
1887 // Preserve new sub group in database for non-raid groups
1888 if (!isBGGroup() && !isBFGroup())
1889 {
1891
1892 stmt->setUInt8(0, group);
1893 stmt->setUInt32(1, guid.GetCounter());
1894
1895 CharacterDatabase.Execute(stmt);
1896 }
1897
1898 // In case the moved player is online, update the player object with the new sub group references
1899 if (Player* player = ObjectAccessor::FindConnectedPlayer(guid))
1900 {
1901 if (player->GetGroup() == this)
1902 player->GetGroupRef().setSubGroup(group);
1903 else
1904 {
1905 // 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
1906 prevSubGroup = player->GetOriginalSubGroup();
1907 player->GetOriginalGroupRef().setSubGroup(group);
1908 }
1909 }
1910
1911 // Broadcast the changes to the group
1912 SendUpdate();
1913}
1914
1915// Retrieve the next Round-Roubin player for the group
1916//
1917// No update done if loot method is FFA.
1918//
1919// If the RR player is not yet set for the group, the first group member becomes the round-robin player.
1920// If the RR player is set, the next player in group becomes the round-robin player.
1921//
1922// If ifneed is true,
1923// the current RR player is checked to be near the looted object.
1924// if yes, no update done.
1925// if not, he loses his turn.
1926void Group::UpdateLooterGuid(WorldObject* pLootedObject, bool ifneed)
1927{
1928 // round robin style looting applies for all low
1929 // quality items in each loot method except free for all
1930 if (GetLootMethod() == FREE_FOR_ALL)
1931 return;
1932
1933 ObjectGuid oldLooterGUID = GetLooterGuid();
1934 member_citerator guid_itr = _getMemberCSlot(oldLooterGUID);
1935 if (guid_itr != m_memberSlots.end())
1936 {
1937 if (ifneed)
1938 {
1939 // not update if only update if need and ok
1940 Player* looter = ObjectAccessor::FindPlayer(guid_itr->guid);
1941 if (looter && looter->IsAtGroupRewardDistance(pLootedObject))
1942 return;
1943 }
1944 ++guid_itr;
1945 }
1946
1947 // search next after current
1948 Player* pNewLooter = nullptr;
1949 for (member_citerator itr = guid_itr; itr != m_memberSlots.end(); ++itr)
1950 {
1951 if (Player* player = ObjectAccessor::FindPlayer(itr->guid))
1952 if (player->IsAtGroupRewardDistance(pLootedObject))
1953 {
1954 pNewLooter = player;
1955 break;
1956 }
1957 }
1958
1959 if (!pNewLooter)
1960 {
1961 // search from start
1962 for (member_citerator itr = m_memberSlots.begin(); itr != guid_itr; ++itr)
1963 {
1964 if (Player* player = ObjectAccessor::FindPlayer(itr->guid))
1965 if (player->IsAtGroupRewardDistance(pLootedObject))
1966 {
1967 pNewLooter = player;
1968 break;
1969 }
1970 }
1971 }
1972
1973 if (pNewLooter)
1974 {
1975 if (oldLooterGUID != pNewLooter->GetGUID())
1976 {
1977 SetLooterGuid(pNewLooter->GetGUID());
1978 SendUpdate();
1979 }
1980 }
1981 else
1982 {
1984 SendUpdate();
1985 }
1986}
1987
1988GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* bgOrTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 /*MaxPlayerCount*/, bool isRated, uint32 arenaSlot, ObjectGuid& errorGuid) const
1989{
1990 errorGuid = ObjectGuid::Empty;
1991
1992 // check if this group is LFG group
1993 if (isLFGGroup())
1995
1996 BattlemasterListEntry const* bgEntry = sBattlemasterListStore.LookupEntry(bgOrTemplate->GetTypeID());
1997 if (!bgEntry)
1998 return ERR_GROUP_JOIN_BATTLEGROUND_FAIL; // shouldn't happen
1999
2000 // check for min / max count
2001 uint32 memberscount = GetMembersCount();
2002
2003 if (memberscount > bgEntry->MaxGroupSize) // no MinPlayerCount for battlegrounds
2004 return ERR_BATTLEGROUND_NONE; // ERR_GROUP_JOIN_BATTLEGROUND_TOO_MANY handled on client side
2005
2006 // get a player as reference, to compare other players' stats to (arena team id, queue id based on level, etc.)
2007 Player* reference = ASSERT_NOTNULL(GetFirstMember())->GetSource();
2008 // no reference found, can't join this way
2009 if (!reference)
2011
2012 PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bgOrTemplate->GetMapId(), reference->GetLevel());
2013 if (!bracketEntry)
2015
2016 uint32 arenaTeamId = reference->GetArenaTeamId(arenaSlot);
2017 uint32 team = reference->GetTeam();
2018
2019 // check every member of the group to be able to join
2020 memberscount = 0;
2021 for (GroupReference const* itr = GetFirstMember(); itr != nullptr; itr = itr->next(), ++memberscount)
2022 {
2023 Player* member = itr->GetSource();
2024 // offline member? don't let join
2025 if (!member)
2027 errorGuid = member->GetGUID();
2028 // rbac permissions
2029 if (!member->CanJoinToBattleground(bgOrTemplate))
2031 // don't allow cross-faction join as group
2032 if (member->GetTeam() != team)
2034 // not in the same battleground level braket, don't let join
2035 PvPDifficultyEntry const* memberBracketEntry = GetBattlegroundBracketByLevel(bracketEntry->MapID, member->GetLevel());
2036 if (memberBracketEntry != bracketEntry)
2038 // don't let join rated matches if the arena team id doesn't match
2039 if (isRated && member->GetArenaTeamId(arenaSlot) != arenaTeamId)
2041 // don't let join if someone from the group is already in that bg queue
2042 if (member->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeId))
2043 return ERR_BATTLEGROUND_JOIN_FAILED; // not blizz-like
2044 // don't let join if someone from the group is in bg queue random
2045 bool isInRandomBgQueue = member->InBattlegroundQueueForBattlegroundQueueType(BattlegroundMgr::BGQueueTypeId(BATTLEGROUND_RB, memberBracketEntry->GetBracketId(), 0));
2046 if (bgOrTemplate->GetTypeID() != BATTLEGROUND_AA && isInRandomBgQueue)
2047 return ERR_IN_RANDOM_BG;
2048 // don't let join to bg queue random if someone from the group is already in bg queue
2049 if (bgOrTemplate->GetTypeID() == BATTLEGROUND_RB && member->InBattlegroundQueue(true))
2050 return ERR_IN_NON_RANDOM_BG;
2051 // check for deserter debuff in case not arena queue
2052 if (bgOrTemplate->GetTypeID() != BATTLEGROUND_AA && member->IsDeserter())
2054 // check if member can join any more battleground queues
2055 if (!member->HasFreeBattlegroundQueueId())
2056 return ERR_BATTLEGROUND_TOO_MANY_QUEUES; // not blizz-like
2057 // check if someone in party is using dungeon system
2058 if (member->isUsingLfg())
2060 // check Freeze debuff
2061 if (member->HasAura(9454))
2063 }
2064
2065 errorGuid = ObjectGuid::Empty;
2066
2067 // only check for MinPlayerCount since MinPlayerCount == MaxPlayerCount for arenas...
2068 if (bgOrTemplate->isArena() && memberscount != MinPlayerCount)
2070
2071 return GroupJoinBattlegroundResult(bgOrTemplate->GetTypeID());
2072}
2073
2074//===================================================
2075//============== Roll ===============================
2076//===================================================
2077
2079{
2080 // called from link()
2082}
2083
2085{
2086 m_dungeonDifficulty = difficulty;
2087 if (!isBGGroup() && !isBFGroup())
2088 {
2090
2092 stmt->setUInt32(1, m_dbStoreId);
2093
2094 CharacterDatabase.Execute(stmt);
2095 }
2096
2097 SendUpdate();
2098}
2099
2101{
2102 m_raidDifficulty = difficulty;
2103 if (!isBGGroup() && !isBFGroup())
2104 {
2106
2107 stmt->setUInt8(0, uint8(m_raidDifficulty));
2108 stmt->setUInt32(1, m_dbStoreId);
2109
2110 CharacterDatabase.Execute(stmt);
2111 }
2112
2113 SendUpdate();
2114}
2115
2117{
2118 return mapEntry->IsRaid() ? m_raidDifficulty : m_dungeonDifficulty;
2119}
2120
2121void Group::ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo)
2122{
2123 if (isBGGroup() || isBFGroup())
2124 return;
2125
2126 // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_DISBAND
2127
2128 // we assume that when the difficulty changes, all instances that can be reset will be
2130
2131 for (BoundInstancesMap::iterator itr = m_boundInstances[diff].begin(); itr != m_boundInstances[diff].end();)
2132 {
2133 InstanceSave* instanceSave = itr->second.save;
2134 MapEntry const* entry = sMapStore.LookupEntry(itr->first);
2135 if (!entry || entry->IsRaid() != isRaid || (!instanceSave->CanReset() && method != INSTANCE_RESET_GROUP_DISBAND))
2136 {
2137 ++itr;
2138 continue;
2139 }
2140
2141 if (method == INSTANCE_RESET_ALL)
2142 {
2143 // the "reset all instances" method can only reset normal maps
2144 if (entry->InstanceType == MAP_RAID || diff == DUNGEON_DIFFICULTY_HEROIC)
2145 {
2146 ++itr;
2147 continue;
2148 }
2149 }
2150
2151 bool isEmpty = true;
2152 // if the map is loaded, reset it
2153 Map* map = sMapMgr->FindMap(instanceSave->GetMapId(), instanceSave->GetInstanceId());
2154 if (map && map->IsDungeon() && !(method == INSTANCE_RESET_GROUP_DISBAND && !instanceSave->CanReset()))
2155 {
2156 if (instanceSave->CanReset())
2157 isEmpty = ((InstanceMap*)map)->Reset(method);
2158 else
2159 isEmpty = !map->HavePlayers();
2160 }
2161
2162 if (SendMsgTo)
2163 {
2164 if (!isEmpty)
2165 SendMsgTo->SendResetInstanceFailed(0, instanceSave->GetMapId());
2166 else if (sWorld->getBoolConfig(CONFIG_INSTANCES_RESET_ANNOUNCE))
2167 {
2168 if (Group* group = SendMsgTo->GetGroup())
2169 {
2170 for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
2171 if (Player* player = groupRef->GetSource())
2172 player->SendResetInstanceSuccess(instanceSave->GetMapId());
2173 }
2174
2175 else
2176 SendMsgTo->SendResetInstanceSuccess(instanceSave->GetMapId());
2177 }
2178 else
2179 SendMsgTo->SendResetInstanceSuccess(instanceSave->GetMapId());
2180 }
2181
2182 if (isEmpty || method == INSTANCE_RESET_GROUP_DISBAND || method == INSTANCE_RESET_CHANGE_DIFFICULTY)
2183 {
2184 // do not reset the instance, just unbind if others are permanently bound to it
2185 if (isEmpty && instanceSave->CanReset())
2186 {
2187 if (map && map->IsDungeon() && SendMsgTo)
2188 {
2189 AreaTriggerTeleport const * const instanceEntrance = sObjectMgr->GetGoBackTrigger(map->GetId());
2190
2191 if (!instanceEntrance)
2192 TC_LOG_DEBUG("root", "Instance entrance not found for maps {}", map->GetId());
2193 else
2194 {
2195 WorldSafeLocsEntry const * graveyardLocation = sObjectMgr->GetClosestGraveyard(instanceEntrance->target_X, instanceEntrance->target_Y, instanceEntrance->target_Z, instanceEntrance->target_mapId, SendMsgTo->GetTeam(), SendMsgTo);
2196 uint32 const zoneId = sMapMgr->GetZoneId(PHASEMASK_NORMAL, graveyardLocation->Continent, graveyardLocation->Loc.X, graveyardLocation->Loc.Y, graveyardLocation->Loc.Z);
2197
2198 for (MemberSlot const& member : GetMemberSlots())
2199 {
2200 if (!ObjectAccessor::FindConnectedPlayer(member.guid))
2201 {
2203
2204 stmt->setFloat(0, graveyardLocation->Loc.X);
2205 stmt->setFloat(1, graveyardLocation->Loc.Y);
2206 stmt->setFloat(2, graveyardLocation->Loc.Z);
2207 stmt->setFloat(3, instanceEntrance->target_Orientation);
2208 stmt->setUInt32(4, graveyardLocation->Continent);
2209 stmt->setUInt32(5, zoneId);
2210 stmt->setUInt32(6, member.guid.GetCounter());
2211 stmt->setUInt32(7, map->GetId());
2212
2213 CharacterDatabase.Execute(stmt);
2214 }
2215 }
2216 }
2217 }
2218
2219 instanceSave->DeleteFromDB();
2220 }
2221 else
2222 {
2224
2225 stmt->setUInt32(0, instanceSave->GetInstanceId());
2226
2227 CharacterDatabase.Execute(stmt);
2228 }
2229
2230 // i don't know for sure if hash_map iterators
2231 m_boundInstances[diff].erase(itr);
2232 itr = m_boundInstances[diff].begin();
2233 // this unloads the instance save unless online players are bound to it
2234 // (eg. permanent binds or GM solo binds)
2235 instanceSave->RemoveGroup(this);
2236 }
2237 else
2238 ++itr;
2239 }
2240}
2241
2243{
2244 uint32 mapid = player->GetMapId();
2245 MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
2246 return GetBoundInstance(mapEntry);
2247}
2248
2253
2255{
2256 if (!mapEntry || !mapEntry->IsDungeon())
2257 return nullptr;
2258
2259 Difficulty difficulty = GetDifficultyID(mapEntry);
2260 return GetBoundInstance(difficulty, mapEntry->ID);
2261}
2262
2264{
2265 // some instances only have one difficulty
2266 GetDownscaledMapDifficultyData(mapId, difficulty);
2267
2268 BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapId);
2269 if (itr != m_boundInstances[difficulty].end())
2270 return &itr->second;
2271 else
2272 return nullptr;
2273}
2274
2275InstanceGroupBind* Group::BindToInstance(InstanceSave* save, bool permanent, bool load)
2276{
2277 if (!save || isBGGroup() || isBFGroup())
2278 return nullptr;
2279
2281 if (!load && (!bind.save || permanent != bind.perm || save != bind.save))
2282 {
2284
2285 stmt->setUInt32(0, m_dbStoreId);
2286 stmt->setUInt32(1, save->GetInstanceId());
2287 stmt->setBool(2, permanent);
2288
2289 CharacterDatabase.Execute(stmt);
2290 }
2291
2292 if (bind.save != save)
2293 {
2294 if (bind.save)
2295 bind.save->RemoveGroup(this);
2296 save->AddGroup(this);
2297 }
2298
2299 bind.save = save;
2300 bind.perm = permanent;
2301 if (!load)
2302 TC_LOG_DEBUG("maps", "Group::BindToInstance: {}, storage id: {} is now bound to map {}, instance {}, difficulty {}",
2303 GetGUID().ToString(), m_dbStoreId, save->GetMapId(), save->GetInstanceId(), static_cast<uint32>(save->GetDifficultyID()));
2304
2305 return &bind;
2306}
2307
2308void Group::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload)
2309{
2310 BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
2311 if (itr != m_boundInstances[difficulty].end())
2312 {
2313 if (!unload)
2314 {
2316
2317 stmt->setUInt32(0, m_dbStoreId);
2318 stmt->setUInt32(1, itr->second.save->GetInstanceId());
2319
2320 CharacterDatabase.Execute(stmt);
2321 }
2322
2323 itr->second.save->RemoveGroup(this); // save can become invalid
2324 m_boundInstances[difficulty].erase(itr);
2325 }
2326}
2327
2329{
2330 if (player && !player->IsGameMaster() && sMapStore.LookupEntry(player->GetMapId())->IsDungeon())
2331 player->m_InstanceValid = false;
2332}
2333
2335{
2336 // FG: HACK: force flags update on group leave - for values update hack
2337 // -- not very efficient but safe
2338 for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
2339 {
2340 Player* pp = ObjectAccessor::FindPlayer(citr->guid);
2341 if (pp)
2342 {
2345 TC_LOG_DEBUG("misc", "-- Forced group value update for '{}'", pp->GetName());
2346 }
2347 }
2348}
2349
2351{
2353 Player* member = nullptr;
2354 for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
2355 {
2356 member = ObjectAccessor::FindPlayer(citr->guid);
2357 if (member && m_maxEnchantingLevel < member->GetSkillValue(SKILL_ENCHANTING))
2359 }
2360}
2361
2363{
2364 m_lootMethod = method;
2365}
2366
2368{
2369 m_looterGuid = guid;
2370}
2371
2376
2378{
2379 m_lootThreshold = threshold;
2380}
2381
2383{
2384 member_witerator slot = _getMemberWSlot(guid);
2385 if (slot == m_memberSlots.end())
2386 return;
2387
2388 slot->roles = roles;
2389 SendUpdate();
2390}
2391
2392bool Group::IsFull() const
2393{
2394 return isRaidGroup() ? (m_memberSlots.size() >= MAX_RAID_SIZE) : (m_memberSlots.size() >= MAX_GROUP_SIZE);
2395}
2396
2398{
2399 return (m_groupType & GROUPTYPE_LFG) != 0;
2400}
2401
2403{
2404 return (m_groupType & GROUPTYPE_RAID) != 0;
2405}
2406
2408{
2409 return m_bgGroup != nullptr;
2410}
2411
2413{
2414 return m_bfGroup != nullptr;
2415}
2416
2418{
2419 return GetMembersCount() > 0;
2420}
2421
2423{
2424 return m_leaderGuid;
2425}
2426
2428{
2429 return m_guid;
2430}
2431
2432char const* Group::GetLeaderName() const
2433{
2434 return m_leaderName.c_str();
2435}
2436
2438{
2439 return m_lootMethod;
2440}
2441
2443{
2444 if (GetLootMethod() == FREE_FOR_ALL)
2445 return ObjectGuid::Empty;
2446 return m_looterGuid;
2447}
2448
2453
2458
2460{
2461 return _getMemberCSlot(guid) != m_memberSlots.end();
2462}
2463
2465{
2466 return (GetLeaderGUID() == guid);
2467}
2468
2469ObjectGuid Group::GetMemberGUID(const std::string& name)
2470{
2471 for (member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
2472 if (itr->name == name)
2473 return itr->guid;
2474 return ObjectGuid::Empty;
2475}
2476
2478{
2479 member_citerator mslot = _getMemberCSlot(guid);
2480 if (mslot == m_memberSlots.end())
2481 return 0u;
2482 return mslot->flags;
2483}
2484
2486{
2487 member_citerator mslot2 = _getMemberCSlot(guid2);
2488 if (mslot2 == m_memberSlots.end())
2489 return false;
2490 return SameSubGroup(guid1, &*mslot2);
2491}
2492
2493bool Group::SameSubGroup(ObjectGuid guid1, MemberSlot const* slot2) const
2494{
2495 member_citerator mslot1 = _getMemberCSlot(guid1);
2496 if (mslot1 == m_memberSlots.end() || !slot2)
2497 return false;
2498 return (mslot1->group == slot2->group);
2499}
2500
2502{
2503 return (m_subGroupsCounts && m_subGroupsCounts[subgroup] < MAX_GROUP_SIZE);
2504}
2505
2507{
2508 member_citerator mslot = _getMemberCSlot(guid);
2509 if (mslot == m_memberSlots.end())
2510 return (MAX_RAID_SUBGROUPS+1);
2511 return mslot->group;
2512}
2513
2515{
2516 m_bgGroup = bg;
2517}
2518
2520{
2521 m_bfGroup = bg;
2522}
2523
2525{
2526 // Assistants, main assistants and main tanks are only available in raid groups
2527 if (!isRaidGroup())
2528 return;
2529
2530 // Check if player is really in the raid
2531 member_witerator slot = _getMemberWSlot(guid);
2532 if (slot == m_memberSlots.end())
2533 return;
2534
2535 // Do flag specific actions, e.g ensure uniqueness
2536 switch (flag)
2537 {
2539 RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINASSIST); // Remove main assist flag from current if any.
2540 break;
2542 RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINTANK); // Remove main tank flag from current if any.
2543 break;
2545 break;
2546 default:
2547 return; // This should never happen
2548 }
2549
2550 // Switch the actual flag
2551 ToggleGroupMemberFlag(slot, flag, apply);
2552
2553 // Preserve the new setting in the db
2555
2556 stmt->setUInt8(0, slot->flags);
2557 stmt->setUInt32(1, guid.GetCounter());
2558
2559 CharacterDatabase.Execute(stmt);
2560
2561 // Broadcast the changes to the group
2562 SendUpdate();
2563}
2564
2565Group::Rolls::iterator Group::GetRoll(ObjectGuid Guid)
2566{
2567 Rolls::iterator iter;
2568 for (iter = RollId.begin(); iter != RollId.end(); ++iter)
2569 if ((*iter)->itemGUID == Guid && (*iter)->isValid())
2570 return iter;
2571 return RollId.end();
2572}
2573
2575{
2577}
2578
2580{
2582 while (ref)
2583 {
2584 GroupReference* nextRef = ref->next();
2585 if (ref->GetSource()->GetGUID() == guid)
2586 {
2587 ref->unlink();
2588 break;
2589 }
2590 ref = nextRef;
2591 }
2592}
2593
2595{
2596 return m_boundInstances[difficulty];
2597}
2598
2600{
2601 // Sub group counters initialization
2602 if (!m_subGroupsCounts)
2604
2605 memset((void*)m_subGroupsCounts, 0, (MAX_RAID_SUBGROUPS)*sizeof(uint8));
2606
2607 for (member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
2608 ++m_subGroupsCounts[itr->group];
2609}
2610
2612{
2613 for (member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
2614 if (itr->guid == Guid)
2615 return itr;
2616 return m_memberSlots.end();
2617}
2618
2620{
2621 for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
2622 if (itr->guid == Guid)
2623 return itr;
2624 return m_memberSlots.end();
2625}
2626
2628{
2630 ++m_subGroupsCounts[subgroup];
2631}
2632
2634{
2636 --m_subGroupsCounts[subgroup];
2637}
2638
2640{
2641 for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
2642 if (itr->flags & flag)
2643 itr->flags &= ~flag;
2644}
2645
2647{
2648 if (apply)
2649 slot->flags |= flag;
2650 else
2651 slot->flags &= ~flag;
2652}
2653
2659
2661{
2662 m_isLeaderOffline = false;
2663}
#define sCharacterCache
@ CHAR_DEL_GROUP_INSTANCE_PERM_BINDING
@ CHAR_INS_GROUP_MEMBER
@ CHAR_DEL_GROUP_MEMBER_ALL
@ CHAR_DEL_GROUP
@ CHAR_DEL_GROUP_INSTANCE_BY_INSTANCE
@ CHAR_INS_GROUP
@ CHAR_DEL_GROUP_INSTANCE_BY_GUID
@ CHAR_UPD_GROUP_DIFFICULTY
@ CHAR_UPD_CHARACTER_POSITION_BY_MAPID
@ CHAR_UPD_GROUP_TYPE
@ CHAR_UPD_GROUP_RAID_DIFFICULTY
@ CHAR_UPD_GROUP_MEMBER_FLAG
@ CHAR_REP_GROUP_INSTANCE
@ CHAR_UPD_GROUP_LEADER
@ CHAR_UPD_GROUP_MEMBER_SUBGROUP
@ CHAR_DEL_GROUP_MEMBER
@ CHAR_DEL_LFG_DATA
@ IN_MILLISECONDS
Definition Common.h:35
@ MINUTE
Definition Common.h:29
@ MAP_RAID
Definition DBCEnums.h:335
Difficulty
Definition DBCEnums.h:279
@ RAID_DIFFICULTY_10MAN_NORMAL
Definition DBCEnums.h:286
@ DUNGEON_DIFFICULTY_NORMAL
Definition DBCEnums.h:282
@ DUNGEON_DIFFICULTY_HEROIC
Definition DBCEnums.h:283
@ RAID_DIFFICULTY_10MAN_HEROIC
Definition DBCEnums.h:288
#define MAX_DIFFICULTY
Definition DBCEnums.h:294
@ ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL
Definition DBCEnums.h:155
@ ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT
Definition DBCEnums.h:177
@ ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT
Definition DBCEnums.h:176
MapDifficultyEntry const * GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty)
DBCStorage< BattlemasterListEntry > sBattlemasterListStore(BattlemasterListEntryfmt)
PvPDifficultyEntry const * GetBattlegroundBracketByLevel(uint32 mapid, uint32 level)
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:84
#define ASSERT
Definition Errors.h:68
#define sGroupMgr
Definition GroupMgr.h:58
bool CanRollOnItem(const LootItem &item, Player const *player)
Definition Group.cpp:1028
@ MEMBER_STATUS_OFFLINE
Definition Group.h:61
@ MEMBER_STATUS_PVP
Definition Group.h:63
@ MEMBER_STATUS_ONLINE
Definition Group.h:62
GroupType
Definition Group.h:86
@ GROUPTYPE_NORMAL
Definition Group.h:87
@ GROUPTYPE_LFG_RESTRICTED
Definition Group.h:91
@ GROUPTYPE_RAID
Definition Group.h:89
@ GROUPTYPE_LFG
Definition Group.h:92
@ GROUPTYPE_BGRAID
Definition Group.h:90
#define MAX_GROUP_SIZE
Definition Group.h:43
GroupMemberFlags
Definition Group.h:73
@ MEMBER_FLAG_ASSISTANT
Definition Group.h:74
@ MEMBER_FLAG_MAINASSIST
Definition Group.h:76
@ MEMBER_FLAG_MAINTANK
Definition Group.h:75
#define MAX_RAID_SIZE
Definition Group.h:44
@ GROUP_UPDATE_FULL
Definition Group.h:122
RollVote
Definition Group.h:50
@ PASS
Definition Group.h:51
@ NOT_EMITED_YET
Definition Group.h:55
@ NEED
Definition Group.h:52
@ NOT_VALID
Definition Group.h:56
@ DISENCHANT
Definition Group.h:54
@ GREED
Definition Group.h:53
#define TARGET_ICONS_COUNT
Definition Group.h:47
#define MAX_RAID_SUBGROUPS
Definition Group.h:45
#define sInstanceSaveMgr
InventoryResult
Definition ItemDefines.h:25
@ EQUIP_ERR_OK
Definition ItemDefines.h:26
@ ITEM_FLAG2_CAN_ONLY_ROLL_GREED
#define sLFGMgr
Definition LFGMgr.h:492
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true)
LootMethod
Definition Loot.h:69
@ NEED_BEFORE_GREED
Definition Loot.h:74
@ GROUP_LOOT
Definition Loot.h:73
@ MASTER_LOOT
Definition Loot.h:72
@ FREE_FOR_ALL
Definition Loot.h:70
@ ROLL_ALL_TYPE_NO_DISENCHANT
Definition Loot.h:59
@ ROLL_FLAG_TYPE_DISENCHANT
Definition Loot.h:57
@ MAX_ROLL_TYPE
Definition Loot.h:49
@ ROLL_PASS
Definition Loot.h:45
@ ROLL_GREED
Definition Loot.h:47
@ ROLL_NEED
Definition Loot.h:46
@ ROLL_DISENCHANT
Definition Loot.h:48
#define sMapMgr
Definition MapManager.h:211
@ INSTANCE_RESET_GROUP_DISBAND
Definition Map.h:890
@ INSTANCE_RESET_GROUP_JOIN
Definition Map.h:891
@ INSTANCE_RESET_CHANGE_DIFFICULTY
Definition Map.h:888
@ INSTANCE_RESET_ALL
Definition Map.h:887
@ PHASEMASK_NORMAL
#define sObjectMgr
Definition ObjectMgr.h:1721
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:632
@ PLAYER_FLAGS_GROUP_LEADER
Definition Player.h:346
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
#define sScriptMgr
Definition ScriptMgr.h:1168
GroupJoinBattlegroundResult
@ ERR_BATTLEGROUND_JOIN_TIMED_OUT
@ ERR_BATTLEGROUND_JOIN_FAILED
@ ERR_LFG_CANT_USE_BATTLEGROUND
@ ERR_IN_NON_RANDOM_BG
@ ERR_BATTLEGROUND_NONE
@ ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS
@ ERR_ARENA_TEAM_PARTY_SIZE
@ ERR_BATTLEGROUND_TOO_MANY_QUEUES
@ ERR_GROUP_JOIN_BATTLEGROUND_FAIL
@ ERR_BATTLEGROUND_JOIN_RANGE_INDEX
@ ERR_IN_RANDOM_BG
ItemQualities
@ ITEM_QUALITY_UNCOMMON
@ ALLIANCE
@ HORDE
@ BATTLEGROUND_AA
@ BATTLEGROUND_RB
RemoveMethod
@ GROUP_REMOVEMETHOD_KICK_LFG
@ GROUP_REMOVEMETHOD_KICK
@ SKILL_ENCHANTING
@ NULL_BAG
Definition Unit.h:60
@ NULL_SLOT
Definition Unit.h:61
@ UF_FLAG_PARTY_MEMBER
@ UNIT_FIELD_FACTIONTEMPLATE
@ PLAYER_FLAGS
@ UNIT_FIELD_BYTES_2
static BattlegroundQueueTypeId BGQueueTypeId(BattlegroundTypeId bgTypeId, uint8 bracketId, uint8 arenaType)
uint32 GetMapId() const
BattlegroundTypeId GetTypeID(bool GetRandom=false) const
Group * GetBgRaid(uint32 TeamID) const
void SetBgRaid(uint32 TeamID, Group *bg_raid)
bool isArena() const
void put(std::size_t pos, T value)
Definition ByteBuffer.h:141
Loot loot
Definition Creature.h:218
Class used to access individual fields of database query result.
Definition Field.h:92
uint32 GetUInt32() const
Definition Field.cpp:61
GroupReference * getFirst()
GroupReference * next()
Definition Group.h:165
ObjectGuid m_targetIcons[TARGET_ICONS_COUNT]
Definition Group.h:363
member_citerator _getMemberCSlot(ObjectGuid Guid) const
Definition Group.cpp:2611
MemberSlotList const & GetMemberSlots() const
Definition Group.h:246
void BroadcastGroupUpdate(void)
Definition Group.cpp:2334
uint32 m_counter
Definition Group.h:372
void NeedBeforeGreed(Loot *loot, WorldObject *pLootedObject)
Definition Group.cpp:1200
bool isLFGGroup() const
Definition Group.cpp:2397
void EndRoll(Loot *loot, Map *allowedMap)
Definition Group.cpp:1443
bool m_isLeaderOffline
Definition Group.h:375
void StartLeaderOfflineTimer()
Definition Group.cpp:2654
uint8 GetMemberGroup(ObjectGuid guid) const
Definition Group.cpp:2506
ObjectGuid GetMasterLooterGuid() const
Definition Group.cpp:2449
Battlefield * m_bfGroup
Definition Group.h:362
bool AddLeaderInvite(Player *player)
Definition Group.cpp:338
void SetBattlefieldGroup(Battlefield *bf)
Definition Group.cpp:2519
void SendLootAllPassed(Roll const &roll)
Definition Group.cpp:987
InvitesList m_invitees
Definition Group.h:355
void SendTargetIconList(WorldSession *session)
Definition Group.cpp:1657
uint32 m_maxEnchantingLevel
Definition Group.h:373
bool IsCreated() const
Definition Group.cpp:2417
bool _setMembersGroup(ObjectGuid guid, uint8 group)
Definition Group.cpp:1827
void SubGroupCounterDecrease(uint8 subgroup)
Definition Group.cpp:2633
void SetLootMethod(LootMethod method)
Definition Group.cpp:2362
void ChangeMembersGroup(ObjectGuid guid, uint8 group)
Definition Group.cpp:1862
void SendUpdateToPlayer(Player const *player, MemberSlot const *slot=nullptr)
Definition Group.cpp:1689
ObjectGuid m_leaderGuid
Definition Group.h:356
void RemoveAllInvites()
Definition Group.cpp:357
std::string m_leaderName
Definition Group.h:357
bool IsAssistant(ObjectGuid guid) const
Definition Group.h:233
void _initRaidSubGroupsCounter()
Definition Group.cpp:2599
ObjectGuid m_looterGuid
Definition Group.h:366
void SetLootThreshold(ItemQualities threshold)
Definition Group.cpp:2377
void GroupLoot(Loot *loot, WorldObject *pLootedObject)
Definition Group.cpp:1045
void Disband(bool hideDestroy=false)
Definition Group.cpp:789
InstanceGroupBind * BindToInstance(InstanceSave *save, bool permanent, bool load=false)
Definition Group.cpp:2275
void LoadGroupFromDB(Field *field)
Definition Group.cpp:221
bool AddMember(Player *player)
Definition Group.cpp:386
void SetTargetIcon(uint8 id, ObjectGuid whoGuid, ObjectGuid targetGuid)
Definition Group.cpp:1636
bool IsLeader(ObjectGuid guid) const
Definition Group.cpp:2464
Battleground * m_bgGroup
Definition Group.h:361
BoundInstancesMap & GetBoundInstances(Difficulty difficulty)
Definition Group.cpp:2594
Difficulty m_raidDifficulty
Definition Group.h:360
void SendUpdate()
Definition Group.cpp:1677
GroupRefManager m_memberMgr
Definition Group.h:354
Rolls RollId
Definition Group.h:368
void SetDungeonDifficultyID(Difficulty difficulty)
Definition Group.cpp:2084
void SetMasterLooterGuid(ObjectGuid guid)
Definition Group.cpp:2372
void SetRaidDifficultyID(Difficulty difficulty)
Definition Group.cpp:2100
ObjectGuid GetGUID() const
Definition Group.cpp:2427
void ResetInstances(uint8 method, bool isRaid, Player *SendMsgTo)
Definition Group.cpp:2121
void RemoveInvite(Player *player)
Definition Group.cpp:348
bool isBGGroup() const
Definition Group.cpp:2407
void ConvertToRaid()
Definition Group.cpp:293
ItemQualities GetLootThreshold() const
Definition Group.cpp:2454
MemberSlotList m_memberSlots
Definition Group.h:353
void SendOriginalGroupUpdateToPlayer(Player const *player) const
Definition Group.cpp:1762
uint32 GetMembersCount() const
Definition Group.h:249
Group()
Definition Group.cpp:62
void StopLeaderOfflineTimer()
Definition Group.cpp:2660
Rolls::iterator GetRoll(ObjectGuid Guid)
Definition Group.cpp:2565
void Update(uint32 diff)
Definition Group.cpp:102
void ResetMaxEnchantingLevel()
Definition Group.cpp:2350
void ToggleGroupMemberFlag(member_witerator slot, uint8 flag, bool apply)
Definition Group.cpp:2646
void _homebindIfInstance(Player *player)
Definition Group.cpp:2328
void SendLootStartRoll(uint32 CountDown, uint32 mapid, Roll const &r)
Definition Group.cpp:894
Difficulty GetRaidDifficultyID() const
Definition Group.h:271
void SetLfgRoles(ObjectGuid guid, uint8 roles)
Definition Group.cpp:2382
void SetGroupMemberFlag(ObjectGuid guid, bool apply, GroupMemberFlags flag)
Definition Group.cpp:2524
TimeTracker m_leaderOfflineTimer
Definition Group.h:376
member_witerator _getMemberWSlot(ObjectGuid Guid)
Definition Group.cpp:2619
ObjectGuid GetLooterGuid() const
Definition Group.cpp:2442
uint32 m_dbStoreId
Definition Group.h:374
void DelinkMember(ObjectGuid guid)
Definition Group.cpp:2579
void ChangeLeader(ObjectGuid guid)
Definition Group.cpp:684
void SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player *p, bool canNeed, Roll const &r)
Definition Group.cpp:918
const char * GetLeaderName() const
Definition Group.cpp:2432
void SendLootRollWon(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, Roll const &r)
Definition Group.cpp:964
ObjectGuid GetMemberGUID(const std::string &name)
Definition Group.cpp:2469
void ConvertToLFG()
Definition Group.cpp:276
ObjectGuid m_masterLooterGuid
Definition Group.h:367
MemberSlotList::iterator member_witerator
Definition Group.h:180
void SetBattlegroundGroup(Battleground *bg)
Definition Group.cpp:2514
void UpdatePlayerOutOfRange(Player *player)
Definition Group.cpp:1771
void BroadcastPacket(WorldPacket const *packet, bool ignorePlayersInBGRaid, int group=-1, ObjectGuid ignoredPlayer=ObjectGuid::Empty)
Definition Group.cpp:1788
LootMethod GetLootMethod() const
Definition Group.cpp:2437
void UpdateLooterGuid(WorldObject *pLootedObject, bool ifneed=false)
Definition Group.cpp:1926
Player * GetInvited(ObjectGuid guid) const
Definition Group.cpp:366
bool HasFreeSlotSubGroup(uint8 subgroup) const
Definition Group.cpp:2501
bool isBFGroup() const
Definition Group.cpp:2412
void LoadMemberFromDB(ObjectGuid::LowType guidLow, uint8 memberFlags, uint8 subgroup, uint8 roles)
Definition Group.cpp:251
bool IsMember(ObjectGuid guid) const
Definition Group.cpp:2459
std::unordered_map< uint32, InstanceGroupBind > BoundInstancesMap
Definition Group.h:178
GroupReference * GetFirstMember()
Definition Group.h:247
LootMethod m_lootMethod
Definition Group.h:364
Difficulty GetDungeonDifficultyID() const
Definition Group.h:270
void SelectNewPartyOrRaidLeader()
Definition Group.cpp:115
bool RemoveMember(ObjectGuid guid, RemoveMethod const &method=GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker=ObjectGuid::Empty, char const *reason=nullptr)
Definition Group.cpp:518
void CountTheRoll(Rolls::iterator roll, Map *allowedMap)
Definition Group.cpp:1456
bool SameSubGroup(ObjectGuid guid1, ObjectGuid guid2) const
Definition Group.cpp:2485
ObjectGuid m_guid
Definition Group.h:371
bool CountRollVote(ObjectGuid playerGUID, ObjectGuid Guid, uint8 Choise)
Definition Group.cpp:1396
bool AddInvite(Player *player)
Definition Group.cpp:317
uint8 * m_subGroupsCounts
Definition Group.h:370
Difficulty GetDifficultyID(MapEntry const *mapEntry) const
Definition Group.cpp:2116
void BroadcastReadyCheck(WorldPacket const *packet)
Definition Group.cpp:1801
MemberSlotList::const_iterator member_citerator
Definition Group.h:176
BoundInstancesMap m_boundInstances[MAX_DIFFICULTY]
Definition Group.h:369
void SubGroupCounterIncrease(uint8 subgroup)
Definition Group.cpp:2627
bool Create(Player *leader)
Definition Group.cpp:151
GroupJoinBattlegroundResult CanJoinBattlegroundQueue(Battleground const *bgOrTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot, ObjectGuid &errorGuid) const
Definition Group.cpp:1988
bool IsFull() const
Definition Group.cpp:2392
ObjectGuid GetLeaderGUID() const
Definition Group.cpp:2422
Difficulty m_dungeonDifficulty
Definition Group.h:359
uint8 GetMemberFlags(ObjectGuid guid) const
Definition Group.cpp:2477
void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload=false)
Definition Group.cpp:2308
InstanceGroupBind * GetBoundInstance(Player *player)
Definition Group.cpp:2242
static void ConvertLeaderInstancesToGroup(Player *player, Group *group, bool switchLeader)
convert the player's binds to the group
Definition Group.cpp:753
void SendLootRoll(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, Roll const &r, bool autoPass=false)
Definition Group.cpp:940
~Group()
Definition Group.cpp:72
void SetLooterGuid(ObjectGuid guid)
Definition Group.cpp:2367
void LinkMember(GroupReference *pRef)
Definition Group.cpp:2574
ItemQualities m_lootThreshold
Definition Group.h:365
bool isRaidGroup() const
Definition Group.cpp:2402
GroupType m_groupType
Definition Group.h:358
void RemoveUniqueGroupMemberFlag(GroupMemberFlags flag)
Definition Group.cpp:2639
void MasterLoot(Loot *loot, WorldObject *pLootedObject)
Definition Group.cpp:1348
void OfflineReadyCheck()
Definition Group.cpp:1812
void SendLooter(Creature *creature, Player *pLooter)
Definition Group.cpp:1008
bool RemoveGroup(Group *group)
Difficulty GetDifficultyID() const
uint32 GetInstanceId() const
uint32 GetMapId() const
void AddGroup(Group *group)
bool CanReset() const
uint32 getSize() const
Definition LinkedList.h:126
void insertFirst(LinkedListElement *pElem)
Definition LinkedList.h:116
Definition Map.h:302
bool IsDungeon() const
Definition Map.cpp:4231
bool HavePlayers() const
Definition Map.h:457
MapEntry const * GetEntry() const
Definition Map.h:308
uint32 GetId() const
Definition Map.cpp:4216
LowType GetCounter() const
Definition ObjectGuid.h:156
static ObjectGuid const Empty
Definition ObjectGuid.h:140
bool IsEmpty() const
Definition ObjectGuid.h:172
PackedGuidWriter WriteAsPacked() const
Definition ObjectGuid.h:152
uint32 LowType
Definition ObjectGuid.h:142
void Clear()
Definition ObjectGuid.h:150
void BuildValuesUpdateBlockForPlayer(UpdateData *data, Player const *target) const
Definition Object.cpp:206
static Creature * ToCreature(Object *o)
Definition Object.h:189
PackedGuid const & GetPackGUID() const
Definition Object.h:80
static GameObject * ToGameObject(Object *o)
Definition Object.h:201
bool IsInWorld() const
Definition Object.h:73
void RemoveFieldNotifyFlag(uint16 flag)
Definition Object.h:165
void SetFlag(uint16 index, uint32 newFlag)
Definition Object.cpp:761
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
void SetFieldNotifyFlag(uint16 flag)
Definition Object.h:164
void ForceValuesUpdateAtIndex(uint32)
Definition Object.cpp:1778
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition Player.cpp:13070
bool HaveAtClient(Object const *u) const
Definition Player.cpp:22065
uint32 GetTeam() const
Definition Player.h:1818
bool InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
Definition Player.cpp:23062
BoundInstancesMap m_boundInstances[MAX_DIFFICULTY]
Definition Player.h:2134
bool m_InstanceValid
Definition Player.h:2132
void SetOriginalGroup(Group *group, int8 subgroup=-1)
Definition Player.cpp:23987
void UpdateVisibleGameobjectsOrSpellClicks()
Definition Player.cpp:23237
Item * StoreNewItem(ItemPosCountVec const &pos, uint32 itemId, bool update, int32 randomPropertyId=0, GuidSet const &allowedLooters=GuidSet())
Definition Player.cpp:11619
void SetGroupUpdateFlag(uint32 flag)
Definition Player.h:2165
InventoryResult CanRollForItemInLFG(ItemTemplate const *item, WorldObject const *lootedObject) const
Definition Player.cpp:11479
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6163
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:5906
void SendResetInstanceFailed(uint32 reason, uint32 MapId) const
Definition Player.cpp:20183
void SetGroup(Group *group, int8 subgroup=-1)
Definition Player.cpp:22390
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1=0, uint32 miscValue2=0, WorldObject *ref=nullptr)
Definition Player.cpp:24914
void SetGroupInvite(Group *group)
Definition Player.h:2158
void RemoveFromBattlegroundOrBattlefieldRaid()
Definition Player.cpp:23975
Group * GetOriginalGroup() const
Definition Player.h:2174
void ResetInstances(uint8 method, bool isRaid)
Reset all solo instances and optionally send a message on success for each.
Definition Player.cpp:20128
void SendItemRetrievalMail(uint32 itemEntry, uint32 count)
Definition Player.cpp:26064
uint32 GetItemCount(uint32 item, bool inBankAlso=false, Item *skipItem=nullptr) const
Definition Player.cpp:9436
void UnbindInstance(uint32 mapid, Difficulty difficulty, bool unload=false)
Definition Player.cpp:18594
bool IsAtGroupRewardDistance(WorldObject const *pRewardSource) const
Definition Player.cpp:23639
bool IsDeserter() const
Definition Player.h:1976
bool InBattlegroundQueue(bool ignoreArena=false) const
Definition Player.cpp:23032
WorldSession * GetSession() const
Definition Player.h:1705
Difficulty GetDungeonDifficultyID() const
Definition Player.h:1621
uint32 GetArenaTeamId(uint8 slot) const
Definition Player.h:1615
bool HasFreeBattlegroundQueueId() const
Definition Player.cpp:23087
Group * GetGroup()
Definition Player.h:2159
void AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const &store, bool broadcast=false, bool createdByPlayer=false)
Definition Player.cpp:24504
bool IsGameMaster() const
Definition Player.h:976
bool CanJoinToBattleground(Battleground const *bg) const
Definition Player.cpp:21990
bool CheckInstanceValidity(bool)
Definition Player.cpp:18872
Difficulty GetRaidDifficultyID() const
Definition Player.h:1622
bool GetPassOnGroupLoot() const
Definition Player.h:2180
void SendResetInstanceSuccess(uint32 MapId) const
Definition Player.cpp:20176
static Difficulty CheckLoadedRaidDifficultyID(Difficulty difficulty)
Definition Player.cpp:26377
uint8 GetSubGroup() const
Definition Player.h:2163
Group * GetGroupInvite() const
Definition Player.h:2157
static Difficulty CheckLoadedDungeonDifficultyID(Difficulty difficulty)
Definition Player.cpp:26369
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
Definition Player.cpp:9987
void SetBattlegroundOrBattlefieldRaid(Group *group, int8 subgroup=-1)
Definition Player.cpp:23965
bool isUsingLfg() const
Definition Player.cpp:23949
void setUInt32(uint8 index, uint32 value)
void setBool(uint8 index, bool value)
void setFloat(uint8 index, float value)
void setUInt64(uint8 index, uint64 value)
void setUInt8(uint8 index, uint8 value)
void unlink()
Definition Reference.h:61
void link(Loot *toObj, LootValidatorRef *fromObj)
Definition Reference.h:46
bool isValid() const
Definition Reference.h:78
FROM * GetSource() const
Definition Reference.h:96
Definition Group.h:130
void setLoot(Loot *pLoot)
Definition Group.cpp:52
int32 itemRandomPropId
Definition Group.h:140
uint8 totalGreed
Definition Group.h:147
uint8 totalPlayersRolling
Definition Group.h:145
uint8 itemSlot
Definition Group.h:149
uint32 itemRandomPropertySeed
Definition Group.h:141
uint32 itemid
Definition Group.h:139
uint8 itemCount
Definition Group.h:142
~Roll()
Definition Group.cpp:50
uint8 rollVoteMask
Definition Group.h:150
Roll(ObjectGuid _guid, LootItem const &li)
Definition Group.cpp:45
uint8 totalNeed
Definition Group.h:146
void targetObjectBuildLink() override
Definition Group.cpp:2078
uint8 totalPass
Definition Group.h:148
Loot * getLoot()
Definition Group.cpp:57
ObjectGuid itemGUID
Definition Group.h:138
PlayerVote playerVote
Definition Group.h:144
bool IsAlive() const
Definition Unit.h:1247
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4558
void RemoveAllGroupBuffsFromCaster(ObjectGuid casterGUID)
Definition Unit.cpp:4337
uint8 GetLevel() const
Definition Unit.h:903
bool HasData() const
Definition UpdateData.h:69
bool BuildPacket(WorldPacket *packet)
uint32 GetMapId() const
Definition Position.h:193
Map * FindMap() const
Definition Object.h:452
float GetSightRange(WorldObject const *target=nullptr) const
Definition Object.cpp:1503
std::string const & GetName() const
Definition Object.h:384
bool IsWithinDist(WorldObject const *obj, float dist2compare, bool is3D=true) const
Definition Object.cpp:1188
bool IsInMap(WorldObject const *obj) const
Definition Object.cpp:1161
void Initialize(uint16 opcode, size_t newres=200)
Definition WorldPacket.h:51
Player session in the World.
void SendPacket(WorldPacket const *packet)
Send a packet to the client.
bool PlayerLogout() const
void BuildPartyMemberStatsChangedPacket(Player *player, WorldPacket *data)
@ MSG_RAID_READY_CHECK_CONFIRM
Definition Opcodes.h:971
@ SMSG_GROUP_LIST
Definition Opcodes.h:154
@ SMSG_LOOT_MASTER_LIST
Definition Opcodes.h:705
@ SMSG_REAL_GROUP_UPDATE
Definition Opcodes.h:948
@ SMSG_LOOT_START_ROLL
Definition Opcodes.h:702
@ SMSG_GROUP_UNINVITE
Definition Opcodes.h:148
@ SMSG_LOOT_ALL_PASSED
Definition Opcodes.h:699
@ SMSG_LOOT_LIST
Definition Opcodes.h:1046
@ SMSG_GROUP_DESTROYED
Definition Opcodes.h:153
@ MSG_RAID_TARGET_UPDATE
Definition Opcodes.h:830
@ SMSG_GROUP_SET_LEADER
Definition Opcodes.h:150
@ SMSG_LOOT_ROLL
Definition Opcodes.h:703
@ SMSG_LOOT_ROLL_WON
Definition Opcodes.h:700
#define sWorld
Definition World.h:901
@ CONFIG_INSTANCES_RESET_ANNOUNCE
Definition World.h:160
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
@ LFG_STATE_FINISHED_DUNGEON
Definition LFG.h:73
ObjectGuid guid
Definition Group.h:169
std::string name
Definition Group.h:170
InstanceSave * save
Definition Group.h:155
uint32 DisenchantID
uint32 GetQuality() const
int32 GetMaxCount() const
uint32 GetRequiredDisenchantSkill() const
bool HasFlag(ItemFlags flag) const
uint32 itemid
Definition Loot.h:150
bool is_blocked
Definition Loot.h:159
ObjectGuid rollWinnerGUID
Definition Loot.h:156
int32 randomPropertyId
Definition Loot.h:153
uint8 count
Definition Loot.h:157
bool is_looted
Definition Loot.h:158
GuidSet const & GetAllowedLooters() const
Definition Loot.h:180
bool AllowedForPlayer(Player const *player, bool isGivenByMasterLooter, ObjectGuid ownerGuid) const
Definition Loot.cpp:69
Definition Loot.h:226
uint32 GetMaxSlotInLootFor(Player *player) const
Definition Loot.cpp:542
bool hasOverThresholdItem() const
Definition Loot.cpp:607
bool FillLoot(uint32 lootId, LootStore const &store, Player *lootOwner, bool personal, bool noEmptyError=false, uint16 lootMode=LOOT_MODE_DEFAULT)
Definition Loot.cpp:221
uint8 unlootedCount
Definition Loot.h:234
LootItem * LootItemInSlot(uint32 lootslot, Player *player, NotNormalLootItem **qitem=nullptr, NotNormalLootItem **ffaitem=nullptr, NotNormalLootItem **conditem=nullptr)
Definition Loot.cpp:479
std::vector< LootItem > items
Definition Loot.h:231
void addLootValidatorRef(LootValidatorRef *pLootValidatorRef)
Definition Loot.h:248
void NotifyItemRemoved(uint8 lootIndex)
Definition Loot.cpp:401
std::vector< LootItem > quest_items
Definition Loot.h:232
uint32 InstanceType
bool IsDungeon() const
bool IsRaid() const
BattlegroundBracketId GetBracketId() const
void Update(int32 diff)
Definition Timer.h:121
bool Passed() const
Definition Timer.h:131
void Reset(int32 expiry)
Definition Timer.h:136
DBCPosition3D Loc