TrinityCore
Loot.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 "Loot.h"
19#include "Containers.h"
20#include "DatabaseEnv.h"
21#include "DB2Stores.h"
22#include "GameTime.h"
23#include "Group.h"
24#include "Item.h"
25#include "ItemBonusMgr.h"
26#include "ItemTemplate.h"
27#include "Log.h"
28#include "LootMgr.h"
29#include "LootPackets.h"
30#include "Map.h"
31#include "ObjectAccessor.h"
32#include "ObjectMgr.h"
33#include "Player.h"
34#include "Random.h"
35#include "World.h"
36#include "WorldSession.h"
37
38//
39// --------- LootItem ---------
40//
41
42// Constructor, copies most fields from LootStoreItem and generates random count
44{
45 itemid = li.itemid;
46 LootListId = 0;
48
49 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid);
50 freeforall = proto && proto->HasFlag(ITEM_FLAG_MULTI_DROP);
52
54
57 count = 0;
58 is_looted = false;
59 is_blocked = false;
60 is_underthreshold = false;
61 is_counted = false;
63}
64
65LootItem::LootItem(LootItem const&) = default;
66LootItem::LootItem(LootItem&&) noexcept = default;
67LootItem& LootItem::operator=(LootItem const&) = default;
68LootItem& LootItem::operator=(LootItem&&) noexcept = default;
69LootItem::~LootItem() = default;
70
71// Basic checks for player/item compatibility - if false no chance to see the item in the loot
72bool LootItem::AllowedForPlayer(Player const* player, Loot const* loot) const
73{
74 return AllowedForPlayer(player, loot, itemid, needs_quest, follow_loot_rules, false, conditions);
75}
76
77bool LootItem::AllowedForPlayer(Player const* player, Loot const* loot, uint32 itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck,
78 ConditionsReference const& conditions)
79{
80 // DB conditions check
81 if (!conditions.Meets(player))
82 return false;
83
84 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
85 if (!pProto)
86 return false;
87
88 // not show loot for not own team
89 if (pProto->HasFlag(ITEM_FLAG2_FACTION_HORDE) && player->GetTeam() != HORDE)
90 return false;
91
92 if (pProto->HasFlag(ITEM_FLAG2_FACTION_ALLIANCE) && player->GetTeam() != ALLIANCE)
93 return false;
94
95 // Master looter can see all items even if the character can't loot them
96 if (loot && loot->GetLootMethod() == MASTER_LOOT && follow_loot_rules && loot->GetLootMasterGUID() == player->GetGUID())
97 return true;
98
99 // Don't allow loot for players without profession or those who already know the recipe
101 {
102 if (!player->HasSkill(pProto->GetRequiredSkill()))
103 return false;
104
105 for (ItemEffectEntry const* itemEffect : pProto->Effects)
106 {
107 if (itemEffect->TriggerType != ITEM_SPELLTRIGGER_ON_LEARN)
108 continue;
109
110 if (player->HasSpell(itemEffect->SpellID))
111 return false;
112 }
113 }
114
115 // check quest requirements
116 if (!pProto->HasFlag(ITEM_FLAGS_CU_IGNORE_QUEST_STATUS) && ((needs_quest || (pProto->GetStartQuest() && player->GetQuestStatus(pProto->GetStartQuest()) != QUEST_STATUS_NONE)) && !player->HasQuestForItem(itemid)))
117 return false;
118
119 if (strictUsabilityCheck)
120 {
121 if ((pProto->IsWeapon() || pProto->IsArmor()) && !pProto->IsUsableByLootSpecialization(player, true))
122 return false;
123
124 if (player->CanRollNeedForItem(pProto, nullptr, false) != EQUIP_ERR_OK)
125 return false;
126 }
127
128 return true;
129}
130
132{
133 allowedGUIDs.insert(player->GetGUID());
134}
135
136bool LootItem::HasAllowedLooter(ObjectGuid const& looter) const
137{
138 return allowedGUIDs.find(looter) != allowedGUIDs.end();
139}
140
142{
143 if (is_looted)
144 return {};
145
146 if (allowedGUIDs.find(player->GetGUID()) == allowedGUIDs.end())
147 return {};
148
149 if (freeforall)
150 {
151 if (std::unique_ptr<NotNormalLootItemList> const* ffaItems = Trinity::Containers::MapGetValuePtr(loot.GetPlayerFFAItems(), player->GetGUID()))
152 {
153 auto ffaItemItr = std::find_if(ffaItems->get()->begin(), ffaItems->get()->end(), [&](NotNormalLootItem const& ffaItem)
154 {
155 return ffaItem.LootListId == LootListId;
156 });
157 if (ffaItemItr != ffaItems->get()->end() && !ffaItemItr->is_looted)
159 }
160 return {};
161 }
162
165
166 switch (loot.GetLootMethod())
167 {
168 case FREE_FOR_ALL:
170 case ROUND_ROBIN:
171 if (!loot.roundRobinPlayer.IsEmpty() && loot.roundRobinPlayer != player->GetGUID())
172 return {};
173
175 case MASTER_LOOT:
177 {
178 if (!loot.roundRobinPlayer.IsEmpty() && loot.roundRobinPlayer != player->GetGUID())
179 return {};
180
182 }
183
185 case GROUP_LOOT:
188 if (!loot.roundRobinPlayer.IsEmpty() && loot.roundRobinPlayer != player->GetGUID())
189 return {};
190
191 if (is_blocked)
193
194 if (rollWinnerGUID.IsEmpty()) // all passed
196
197 if (rollWinnerGUID == player->GetGUID())
199
200 return {};
201 case PERSONAL_LOOT:
203 default:
204 break;
205 }
206
207 return {};
208}
209
210//
211// ------- Loot Roll -------
212//
213
214// Send the roll for the whole group
216{
217 ItemTemplate const* itemTemplate = ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(m_lootItem->itemid));
218 for (auto const& [playerGuid, roll] : m_rollVoteMap)
219 {
220 if (roll.Vote != RollVote::NotEmitedYet)
221 continue;
222
223 Player* player = ObjectAccessor::GetPlayer(m_map, playerGuid);
224 if (!player)
225 continue;
226
228 startLootRoll.LootObj = m_loot->GetGUID();
229 startLootRoll.MapID = m_map->GetId();
230 startLootRoll.RollTime = LOOT_ROLL_TIMEOUT;
231 startLootRoll.Method = m_loot->GetLootMethod();
232 startLootRoll.ValidRolls = m_voteMask;
233 // In NEED_BEFORE_GREED need disabled for non-usable item for player
234 if (m_loot->GetLootMethod() == NEED_BEFORE_GREED && player->CanRollNeedForItem(itemTemplate, m_map, true) != EQUIP_ERR_OK)
235 startLootRoll.ValidRolls &= ~ROLL_FLAG_TYPE_NEED;
236
237 FillPacket(startLootRoll.Item);
240
241 player->SendDirectMessage(startLootRoll.Write());
242 }
243
244 // Handle auto pass option
245 for (auto const& [playerGuid, roll] : m_rollVoteMap)
246 {
247 if (roll.Vote != RollVote::Pass)
248 continue;
249
250 SendRoll(playerGuid, -1, RollVote::Pass, {});
251 }
252}
253
254// Send all passed message
256{
258 lootAllPassed.LootObj = m_loot->GetGUID();
259 FillPacket(lootAllPassed.Item);
260 lootAllPassed.Item.UIType = LOOT_SLOT_TYPE_ALLOW_LOOT;
262 lootAllPassed.Write();
263
264 for (auto const& [playerGuid, roll] : m_rollVoteMap)
265 {
266 if (roll.Vote != RollVote::NotValid)
267 continue;
268
269 Player* player = ObjectAccessor::GetPlayer(m_map, playerGuid);
270 if (!player)
271 continue;
272
273 player->SendDirectMessage(lootAllPassed.GetRawPacket());
274 }
275}
276
277// Send roll of targetGuid to the whole group (included targuetGuid)
278void LootRoll::SendRoll(ObjectGuid const& targetGuid, int32 rollNumber, RollVote rollType, Optional<ObjectGuid> const& rollWinner)
279{
281 lootRoll.LootObj = m_loot->GetGUID();
282 lootRoll.Player = targetGuid;
283 lootRoll.Roll = rollNumber;
284 lootRoll.RollType = AsUnderlyingType(rollType);
285 lootRoll.Autopassed = false;
286 FillPacket(lootRoll.Item);
289 lootRoll.Write();
290
291 for (auto const& [playerGuid, roll] : m_rollVoteMap)
292 {
293 if (roll.Vote == RollVote::NotValid)
294 continue;
295
296 if (playerGuid == rollWinner)
297 continue;
298
299 Player* player = ObjectAccessor::GetPlayer(m_map, playerGuid);
300 if (!player)
301 continue;
302
303 player->SendDirectMessage(lootRoll.GetRawPacket());
304 }
305
306 if (rollWinner)
307 {
308 if (Player* player = ObjectAccessor::GetPlayer(m_map, *rollWinner))
309 {
311 lootRoll.Clear();
312 player->SendDirectMessage(lootRoll.Write());
313 }
314 }
315}
316
317// Send roll 'value' of the whole group and the winner to the whole group
318void LootRoll::SendLootRollWon(ObjectGuid const& targetGuid, int32 rollNumber, RollVote rollType)
319{
320 // Send roll values
321 for (auto const& [playerGuid, roll] : m_rollVoteMap)
322 {
323 switch (roll.Vote)
324 {
325 case RollVote::Pass:
326 break;
329 SendRoll(playerGuid, 0, RollVote::Pass, targetGuid);
330 break;
331 default:
332 SendRoll(playerGuid, roll.RollNumber, roll.Vote, targetGuid);
333 break;
334 }
335 }
336
338 lootRollWon.LootObj = m_loot->GetGUID();
339 lootRollWon.Winner = targetGuid;
340 lootRollWon.Roll = rollNumber;
341 lootRollWon.RollType = AsUnderlyingType(rollType);
342 FillPacket(lootRollWon.Item);
343 lootRollWon.Item.UIType = LOOT_SLOT_TYPE_LOCKED;
345 lootRollWon.MainSpec = true; // offspec rolls not implemented
346 lootRollWon.Write();
347
348 for (auto const& [playerGuid, roll] : m_rollVoteMap)
349 {
350 if (roll.Vote == RollVote::NotValid)
351 continue;
352
353 if (playerGuid == targetGuid)
354 continue;
355
356 Player* player = ObjectAccessor::GetPlayer(m_map, playerGuid);
357 if (!player)
358 continue;
359
360 player->SendDirectMessage(lootRollWon.GetRawPacket());
361 }
362
363 if (Player* player = ObjectAccessor::GetPlayer(m_map, targetGuid))
364 {
366 lootRollWon.Clear();
367 player->SendDirectMessage(lootRollWon.Write());
368 }
369}
370
372{
373 lootItem.Quantity = m_lootItem->count;
374 lootItem.LootListID = m_lootItem->LootListId;
375 lootItem.CanTradeToTapList = m_lootItem->allowedGUIDs.size() > 1;
376 lootItem.Loot.Initialize(*m_lootItem);
377}
378
380{
381 if (m_isStarted)
383
384 for (auto const& [playerGuid, roll] : m_rollVoteMap)
385 {
386 if (roll.Vote != RollVote::NotEmitedYet)
387 continue;
388
389 Player* player = ObjectAccessor::GetPlayer(m_map, playerGuid);
390 if (!player)
391 continue;
392
393 player->RemoveLootRoll(this);
394 }
395}
396
397// Try to start the group roll for the specified item (it may fail for quest item or any condition
398// If this method return false the roll have to be removed from the container to avoid any problem
399bool LootRoll::TryToStart(Map* map, Loot& loot, uint32 lootListId, uint16 enchantingSkill)
400{
401 if (!m_isStarted)
402 {
403 if (lootListId >= loot.items.size())
404 return false;
405
406 m_map = map;
407
408 // initialize the data needed for the roll
409 m_lootItem = &loot.items[lootListId];
410
411 m_loot = &loot;
412 m_lootItem->is_blocked = true; // block the item while rolling
413
414 uint32 playerCount = 0;
415 for (ObjectGuid allowedLooter : m_lootItem->GetAllowedLooters())
416 {
417 Player* plr = ObjectAccessor::GetPlayer(m_map, allowedLooter);
418 if (!plr || !m_lootItem->HasAllowedLooter(plr->GetGUID())) // check if player meet the condition to be able to roll this item
419 {
420 m_rollVoteMap[allowedLooter].Vote = RollVote::NotValid;
421 continue;
422 }
423 // initialize player vote map
425 if (!plr->GetPassOnGroupLoot())
426 plr->AddLootRoll(this);
427
428 ++playerCount;
429 }
430
431 // initialize item prototype and check enchant possibilities for this group
432 ItemTemplate const* itemTemplate = ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(m_lootItem->itemid));
434 if (itemTemplate->HasFlag(ITEM_FLAG2_CAN_ONLY_ROLL_GREED))
436 if (ItemDisenchantLootEntry const* disenchant = GetItemDisenchantLoot(); !disenchant || disenchant->SkillRequired > enchantingSkill)
438
439 if (playerCount > 1) // check if more than one player can loot this item
440 {
441 // start the roll
444 m_isStarted = true;
445 return true;
446 }
447 // no need to start roll if one or less player can loot this item so place it under threshold
449 m_lootItem->is_blocked = false;
450 }
451 return false;
452}
453
454// Add vote from playerGuid
456{
457 ObjectGuid const& playerGuid = player->GetGUID();
458 RollVoteMap::iterator voterItr = m_rollVoteMap.find(playerGuid);
459 if (voterItr == m_rollVoteMap.end())
460 return false;
461
462 voterItr->second.Vote = vote;
463
464 if (vote != RollVote::Pass && vote != RollVote::NotValid)
465 voterItr->second.RollNumber = urand(1, 100);
466
467 switch (vote)
468 {
469 case RollVote::Pass: // Player choose pass
470 {
471 SendRoll(playerGuid, -1, RollVote::Pass, {});
472 break;
473 }
474 case RollVote::Need: // player choose Need
475 {
476 SendRoll(playerGuid, 0, RollVote::Need, {});
478 break;
479 }
480 case RollVote::Greed: // player choose Greed
481 {
482 SendRoll(playerGuid, -1, RollVote::Greed, {});
484 break;
485 }
486 case RollVote::Disenchant: // player choose Disenchant
487 {
488 SendRoll(playerGuid, -1, RollVote::Disenchant, {});
490 break;
491 }
492 default: // Roll removed case
493 return false;
494 }
495 return true;
496}
497
498// check if we can found a winner for this roll or if timer is expired
500{
501 RollVoteMap::const_iterator winnerItr = m_rollVoteMap.end();
502
503 if (AllPlayerVoted(winnerItr) || m_endTime <= GameTime::Now())
504 {
505 Finish(winnerItr);
506 return true;
507 }
508 return false;
509}
510
511bool LootRoll::IsLootItem(ObjectGuid const& lootObject, uint32 lootListId) const
512{
513 return m_loot->GetGUID() == lootObject && m_lootItem->LootListId == lootListId;
514}
515
521bool LootRoll::AllPlayerVoted(RollVoteMap::const_iterator& winnerItr)
522{
523 uint32 notVoted = 0;
524 bool isSomeoneNeed = false;
525
526 winnerItr = m_rollVoteMap.end();
527 for (RollVoteMap::const_iterator itr = m_rollVoteMap.begin(); itr != m_rollVoteMap.end(); ++itr)
528 {
529 switch (itr->second.Vote)
530 {
531 case RollVote::Need:
532 if (!isSomeoneNeed || winnerItr == m_rollVoteMap.end() || itr->second.RollNumber > winnerItr->second.RollNumber)
533 {
534 isSomeoneNeed = true; // first passage will force to set winner because need is prioritized
535 winnerItr = itr;
536 }
537 break;
538 case RollVote::Greed:
540 if (!isSomeoneNeed) // if at least one need is detected then winner can't be a greed
541 {
542 if (winnerItr == m_rollVoteMap.end() || itr->second.RollNumber > winnerItr->second.RollNumber)
543 winnerItr = itr;
544 }
545 break;
546 // Explicitly passing excludes a player from winning loot, so no action required.
547 case RollVote::Pass:
548 break;
550 ++notVoted;
551 break;
552 default:
553 break;
554 }
555 }
556
557 return notVoted == 0;
558}
559
561{
563 itemInstance.Initialize(*m_lootItem);
564
565 BonusData bonusData;
566 bonusData.Initialize(itemInstance);
567 if (!bonusData.CanDisenchant)
568 return nullptr;
569
570 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(m_lootItem->itemid);
571 uint32 itemLevel = Item::GetItemLevel(itemTemplate, bonusData, 1, 0, 0, 0, 0, false, 0);
572 return Item::GetDisenchantLoot(itemTemplate, bonusData.Quality, itemLevel);
573}
574
575// terminate the roll
576void LootRoll::Finish(RollVoteMap::const_iterator winnerItr)
577{
578 m_lootItem->is_blocked = false;
579 if (winnerItr == m_rollVoteMap.end())
580 {
582 }
583 else
584 {
585 m_lootItem->rollWinnerGUID = winnerItr->first;
586
587 SendLootRollWon(winnerItr->first, winnerItr->second.RollNumber, winnerItr->second.Vote);
588
589 if (Player* player = ObjectAccessor::FindConnectedPlayer(winnerItr->first))
590 {
591 if (winnerItr->second.Vote == RollVote::Need)
592 player->UpdateCriteria(CriteriaType::RollNeed, m_lootItem->itemid, winnerItr->second.RollNumber);
593 else if (winnerItr->second.Vote == RollVote::Disenchant)
594 player->UpdateCriteria(CriteriaType::CastSpell, 13262);
595 else
596 player->UpdateCriteria(CriteriaType::RollGreed, m_lootItem->itemid, winnerItr->second.RollNumber);
597
598 if (winnerItr->second.Vote == RollVote::Disenchant)
599 {
601 Loot loot(m_map, m_loot->GetOwnerGUID(), LOOT_DISENCHANTING, nullptr);
602 loot.FillLoot(disenchant->ID, LootTemplates_Disenchant, player, true, false, LOOT_MODE_DEFAULT, ItemContext::NONE);
603 if (!loot.AutoStore(player, NULL_BAG, NULL_SLOT, true))
604 {
605 for (uint32 i = 0; i < loot.items.size(); ++i)
606 if (LootItem* disenchantLoot = loot.LootItemInSlot(i, player))
607 player->SendItemRetrievalMail(disenchantLoot->itemid, disenchantLoot->count, disenchantLoot->context);
608 }
609 else
611 }
612 else
613 player->StoreLootItem(m_loot->GetOwnerGUID(), m_lootItem->LootListId, m_loot);
614 }
615 }
616 m_isStarted = false;
617}
618
619//
620// --------- Loot ---------
621//
622
623Loot::Loot(Map* map, ObjectGuid owner, LootType type, Group const* group) : gold(0), unlootedCount(0), loot_type(type),
624 _guid(map ? ObjectGuid::Create<HighGuid::LootObject>(map->GetId(), 0, map->GenerateLowGuid<HighGuid::LootObject>()) : ObjectGuid::Empty),
625 _owner(owner), _itemContext(ItemContext::NONE), _lootMethod(group ? group->GetLootMethod() : FREE_FOR_ALL),
626 _lootMaster(group ? group->GetMasterLooterGuid() : ObjectGuid::Empty), _wasOpened(false), _changed(false), _dungeonEncounterId(0)
627{
628}
629
631{
632 GuidSet activeLooters = std::move(PlayersLooting);
633 for (ObjectGuid playerGuid : activeLooters)
634 if (Player* player = ObjectAccessor::FindConnectedPlayer(playerGuid))
635 player->GetSession()->DoLootRelease(this);
636}
637
638void Loot::NotifyLootList(Map const* map) const
639{
641
642 lootList.Owner = GetOwnerGUID();
643 lootList.LootObj = GetGUID();
644
646 lootList.Master = GetLootMasterGUID();
647
650
651 lootList.Write();
652
653 for (ObjectGuid allowedLooterGuid : _allowedLooters)
654 if (Player* allowedLooter = ObjectAccessor::GetPlayer(map, allowedLooterGuid))
655 allowedLooter->SendDirectMessage(lootList.GetRawPacket());
656}
657
658void Loot::NotifyItemRemoved(uint8 lootListId, Map const* map)
659{
660 // notify all players that are looting this that the item was removed
661 // convert the index to the slot the player sees
662 for (auto itr = PlayersLooting.begin(); itr != PlayersLooting.end();)
663 {
664 LootItem const& item = items[lootListId];
665 if (item.GetAllowedLooters().find(*itr) == item.GetAllowedLooters().end())
666 {
667 ++itr;
668 continue;
669 }
670
671 if (Player* player = ObjectAccessor::GetPlayer(map, *itr))
672 {
673 player->SendNotifyLootItemRemoved(GetGUID(), GetOwnerGUID(), lootListId);
674 ++itr;
675 }
676 else
677 itr = PlayersLooting.erase(itr);
678 }
679}
680
682{
683 // notify all players that are looting this that the money was removed
684 for (auto itr = PlayersLooting.begin(); itr != PlayersLooting.end();)
685 {
686 if (Player* player = ObjectAccessor::GetPlayer(map, *itr))
687 {
688 player->SendNotifyLootMoneyRemoved(GetGUID());
689 ++itr;
690 }
691 else
692 itr = PlayersLooting.erase(itr);
693 }
694}
695
697{
698 AddLooter(looter);
699 if (!_wasOpened)
700 {
701 _wasOpened = true;
702
704 {
705 uint16 maxEnchantingSkill = 0;
706 for (ObjectGuid allowedLooterGuid : _allowedLooters)
707 if (Player* allowedLooter = ObjectAccessor::GetPlayer(map, allowedLooterGuid))
708 maxEnchantingSkill = std::max(maxEnchantingSkill, allowedLooter->GetSkillValue(SKILL_ENCHANTING));
709
710 for (uint32 lootListId = 0; lootListId < items.size(); ++lootListId)
711 {
712 LootItem& item = items[lootListId];
713 if (!item.is_blocked)
714 continue;
715
716 auto&& [itr, inserted] = _rolls.try_emplace(lootListId);
717 if (!itr->second.TryToStart(map, *this, lootListId, maxEnchantingSkill))
718 _rolls.erase(itr);
719 }
720
721 if (!_rolls.empty())
722 _changed = true;
723 }
724 else if (_lootMethod == MASTER_LOOT)
725 {
726 if (looter == _lootMaster)
727 {
728 if (Player* lootMaster = ObjectAccessor::GetPlayer(map, looter))
729 {
730 WorldPackets::Loot::MasterLootCandidateList masterLootCandidateList;
731 masterLootCandidateList.LootObj = GetGUID();
732 masterLootCandidateList.Players = _allowedLooters;
733 lootMaster->SendDirectMessage(masterLootCandidateList.Write());
734 }
735 }
736 }
737 }
738}
739
740bool Loot::HasAllowedLooter(ObjectGuid const& looter) const
741{
742 return _allowedLooters.find(looter) != _allowedLooters.end();
743}
744
745void Loot::generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
746{
747 if (maxAmount > 0)
748 {
749 if (maxAmount <= minAmount)
750 gold = uint32(maxAmount * sWorld->getRate(RATE_DROP_MONEY));
751 else if ((maxAmount - minAmount) < 32700)
752 gold = uint32(urand(minAmount, maxAmount) * sWorld->getRate(RATE_DROP_MONEY));
753 else
754 gold = uint32(urand(minAmount >> 8, maxAmount >> 8) * sWorld->getRate(RATE_DROP_MONEY)) << 8;
755 }
756}
757
758// Calls processor of corresponding LootTemplate (which handles everything including references)
759bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError, uint16 lootMode /*= LOOT_MODE_DEFAULT*/, ItemContext context /*= ItemContext::NONE*/)
760{
761 // Must be provided
762 if (!lootOwner)
763 return false;
764
765 LootTemplate const* tab = store.GetLootFor(lootId);
766
767 if (!tab)
768 {
769 if (!noEmptyError)
770 TC_LOG_ERROR("sql.sql", "Table '{}' loot id #{} used but it doesn't have records.", store.GetName(), lootId);
771 return false;
772 }
773
774 _itemContext = context;
775
776 items.reserve(MAX_NR_LOOT_ITEMS);
777
778 tab->Process(*this, store.IsRatesAllowed(), lootMode, 0); // Processing is done there, callback via Loot::AddItem()
779
780 // Setting access rights for group loot case
781 Group const* group = lootOwner->GetGroup();
782 if (!personal && group)
783 {
784 if (loot_type == LOOT_CORPSE)
785 roundRobinPlayer = lootOwner->GetGUID();
786
787 for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
788 if (Player const* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter
789 if (player->IsAtGroupRewardDistance(lootOwner))
790 FillNotNormalLootFor(player);
791
792 for (LootItem& item : items)
793 {
794 if (!item.follow_loot_rules || item.freeforall)
795 continue;
796
797 if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid))
798 {
799 if (proto->GetQuality() < uint32(group->GetLootThreshold()))
800 item.is_underthreshold = true;
801 else
802 {
803 switch (_lootMethod)
804 {
805 case MASTER_LOOT:
806 case GROUP_LOOT:
808 {
809 item.is_blocked = true;
810 break;
811 }
812 default:
813 break;
814 }
815 }
816 }
817 }
818 }
819 // ... for personal loot
820 else
821 FillNotNormalLootFor(lootOwner);
822
823 return true;
824}
825
826// Inserts the item into the loot (called by LootTemplate processors)
828{
829 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid);
830 if (!proto)
831 return;
832
833 uint32 count = urand(item.mincount, item.maxcount);
834 uint32 stacks = count / proto->GetMaxStackSize() + ((count % proto->GetMaxStackSize()) ? 1 : 0);
835
836 for (uint32 i = 0; i < stacks && items.size() < MAX_NR_LOOT_ITEMS; ++i)
837 {
838 LootItem generatedLoot(item);
839 generatedLoot.context = _itemContext;
840 generatedLoot.count = std::min(count, proto->GetMaxStackSize());
841 generatedLoot.LootListId = items.size();
843
844 items.push_back(generatedLoot);
845 count -= proto->GetMaxStackSize();
846 }
847}
848
849bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool createdByPlayer)
850{
851 bool allLooted = true;
852 for (uint32 i = 0; i < items.size(); ++i)
853 {
854 NotNormalLootItem* ffaitem = nullptr;
855
856 LootItem* lootItem = LootItemInSlot(i, player, &ffaitem);
857 if (!lootItem || lootItem->is_looted)
858 continue;
859
860 if (!lootItem->HasAllowedLooter(player->GetGUID()))
861 continue;
862
863 if (lootItem->is_blocked)
864 continue;
865
866 // dont allow protected item to be looted by someone else
867 if (!lootItem->rollWinnerGUID.IsEmpty() && lootItem->rollWinnerGUID != GetGUID())
868 continue;
869
870 ItemPosCountVec dest;
871 InventoryResult msg = player->CanStoreNewItem(bag, slot, dest, lootItem->itemid, lootItem->count);
872 if (msg != EQUIP_ERR_OK && slot != NULL_SLOT)
873 msg = player->CanStoreNewItem(bag, NULL_SLOT, dest, lootItem->itemid, lootItem->count);
874 if (msg != EQUIP_ERR_OK && bag != NULL_BAG)
875 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, lootItem->itemid, lootItem->count);
876 if (msg != EQUIP_ERR_OK)
877 {
878 player->SendEquipError(msg, nullptr, nullptr, lootItem->itemid);
879 allLooted = false;
880 continue;
881 }
882
883 if (ffaitem)
884 ffaitem->is_looted = true;
885
886 if (!lootItem->freeforall)
887 lootItem->is_looted = true;
888
890
891 if (Item* pItem = player->StoreNewItem(dest, lootItem->itemid, true, lootItem->randomBonusListId, GuidSet(), lootItem->context, &lootItem->BonusListIDs))
892 {
893 player->SendNewItem(pItem, lootItem->count, false, createdByPlayer, broadcast, GetDungeonEncounterId());
894 player->ApplyItemLootedSpell(pItem, true);
895 }
896 else
897 player->ApplyItemLootedSpell(sObjectMgr->GetItemTemplate(lootItem->itemid));
898 }
899
900 return allLooted;
901}
902
904{
905 gold = 0;
906 _changed = true;
907}
908
909LootItem const* Loot::GetItemInSlot(uint32 lootListId) const
910{
911 if (lootListId < items.size())
912 return &items[lootListId];
913
914 return nullptr;
915}
916
917LootItem* Loot::LootItemInSlot(uint32 lootListId, Player const* player, NotNormalLootItem** ffaItem)
918{
919 if (lootListId >= items.size())
920 return nullptr;
921
922 LootItem* item = &items[lootListId];
923 bool is_looted = item->is_looted;
924
925 if (item->freeforall)
926 {
927 auto itr = PlayerFFAItems.find(player->GetGUID());
928 if (itr != PlayerFFAItems.end())
929 {
930 for (NotNormalLootItem& notNormalLootItem : *itr->second)
931 {
932 if (notNormalLootItem.LootListId == lootListId)
933 {
934 is_looted = notNormalLootItem.is_looted;
935 if (ffaItem)
936 *ffaItem = &notNormalLootItem;
937
938 break;
939 }
940 }
941 }
942 }
943
944 if (is_looted)
945 return nullptr;
946
947 _changed = true;
948 return item;
949}
950
951// return true if there is any item that is lootable for any player (not quest item, FFA or conditional)
953{
954 // Gold is always lootable
955 if (gold)
956 return true;
957
958 for (LootItem const& item : items)
959 if (!item.is_looted && item.follow_loot_rules && !item.freeforall && item.conditions.IsEmpty())
960 return true;
961 return false;
962}
963
964// return true if there is any FFA, quest or conditional item for the player.
965bool Loot::hasItemFor(Player const* player) const
966{
967 // quest items
968 for (LootItem const& lootItem : items)
969 if (!lootItem.is_looted && !lootItem.follow_loot_rules && lootItem.GetAllowedLooters().find(player->GetGUID()) != lootItem.GetAllowedLooters().end())
970 return true;
971
972 if (std::unique_ptr<NotNormalLootItemList> const* ffaItems = Trinity::Containers::MapGetValuePtr(GetPlayerFFAItems(), player->GetGUID()))
973 {
974 bool hasFfaItem = std::any_of(ffaItems->get()->begin(), ffaItems->get()->end(), [&](NotNormalLootItem const& ffaItem)
975 {
976 return !ffaItem.is_looted;
977 });
978 if (hasFfaItem)
979 return true;
980 }
981
982 return false;
983}
984
985// return true if there is any item over the group threshold (i.e. not underthreshold).
987{
988 for (uint8 i = 0; i < items.size(); ++i)
989 {
990 if (!items[i].is_looted && !items[i].is_underthreshold && !items[i].freeforall)
991 return true;
992 }
993
994 return false;
995}
996
998{
999 packet.Coins = gold;
1000
1001 for (LootItem const& item : items)
1002 {
1003 Optional<LootSlotType> uiType = item.GetUiTypeForPlayer(viewer, *this);
1004 if (!uiType)
1005 continue;
1006
1007 WorldPackets::Loot::LootItemData& lootItem = packet.Items.emplace_back();
1008 lootItem.LootListID = item.LootListId;
1009 lootItem.UIType = *uiType;
1010 lootItem.Quantity = item.count;
1011 lootItem.Loot.Initialize(item);
1012 }
1013}
1014
1016{
1017 for (auto itr = _rolls.begin(); itr != _rolls.end(); )
1018 {
1019 if (itr->second.UpdateRoll())
1020 itr = _rolls.erase(itr);
1021 else
1022 ++itr;
1023 }
1024}
1025
1027{
1028 ObjectGuid plguid = player->GetGUID();
1029 _allowedLooters.insert(plguid);
1030
1031 std::unique_ptr<NotNormalLootItemList> ffaItems = std::make_unique<NotNormalLootItemList>();
1032
1033 for (LootItem& item : items)
1034 {
1035 if (!item.AllowedForPlayer(player, this))
1036 continue;
1037
1038 item.AddAllowedLooter(player);
1039
1040 if (item.freeforall)
1041 {
1042 ffaItems->emplace_back(item.LootListId);
1043 ++unlootedCount;
1044 }
1045 else if (!item.is_counted)
1046 {
1047 item.is_counted = true;
1048 ++unlootedCount;
1049 }
1050 }
1051
1052 if (!ffaItems->empty())
1053 PlayerFFAItems[player->GetGUID()] = std::move(ffaItems);
1054}
1055
1056//
1057// --------- AELootResult ---------
1058//
1059
1060void AELootResult::Add(Item* item, uint8 count, LootType lootType, uint32 dungeonEncounterId)
1061{
1062 auto itr = _byItem.find(item);
1063 if (itr != _byItem.end())
1064 _byOrder[itr->second].count += count;
1065 else
1066 {
1067 _byItem[item] = _byOrder.size();
1068 ResultValue value;
1069 value.item = item;
1070 value.count = count;
1071 value.lootType = lootType;
1072 value.dungeonEncounterId = dungeonEncounterId;
1073 _byOrder.push_back(value);
1074 }
1075}
1076
1077AELootResult::OrderedStorage::const_iterator AELootResult::begin() const
1078{
1079 return _byOrder.begin();
1080}
1081
1082AELootResult::OrderedStorage::const_iterator AELootResult::end() const
1083{
1084 return _byOrder.end();
1085}
ItemContext
Definition: DBCEnums.h:1063
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
#define ASSERT_NOTNULL(pointer)
Definition: Errors.h:84
InventoryResult
Definition: ItemDefines.h:25
@ EQUIP_ERR_OK
Definition: ItemDefines.h:26
ItemRandomBonusListId GenerateItemRandomBonusListId(uint32 item_id)
@ ITEM_FLAG2_FACTION_HORDE
Definition: ItemTemplate.h:212
@ ITEM_FLAG2_FACTION_ALLIANCE
Definition: ItemTemplate.h:213
@ ITEM_FLAG2_CAN_ONLY_ROLL_GREED
Definition: ItemTemplate.h:220
@ ITEM_SPELLTRIGGER_ON_LEARN
Definition: ItemTemplate.h:110
@ ITEM_FLAG_HIDE_UNUSABLE_RECIPE
Definition: ItemTemplate.h:201
@ ITEM_FLAG_MULTI_DROP
Definition: ItemTemplate.h:187
@ ITEM_FLAGS_CU_FOLLOW_LOOT_RULES
Definition: ItemTemplate.h:319
@ ITEM_FLAGS_CU_IGNORE_QUEST_STATUS
Definition: ItemTemplate.h:318
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true)
LootType
Definition: Loot.h:98
@ LOOT_CORPSE
Definition: Loot.h:101
@ LOOT_DISENCHANTING
Definition: Loot.h:104
@ PERSONAL_LOOT
Definition: Loot.h:94
@ NEED_BEFORE_GREED
Definition: Loot.h:93
@ GROUP_LOOT
Definition: Loot.h:92
@ MASTER_LOOT
Definition: Loot.h:91
@ ROUND_ROBIN
Definition: Loot.h:90
@ FREE_FOR_ALL
Definition: Loot.h:89
RollMask
Definition: Loot.h:74
@ ROLL_FLAG_TYPE_DISENCHANT
Definition: Loot.h:78
@ ROLL_ALL_TYPE_MASK
Definition: Loot.h:82
@ ROLL_FLAG_TYPE_NEED
Definition: Loot.h:76
@ LOOT_SLOT_TYPE_MASTER
Definition: Loot.h:159
@ LOOT_SLOT_TYPE_ROLL_ONGOING
Definition: Loot.h:158
@ LOOT_SLOT_TYPE_ALLOW_LOOT
Definition: Loot.h:157
@ LOOT_SLOT_TYPE_OWNER
Definition: Loot.h:161
@ LOOT_SLOT_TYPE_LOCKED
Definition: Loot.h:160
#define MAX_NR_LOOT_ITEMS
Definition: Loot.h:85
RollVote
Definition: Loot.h:64
constexpr Minutes LOOT_ROLL_TIMEOUT
Definition: Loot.h:33
std::set< ObjectGuid > GuidSet
Definition: ObjectGuid.h:393
HighGuid
Definition: ObjectGuid.h:75
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
std::vector< ItemPosCount > ItemPosCountVec
Definition: Player.h:750
@ QUEST_STATUS_NONE
Definition: QuestDef.h:142
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
@ ALLIANCE
@ HORDE
@ LOOT_MODE_DEFAULT
Definition: SharedDefines.h:77
@ SKILL_ENCHANTING
@ NULL_BAG
Definition: Unit.h:62
@ NULL_SLOT
Definition: Unit.h:63
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
OrderedStorage _byOrder
Definition: Loot.h:375
std::unordered_map< Item *, OrderedStorage::size_type > _byItem
Definition: Loot.h:376
OrderedStorage::const_iterator end() const
Definition: Loot.cpp:1082
OrderedStorage::const_iterator begin() const
Definition: Loot.cpp:1077
void Add(Item *item, uint8 count, LootType lootType, uint32 dungeonEncounterId)
Definition: Loot.cpp:1060
GroupReference * next()
Definition: Group.h:197
ItemQualities GetLootThreshold() const
Definition: Group.cpp:1690
GroupReference * GetFirstMember()
Definition: Group.h:325
Definition: Item.h:170
ItemDisenchantLootEntry const * GetDisenchantLoot(Player const *owner) const
Definition: Item.cpp:2360
uint32 GetItemLevel(Player const *owner) const
Definition: Item.cpp:2279
bool PlayerVote(Player *player, RollVote vote)
Definition: Loot.cpp:455
bool UpdateRoll()
Definition: Loot.cpp:499
TimePoint m_endTime
Definition: Loot.h:277
void Finish(RollVoteMap::const_iterator winnerItr)
Definition: Loot.cpp:576
bool AllPlayerVoted(RollVoteMap::const_iterator &winnerItr)
Check if all player have voted and return true in that case. Also return current winner.
Definition: Loot.cpp:521
bool TryToStart(Map *map, Loot &loot, uint32 lootListId, uint16 enchantingSkill)
Definition: Loot.cpp:399
bool m_isStarted
Definition: Loot.h:273
ItemDisenchantLootEntry const * GetItemDisenchantLoot() const
Definition: Loot.cpp:560
LootItem * m_lootItem
Definition: Loot.h:274
void SendStartRoll()
Definition: Loot.cpp:215
Loot * m_loot
Definition: Loot.h:275
bool IsLootItem(ObjectGuid const &lootObject, uint32 lootListId) const
Definition: Loot.cpp:511
RollVoteMap m_rollVoteMap
Definition: Loot.h:272
~LootRoll()
Definition: Loot.cpp:379
RollMask m_voteMask
Definition: Loot.h:276
void SendLootRollWon(ObjectGuid const &targetGuid, int32 rollNumber, RollVote rollType)
Definition: Loot.cpp:318
Map * m_map
Definition: Loot.h:271
void SendAllPassed()
Definition: Loot.cpp:255
void SendRoll(ObjectGuid const &targetGuid, int32 rollNumber, RollVote rollType, Optional< ObjectGuid > const &rollWinner)
Definition: Loot.cpp:278
void FillPacket(WorldPackets::Loot::LootItemData &lootItem) const
Definition: Loot.cpp:371
LootTemplate const * GetLootFor(uint32 loot_id) const
Definition: LootMgr.cpp:219
bool IsRatesAllowed() const
Definition: LootMgr.h:92
char const * GetName() const
Definition: LootMgr.h:90
void Process(Loot &loot, bool rate, uint16 lootMode, uint8 groupId, Player const *personalLooter=nullptr) const
Definition: LootMgr.cpp:557
Definition: Map.h:189
uint32 GetId() const
Definition: Map.cpp:3228
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsEmpty() const
Definition: ObjectGuid.h:319
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition: Player.cpp:13254
Item * StoreNewItem(ItemPosCountVec const &pos, uint32 itemId, bool update, ItemRandomBonusListId randomBonusListId=0, GuidSet const &allowedLooters=GuidSet(), ItemContext context=ItemContext::NONE, std::vector< int32 > const *bonusListIDs=nullptr, bool addToCollection=true)
Definition: Player.cpp:11537
void ApplyItemLootedSpell(Item *item, bool apply)
Definition: Player.cpp:8869
InventoryResult CanRollNeedForItem(ItemTemplate const *item, Map const *map, bool restrictOnlyLfg) const
Definition: Player.cpp:11493
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6324
bool HasQuestForItem(uint32 itemId) const
Definition: Player.cpp:16900
bool HasSkill(uint32 skill) const
Definition: Player.cpp:6031
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
void AddLootRoll(LootRoll *roll)
Definition: Player.h:2096
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition: Player.cpp:16050
bool GetPassOnGroupLoot() const
Definition: Player.h:2631
bool HasSpell(uint32 spell) const override
Definition: Player.cpp:3792
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
void RemoveLootRoll(LootRoll *roll)
Definition: Player.cpp:9055
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
Definition: Player.cpp:10032
Team GetTeam() const
Definition: Player.h:2235
void SendNewItem(Item *item, uint32 quantity, bool received, bool created, bool broadcast=false, uint32 dungeonEncounterId=0)
Definition: Player.cpp:13990
WorldPacket const * Write() override
Optional< ObjectGuid > Master
Definition: LootPackets.h:203
WorldPacket const * Write() override
Optional< ObjectGuid > RoundRobinWinner
Definition: LootPackets.h:204
std::vector< LootItemData > Items
Definition: LootPackets.h:74
WorldPacket const * Write() override
int32 Roll
Roll value can be negative, it means that it is an "offspec" roll but only during roll selection broa...
Definition: LootPackets.h:243
bool Autopassed
Triggers message |HlootHistory:d|h[Loot]|h: You automatically passed on: s because you cannot loot th...
Definition: LootPackets.h:246
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Duration< Milliseconds, uint32 > RollTime
Definition: LootPackets.h:226
WorldPacket const * GetRawPacket() const
Definition: Packet.h:38
#define sWorld
Definition: World.h:931
@ RATE_DROP_MONEY
Definition: World.h:482
TC_GAME_API uint32 GetId(std::string_view username)
TimePoint Now()
Current chrono steady_clock time point.
Definition: GameTime.cpp:59
std::vector< int32 > GetBonusListsForItem(uint32 itemId, ItemBonusGenerationParams const &params)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition: MapUtils.h:29
std::unique_ptr< VignetteData > Create(VignetteEntry const *vignetteData, WorldObject const *owner)
Definition: Vignette.cpp:72
uint32 dungeonEncounterId
Definition: Loot.h:365
Definition: Item.h:69
bool CanDisenchant
Definition: Item.h:93
uint32 Quality
Definition: Item.h:70
void Initialize(ItemTemplate const *proto)
Definition: Item.cpp:2829
bool Meets(WorldObject const *object) const
Definition: ConditionMgr.h:369
uint32 GetMaxStackSize() const
Definition: ItemTemplate.h:847
uint32 GetStartQuest() const
Definition: ItemTemplate.h:809
std::vector< ItemEffectEntry const * > Effects
Definition: ItemTemplate.h:828
bool HasFlag(ItemFlags flag) const
Definition: ItemTemplate.h:871
bool IsUsableByLootSpecialization(Player const *player, bool alwaysAllowBoundToAccount) const
bool IsArmor() const
Definition: ItemTemplate.h:861
bool IsWeapon() const
Definition: ItemTemplate.h:860
uint32 GetRequiredSkill() const
Definition: ItemTemplate.h:791
Definition: Loot.h:176
bool HasAllowedLooter(ObjectGuid const &looter) const
Definition: Loot.cpp:136
std::vector< int32 > BonusListIDs
Definition: Loot.h:180
uint32 itemid
Definition: Loot.h:177
bool is_blocked
Definition: Loot.h:187
Optional< LootSlotType > GetUiTypeForPlayer(Player const *player, Loot const &loot) const
Definition: Loot.cpp:141
void AddAllowedLooter(Player const *player)
Definition: Loot.cpp:131
ObjectGuid rollWinnerGUID
Definition: Loot.h:184
bool needs_quest
Definition: Loot.h:191
bool follow_loot_rules
Definition: Loot.h:192
bool is_underthreshold
Definition: Loot.h:189
GuidSet allowedGUIDs
Definition: Loot.h:183
bool AllowedForPlayer(Player const *player, Loot const *loot) const
Definition: Loot.cpp:72
uint32 LootListId
Definition: Loot.h:178
uint8 count
Definition: Loot.h:185
bool is_looted
Definition: Loot.h:186
ItemRandomBonusListId randomBonusListId
Definition: Loot.h:179
ItemContext context
Definition: Loot.h:181
LootItem()
Definition: Loot.h:199
ConditionsReference conditions
Definition: Loot.h:182
GuidSet const & GetAllowedLooters() const
Definition: Loot.h:213
bool freeforall
Definition: Loot.h:188
bool is_counted
Definition: Loot.h:190
ConditionsReference conditions
Definition: LootMgr.h:49
bool needs_quest
Definition: LootMgr.h:45
uint32 itemid
Definition: LootMgr.h:41
uint8 maxcount
Definition: LootMgr.h:48
uint8 mincount
Definition: LootMgr.h:47
Definition: Loot.h:281
bool _wasOpened
Definition: Loot.h:352
void AddLooter(ObjectGuid GUID)
Definition: Loot.h:314
void NotifyLootList(Map const *map) const
Definition: Loot.cpp:638
ItemContext _itemContext
Definition: Loot.h:347
bool AutoStore(Player *player, uint8 bag, uint8 slot, bool broadcast=false, bool createdByPlayer=false)
Definition: Loot.cpp:849
GuidUnorderedSet _allowedLooters
Definition: Loot.h:351
void OnLootOpened(Map *map, ObjectGuid looter)
Definition: Loot.cpp:696
bool hasOverThresholdItem() const
Definition: Loot.cpp:986
void LootMoney()
Definition: Loot.cpp:903
NotNormalLootItemMap PlayerFFAItems
Definition: Loot.h:342
void BuildLootResponse(WorldPackets::Loot::LootResponse &packet, Player const *viewer) const
Definition: Loot.cpp:997
bool _changed
Definition: Loot.h:353
void NotifyMoneyRemoved(Map const *map)
Definition: Loot.cpp:681
LootMethod _lootMethod
Definition: Loot.h:348
void NotifyItemRemoved(uint8 lootListId, Map const *map)
Definition: Loot.cpp:658
Loot(Map *map, ObjectGuid owner, LootType type, Group const *group)
Definition: Loot.cpp:623
uint8 unlootedCount
Definition: Loot.h:286
void AddItem(LootStoreItem const &item)
Definition: Loot.cpp:827
void Update()
Definition: Loot.cpp:1015
LootItem const * GetItemInSlot(uint32 lootListId) const
Definition: Loot.cpp:909
ObjectGuid roundRobinPlayer
Definition: Loot.h:287
ObjectGuid const & GetOwnerGUID() const
Definition: Loot.h:299
GuidSet PlayersLooting
Definition: Loot.h:341
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
Definition: Loot.cpp:745
bool hasItemFor(Player const *player) const
Definition: Loot.cpp:965
uint32 gold
Definition: Loot.h:285
bool hasItemForAll() const
Definition: Loot.cpp:952
LootItem * LootItemInSlot(uint32 lootListId, Player const *player, NotNormalLootItem **ffaItem=nullptr)
Definition: Loot.cpp:917
ObjectGuid const & GetGUID() const
Definition: Loot.h:298
~Loot()
Definition: Loot.cpp:630
std::vector< LootItem > items
Definition: Loot.h:284
std::unordered_map< uint32, LootRoll > _rolls
Definition: Loot.h:349
ObjectGuid _lootMaster
Definition: Loot.h:350
NotNormalLootItemMap const & GetPlayerFFAItems() const
Definition: Loot.h:282
bool FillLoot(uint32 lootId, LootStore const &store, Player *lootOwner, bool personal, bool noEmptyError=false, uint16 lootMode=LOOT_MODE_DEFAULT, ItemContext context=ItemContext::NONE)
Definition: Loot.cpp:759
uint32 GetDungeonEncounterId() const
Definition: Loot.h:304
ObjectGuid const & GetLootMasterGUID() const
Definition: Loot.h:303
LootMethod GetLootMethod() const
Definition: Loot.h:302
LootType loot_type
Definition: Loot.h:288
void FillNotNormalLootFor(Player const *player)
Definition: Loot.cpp:1026
bool HasAllowedLooter(ObjectGuid const &looter) const
Definition: Loot.cpp:740
uint8 LootListId
Definition: Loot.h:220
bool is_looted
Definition: Loot.h:221
void Initialize(::Item const *item)
WorldPackets::Item::ItemInstance Loot
Definition: LootPackets.h:49