TrinityCore
LootMgr.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 "LootMgr.h"
19#include "Containers.h"
20#include "DatabaseEnv.h"
21#include "DB2Stores.h"
22#include "ItemBonusMgr.h"
23#include "ItemTemplate.h"
24#include "Log.h"
25#include "Loot.h"
26#include "ObjectMgr.h"
27#include "Player.h"
28#include "Random.h"
29#include "SpellInfo.h"
30#include "SpellMgr.h"
31#include "World.h"
32
34{
35 RATE_DROP_ITEM_POOR, // ITEM_QUALITY_POOR
36 RATE_DROP_ITEM_NORMAL, // ITEM_QUALITY_NORMAL
37 RATE_DROP_ITEM_UNCOMMON, // ITEM_QUALITY_UNCOMMON
38 RATE_DROP_ITEM_RARE, // ITEM_QUALITY_RARE
39 RATE_DROP_ITEM_EPIC, // ITEM_QUALITY_EPIC
40 RATE_DROP_ITEM_LEGENDARY, // ITEM_QUALITY_LEGENDARY
41 RATE_DROP_ITEM_ARTIFACT, // ITEM_QUALITY_ARTIFACT
42};
43
44LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true);
45LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true);
46LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true);
47LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject entry", true);
48LootStore LootTemplates_Item("item_loot_template", "item entry", true);
49LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false);
50LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true);
51LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket lootid", true);
52LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true);
53LootStore LootTemplates_Reference("reference_loot_template", "reference id", false);
54LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true);
55LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false);
56
57// Selects invalid loot items to be removed from group possible entries (before rolling)
59{
60 explicit LootGroupInvalidSelector(uint16 lootMode, Player const* personalLooter) : _lootMode(lootMode), _personalLooter(personalLooter) { }
61
62 bool operator()(LootStoreItem const* item) const
63 {
64 if (!(item->lootmode & _lootMode))
65 return true;
66
68 !item->needs_quest || ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(item->itemid))->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES),
69 true, item->conditions))
70 return true;
71
72 return false;
73 }
74
75private:
78};
79
80class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed)
81{
82 public:
83 LootGroup() = default;
84 LootGroup(LootGroup const&) = delete;
85 LootGroup(LootGroup&&) = delete;
86 LootGroup& operator=(LootGroup const&) = delete;
88 ~LootGroup();
89
90 void AddEntry(LootStoreItem* item); // Adds an entry to the group (at loading stage)
91 bool HasDropForPlayer(Player const* player, bool strictUsabilityCheck) const;
92 bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
93 bool HasQuestDropForPlayer(Player const* player) const;
94 // The same for active quests of the player
95 void Process(Loot& loot, uint16 lootMode,
96 Player const* personalLooter = nullptr) const; // Rolls an item from the group (if any) and adds the item to the loot
97 float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
98 float TotalChance() const; // Overall chance for the group
99
100 void Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const;
101 void CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const;
104 private:
105 LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
106 LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
107
108 // Rolls an item from the group, returns NULL if all miss their chances
109 LootStoreItem const* Roll(uint16 lootMode, Player const* personalLooter = nullptr) const;
110};
111
112//Remove all data and free all memory
114{
115 for (LootTemplateMap::const_iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
116 delete itr->second;
117 m_LootTemplates.clear();
118}
119
120// Checks validity of the loot store
121// Actual checks are done within LootTemplate::Verify() which is called for every template
123{
124 for (LootTemplateMap::const_iterator i = m_LootTemplates.begin(); i != m_LootTemplates.end(); ++i)
125 i->second->Verify(*this, i->first);
126}
127
128// Loads a *_loot_template DB table into loot store
129// All checks of the loaded template are called from here, no error reports at loot generation required
131{
132 LootTemplateMap::const_iterator tab;
133
134 // Clearing store (for reloading case)
135 Clear();
136
137 // 0 1 2 3 4 5 6
138 QueryResult result = WorldDatabase.PQuery("SELECT Entry, Item, Reference, Chance, QuestRequired, LootMode, GroupId, MinCount, MaxCount FROM {}", GetName());
139
140 if (!result)
141 return 0;
142
143 uint32 count = 0;
144
145 do
146 {
147 Field* fields = result->Fetch();
148
149 uint32 entry = fields[0].GetUInt32();
150 uint32 item = fields[1].GetUInt32();
151 uint32 reference = fields[2].GetUInt32();
152 float chance = fields[3].GetFloat();
153 bool needsquest = fields[4].GetBool();
154 uint16 lootmode = fields[5].GetUInt16();
155 uint8 groupid = fields[6].GetUInt8();
156 uint8 mincount = fields[7].GetUInt8();
157 uint8 maxcount = fields[8].GetUInt8();
158
159 if (groupid >= 1 << 7) // it stored in 7 bit field
160 {
161 TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} Item {}: GroupId ({}) must be less {} - skipped", GetName(), entry, item, groupid, 1 << 7);
162 return 0;
163 }
164
165 LootStoreItem* storeitem = new LootStoreItem(item, reference, chance, needsquest, lootmode, groupid, mincount, maxcount);
166
167 if (!storeitem->IsValid(*this, entry)) // Validity checks
168 {
169 delete storeitem;
170 continue;
171 }
172
173 // Looking for the template of the entry
174 // often entries are put together
175 if (m_LootTemplates.empty() || tab->first != entry)
176 {
177 // Searching the template (in case template Id changed)
178 tab = m_LootTemplates.find(entry);
179 if (tab == m_LootTemplates.end())
180 {
181 std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate()));
182 tab = pr.first;
183 }
184 }
185 // else is empty - template Id and iter are the same
186 // finally iter refers to already existed or just created <entry, LootTemplate>
187
188 // Adds current row to the template
189 tab->second->AddEntry(storeitem);
190 ++count;
191 }
192 while (result->NextRow());
193
194 Verify(); // Checks validity of the loot store
195
196 return count;
197}
198
200{
201 LootTemplateMap::const_iterator itr = m_LootTemplates.find(loot_id);
202 if (itr == m_LootTemplates.end())
203 return false;
204
205 // scan loot for quest items
206 return itr->second->HasQuestDrop(m_LootTemplates);
207}
208
209bool LootStore::HaveQuestLootForPlayer(uint32 loot_id, Player const* player) const
210{
211 LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
212 if (tab != m_LootTemplates.end())
213 if (tab->second->HasQuestDropForPlayer(m_LootTemplates, player))
214 return true;
215
216 return false;
217}
218
220{
221 LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
222
223 if (tab == m_LootTemplates.end())
224 return nullptr;
225
226 return tab->second;
227}
228
230{
231 LootTemplateMap::iterator tab = m_LootTemplates.find(loot_id);
232
233 if (tab == m_LootTemplates.end())
234 return nullptr;
235
236 return tab->second;
237}
238
240{
241 uint32 count = LoadLootTable();
242
243 for (LootTemplateMap::const_iterator tab = m_LootTemplates.begin(); tab != m_LootTemplates.end(); ++tab)
244 lootIdSet.insert(tab->first);
245
246 return count;
247}
248
250{
251 for (LootTemplateMap::const_iterator ltItr = m_LootTemplates.begin(); ltItr != m_LootTemplates.end(); ++ltItr)
252 ltItr->second->CheckLootRefs(m_LootTemplates, ref_set);
253}
254
255void LootStore::ReportUnusedIds(LootIdSet const& lootIdSet) const
256{
257 // all still listed ids isn't referenced
258 for (LootIdSet::const_iterator itr = lootIdSet.begin(); itr != lootIdSet.end(); ++itr)
259 TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} isn't {} and not referenced from loot, and thus useless.", GetName(), *itr, GetEntryName());
260}
261
263{
264 TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} does not exist", GetName(), lootId);
265}
266
267void LootStore::ReportNonExistingId(uint32 lootId, char const* ownerType, uint32 ownerId) const
268{
269 TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} does not exist but it is used by {} {}", GetName(), lootId, ownerType, ownerId);
270}
271
272//
273// --------- LootStoreItem ---------
274//
275
276// Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
277// RATE_DROP_ITEMS is no longer used for all types of entries
278bool LootStoreItem::Roll(bool rate) const
279{
280 if (chance >= 100.0f)
281 return true;
282
283 if (reference > 0) // reference case
284 return roll_chance_f(chance* (rate ? sWorld->getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
285
286 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
287
288 float qualityModifier = pProto && rate ? sWorld->getRate(qualityToRate[pProto->GetQuality()]) : 1.0f;
289
290 return roll_chance_f(chance * qualityModifier);
291}
292
293// Checks correctness of values
294bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
295{
296 if (mincount == 0)
297 {
298 TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} Item {}: wrong MinCount ({}) - skipped", store.GetName(), entry, itemid, mincount);
299 return false;
300 }
301
302 if (reference == 0) // item (quest or non-quest) entry, maybe grouped
303 {
304 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid);
305 if (!proto)
306 {
307 TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} Item {}: item does not exist - skipped", store.GetName(), entry, itemid);
308 return false;
309 }
310
311 if (chance == 0 && groupid == 0) // Zero chance is allowed for grouped entries only
312 {
313 TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} Item {}: equal-chanced grouped entry, but group not defined - skipped", store.GetName(), entry, itemid);
314 return false;
315 }
316
317 if (chance != 0 && chance < 0.000001f) // loot with low chance
318 {
319 TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} Item {}: low chance ({}) - skipped",
320 store.GetName(), entry, itemid, chance);
321 return false;
322 }
323
324 if (maxcount < mincount) // wrong max count
325 {
326 TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} Item {}: MaxCount ({}) less that MinCount ({}) - skipped", store.GetName(), entry, itemid, int32(maxcount), mincount);
327 return false;
328 }
329 }
330 else // if reference loot
331 {
332 if (needs_quest)
333 TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} Item {}: quest required will be ignored", store.GetName(), entry, itemid);
334 else if (chance == 0) // no chance for the reference
335 {
336 TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} Item {}: zero chance is specified for a reference, skipped", store.GetName(), entry, itemid);
337 return false;
338 }
339 }
340 return true; // Referenced template existence is checked at whole store level
341}
342
343//
344// --------- LootTemplate::LootGroup ---------
345//
346
348{
349 while (!ExplicitlyChanced.empty())
350 {
351 delete ExplicitlyChanced.back();
352 ExplicitlyChanced.pop_back();
353 }
354
355 while (!EqualChanced.empty())
356 {
357 delete EqualChanced.back();
358 EqualChanced.pop_back();
359 }
360}
361
362// Adds an entry to the group (at loading stage)
364{
365 if (item->chance != 0)
366 ExplicitlyChanced.push_back(item);
367 else
368 EqualChanced.push_back(item);
369}
370
371// Rolls an item from the group, returns NULL if all miss their chances
372LootStoreItem const* LootTemplate::LootGroup::Roll(uint16 lootMode, Player const* personalLooter /*= nullptr*/) const
373{
374 LootStoreItemList possibleLoot = ExplicitlyChanced;
375 possibleLoot.remove_if(LootGroupInvalidSelector(lootMode, personalLooter));
376
377 if (!possibleLoot.empty()) // First explicitly chanced entries are checked
378 {
379 float roll = rand_chance();
380
381 for (LootStoreItemList::const_iterator itr = possibleLoot.begin(); itr != possibleLoot.end(); ++itr) // check each explicitly chanced entry in the template and modify its chance based on quality.
382 {
383 LootStoreItem* item = *itr;
384 if (item->chance >= 100.0f)
385 return item;
386
387 roll -= item->chance;
388 if (roll < 0)
389 return item;
390 }
391 }
392
393 possibleLoot = EqualChanced;
394 possibleLoot.remove_if(LootGroupInvalidSelector(lootMode, personalLooter));
395 if (!possibleLoot.empty()) // If nothing selected yet - an item is taken from equal-chanced part
397
398 return nullptr; // Empty drop from the group
399}
400
401bool LootTemplate::LootGroup::HasDropForPlayer(Player const* player, bool strictUsabilityCheck) const
402{
403 for (LootStoreItem const* lootStoreItem : ExplicitlyChanced)
404 if (LootItem::AllowedForPlayer(player, nullptr, lootStoreItem->itemid, lootStoreItem->needs_quest,
405 !lootStoreItem->needs_quest || ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(lootStoreItem->itemid))->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES),
406 strictUsabilityCheck, lootStoreItem->conditions))
407 return true;
408
409 for (LootStoreItem const* lootStoreItem : EqualChanced)
410 if (LootItem::AllowedForPlayer(player, nullptr, lootStoreItem->itemid, lootStoreItem->needs_quest,
411 !lootStoreItem->needs_quest || ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(lootStoreItem->itemid))->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES),
412 strictUsabilityCheck, lootStoreItem->conditions))
413 return true;
414
415 return false;
416}
417
418// True if group includes at least 1 quest drop entry
420{
421 for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
422 if ((*i)->needs_quest)
423 return true;
424
425 for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
426 if ((*i)->needs_quest)
427 return true;
428
429 return false;
430}
431
432// True if group includes at least 1 quest drop entry for active quests of the player
434{
435 for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
436 if (player->HasQuestForItem((*i)->itemid))
437 return true;
438
439 for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
440 if (player->HasQuestForItem((*i)->itemid))
441 return true;
442
443 return false;
444}
445
446// Rolls an item from the group (if any takes its chance) and adds the item to the loot
447void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode, Player const* personalLooter /*= nullptr*/) const
448{
449 if (LootStoreItem const* item = Roll(lootMode, personalLooter))
450 loot.AddItem(*item);
451}
452
453// Overall chance for the group without equal chanced items
455{
456 float result = 0;
457
458 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
459 if (!(*i)->needs_quest)
460 result += (*i)->chance;
461
462 return result;
463}
464
465// Overall chance for the group
467{
468 float result = RawTotalChance();
469
470 if (!EqualChanced.empty() && result < 100.0f)
471 return 100.0f;
472
473 return result;
474}
475
476void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const
477{
478 float chance = RawTotalChance();
479 if (chance > 101.0f)
480 TC_LOG_ERROR("sql.sql", "Table '{}' entry {} group {} has total chance > 100% ({})", lootstore.GetName(), id, group_id, chance);
481
482 if (chance >= 100.0f && !EqualChanced.empty())
483 TC_LOG_ERROR("sql.sql", "Table '{}' entry {} group {} has items with chance=0% but group total chance >= 100% ({})", lootstore.GetName(), id, group_id, chance);
484}
485
487{
488 for (LootStoreItemList::const_iterator ieItr = ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
489 {
490 LootStoreItem* item = *ieItr;
491 if (item->reference > 0)
492 {
495 else if (ref_set)
496 ref_set->erase(item->reference);
497 }
498 }
499
500 for (LootStoreItemList::const_iterator ieItr = EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
501 {
502 LootStoreItem* item = *ieItr;
503 if (item->reference > 0)
504 {
507 else if (ref_set)
508 ref_set->erase(item->reference);
509 }
510 }
511}
512
513//
514// --------- LootTemplate ---------
515//
516
518{
519 for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
520 delete *i;
521
522 for (size_t i = 0; i < Groups.size(); ++i)
523 delete Groups[i];
524}
525
526// Adds an entry to the group (at loading stage)
528{
529 if (item->groupid > 0 && item->reference == 0) // Group
530 {
531 if (item->groupid >= Groups.size())
532 Groups.resize(item->groupid, nullptr); // Adds new group the the loot template if needed
533 if (!Groups[item->groupid - 1])
534 Groups[item->groupid - 1] = new LootGroup();
535
536 Groups[item->groupid - 1]->AddEntry(item); // Adds new entry to the group
537 }
538 else // Non-grouped entries and references are stored together
539 Entries.push_back(item);
540}
541
543{
544 // Copies the conditions list from a template item to a LootItemData
545 for (LootStoreItemList::const_iterator _iter = Entries.begin(); _iter != Entries.end(); ++_iter)
546 {
547 LootStoreItem* item = *_iter;
548 if (item->itemid != li->itemid)
549 continue;
550
551 li->conditions = item->conditions;
552 break;
553 }
554}
555
556// Rolls for every item in the template and adds the rolled items the the loot
557void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId, Player const* personalLooter /*= nullptr*/) const
558{
559 if (groupId) // Group reference uses own processing of the group
560 {
561 if (groupId > Groups.size())
562 return; // Error message already printed at loading stage
563
564 if (!Groups[groupId - 1])
565 return;
566
567 Groups[groupId - 1]->Process(loot, lootMode, personalLooter);
568 return;
569 }
570
571 // Rolling non-grouped items
572 for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
573 {
574 LootStoreItem* item = *i;
575 if (!(item->lootmode & lootMode)) // Do not add if mode mismatch
576 continue;
577
578 if (!item->Roll(rate))
579 continue; // Bad luck for the entry
580
581 if (item->reference > 0) // References processing
582 {
583 LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(item->reference);
584 if (!Referenced)
585 continue; // Error message already printed at loading stage
586
587 uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
588 for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
589 Referenced->Process(loot, rate, lootMode, item->groupid, personalLooter);
590 }
591 else
592 {
593 // Plain entries (not a reference, not grouped)
594 // Chance is already checked, just add
595 if (!personalLooter
596 || LootItem::AllowedForPlayer(personalLooter, nullptr, item->itemid, item->needs_quest,
597 !item->needs_quest || ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(item->itemid))->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES),
598 true, item->conditions))
599 loot.AddItem(*item);
600 }
601 }
602
603 // Now processing groups
604 for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
605 if (LootGroup* group = *i)
606 group->Process(loot, lootMode, personalLooter);
607}
608
609void LootTemplate::ProcessPersonalLoot(std::unordered_map<Player*, std::unique_ptr<Loot>>& personalLoot, bool rate, uint16 lootMode) const
610{
611 auto getLootersForItem = [&personalLoot](auto&& predicate)
612 {
613 std::vector<Player*> lootersForItem;
614 for (auto&& [looter, loot] : personalLoot)
615 {
616 if (predicate(looter))
617 lootersForItem.push_back(looter);
618 }
619 return lootersForItem;
620 };
621
622 // Rolling non-grouped items
623 for (LootStoreItem const* item : Entries)
624 {
625 if (!(item->lootmode & lootMode)) // Do not add if mode mismatch
626 continue;
627
628 if (!item->Roll(rate))
629 continue; // Bad luck for the entry
630
631 if (item->reference > 0) // References processing
632 {
633 LootTemplate const* referenced = LootTemplates_Reference.GetLootFor(item->reference);
634 if (!referenced)
635 continue; // Error message already printed at loading stage
636
637 uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
638 std::vector<Player*> gotLoot;
639 for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
640 {
641 std::vector<Player*> lootersForItem = getLootersForItem([&](Player const* looter)
642 {
643 return referenced->HasDropForPlayer(looter, item->groupid, true);
644 });
645
646 // nobody can loot this, skip it
647 if (lootersForItem.empty())
648 break;
649
650 auto newEnd = std::remove_if(lootersForItem.begin(), lootersForItem.end(), [&](Player const* looter)
651 {
652 return std::find(gotLoot.begin(), gotLoot.end(), looter) != gotLoot.end();
653 });
654
655 if (lootersForItem.begin() == newEnd)
656 {
657 // if we run out of looters this means that there are more items dropped than players
658 // start a new cycle adding one item to everyone
659 gotLoot.clear();
660 }
661 else
662 lootersForItem.erase(newEnd, lootersForItem.end());
663
664 Player* chosenLooter = Trinity::Containers::SelectRandomContainerElement(lootersForItem);
665 referenced->Process(*personalLoot[chosenLooter], rate, lootMode, item->groupid, chosenLooter);
666 gotLoot.push_back(chosenLooter);
667 }
668 }
669 else
670 {
671 // Plain entries (not a reference, not grouped)
672 // Chance is already checked, just add
673 std::vector<Player*> lootersForItem = getLootersForItem([&](Player const* looter)
674 {
675 return LootItem::AllowedForPlayer(looter, nullptr, item->itemid, item->needs_quest,
676 !item->needs_quest || ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(item->itemid))->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES),
677 true, item->conditions);
678 });
679
680 if (!lootersForItem.empty())
681 {
682 Player* chosenLooter = Trinity::Containers::SelectRandomContainerElement(lootersForItem);
683 personalLoot[chosenLooter]->AddItem(*item);
684 }
685 }
686 }
687
688 // Now processing groups
689 for (LootGroup const* group : Groups)
690 {
691 if (group)
692 {
693 std::vector<Player*> lootersForGroup = getLootersForItem([&](Player const* looter)
694 {
695 return group->HasDropForPlayer(looter, true);
696 });
697
698 if (!lootersForGroup.empty())
699 {
700 Player* chosenLooter = Trinity::Containers::SelectRandomContainerElement(lootersForGroup);
701 group->Process(*personalLoot[chosenLooter], lootMode);
702 }
703 }
704 }
705}
706
707// True if template includes at least 1 drop for the player
708bool LootTemplate::HasDropForPlayer(Player const* player, uint8 groupId, bool strictUsabilityCheck) const
709{
710 if (groupId) // Group reference
711 {
712 if (groupId > Groups.size())
713 return false; // Error message already printed at loading stage
714
715 if (!Groups[groupId - 1])
716 return false;
717
718 return Groups[groupId - 1]->HasDropForPlayer(player, strictUsabilityCheck);
719 }
720
721 // Checking non-grouped entries
722 for (LootStoreItem* lootStoreItem : Entries)
723 {
724 if (lootStoreItem->reference > 0) // References processing
725 {
726 LootTemplate const* referenced = LootTemplates_Reference.GetLootFor(lootStoreItem->reference);
727 if (!referenced)
728 continue; // Error message already printed at loading stage
729 if (referenced->HasDropForPlayer(player, lootStoreItem->groupid, strictUsabilityCheck))
730 return true;
731 }
732 else if (LootItem::AllowedForPlayer(player, nullptr, lootStoreItem->itemid, lootStoreItem->needs_quest,
733 !lootStoreItem->needs_quest || ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(lootStoreItem->itemid))->HasFlag(ITEM_FLAGS_CU_FOLLOW_LOOT_RULES),
734 strictUsabilityCheck, lootStoreItem->conditions))
735 return true; // active quest drop found
736 }
737
738 // Now checking groups
739 for (LootGroup* group : Groups)
740 if (group)
741 if (group->HasDropForPlayer(player, strictUsabilityCheck))
742 return true;
743
744 return false;
745}
746
747// True if template includes at least 1 quest drop entry
748bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) const
749{
750 if (groupId) // Group reference
751 {
752 if (groupId > Groups.size())
753 return false; // Error message [should be] already printed at loading stage
754
755 if (!Groups[groupId - 1])
756 return false;
757
758 return Groups[groupId-1]->HasQuestDrop();
759 }
760
761 for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
762 {
763 LootStoreItem* item = *i;
764 if (item->reference > 0) // References
765 {
766 LootTemplateMap::const_iterator Referenced = store.find(item->reference);
767 if (Referenced == store.end())
768 continue; // Error message [should be] already printed at loading stage
769 if (Referenced->second->HasQuestDrop(store, item->groupid))
770 return true;
771 }
772 else if (item->needs_quest)
773 return true; // quest drop found
774 }
775
776 // Now processing groups
777 for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
778 if (LootGroup* group = *i)
779 if (group->HasQuestDrop())
780 return true;
781
782 return false;
783}
784
785// True if template includes at least 1 quest drop for an active quest of the player
786bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player const* player, uint8 groupId) const
787{
788 if (groupId) // Group reference
789 {
790 if (groupId > Groups.size())
791 return false; // Error message already printed at loading stage
792
793 if (!Groups[groupId - 1])
794 return false;
795
796 return Groups[groupId - 1]->HasQuestDropForPlayer(player);
797 }
798
799 // Checking non-grouped entries
800 for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
801 {
802 LootStoreItem* item = *i;
803 if (item->reference > 0) // References processing
804 {
805 LootTemplateMap::const_iterator Referenced = store.find(item->reference);
806 if (Referenced == store.end())
807 continue; // Error message already printed at loading stage
808 if (Referenced->second->HasQuestDropForPlayer(store, player, item->groupid))
809 return true;
810 }
811 else if (player->HasQuestForItem(item->itemid))
812 return true; // active quest drop found
813 }
814
815 // Now checking groups
816 for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
817 if (LootGroup* group = *i)
818 if (group->HasQuestDropForPlayer(player))
819 return true;
820
821 return false;
822}
823
824// Checks integrity of the template
825void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const
826{
827 // Checking group chances
828 for (uint32 i = 0; i < Groups.size(); ++i)
829 if (Groups[i])
830 Groups[i]->Verify(lootstore, id, i + 1);
831
833}
834
835void LootTemplate::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const
836{
837 for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
838 {
839 LootStoreItem* item = *ieItr;
840 if (item->reference > 0)
841 {
844 else if (ref_set)
845 ref_set->erase(item->reference);
846 }
847 }
848
849 for (LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
850 if (LootGroup* group = *grItr)
851 group->CheckLootRefs(store, ref_set);
852}
853
855{
856 if (!Entries.empty())
857 {
858 for (LootStoreItem* item : Entries)
859 {
860 if (item->itemid == uint32(id.SourceEntry))
861 {
862 item->conditions = std::move(reference);
863 return true;
864 }
865 }
866 }
867
868 if (!Groups.empty())
869 {
870 for (LootGroup* group : Groups)
871 {
872 if (!group)
873 continue;
874
875 LootStoreItemList* itemList = group->GetExplicitlyChancedItemList();
876 if (!itemList->empty())
877 {
878 for (LootStoreItem* item : *itemList)
879 {
880 if (item->itemid == uint32(id.SourceEntry))
881 {
882 item->conditions = std::move(reference);
883 return true;
884 }
885 }
886 }
887
888 itemList = group->GetEqualChancedItemList();
889 if (!itemList->empty())
890 {
891 for (LootStoreItem* item : *itemList)
892 {
893 if (item->itemid == uint32(id.SourceEntry))
894 {
895 item->conditions = std::move(reference);
896 return true;
897 }
898 }
899 }
900 }
901 }
902 return false;
903}
904
906{
907 for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
908 if ((*ieItr)->itemid == id && (*ieItr)->reference > 0)
909 return true;
910
911 return false;//not found or not reference
912}
913
914std::unordered_map<ObjectGuid, std::unique_ptr<Loot>> GenerateDungeonEncounterPersonalLoot(uint32 dungeonEncounterId, uint32 lootId, LootStore const& store,
915 LootType type, WorldObject const* lootOwner, uint32 minMoney, uint32 maxMoney, uint16 lootMode, MapDifficultyEntry const* mapDifficulty,
916 std::vector<Player*> const& tappers)
917{
918 std::unordered_map<Player*, std::unique_ptr<Loot>> tempLoot;
919
920 for (Player* tapper : tappers)
921 {
922 if (tapper->IsLockedToDungeonEncounter(dungeonEncounterId))
923 continue;
924
925 std::unique_ptr<Loot>& loot = tempLoot[tapper];
926 loot.reset(new Loot(lootOwner->GetMap(), lootOwner->GetGUID(), type, nullptr));
927 loot->SetItemContext(ItemBonusMgr::GetContextForPlayer(mapDifficulty, tapper));
928 loot->SetDungeonEncounterId(dungeonEncounterId);
929 loot->generateMoneyLoot(minMoney, maxMoney);
930 }
931
932 if (LootTemplate const* tab = store.GetLootFor(lootId))
933 tab->ProcessPersonalLoot(tempLoot, store.IsRatesAllowed(), lootMode);
934
935 std::unordered_map<ObjectGuid, std::unique_ptr<Loot>> personalLoot;
936 for (auto&& [looter, loot] : tempLoot)
937 {
938 loot->FillNotNormalLootFor(looter);
939
940 if (loot->isLooted())
941 continue;
942
943 personalLoot[looter->GetGUID()] = std::move(loot);
944 }
945
946 return personalLoot;
947}
948
950{
951 TC_LOG_INFO("server.loading", "Loading creature loot templates...");
952
953 uint32 oldMSTime = getMSTime();
954
955 LootIdSet lootIdSet, lootIdSetUsed;
957
958 // Remove real entries and check loot existence
959 CreatureTemplateContainer const& ctc = sObjectMgr->GetCreatureTemplates();
960 for (auto const& creatureTemplatePair : ctc)
961 {
962 for (auto const& [difficulty, creatureDifficulty] : creatureTemplatePair.second.difficultyStore)
963 {
964 if (uint32 lootid = creatureDifficulty.LootID)
965 {
966 if (!lootIdSet.count(lootid))
967 LootTemplates_Creature.ReportNonExistingId(lootid, "Creature", creatureTemplatePair.first);
968 else
969 lootIdSetUsed.insert(lootid);
970 }
971 }
972 }
973
974 for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr)
975 lootIdSet.erase(*itr);
976
977 // 1 means loot for player corpse
978 lootIdSet.erase(PLAYER_CORPSE_LOOT_ENTRY);
979
980 // output error for any still listed (not referenced from appropriate table) ids
982
983 if (count)
984 TC_LOG_INFO("server.loading", ">> Loaded {} creature loot templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
985 else
986 TC_LOG_INFO("server.loading", ">> Loaded 0 creature loot templates. DB table `creature_loot_template` is empty");
987}
988
990{
991 TC_LOG_INFO("server.loading", "Loading disenchanting loot templates...");
992
993 uint32 oldMSTime = getMSTime();
994
995 LootIdSet lootIdSet, lootIdSetUsed;
997
998 for (ItemDisenchantLootEntry const* disenchant : sItemDisenchantLootStore)
999 {
1000 uint32 lootid = disenchant->ID;
1001 if (lootIdSet.find(lootid) == lootIdSet.end())
1003 else
1004 lootIdSetUsed.insert(lootid);
1005 }
1006
1007 for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr)
1008 lootIdSet.erase(*itr);
1009
1010 // output error for any still listed (not referenced from appropriate table) ids
1012
1013 if (count)
1014 TC_LOG_INFO("server.loading", ">> Loaded {} disenchanting loot templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1015 else
1016 TC_LOG_INFO("server.loading", ">> Loaded 0 disenchanting loot templates. DB table `disenchant_loot_template` is empty");
1017}
1018
1020{
1021 TC_LOG_INFO("server.loading", "Loading fishing loot templates...");
1022
1023 uint32 oldMSTime = getMSTime();
1024
1025 LootIdSet lootIdSet;
1027
1028 // remove real entries and check existence loot
1029 for (AreaTableEntry const* areaTable : sAreaTableStore)
1030 if (lootIdSet.find(areaTable->ID) != lootIdSet.end())
1031 lootIdSet.erase(areaTable->ID);
1032
1033 // output error for any still listed (not referenced from appropriate table) ids
1035
1036 if (count)
1037 TC_LOG_INFO("server.loading", ">> Loaded {} fishing loot templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1038 else
1039 TC_LOG_INFO("server.loading", ">> Loaded 0 fishing loot templates. DB table `fishing_loot_template` is empty");
1040}
1041
1043{
1044 TC_LOG_INFO("server.loading", "Loading gameobject loot templates...");
1045
1046 uint32 oldMSTime = getMSTime();
1047
1048 LootIdSet lootIdSet, lootIdSetUsed;
1050
1051 auto checkLootId = [&](uint32 lootId, uint32 gameObjectId)
1052 {
1053 if (!lootIdSet.count(lootId))
1054 LootTemplates_Gameobject.ReportNonExistingId(lootId, "Gameobject", gameObjectId);
1055 else
1056 lootIdSetUsed.insert(lootId);
1057 };
1058
1059 // remove real entries and check existence loot
1060 GameObjectTemplateContainer const& gotc = sObjectMgr->GetGameObjectTemplates();
1061 for (auto const& [gameObjectId, gameObjectTemplate] : gotc)
1062 {
1063 if (uint32 lootid = gameObjectTemplate.GetLootId())
1064 checkLootId(lootid, gameObjectId);
1065
1066 if (gameObjectTemplate.type == GAMEOBJECT_TYPE_CHEST)
1067 {
1068 if (gameObjectTemplate.chest.chestPersonalLoot)
1069 checkLootId(gameObjectTemplate.chest.chestPersonalLoot, gameObjectId);
1070
1071 if (gameObjectTemplate.chest.chestPushLoot)
1072 checkLootId(gameObjectTemplate.chest.chestPushLoot, gameObjectId);
1073 }
1074 }
1075
1076 for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr)
1077 lootIdSet.erase(*itr);
1078
1079 // output error for any still listed (not referenced from appropriate table) ids
1081
1082 if (count)
1083 TC_LOG_INFO("server.loading", ">> Loaded {} gameobject loot templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1084 else
1085 TC_LOG_INFO("server.loading", ">> Loaded 0 gameobject loot templates. DB table `gameobject_loot_template` is empty");
1086}
1087
1089{
1090 TC_LOG_INFO("server.loading", "Loading item loot templates...");
1091
1092 uint32 oldMSTime = getMSTime();
1093
1094 LootIdSet lootIdSet;
1096
1097 // remove real entries and check existence loot
1098 ItemTemplateContainer const& its = sObjectMgr->GetItemTemplateStore();
1099 for (auto const& itemTemplatePair : its)
1100 if (lootIdSet.count(itemTemplatePair.first) > 0 && itemTemplatePair.second.HasFlag(ITEM_FLAG_HAS_LOOT))
1101 lootIdSet.erase(itemTemplatePair.first);
1102
1103 // output error for any still listed (not referenced from appropriate table) ids
1105
1106 if (count)
1107 TC_LOG_INFO("server.loading", ">> Loaded {} item loot templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1108 else
1109 TC_LOG_INFO("server.loading", ">> Loaded 0 item loot templates. DB table `item_loot_template` is empty");
1110}
1111
1113{
1114 TC_LOG_INFO("server.loading", "Loading milling loot templates...");
1115
1116 uint32 oldMSTime = getMSTime();
1117
1118 LootIdSet lootIdSet;
1120
1121 // remove real entries and check existence loot
1122 ItemTemplateContainer const& its = sObjectMgr->GetItemTemplateStore();
1123 for (auto const& itemTemplatePair : its)
1124 {
1125 if (!itemTemplatePair.second.HasFlag(ITEM_FLAG_IS_MILLABLE))
1126 continue;
1127
1128 if (lootIdSet.count(itemTemplatePair.first) > 0)
1129 lootIdSet.erase(itemTemplatePair.first);
1130 }
1131
1132 // output error for any still listed (not referenced from appropriate table) ids
1134
1135 if (count)
1136 TC_LOG_INFO("server.loading", ">> Loaded {} milling loot templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1137 else
1138 TC_LOG_INFO("server.loading", ">> Loaded 0 milling loot templates. DB table `milling_loot_template` is empty");
1139}
1140
1142{
1143 TC_LOG_INFO("server.loading", "Loading pickpocketing loot templates...");
1144
1145 uint32 oldMSTime = getMSTime();
1146
1147 LootIdSet lootIdSet, lootIdSetUsed;
1149
1150 // Remove real entries and check loot existence
1151 CreatureTemplateContainer const& ctc = sObjectMgr->GetCreatureTemplates();
1152 for (auto const& creatureTemplatePair : ctc)
1153 {
1154 for (auto const& [difficulty, creatureDifficulty] : creatureTemplatePair.second.difficultyStore)
1155 {
1156 if (uint32 lootid = creatureDifficulty.PickPocketLootID)
1157 {
1158 if (!lootIdSet.count(lootid))
1159 LootTemplates_Pickpocketing.ReportNonExistingId(lootid, "Creature", creatureTemplatePair.first);
1160 else
1161 lootIdSetUsed.insert(lootid);
1162 }
1163 }
1164 }
1165
1166 for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr)
1167 lootIdSet.erase(*itr);
1168
1169 // output error for any still listed (not referenced from appropriate table) ids
1171
1172 if (count)
1173 TC_LOG_INFO("server.loading", ">> Loaded {} pickpocketing loot templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1174 else
1175 TC_LOG_INFO("server.loading", ">> Loaded 0 pickpocketing loot templates. DB table `pickpocketing_loot_template` is empty");
1176}
1177
1179{
1180 TC_LOG_INFO("server.loading", "Loading prospecting loot templates...");
1181
1182 uint32 oldMSTime = getMSTime();
1183
1184 LootIdSet lootIdSet;
1186
1187 // remove real entries and check existence loot
1188 ItemTemplateContainer const& its = sObjectMgr->GetItemTemplateStore();
1189 for (auto const& itemTemplatePair : its)
1190 {
1191 if (!itemTemplatePair.second.HasFlag(ITEM_FLAG_IS_PROSPECTABLE))
1192 continue;
1193
1194 if (lootIdSet.count(itemTemplatePair.first) > 0)
1195 lootIdSet.erase(itemTemplatePair.first);
1196 }
1197
1198 // output error for any still listed (not referenced from appropriate table) ids
1200
1201 if (count)
1202 TC_LOG_INFO("server.loading", ">> Loaded {} prospecting loot templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1203 else
1204 TC_LOG_INFO("server.loading", ">> Loaded 0 prospecting loot templates. DB table `prospecting_loot_template` is empty");
1205}
1206
1208{
1209 TC_LOG_INFO("server.loading", "Loading mail loot templates...");
1210
1211 uint32 oldMSTime = getMSTime();
1212
1213 LootIdSet lootIdSet;
1215
1216 // remove real entries and check existence loot
1217 for (uint32 i = 1; i < sMailTemplateStore.GetNumRows(); ++i)
1218 if (sMailTemplateStore.LookupEntry(i))
1219 if (lootIdSet.find(i) != lootIdSet.end())
1220 lootIdSet.erase(i);
1221
1222 // output error for any still listed (not referenced from appropriate table) ids
1224
1225 if (count)
1226 TC_LOG_INFO("server.loading", ">> Loaded {} mail loot templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1227 else
1228 TC_LOG_INFO("server.loading", ">> Loaded 0 mail loot templates. DB table `mail_loot_template` is empty");
1229}
1230
1232{
1233 TC_LOG_INFO("server.loading", "Loading skinning loot templates...");
1234
1235 uint32 oldMSTime = getMSTime();
1236
1237 LootIdSet lootIdSet, lootIdSetUsed;
1239
1240 // remove real entries and check existence loot
1241 CreatureTemplateContainer const& ctc = sObjectMgr->GetCreatureTemplates();
1242 for (auto const& creatureTemplatePair : ctc)
1243 {
1244 for (auto const& [difficulty, creatureDifficulty] : creatureTemplatePair.second.difficultyStore)
1245 {
1246 if (uint32 lootid = creatureDifficulty.SkinLootID)
1247 {
1248 if (!lootIdSet.count(lootid))
1249 LootTemplates_Skinning.ReportNonExistingId(lootid, "Creature", creatureTemplatePair.first);
1250 else
1251 lootIdSetUsed.insert(lootid);
1252 }
1253 }
1254 }
1255
1256 for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr)
1257 lootIdSet.erase(*itr);
1258
1259 // output error for any still listed (not referenced from appropriate table) ids
1261
1262 if (count)
1263 TC_LOG_INFO("server.loading", ">> Loaded {} skinning loot templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1264 else
1265 TC_LOG_INFO("server.loading", ">> Loaded 0 skinning loot templates. DB table `skinning_loot_template` is empty");
1266}
1267
1269{
1270 // TODO: change this to use MiscValue from spell effect as id instead of spell id
1271 TC_LOG_INFO("server.loading", "Loading spell loot templates...");
1272
1273 uint32 oldMSTime = getMSTime();
1274
1275 LootIdSet lootIdSet;
1277
1278 // remove real entries and check existence loot
1279 for (SpellNameEntry const* spellNameEntry : sSpellNameStore)
1280 {
1281 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellNameEntry->ID, DIFFICULTY_NONE);
1282 if (!spellInfo)
1283 continue;
1284
1285 // possible cases
1286 if (!spellInfo->IsLootCrafting())
1287 continue;
1288
1289 if (lootIdSet.find(spellInfo->Id) == lootIdSet.end())
1290 {
1291 // not report about not trainable spells (optionally supported by DB)
1292 // ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
1294 LootTemplates_Spell.ReportNonExistingId(spellInfo->Id, "Spell", spellInfo->Id);
1295 }
1296 else
1297 lootIdSet.erase(spellInfo->Id);
1298 }
1299
1300 // output error for any still listed (not referenced from appropriate table) ids
1302
1303 if (count)
1304 TC_LOG_INFO("server.loading", ">> Loaded {} spell loot templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1305 else
1306 TC_LOG_INFO("server.loading", ">> Loaded 0 spell loot templates. DB table `spell_loot_template` is empty");
1307}
1308
1310{
1311 TC_LOG_INFO("server.loading", "Loading reference loot templates...");
1312
1313 uint32 oldMSTime = getMSTime();
1314
1315 LootIdSet lootIdSet;
1317
1318 // check references and remove used
1330
1331 // output error for any still listed ids (not referenced from any loot table)
1333
1334 TC_LOG_INFO("server.loading", ">> Loaded reference loot templates in {} ms", GetMSTimeDiffToNow(oldMSTime));
1335}
1336
1338{
1350
1352}
DB2Storage< SpellNameEntry > sSpellNameStore("SpellName.db2", &SpellNameLoadInfo::Instance)
DB2Storage< MailTemplateEntry > sMailTemplateStore("MailTemplate.db2", &MailTemplateLoadInfo::Instance)
DB2Storage< ItemDisenchantLootEntry > sItemDisenchantLootStore("ItemDisenchantLoot.db2", &ItemDisenchantLootLoadInfo::Instance)
DB2Storage< AreaTableEntry > sAreaTableStore("AreaTable.db2", &AreaTableLoadInfo::Instance)
@ DIFFICULTY_NONE
Definition: DBCEnums.h:874
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
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
@ ITEM_FLAG_IS_MILLABLE
Definition: ItemTemplate.h:205
@ ITEM_FLAG_IS_PROSPECTABLE
Definition: ItemTemplate.h:194
@ ITEM_FLAG_HAS_LOOT
Definition: ItemTemplate.h:178
@ ITEM_FLAGS_CU_FOLLOW_LOOT_RULES
Definition: ItemTemplate.h:319
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
void LoadLootTemplates_Pickpocketing()
Definition: LootMgr.cpp:1141
LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false)
LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true)
void LoadLootTemplates_Spell()
Definition: LootMgr.cpp:1268
void LoadLootTemplates_Milling()
Definition: LootMgr.cpp:1112
LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject entry", true)
void LoadLootTemplates_Gameobject()
Definition: LootMgr.cpp:1042
void LoadLootTemplates_Creature()
Definition: LootMgr.cpp:949
LootStore LootTemplates_Item("item_loot_template", "item entry", true)
LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true)
LootStore LootTemplates_Reference("reference_loot_template", "reference id", false)
LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true)
LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true)
void LoadLootTemplates_Fishing()
Definition: LootMgr.cpp:1019
static Rates const qualityToRate[MAX_ITEM_QUALITY]
Definition: LootMgr.cpp:33
void LoadLootTables()
Definition: LootMgr.cpp:1337
void LoadLootTemplates_Reference()
Definition: LootMgr.cpp:1309
LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true)
void LoadLootTemplates_Prospecting()
Definition: LootMgr.cpp:1178
LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket lootid", true)
void LoadLootTemplates_Mail()
Definition: LootMgr.cpp:1207
void LoadLootTemplates_Disenchant()
Definition: LootMgr.cpp:989
void LoadLootTemplates_Item()
Definition: LootMgr.cpp:1088
std::unordered_map< ObjectGuid, std::unique_ptr< Loot > > GenerateDungeonEncounterPersonalLoot(uint32 dungeonEncounterId, uint32 lootId, LootStore const &store, LootType type, WorldObject const *lootOwner, uint32 minMoney, uint32 maxMoney, uint16 lootMode, MapDifficultyEntry const *mapDifficulty, std::vector< Player * > const &tappers)
Definition: LootMgr.cpp:914
LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false)
void LoadLootTemplates_Skinning()
Definition: LootMgr.cpp:1231
LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true)
std::unordered_map< uint32, LootTemplate * > LootTemplateMap
Definition: LootMgr.h:63
std::set< uint32 > LootIdSet
Definition: LootMgr.h:65
std::list< LootStoreItem * > LootStoreItemList
Definition: LootMgr.h:62
LootType
Definition: Loot.h:98
std::unordered_map< uint32, ItemTemplate > ItemTemplateContainer
Definition: ObjectMgr.h:518
std::unordered_map< uint32, GameObjectTemplate > GameObjectTemplateContainer
Definition: ObjectMgr.h:506
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::unordered_map< uint32, CreatureTemplate > CreatureTemplateContainer
Definition: ObjectMgr.h:495
float rand_chance()
Definition: Random.cpp:81
bool roll_chance_f(float chance)
Definition: Random.h:53
#define PLAYER_CORPSE_LOOT_ENTRY
@ GAMEOBJECT_TYPE_CHEST
@ MAX_ITEM_QUALITY
@ SPELL_ATTR0_IS_TRADESKILL
@ SPELL_ATTR0_NOT_SHAPESHIFTED
#define sSpellMgr
Definition: SpellMgr.h:849
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition: Timer.h:57
uint32 getMSTime()
Definition: Timer.h:33
Class used to access individual fields of database query result.
Definition: Field.h:90
uint8 GetUInt8() const
Definition: Field.cpp:30
uint16 GetUInt16() const
Definition: Field.cpp:46
float GetFloat() const
Definition: Field.cpp:94
bool GetBool() const
Definition: Field.h:98
uint32 GetUInt32() const
Definition: Field.cpp:62
uint32 LoadLootTable()
Definition: LootMgr.cpp:130
uint32 LoadAndCollectLootIds(LootIdSet &ids_set)
Definition: LootMgr.cpp:239
LootTemplate const * GetLootFor(uint32 loot_id) const
Definition: LootMgr.cpp:219
LootTemplateMap m_LootTemplates
Definition: LootMgr.h:97
void CheckLootRefs(LootIdSet *ref_set=nullptr) const
Definition: LootMgr.cpp:249
char const * GetEntryName() const
Definition: LootMgr.h:91
bool HaveQuestLootFor(uint32 loot_id) const
Definition: LootMgr.cpp:199
LootTemplate * GetLootForConditionFill(uint32 loot_id)
Definition: LootMgr.cpp:229
bool IsRatesAllowed() const
Definition: LootMgr.h:92
void ReportNonExistingId(uint32 lootId) const
Definition: LootMgr.cpp:262
void Clear()
Definition: LootMgr.cpp:113
char const * GetName() const
Definition: LootMgr.h:90
bool HaveQuestLootForPlayer(uint32 loot_id, Player const *player) const
Definition: LootMgr.cpp:209
void ReportUnusedIds(LootIdSet const &ids_set) const
Definition: LootMgr.cpp:255
void Verify() const
Definition: LootMgr.cpp:122
void CheckLootRefs(LootTemplateMap const &store, LootIdSet *ref_set) const
Definition: LootMgr.cpp:486
LootStoreItemList ExplicitlyChanced
Definition: LootMgr.cpp:105
LootGroup(LootGroup &&)=delete
LootGroup & operator=(LootGroup &&)=delete
LootStoreItemList * GetEqualChancedItemList()
Definition: LootMgr.cpp:103
LootStoreItem const * Roll(uint16 lootMode, Player const *personalLooter=nullptr) const
Definition: LootMgr.cpp:372
LootGroup & operator=(LootGroup const &)=delete
LootStoreItemList EqualChanced
Definition: LootMgr.cpp:106
void Verify(LootStore const &lootstore, uint32 id, uint8 group_id) const
Definition: LootMgr.cpp:476
LootStoreItemList * GetExplicitlyChancedItemList()
Definition: LootMgr.cpp:102
float RawTotalChance() const
Definition: LootMgr.cpp:454
void AddEntry(LootStoreItem *item)
Definition: LootMgr.cpp:363
bool HasQuestDropForPlayer(Player const *player) const
Definition: LootMgr.cpp:433
void Process(Loot &loot, uint16 lootMode, Player const *personalLooter=nullptr) const
Definition: LootMgr.cpp:447
LootGroup(LootGroup const &)=delete
float TotalChance() const
Definition: LootMgr.cpp:466
bool HasQuestDrop() const
Definition: LootMgr.cpp:419
bool HasDropForPlayer(Player const *player, bool strictUsabilityCheck) const
Definition: LootMgr.cpp:401
void ProcessPersonalLoot(std::unordered_map< Player *, std::unique_ptr< Loot > > &personalLoot, bool rate, uint16 lootMode) const
Definition: LootMgr.cpp:609
void Process(Loot &loot, bool rate, uint16 lootMode, uint8 groupId, Player const *personalLooter=nullptr) const
Definition: LootMgr.cpp:557
void CheckLootRefs(LootTemplateMap const &store, LootIdSet *ref_set) const
Definition: LootMgr.cpp:835
void CopyConditions(LootItem *li) const
Definition: LootMgr.cpp:542
bool isReference(uint32 id)
Definition: LootMgr.cpp:905
void AddEntry(LootStoreItem *item)
Definition: LootMgr.cpp:527
bool LinkConditions(ConditionId const &id, ConditionsReference reference)
Definition: LootMgr.cpp:854
bool HasQuestDropForPlayer(LootTemplateMap const &store, Player const *player, uint8 groupId=0) const
Definition: LootMgr.cpp:786
bool HasDropForPlayer(Player const *player, uint8 groupId=0, bool strictUsabilityCheck=false) const
Definition: LootMgr.cpp:708
void Verify(LootStore const &store, uint32 Id) const
Definition: LootMgr.cpp:825
bool HasQuestDrop(LootTemplateMap const &store, uint8 groupId=0) const
Definition: LootMgr.cpp:748
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
bool HasQuestForItem(uint32 itemId) const
Definition: Player.cpp:16900
uint32 const Id
Definition: SpellInfo.h:325
bool IsLootCrafting() const
Definition: SpellInfo.cpp:1481
bool HasAttribute(SpellAttr0 attribute) const
Definition: SpellInfo.h:449
Map * GetMap() const
Definition: Object.h:624
#define sWorld
Definition: World.h:931
Rates
Server rates.
Definition: World.h:452
@ RATE_DROP_ITEM_REFERENCED_AMOUNT
Definition: World.h:481
@ RATE_DROP_ITEM_RARE
Definition: World.h:476
@ RATE_DROP_ITEM_LEGENDARY
Definition: World.h:478
@ RATE_DROP_ITEM_POOR
Definition: World.h:473
@ RATE_DROP_ITEM_UNCOMMON
Definition: World.h:475
@ RATE_DROP_ITEM_REFERENCED
Definition: World.h:480
@ RATE_DROP_ITEM_EPIC
Definition: World.h:477
@ RATE_DROP_ITEM_ARTIFACT
Definition: World.h:479
@ RATE_DROP_ITEM_NORMAL
Definition: World.h:474
ItemContext GetContextForPlayer(MapDifficultyEntry const *mapDifficulty, Player const *player)
auto SelectRandomContainerElement(C const &container) -> typename std::add_const< decltype(*std::begin(container))>::type &
Definition: Containers.h:109
uint32 GetQuality() const
Definition: ItemTemplate.h:779
LootGroupInvalidSelector(uint16 lootMode, Player const *personalLooter)
Definition: LootMgr.cpp:60
bool operator()(LootStoreItem const *item) const
Definition: LootMgr.cpp:62
Player const * _personalLooter
Definition: LootMgr.cpp:77
Definition: Loot.h:176
uint32 itemid
Definition: Loot.h:177
bool AllowedForPlayer(Player const *player, Loot const *loot) const
Definition: Loot.cpp:72
ConditionsReference conditions
Definition: Loot.h:182
float chance
Definition: LootMgr.h:43
bool Roll(bool rate) const
Definition: LootMgr.cpp:278
ConditionsReference conditions
Definition: LootMgr.h:49
bool needs_quest
Definition: LootMgr.h:45
uint32 itemid
Definition: LootMgr.h:41
uint32 reference
Definition: LootMgr.h:42
uint8 maxcount
Definition: LootMgr.h:48
uint16 lootmode
Definition: LootMgr.h:44
uint8 groupid
Definition: LootMgr.h:46
uint8 mincount
Definition: LootMgr.h:47
bool IsValid(LootStore const &store, uint32 entry) const
Definition: LootMgr.cpp:294
Definition: Loot.h:281
void AddItem(LootStoreItem const &item)
Definition: Loot.cpp:827