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