TrinityCore
Loading...
Searching...
No Matches
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 "Group.h"
20#include "ItemEnchantmentMgr.h"
21#include "ItemTemplate.h"
22#include "Log.h"
23#include "LootMgr.h"
24#include "LootPackets.h"
25#include "ObjectAccessor.h"
26#include "ObjectMgr.h"
27#include "Player.h"
28#include "Random.h"
29#include "World.h"
30
31 //
32 // --------- LootItem ---------
33 //
34
35 // Constructor, copies most fields from LootStoreItem and generates random count
57
58bool LootItem::AllowedForPlayer(Player const* player, ObjectGuid ownerGuid) const
59{
60 return AllowedForPlayer(player, false, ownerGuid);
61}
62
63bool LootItem::AllowedForPlayer(Player const* player, bool isGivenByMasterLooter) const
64{
65 return AllowedForPlayer(player, isGivenByMasterLooter, ObjectGuid::Empty);
66}
67
68// Basic checks for player/item compatibility - if false no chance to see the item in the loot
69bool LootItem::AllowedForPlayer(Player const* player, bool isGivenByMasterLooter, ObjectGuid ownerGuid) const
70{
71 // DB conditions check
72 if (!sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(player), conditions))
73 return false;
74
75 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
76 if (!pProto)
77 return false;
78
79 // not show loot for not own team
80 if (pProto->HasFlag(ITEM_FLAG2_FACTION_HORDE) && player->GetTeam() != HORDE)
81 return false;
82
83 if (pProto->HasFlag(ITEM_FLAG2_FACTION_ALLIANCE) && player->GetTeam() != ALLIANCE)
84 return false;
85
86 // Master looter can see all items even if the character can't loot them
87 if (!isGivenByMasterLooter && player->GetGroup() && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID())
88 {
89 return true;
90 }
91
92 // Don't allow loot for players without profession or those who already know the recipe
94 {
95 if (!player->HasSkill(pProto->GetRequiredSkill()))
96 return false;
97
98 for (ItemEffect const& itemEffect : pProto->Effects)
99 {
100 if (itemEffect.TriggerType != ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
101 continue;
102
103 if (player->HasSpell(itemEffect.SpellID))
104 return false;
105 }
106 }
107
108 // Don't allow to loot soulbound recipes that the player has already learned
109 if (pProto->GetClass() == ITEM_CLASS_RECIPE && pProto->GetBonding() == BIND_WHEN_PICKED_UP)
110 {
111 for (ItemEffect const& itemEffect : pProto->Effects)
112 {
113 if (itemEffect.TriggerType != ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
114 continue;
115
116 if (player->HasSpell(itemEffect.SpellID))
117 return false;
118 }
119 }
120
121 if (needs_quest && !freeforall && player->GetGroup() && (player->GetGroup()->GetLootMethod() == GROUP_LOOT || player->GetGroup()->GetLootMethod() == ROUND_ROBIN) && !ownerGuid.IsEmpty() && ownerGuid != player->GetGUID())
122 return false;
123
124 // check quest requirements
125 if (!pProto->HasFlag(ITEM_FLAGS_CU_IGNORE_QUEST_STATUS) && ((needs_quest || (pProto->GetStartQuest() && player->GetQuestStatus(pProto->GetStartQuest()) != QUEST_STATUS_NONE)) && !player->HasQuestForItem(itemid)))
126 return false;
127
128 return true;
129}
130
132{
133 allowedGUIDs.insert(player->GetGUID());
134}
135
136//
137// --------- Loot ---------
138//
139
140Loot::Loot(uint32 _gold /*= 0*/) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_NONE), maxDuplicates(1), containerID(0)
141{
142}
143
145{
146 clear();
147}
148
150{
151 for (NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.begin(); itr != PlayerQuestItems.end(); ++itr)
152 delete itr->second;
153 PlayerQuestItems.clear();
154
155 for (NotNormalLootItemMap::const_iterator itr = PlayerFFAItems.begin(); itr != PlayerFFAItems.end(); ++itr)
156 delete itr->second;
157 PlayerFFAItems.clear();
158
159 for (NotNormalLootItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.begin(); itr != PlayerNonQuestNonFFAConditionalItems.end(); ++itr)
160 delete itr->second;
162
163 PlayersLooting.clear();
164 items.clear();
165 quest_items.clear();
166 gold = 0;
167 unlootedCount = 0;
171}
172
173// Inserts the item into the loot (called by LootTemplate processors)
175{
176 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid);
177 if (!proto)
178 return;
179
180 uint32 count = urand(item.mincount, item.maxcount);
181 uint32 stacks = count / proto->GetMaxStackSize() + ((count % proto->GetMaxStackSize()) ? 1 : 0);
182
183 std::vector<LootItem>& lootItems = item.needs_quest ? quest_items : items;
185
186 for (uint32 i = 0; i < stacks && lootItems.size() < limit; ++i)
187 {
188 LootItem generatedLoot(item);
189 generatedLoot.count = std::min(count, proto->GetMaxStackSize());
190 generatedLoot.itemIndex = lootItems.size();
191 lootItems.push_back(generatedLoot);
192 count -= proto->GetMaxStackSize();
193
194 // In some cases, a dropped item should be visible/lootable only for some players in group
195 bool canSeeItemInLootWindow = false;
197 {
198 if (Group* group = player->GetGroup())
199 {
200 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
201 if (Player* member = itr->GetSource())
202 if (generatedLoot.AllowedForPlayer(member, lootOwnerGUID))
203 canSeeItemInLootWindow = true;
204 }
205 else if (generatedLoot.AllowedForPlayer(player, lootOwnerGUID))
206 canSeeItemInLootWindow = true;
207 }
208
209 if (!canSeeItemInLootWindow)
210 continue;
211
212 // non-conditional one-player only items are counted here,
213 // free for all items are counted in FillFFALoot(),
214 // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
215 if (!item.needs_quest && item.conditions.empty() && !proto->HasFlag(ITEM_FLAG_MULTI_DROP))
217 }
218}
219
220// Calls processor of corresponding LootTemplate (which handles everything including references)
221bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError, uint16 lootMode /*= LOOT_MODE_DEFAULT*/)
222{
223 // Must be provided
224 if (!lootOwner)
225 return false;
226
227 lootOwnerGUID = lootOwner->GetGUID();
228
229 LootTemplate const* tab = store.GetLootFor(lootId);
230
231 if (!tab)
232 {
233 if (!noEmptyError)
234 TC_LOG_ERROR("sql.sql", "Table '{}' loot id #{} used but it doesn't have records.", store.GetName(), lootId);
235 return false;
236 }
237
238 items.reserve(MAX_NR_LOOT_ITEMS);
240
241 tab->Process(*this, store.IsRatesAllowed(), lootMode); // Processing is done there, callback via Loot::AddItem()
242
243 // Setting access rights for group loot case
244 Group* group = lootOwner->GetGroup();
245 if (!personal && group)
246 {
247 roundRobinPlayer = lootOwner->GetGUID();
248
249 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
250 if (Player* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter
251 if (player->IsInMap(lootOwner))
252 FillNotNormalLootFor(player, player->IsAtGroupRewardDistance(lootOwner));
253
254 for (uint8 i = 0; i < items.size(); ++i)
255 {
256 if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(items[i].itemid))
257 if (proto->GetQuality() < uint32(group->GetLootThreshold()))
258 items[i].is_underthreshold = true;
259 }
260 }
261 // ... for personal loot
262 else
263 FillNotNormalLootFor(lootOwner, true);
264
265 return true;
266}
267
268void Loot::FillNotNormalLootFor(Player* player, bool presentAtLooting)
269{
270 ObjectGuid plguid = player->GetGUID();
271
272 NotNormalLootItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid);
273 if (qmapitr == PlayerQuestItems.end())
274 FillQuestLoot(player);
275
276 qmapitr = PlayerFFAItems.find(plguid);
277 if (qmapitr == PlayerFFAItems.end())
278 FillFFALoot(player);
279
280 qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
281 if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
282 FillNonQuestNonFFAConditionalLoot(player, presentAtLooting);
283
284 // if not auto-processed player will have to come and pick it up manually
285 if (!presentAtLooting)
286 return;
287
288 // Process currency items
289 uint32 max_slot = GetMaxSlotInLootFor(player);
290 LootItem const* item = nullptr;
291 uint32 itemsSize = uint32(items.size());
292 for (uint32 i = 0; i < max_slot; ++i)
293 {
294 if (i < items.size())
295 item = &items[i];
296 else
297 item = &quest_items[i - itemsSize];
298
299 if (!item->is_looted && item->freeforall && item->AllowedForPlayer(player, lootOwnerGUID))
300 if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item->itemid))
301 if (proto->IsCurrencyToken())
302 player->StoreLootItem(i, this);
303 }
304}
305
307{
309
310 for (uint8 i = 0; i < items.size(); ++i)
311 {
312 LootItem &item = items[i];
313 if (!item.is_looted && item.freeforall && item.AllowedForPlayer(player, lootOwnerGUID))
314 {
315 ql->push_back(NotNormalLootItem(i));
317 }
318 }
319 if (ql->empty())
320 {
321 delete ql;
322 return nullptr;
323 }
324
325 PlayerFFAItems[player->GetGUID()] = ql;
326 return ql;
327}
328
330{
331 if (items.size() == MAX_NR_LOOT_ITEMS)
332 return nullptr;
333
335
336 for (uint8 i = 0; i < quest_items.size(); ++i)
337 {
338 LootItem &item = quest_items[i];
339
340 if (!item.is_looted && (item.AllowedForPlayer(player, lootOwnerGUID) || (item.follow_loot_rules && player->GetGroup() && ((player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID()) || player->GetGroup()->GetLootMethod() != MASTER_LOOT))))
341 {
342 ql->push_back(NotNormalLootItem(i));
343
344 // quest items get blocked when they first appear in a
345 // player's quest vector
346 //
347 // increase once if one looter only, looter-times if free for all
348 if (item.freeforall || !item.is_blocked)
350 if (!player->GetGroup() || (player->GetGroup()->GetLootMethod() != GROUP_LOOT && player->GetGroup()->GetLootMethod() != ROUND_ROBIN))
351 item.is_blocked = true;
352
353 if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS)
354 break;
355 }
356 }
357 if (ql->empty())
358 {
359 delete ql;
360 return nullptr;
361 }
362
363 PlayerQuestItems[player->GetGUID()] = ql;
364 return ql;
365}
366
368{
370
371 for (uint8 i = 0; i < items.size(); ++i)
372 {
373 LootItem &item = items[i];
374 if (!item.is_looted && !item.freeforall && (item.AllowedForPlayer(player, lootOwnerGUID)))
375 {
376 if (presentAtLooting)
377 item.AddAllowedLooter(player);
378 if (!item.conditions.empty())
379 {
380 ql->push_back(NotNormalLootItem(i));
381 if (!item.is_counted)
382 {
384 item.is_counted = true;
385 }
386 }
387 }
388 }
389 if (ql->empty())
390 {
391 delete ql;
392 return nullptr;
393 }
394
396 return ql;
397}
398
399//===================================================
400
402{
403 // notify all players that are looting this that the item was removed
404 // convert the index to the slot the player sees
405 GuidSet::iterator i_next;
406 for (GuidSet::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
407 {
408 i_next = i;
409 ++i_next;
410 if (Player* player = ObjectAccessor::FindPlayer(*i))
411 player->SendNotifyLootItemRemoved(lootIndex);
412 else
413 PlayersLooting.erase(i);
414 }
415}
416
418{
419 // notify all players that are looting this that the money was removed
420 GuidSet::iterator i_next;
421 for (GuidSet::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
422 {
423 i_next = i;
424 ++i_next;
425 if (Player* player = ObjectAccessor::FindPlayer(*i))
426 player->SendNotifyLootMoneyRemoved();
427 else
428 PlayersLooting.erase(i);
429 }
430}
431
433{
434 // when a free for all questitem is looted
435 // all players will get notified of it being removed
436 // (other questitems can be looted by each group member)
437 // bit inefficient but isn't called often
438
439 GuidSet::iterator i_next;
440 for (GuidSet::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
441 {
442 i_next = i;
443 ++i_next;
444 if (Player* player = ObjectAccessor::FindPlayer(*i))
445 {
446 NotNormalLootItemMap::const_iterator pq = PlayerQuestItems.find(player->GetGUID());
447 if (pq != PlayerQuestItems.end() && pq->second)
448 {
449 // find where/if the player has the given item in it's vector
450 NotNormalLootItemList& pql = *pq->second;
451
452 uint8 j;
453 for (j = 0; j < pql.size(); ++j)
454 if (pql[j].index == questIndex)
455 break;
456
457 if (j < pql.size())
458 player->SendNotifyLootItemRemoved(items.size() + j);
459 }
460 }
461 else
462 PlayersLooting.erase(i);
463 }
464}
465
466void Loot::generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
467{
468 if (maxAmount > 0)
469 {
470 if (maxAmount <= minAmount)
471 gold = uint32(maxAmount * sWorld->getRate(RATE_DROP_MONEY));
472 else if ((maxAmount - minAmount) < 32700)
473 gold = uint32(urand(minAmount, maxAmount) * sWorld->getRate(RATE_DROP_MONEY));
474 else
475 gold = uint32(urand(minAmount >> 8, maxAmount >> 8) * sWorld->getRate(RATE_DROP_MONEY)) << 8;
476 }
477}
478
480{
481 LootItem* item = nullptr;
482 bool is_looted = true;
483 if (lootSlot >= items.size())
484 {
485 uint32 questSlot = lootSlot - items.size();
486 NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID());
487 if (itr != PlayerQuestItems.end() && questSlot < itr->second->size())
488 {
489 NotNormalLootItem* qitem2 = &itr->second->at(questSlot);
490 if (qitem)
491 *qitem = qitem2;
492 item = &quest_items[qitem2->index];
493 is_looted = qitem2->is_looted;
494 }
495 }
496 else
497 {
498 item = &items[lootSlot];
499 is_looted = item->is_looted;
500 if (item->freeforall)
501 {
502 NotNormalLootItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUID());
503 if (itr != PlayerFFAItems.end())
504 {
505 for (NotNormalLootItemList::const_iterator iter = itr->second->begin(); iter != itr->second->end(); ++iter)
506 if (iter->index == lootSlot)
507 {
508 NotNormalLootItem* ffaitem2 = (NotNormalLootItem*)&(*iter);
509 if (ffaitem)
510 *ffaitem = ffaitem2;
511 is_looted = ffaitem2->is_looted;
512 break;
513 }
514 }
515 }
516 else if (!item->conditions.empty())
517 {
518 NotNormalLootItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUID());
520 {
521 for (NotNormalLootItemList::const_iterator iter = itr->second->begin(); iter != itr->second->end(); ++iter)
522 {
523 if (iter->index == lootSlot)
524 {
525 NotNormalLootItem* conditem2 = (NotNormalLootItem*)&(*iter);
526 if (conditem)
527 *conditem = conditem2;
528 is_looted = conditem2->is_looted;
529 break;
530 }
531 }
532 }
533 }
534 }
535
536 if (is_looted)
537 return nullptr;
538
539 return item;
540}
541
543{
544 NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID());
545 return items.size() + (itr != PlayerQuestItems.end() ? itr->second->size() : 0);
546}
547
548// return true if there is any item that is lootable for any player (not quest item, FFA or conditional)
550{
551 // Gold is always lootable
552 if (gold)
553 return true;
554
555 for (LootItem const& item : items)
556 if (!item.is_looted && !item.freeforall && item.conditions.empty())
557 return true;
558 return false;
559}
560
561// return true if there is any FFA, quest or conditional item for the player.
562bool Loot::hasItemFor(Player const* player) const
563{
564 NotNormalLootItemMap const& lootPlayerQuestItems = GetPlayerQuestItems();
565 NotNormalLootItemMap::const_iterator q_itr = lootPlayerQuestItems.find(player->GetGUID());
566 if (q_itr != lootPlayerQuestItems.end())
567 {
568 NotNormalLootItemList* q_list = q_itr->second;
569 for (NotNormalLootItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi)
570 {
571 LootItem const& item = quest_items[qi->index];
572 if (!qi->is_looted && !item.is_looted)
573 return true;
574 }
575 }
576
577 NotNormalLootItemMap const& lootPlayerFFAItems = GetPlayerFFAItems();
578 NotNormalLootItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(player->GetGUID());
579 if (ffa_itr != lootPlayerFFAItems.end())
580 {
581 NotNormalLootItemList* ffa_list = ffa_itr->second;
582 for (NotNormalLootItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi)
583 {
584 LootItem const& item = items[fi->index];
585 if (!fi->is_looted && !item.is_looted)
586 return true;
587 }
588 }
589
590 NotNormalLootItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems();
591 NotNormalLootItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(player->GetGUID());
592 if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
593 {
594 NotNormalLootItemList* conditional_list = nn_itr->second;
595 for (NotNormalLootItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci)
596 {
597 LootItem const& item = items[ci->index];
598 if (!ci->is_looted && !item.is_looted)
599 return true;
600 }
601 }
602
603 return false;
604}
605
606// return true if there is any item over the group threshold (i.e. not underthreshold).
608{
609 for (uint8 i = 0; i < items.size(); ++i)
610 {
611 if (!items[i].is_looted && !items[i].is_underthreshold && !items[i].freeforall)
612 return true;
613 }
614
615 return false;
616}
617
618static void FillLootItemData(WorldPackets::Loot::LootItemData& lootItem, uint8 lootListId, LootItem const& li, LootSlotType slot_type)
619{
620 lootItem.LootListID = lootListId;
621 lootItem.UIType = slot_type;
622 lootItem.ItemID = li.itemid;
623 lootItem.Quantity = li.count;
624 lootItem.ItemDisplayInfoID = ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(li.itemid))->GetDisplayId();
627}
628
630{
631 if (permission == NONE_PERMISSION)
632 return;
633
634 packet.Coins = gold;
635
636 switch (permission)
637 {
638 case GROUP_PERMISSION:
641 {
642 // if you are not the round-robin group looter, you can only see
643 // blocked rolled items and quest items, and !ffa items
644 for (uint8 i = 0; i < items.size(); ++i)
645 {
646 if (!items[i].is_looted && !items[i].freeforall && items[i].conditions.empty() && items[i].AllowedForPlayer(viewer, roundRobinPlayer))
647 {
648 LootSlotType slot_type;
649
650 if (items[i].is_blocked) // for ML & restricted is_blocked = !is_underthreshold
651 {
652 switch (permission)
653 {
654 case GROUP_PERMISSION:
655 slot_type = LOOT_SLOT_TYPE_ROLL_ONGOING;
656 break;
658 {
659 if (viewer->GetGroup() && viewer->GetGroup()->GetMasterLooterGuid() == viewer->GetGUID())
660 slot_type = LOOT_SLOT_TYPE_MASTER;
661 else
662 slot_type = LOOT_SLOT_TYPE_LOCKED;
663 break;
664 }
666 slot_type = LOOT_SLOT_TYPE_LOCKED;
667 break;
668 default:
669 continue;
670 }
671 }
672 else if (!items[i].rollWinnerGUID.IsEmpty())
673 {
674 if (items[i].rollWinnerGUID == viewer->GetGUID())
675 slot_type = LOOT_SLOT_TYPE_OWNER;
676 else
677 continue;
678 }
679 else if (roundRobinPlayer.IsEmpty() || viewer->GetGUID() == roundRobinPlayer || !items[i].is_underthreshold)
680 {
681 // no round robin owner or he has released the loot
682 // or it IS the round robin group owner
683 // => item is lootable
684 slot_type = LOOT_SLOT_TYPE_ALLOW_LOOT;
685 }
686 else
687 // item shall not be displayed.
688 continue;
689
690 FillLootItemData(packet.Items.emplace_back(), i, items[i], slot_type);
691 }
692 }
693 break;
694 }
696 {
697 for (uint8 i = 0; i < items.size(); ++i)
698 {
699 if (!items[i].is_looted && !items[i].freeforall && items[i].conditions.empty() && items[i].AllowedForPlayer(viewer, roundRobinPlayer))
700 {
701 if (!roundRobinPlayer.IsEmpty() && viewer->GetGUID() != roundRobinPlayer)
702 // item shall not be displayed.
703 continue;
704
705 FillLootItemData(packet.Items.emplace_back(), i, items[i], LOOT_SLOT_TYPE_ALLOW_LOOT);
706 }
707 }
708 break;
709 }
710 case ALL_PERMISSION:
711 case OWNER_PERMISSION:
712 {
714 for (uint8 i = 0; i < items.size(); ++i)
715 if (!items[i].is_looted && !items[i].freeforall && items[i].conditions.empty() && items[i].AllowedForPlayer(viewer, roundRobinPlayer))
716 FillLootItemData(packet.Items.emplace_back(), i, items[i], slot_type);
717 break;
718 }
719 default:
720 return;
721 }
722
724 NotNormalLootItemMap const& lootPlayerQuestItems = GetPlayerQuestItems();
725 NotNormalLootItemMap::const_iterator q_itr = lootPlayerQuestItems.find(viewer->GetGUID());
726 if (q_itr != lootPlayerQuestItems.end())
727 {
728 NotNormalLootItemList* q_list = q_itr->second;
729 for (NotNormalLootItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi)
730 {
731 LootItem const& item = quest_items[qi->index];
732 if (!qi->is_looted && !item.is_looted)
733 {
734 LootSlotType effectiveSlotType = slotType;
735 if (item.follow_loot_rules)
736 {
737 switch (permission)
738 {
740 effectiveSlotType = LOOT_SLOT_TYPE_MASTER;
741 break;
743 if (item.is_blocked)
744 effectiveSlotType = LOOT_SLOT_TYPE_LOCKED;
745 break;
746 case GROUP_PERMISSION:
749 break;
750 default:
751 break;
752 }
753 }
754
755 FillLootItemData(packet.Items.emplace_back(), items.size() + (qi - q_list->begin()), item, effectiveSlotType);
756 }
757 }
758 }
759
760 NotNormalLootItemMap const& lootPlayerFFAItems = GetPlayerFFAItems();
761 NotNormalLootItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(viewer->GetGUID());
762 if (ffa_itr != lootPlayerFFAItems.end())
763 {
764 NotNormalLootItemList* ffa_list = ffa_itr->second;
765 for (NotNormalLootItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi)
766 {
767 LootItem const& item = items[fi->index];
768 if (!fi->is_looted && !item.is_looted)
769 FillLootItemData(packet.Items.emplace_back(), fi->index, item, slotType);
770 }
771 }
772
773 NotNormalLootItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems();
774 NotNormalLootItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(viewer->GetGUID());
775 if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
776 {
777 NotNormalLootItemList* conditional_list = nn_itr->second;
778 for (NotNormalLootItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci)
779 {
780 LootItem const& item = items[ci->index];
781 if (!ci->is_looted && !item.is_looted)
782 {
783 LootSlotType effectiveSlotType = slotType;
784 switch (permission)
785 {
787 effectiveSlotType = LOOT_SLOT_TYPE_MASTER;
788 break;
790 if (item.is_blocked)
791 effectiveSlotType = LOOT_SLOT_TYPE_LOCKED;
792 break;
793 case GROUP_PERMISSION:
796 break;
797 default:
798 break;
799 }
800
801 FillLootItemData(packet.Items.emplace_back(), ci->index, item, effectiveSlotType);
802 }
803 }
804 }
805}
#define sConditionMgr
uint8_t uint8
Definition Define.h:135
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:84
uint32 GenerateEnchSuffixFactor(uint32 item_id)
int32 GenerateItemRandomPropertyId(uint32 item_id)
@ ITEM_CLASS_RECIPE
@ ITEM_FLAG2_FACTION_HORDE
@ ITEM_FLAG2_FACTION_ALLIANCE
@ ITEM_SPELLTRIGGER_LEARN_SPELL_ID
@ ITEM_FLAG_HIDE_UNUSABLE_RECIPE
@ ITEM_FLAG_MULTI_DROP
@ BIND_WHEN_PICKED_UP
@ ITEM_FLAGS_CU_FOLLOW_LOOT_RULES
@ ITEM_FLAGS_CU_IGNORE_QUEST_STATUS
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
static void FillLootItemData(WorldPackets::Loot::LootItemData &lootItem, uint8 lootListId, LootItem const &li, LootSlotType slot_type)
Definition Loot.cpp:618
@ LOOT_NONE
Definition Loot.h:90
PermissionTypes
Definition Loot.h:78
@ OWNER_PERMISSION
Definition Loot.h:84
@ ALL_PERMISSION
Definition Loot.h:79
@ RESTRICTED_PERMISSION
Definition Loot.h:82
@ NONE_PERMISSION
Definition Loot.h:85
@ ROUND_ROBIN_PERMISSION
Definition Loot.h:83
@ MASTER_PERMISSION
Definition Loot.h:81
@ GROUP_PERMISSION
Definition Loot.h:80
@ GROUP_LOOT
Definition Loot.h:73
@ MASTER_LOOT
Definition Loot.h:72
@ ROUND_ROBIN
Definition Loot.h:71
#define MAX_NR_QUEST_ITEMS
Definition Loot.h:65
LootSlotType
Definition Loot.h:140
@ LOOT_SLOT_TYPE_MASTER
Definition Loot.h:143
@ LOOT_SLOT_TYPE_ROLL_ONGOING
Definition Loot.h:142
@ LOOT_SLOT_TYPE_ALLOW_LOOT
Definition Loot.h:141
@ LOOT_SLOT_TYPE_OWNER
Definition Loot.h:145
@ LOOT_SLOT_TYPE_LOCKED
Definition Loot.h:144
std::unordered_map< ObjectGuid, NotNormalLootItemList * > NotNormalLootItemMap
Definition Loot.h:200
std::vector< NotNormalLootItem > NotNormalLootItemList
Definition Loot.h:198
#define MAX_NR_LOOT_ITEMS
Definition Loot.h:63
#define sObjectMgr
Definition ObjectMgr.h:1721
@ QUEST_STATUS_NONE
Definition QuestDef.h:103
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
@ ALLIANCE
@ HORDE
Definition Group.h:165
ObjectGuid GetMasterLooterGuid() const
Definition Group.cpp:2449
ItemQualities GetLootThreshold() const
Definition Group.cpp:2454
LootMethod GetLootMethod() const
Definition Group.cpp:2437
GroupReference * GetFirstMember()
Definition Group.h:247
LootTemplate const * GetLootFor(uint32 loot_id) const
Definition LootMgr.cpp:227
bool IsRatesAllowed() const
Definition LootMgr.h:88
char const * GetName() const
Definition LootMgr.h:86
void Process(Loot &loot, bool rate, uint16 lootMode, uint8 groupId=0) const
Definition LootMgr.cpp:562
static ObjectGuid const Empty
Definition ObjectGuid.h:140
bool IsEmpty() const
Definition ObjectGuid.h:172
void Clear()
Definition ObjectGuid.h:150
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
uint32 GetTeam() const
Definition Player.h:1818
bool HasQuestForItem(uint32 itemId, uint32 excludeQuestId=0, bool turnIn=false) const
Definition Player.cpp:16468
bool HasSkill(uint32 skill) const
Definition Player.cpp:5885
Group * GetGroup()
Definition Player.h:2159
void StoreLootItem(uint8 lootSlot, Loot *loot)
Definition Player.cpp:24531
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition Player.cpp:15655
bool HasSpell(uint32 spell) const override
Definition Player.cpp:3881
void clearReferences()
Definition RefManager.h:47
std::vector< LootItemData > Items
Definition LootPackets.h:60
#define sWorld
Definition World.h:901
@ RATE_DROP_MONEY
Definition World.h:429
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
std::array< ItemEffect, MAX_ITEM_PROTO_SPELLS > Effects
uint32 GetMaxStackSize() const
ItemBondingType GetBonding() const
uint32 GetStartQuest() const
bool HasFlag(ItemFlags flag) const
uint32 GetClass() const
uint32 GetRequiredSkill() const
uint32 itemid
Definition Loot.h:150
bool is_blocked
Definition Loot.h:159
void AddAllowedLooter(Player const *player)
Definition Loot.cpp:131
ObjectGuid rollWinnerGUID
Definition Loot.h:156
bool needs_quest
Definition Loot.h:163
bool follow_loot_rules
Definition Loot.h:164
bool is_underthreshold
Definition Loot.h:161
GuidSet allowedGUIDs
Definition Loot.h:155
int32 randomPropertyId
Definition Loot.h:153
uint32 itemIndex
Definition Loot.h:151
uint32 randomPropertySeed
Definition Loot.h:152
uint8 count
Definition Loot.h:157
bool is_looted
Definition Loot.h:158
LootItem()
Definition Loot.h:171
ConditionContainer conditions
Definition Loot.h:154
bool AllowedForPlayer(Player const *player, bool isGivenByMasterLooter, ObjectGuid ownerGuid) const
Definition Loot.cpp:69
bool freeforall
Definition Loot.h:160
bool is_counted
Definition Loot.h:162
ConditionContainer conditions
Definition LootMgr.h:44
bool needs_quest
Definition LootMgr.h:40
uint32 itemid
Definition LootMgr.h:36
uint8 maxcount
Definition LootMgr.h:43
uint8 mincount
Definition LootMgr.h:42
uint32 GetMaxSlotInLootFor(Player *player) const
Definition Loot.cpp:542
Loot(uint32 _gold=0)
Definition Loot.cpp:140
NotNormalLootItemMap const & GetPlayerQuestItems() const
Definition Loot.h:227
NotNormalLootItemList * FillQuestLoot(Player *player)
Definition Loot.cpp:329
void clear()
Definition Loot.cpp:149
bool hasOverThresholdItem() const
Definition Loot.cpp:607
void NotifyMoneyRemoved()
Definition Loot.cpp:417
bool FillLoot(uint32 lootId, LootStore const &store, Player *lootOwner, bool personal, bool noEmptyError=false, uint16 lootMode=LOOT_MODE_DEFAULT)
Definition Loot.cpp:221
NotNormalLootItemMap PlayerFFAItems
Definition Loot.h:287
NotNormalLootItemList * FillFFALoot(Player *player)
Definition Loot.cpp:306
uint8 unlootedCount
Definition Loot.h:234
void AddItem(LootStoreItem const &item)
Definition Loot.cpp:174
ObjectGuid roundRobinPlayer
Definition Loot.h:235
ObjectGuid lootOwnerGUID
Definition Loot.h:236
NotNormalLootItemMap PlayerNonQuestNonFFAConditionalItems
Definition Loot.h:288
GuidSet PlayersLooting
Definition Loot.h:285
NotNormalLootItemMap const & GetPlayerNonQuestNonFFAConditionalItems() const
Definition Loot.h:229
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
Definition Loot.cpp:466
NotNormalLootItemList * FillNonQuestNonFFAConditionalLoot(Player *player, bool presentAtLooting)
Definition Loot.cpp:367
bool hasItemFor(Player const *player) const
Definition Loot.cpp:562
uint32 gold
Definition Loot.h:233
bool hasItemForAll() const
Definition Loot.cpp:549
void NotifyQuestItemRemoved(uint8 questIndex)
Definition Loot.cpp:432
LootItem * LootItemInSlot(uint32 lootslot, Player *player, NotNormalLootItem **qitem=nullptr, NotNormalLootItem **ffaitem=nullptr, NotNormalLootItem **conditem=nullptr)
Definition Loot.cpp:479
~Loot()
Definition Loot.cpp:144
std::vector< LootItem > items
Definition Loot.h:231
void BuildLootResponse(WorldPackets::Loot::LootResponse &packet, Player const *viewer, PermissionTypes permission) const
Definition Loot.cpp:629
NotNormalLootItemMap PlayerQuestItems
Definition Loot.h:286
NotNormalLootItemMap const & GetPlayerFFAItems() const
Definition Loot.h:228
void NotifyItemRemoved(uint8 lootIndex)
Definition Loot.cpp:401
LootType loot_type
Definition Loot.h:237
void FillNotNormalLootFor(Player *player, bool presentAtLooting)
Definition Loot.cpp:268
std::vector< LootItem > quest_items
Definition Loot.h:232
LootValidatorRefManager i_LootValidatorRefManager
Definition Loot.h:291