Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
LootMgr.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "Containers.h"
7#include "Group.h"
8#include "Log.h"
9#include "LootMgr.h"
10#include "ObjectMgr.h"
11#include "Player.h"
12#include "SharedDefines.h"
13#include "SpellInfo.h"
14#include "SpellMgr.h"
15#include "UnaryFunction.h"
16#include "Util.h"
17#include "World.h"
18
20{
21 Rates::RATE_DROP_ITEM_POOR, // ITEM_QUALITY_POOR
22 Rates::RATE_DROP_ITEM_NORMAL, // ITEM_QUALITY_NORMAL
23 Rates::RATE_DROP_ITEM_UNCOMMON, // ITEM_QUALITY_UNCOMMON
24 Rates::RATE_DROP_ITEM_RARE, // ITEM_QUALITY_RARE
25 Rates::RATE_DROP_ITEM_EPIC, // ITEM_QUALITY_EPIC
26 Rates::RATE_DROP_ITEM_LEGENDARY, // ITEM_QUALITY_LEGENDARY
27 Rates::RATE_DROP_ITEM_ARTIFACT, // ITEM_QUALITY_ARTIFACT
28};
29
30LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true);
31LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true);
32LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true);
33LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject entry", true);
34LootStore LootTemplates_Item("item_loot_template", "item entry", true);
35LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false);
36LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true);
37LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket lootid", true);
38LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true);
39LootStore LootTemplates_Reference("reference_loot_template", "reference id", false);
40LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true);
41LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false);
42
43// Selects invalid loot items to be removed from group possible entries (before rolling)
44struct LootGroupInvalidSelector : public SF_UNARY_FUNCTION<LootStoreItem*, bool>
45{
46 explicit LootGroupInvalidSelector(Loot const& loot, uint16 lootMode) : _loot(loot), _lootMode(lootMode) { }
47
48 bool operator()(LootStoreItem* item) const
49 {
50 if (!(item->lootmode & _lootMode))
51 return true;
52
53 uint8 foundDuplicates = 0;
54 for (std::vector<LootItem>::const_iterator itr = _loot.items.begin(); itr != _loot.items.end(); ++itr)
55 if (itr->itemid == item->itemid)
56 if (++foundDuplicates == _loot.maxDuplicates)
57 return true;
58
59 return false;
60 }
61
62private:
63 Loot const& _loot;
65};
66
67class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed)
68{
69public:
71 ~LootGroup();
72
73 void AddEntry(LootStoreItem* item); // Adds an entry to the group (at loading stage)
74 bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
75 bool HasQuestDropForPlayer(Player const* player) const;
76 // The same for active quests of the player
77 void Process(Loot& loot, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot
78 float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
79 float TotalChance() const; // Overall chance for the group
80
81 void Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const;
82 void CollectLootIds(LootIdSet& set) const;
83 void CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const;
86 void CopyConditions(ConditionList conditions);
87private:
88 LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
89 LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
90
91 LootStoreItem const* Roll(Loot& loot, uint16 lootMode) const; // Rolls an item from the group, returns NULL if all miss their chances
92
93 // This class must never be copied - storing pointers
96};
97
98//Remove all data and free all memory
100{
101 for (LootTemplateMap::const_iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
102 delete itr->second;
103 m_LootTemplates.clear();
104}
105
106// Checks validity of the loot store
107// Actual checks are done within LootTemplate::Verify() which is called for every template
109{
110 for (LootTemplateMap::const_iterator i = m_LootTemplates.begin(); i != m_LootTemplates.end(); ++i)
111 i->second->Verify(*this, i->first);
112}
113
114// Loads a *_loot_template DB table into loot store
115// All checks of the loaded template are called from here, no error reports at loot generation required
117{
118 LootTemplateMap::const_iterator tab;
119
120 // Clearing store (for reloading case)
121 Clear();
122
123 // 0 1 2 3 4 5 6
124 QueryResult result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, lootmode, groupid, mincountOrRef, maxcount FROM %s", GetName());
125
126 if (!result)
127 return 0;
128
129 uint32 count = 0;
130
131 do
132 {
133 Field* fields = result->Fetch();
134
135 uint32 entry = fields[0].GetUInt32();
136 uint32 item = fields[1].GetUInt32();
137 float chanceOrQuestChance = fields[2].GetFloat();
138 uint16 lootmode = fields[3].GetUInt16();
139 uint8 group = fields[4].GetUInt8();
140 int32 mincountOrRef = fields[5].GetInt32();
141 int32 maxcount = fields[6].GetUInt8();
142
143 if (maxcount > std::numeric_limits<uint8>::max())
144 {
145 SF_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: maxcount value (%u) to large. must be less %u - skipped", GetName(), entry, item, maxcount, std::numeric_limits<uint8>::max());
146 continue; // error already printed to log/console.
147 }
148
149 if (group >= 1 << 7) // it stored in 7 bit field
150 {
151 SF_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: group (%u) must be less %u - skipped", GetName(), entry, item, group, 1 << 7);
152 return false;
153 }
154
155 LootStoreItem* storeitem = new LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount);
156
157 if (!storeitem->IsValid(*this, entry)) // Validity checks
158 {
159 delete storeitem;
160 continue;
161 }
162
163 // Looking for the template of the entry
164 // often entries are put together
165 if (m_LootTemplates.empty() || tab->first != entry)
166 {
167 // Searching the template (in case template Id changed)
168 tab = m_LootTemplates.find(entry);
169 if (tab == m_LootTemplates.end())
170 {
171 std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate()));
172 tab = pr.first;
173 }
174 }
175 // else is empty - template Id and iter are the same
176 // finally iter refers to already existed or just created <entry, LootTemplate>
177
178 // Adds current row to the template
179 tab->second->AddEntry(storeitem);
180 ++count;
181 } while (result->NextRow());
182
183 Verify(); // Checks validity of the loot store
184
185 return count;
186}
187
189{
190 LootTemplateMap::const_iterator itr = m_LootTemplates.find(loot_id);
191 if (itr == m_LootTemplates.end())
192 return false;
193
194 // scan loot for quest items
195 return itr->second->HasQuestDrop(m_LootTemplates);
196}
197
199{
200 LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
201 if (tab != m_LootTemplates.end())
202 if (tab->second->HasQuestDropForPlayer(m_LootTemplates, player))
203 return true;
204
205 return false;
206}
207
209{
210 for (LootTemplateMap::iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
211 {
212 ConditionList empty;
213 itr->second->CopyConditions(empty);
214 }
215}
216
218{
219 LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
220
221 if (tab == m_LootTemplates.end())
222 return NULL;
223
224 return tab->second;
225}
226
228{
229 LootTemplateMap::iterator tab = m_LootTemplates.find(loot_id);
230
231 if (tab == m_LootTemplates.end())
232 return NULL;
233
234 return tab->second;
235}
236
238{
239 uint32 count = LoadLootTable();
240
241 for (LootTemplateMap::const_iterator tab = m_LootTemplates.begin(); tab != m_LootTemplates.end(); ++tab)
242 lootIdSet.insert(tab->first);
243
244 return count;
245}
246
248{
249 for (LootTemplateMap::const_iterator ltItr = m_LootTemplates.begin(); ltItr != m_LootTemplates.end(); ++ltItr)
250 ltItr->second->CheckLootRefs(m_LootTemplates, ref_set);
251}
252
253void LootStore::ReportUnusedIds(LootIdSet const& lootIdSet) const
254{
255 // all still listed ids isn't referenced
256 for (LootIdSet::const_iterator itr = lootIdSet.begin(); itr != lootIdSet.end(); ++itr)
257 SF_LOG_ERROR("sql.sql", "Table '%s' entry %d isn't %s and not referenced from loot, and then useless.", GetName(), *itr, GetEntryName());
258}
259
261{
262 SF_LOG_ERROR("sql.sql", "Table '%s' entry %d (%s) does not exist but used as loot id in DB.", GetName(), id, GetEntryName());
263}
264
265//
266// --------- LootStoreItem ---------
267//
268
269// Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
270// RATE_DROP_ITEMS is no longer used for all types of entries
271bool LootStoreItem::Roll(bool rate) const
272{
273 if (chance >= 100.0f)
274 return true;
275
276 if (mincountOrRef < 0) // reference case
277 return roll_chance_f(chance * (rate ? sWorld->getRate(Rates::RATE_DROP_ITEM_REFERENCED) : 1.0f));
278
279 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
280
281 float qualityModifier = pProto && rate ? sWorld->getRate(qualityToRate[pProto->Quality]) : 1.0f;
282
283 return roll_chance_f(chance * qualityModifier);
284}
285
286// Checks correctness of values
287bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
288{
289 if (mincountOrRef == 0)
290 {
291 SF_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincountOrRef);
292 return false;
293 }
294
295 if (mincountOrRef > 0) // item (quest or non-quest) entry, maybe grouped
296 {
297 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid);
298 if (!proto)
299 {
300 SF_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store.GetName(), entry, itemid);
301 return false;
302 }
303
304 if (chance == 0 && group == 0) // Zero chance is allowed for grouped entries only
305 {
306 SF_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: equal-chanced grouped entry, but group not defined - skipped", store.GetName(), entry, itemid);
307 return false;
308 }
309
310 if (chance != 0 && chance < 0.000001f) // loot with low chance
311 {
312 SF_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: low chance (%f) - skipped",
313 store.GetName(), entry, itemid, chance);
314 return false;
315 }
316
317 if (maxcount < mincountOrRef) // wrong max count
318 {
319 SF_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store.GetName(), entry, itemid, int32(maxcount), mincountOrRef);
320 return false;
321 }
322 }
323 else // mincountOrRef < 0
324 {
325 if (needs_quest)
326 SF_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: quest chance will be treated as non-quest chance", store.GetName(), entry, itemid);
327 else if (chance == 0) // no chance for the reference
328 {
329 SF_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: zero chance is specified for a reference, skipped", store.GetName(), entry, itemid);
330 return false;
331 }
332 }
333 return true; // Referenced template existence is checked at whole store level
334}
335
336//
337// --------- LootItem ---------
338//
339
340// Constructor, copies most fields from LootStoreItem and generates random count
350
351// Basic checks for player/item compatibility - if false no chance to see the item in the loot
352bool LootItem::AllowedForPlayer(Player const* player) const
353{
354 // DB conditions check
355 if (!sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(player), conditions))
356 return false;
357
358 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
359 if (!pProto)
360 return false;
361
362 // not show loot for players without profession or those who already know the recipe
363 if ((pProto->Flags & ITEM_PROTO_FLAG_SMART_LOOT) && (!player->HasSkill(pProto->RequiredSkill) || player->HasSpell(pProto->Spells[1].SpellId)))
364 return false;
365
366 // not show loot for not own team
367 if ((pProto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && player->GetTeam() != HORDE)
368 return false;
369
370 if ((pProto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && player->GetTeam() != ALLIANCE)
371 return false;
372
373 // check quest requirements
374 if (!(pProto->FlagsCu & ITEM_FLAGS_CU_IGNORE_QUEST_STATUS) && ((needs_quest || (pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE)) && !player->HasQuestForItem(itemid)))
375 return false;
376
377 return true;
378}
379
381{
382 allowedGUIDs.insert(player->GetGUIDLow());
383}
384
385//
386// --------- Loot ---------
387//
388
389// Inserts the item into the loot (called by LootTemplate processors)
391{
392 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid);
393 if (!proto)
394 return;
395
396 uint32 count = std::rand() % item.maxcount + item.mincountOrRef;
397 uint32 stacks = count / proto->GetMaxStackSize() + ((count % proto->GetMaxStackSize()) ? 1 : 0);
398
399 std::vector<LootItem>& lootItems = item.needs_quest ? quest_items : items;
401
402 for (uint32 i = 0; i < stacks && lootItems.size() < limit; ++i)
403 {
404 LootItem generatedLoot(item);
405 generatedLoot.count = std::min(count, proto->GetMaxStackSize());
406 lootItems.push_back(generatedLoot);
407 count -= proto->GetMaxStackSize();
408
409 // non-conditional one-player only items are counted here,
410 // free for all items are counted in FillFFALoot(),
411 // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
412 if (!item.needs_quest && item.conditions.empty() && !(proto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT))
414 }
415}
416
417// Calls processor of corresponding LootTemplate (which handles everything including references)
418bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError, uint16 lootMode /*= LOOT_MODE_DEFAULT*/)
419{
420 // Must be provided
421 if (!lootOwner)
422 return false;
423
424 LootTemplate const* tab = store.GetLootFor(lootId);
425
426 if (!tab)
427 {
428 if (!noEmptyError)
429 SF_LOG_ERROR("sql.sql", "Table '%s' loot id #%u used but it doesn't have records.", store.GetName(), lootId);
430 return false;
431 }
432
433 items.reserve(MAX_NR_LOOT_ITEMS);
435
436 tab->Process(*this, store.IsRatesAllowed(), lootMode); // Processing is done there, callback via Loot::AddItem()
437
438 // Setting access rights for group loot case
439 Group* group = lootOwner->GetGroup();
440 if (!personal && group)
441 {
442 roundRobinPlayer = lootOwner->GetGUID();
443
444 for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
445 if (Player* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter
446 FillNotNormalLootFor(player, player->IsAtGroupRewardDistance(lootOwner));
447
448 for (uint8 i = 0; i < items.size(); ++i)
449 {
450 if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(items[i].itemid))
451 if (proto->Quality < uint32(group->GetLootThreshold()))
452 items[i].is_underthreshold = true;
453 }
454 }
455 // ... for personal loot
456 else
457 FillNotNormalLootFor(lootOwner, true);
458
459 return true;
460}
461
462void Loot::FillNotNormalLootFor(Player* player, bool presentAtLooting)
463{
464 uint32 plguid = player->GetGUIDLow();
465
466 QuestItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid);
467 if (qmapitr == PlayerQuestItems.end())
468 FillQuestLoot(player);
469
470 qmapitr = PlayerFFAItems.find(plguid);
471 if (qmapitr == PlayerFFAItems.end())
472 FillFFALoot(player);
473
474 qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
475 if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
476 FillNonQuestNonFFAConditionalLoot(player, presentAtLooting);
477
478 // if not auto-processed player will have to come and pick it up manually
479 if (!presentAtLooting)
480 return;
481
482 // Process currency items
483 uint32 max_slot = GetMaxSlotInLootFor(player);
484 LootItem const* item = NULL;
485 uint32 itemsSize = uint32(items.size());
486 for (uint32 i = 0; i < max_slot; ++i)
487 {
488 if (i < items.size())
489 item = &items[i];
490 else
491 item = &quest_items[i - itemsSize];
492
493 if (!item->is_looted && item->freeforall && item->AllowedForPlayer(player))
494 if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item->itemid))
495 if (proto->IsCurrencyToken())
496 player->StoreLootItem(i, this);
497 }
498}
499
501{
502 QuestItemList* ql = new QuestItemList();
503
504 for (uint8 i = 0; i < items.size(); ++i)
505 {
506 LootItem& item = items[i];
507 if (!item.is_looted && item.freeforall && item.AllowedForPlayer(player))
508 {
509 ql->push_back(QuestItem(i));
511 }
512 }
513 if (ql->empty())
514 {
515 delete ql;
516 return NULL;
517 }
518
519 PlayerFFAItems[player->GetGUIDLow()] = ql;
520 return ql;
521}
522
524{
525 if (items.size() == MAX_NR_LOOT_ITEMS)
526 return NULL;
527
528 QuestItemList* ql = new QuestItemList();
529
530 for (uint8 i = 0; i < quest_items.size(); ++i)
531 {
532 LootItem& item = quest_items[i];
533
534 if (!item.is_looted && (item.AllowedForPlayer(player) || (item.follow_loot_rules && player->GetGroup() &&
536 player->GetGroup()->GetLooterGuid() == player->GetGUID()) || player->GetGroup()->GetLootMethod() != LootMethod::MASTER_LOOT))))
537 {
538 ql->push_back(QuestItem(i));
539
540 // quest items get blocked when they first appear in a
541 // player's quest vector
542 //
543 // increase once if one looter only, looter-times if free for all
544 if (item.freeforall || !item.is_blocked)
546 if (!player->GetGroup() || (player->GetGroup()->GetLootMethod() != LootMethod::GROUP_LOOT && player->GetGroup()->GetLootMethod() != LootMethod::ROUND_ROBIN))
547 item.is_blocked = true;
548
549 if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS)
550 break;
551 }
552 }
553 if (ql->empty())
554 {
555 delete ql;
556 return NULL;
557 }
558
559 PlayerQuestItems[player->GetGUIDLow()] = ql;
560 return ql;
561}
562
564{
565 QuestItemList* ql = new QuestItemList();
566
567 for (uint8 i = 0; i < items.size(); ++i)
568 {
569 LootItem& item = items[i];
570 if (!item.is_looted && !item.freeforall && (item.AllowedForPlayer(player) || (item.follow_loot_rules && player->GetGroup() &&
572 player->GetGroup()->GetLooterGuid() == player->GetGUID()) || player->GetGroup()->GetLootMethod() != LootMethod::MASTER_LOOT))))
573 {
574 if (presentAtLooting)
575 item.AddAllowedLooter(player);
576 if (!item.conditions.empty())
577 {
578 ql->push_back(QuestItem(i));
579 if (!item.is_counted)
580 {
582 item.is_counted = true;
583 }
584 }
585 }
586 }
587 if (ql->empty())
588 {
589 delete ql;
590 return NULL;
591 }
592
594 return ql;
595}
596
597//===================================================
598
599void Loot::NotifyItemRemoved(uint8 lootIndex, ObjectGuid lootGuid)
600{
601 // notify all players that are looting this that the item was removed
602 // convert the index to the slot the player sees
603 std::set<uint64>::iterator i_next;
604 for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
605 {
606 i_next = i;
607 ++i_next;
608 if (Player* player = ObjectAccessor::FindPlayer(*i))
609 {
610 uint64 notifyGuid = uint64(lootGuid) ? uint64(lootGuid) : player->GetLootGUID();
611 player->SendNotifyLootItemRemoved(lootIndex, notifyGuid);
612 }
613 else
614 PlayersLooting.erase(i);
615 }
616}
617
619{
620 // notify all players that are looting this that the money was removed
621 std::set<uint64>::iterator i_next;
622 for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
623 {
624 i_next = i;
625 ++i_next;
626 if (Player* player = ObjectAccessor::FindPlayer(*i))
627 {
628 uint64 notifyGuid = uint64(lootGuid) ? uint64(lootGuid) : player->GetLootGUID();
629 player->SendNotifyLootMoneyRemoved(notifyGuid);
630 }
631 else
632 PlayersLooting.erase(i);
633 }
634}
635
637{
638 // when a free for all questitem is looted
639 // all players will get notified of it being removed
640 // (other questitems can be looted by each group member)
641 // bit inefficient but isn't called often
642
643 std::set<uint64>::iterator i_next;
644 for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
645 {
646 i_next = i;
647 ++i_next;
648 if (Player* player = ObjectAccessor::FindPlayer(*i))
649 {
650 QuestItemMap::const_iterator pq = PlayerQuestItems.find(player->GetGUIDLow());
651 if (pq != PlayerQuestItems.end() && pq->second)
652 {
653 // find where/if the player has the given item in it's vector
654 QuestItemList& pql = *pq->second;
655
656 uint8 j;
657 for (j = 0; j < pql.size(); ++j)
658 if (pql[j].index == questIndex)
659 break;
660
661 if (j < pql.size())
662 {
663 uint64 notifyGuid = uint64(lootGuid) ? uint64(lootGuid) : player->GetLootGUID();
664 player->SendNotifyLootItemRemoved(items.size() + j, notifyGuid);
665 }
666 }
667 }
668 else
669 PlayersLooting.erase(i);
670 }
671}
672
673void Loot::generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
674{
675 if (maxAmount > 0)
676 {
677 if (maxAmount <= minAmount)
678 gold = uint32(maxAmount * sWorld->getRate(Rates::RATE_DROP_MONEY));
679 else if ((maxAmount - minAmount) < 32700)
680 gold = uint32((std::rand() % maxAmount + minAmount) * sWorld->getRate(Rates::RATE_DROP_MONEY));
681 else
682 gold = uint32(std::rand() % (maxAmount >> 8) + (minAmount >> 8) * sWorld->getRate(Rates::RATE_DROP_MONEY)) << 8;
683 }
684}
685
687{
688 // Deletes a single item associated with an openable item from the DB
690 stmt->setUInt32(0, containerID);
691 stmt->setUInt32(1, itemID);
692 CharacterDatabase.Execute(stmt);
693
694 // Mark the item looted to prevent resaving
695 for (LootItemList::iterator _itr = items.begin(); _itr != items.end(); ++_itr)
696 {
697 if (_itr->itemid != itemID)
698 continue;
699
700 _itr->canSave = true;
701 break;
702 }
703}
704
706{
707 // Deletes money loot associated with an openable item from the DB
709 stmt->setUInt32(0, containerID);
710 CharacterDatabase.Execute(stmt);
711}
712
713LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem** qitem, QuestItem** ffaitem, QuestItem** conditem)
714{
715 LootItem* item = NULL;
716 bool is_looted = true;
717 if (lootSlot >= items.size())
718 {
719 uint32 questSlot = lootSlot - items.size();
720 QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
721 if (itr != PlayerQuestItems.end() && questSlot < itr->second->size())
722 {
723 QuestItem* qitem2 = &itr->second->at(questSlot);
724 if (qitem)
725 *qitem = qitem2;
726 item = &quest_items[qitem2->index];
727 is_looted = qitem2->is_looted;
728 }
729 }
730 else
731 {
732 item = &items[lootSlot];
733 is_looted = item->is_looted;
734 if (item->freeforall)
735 {
736 QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUIDLow());
737 if (itr != PlayerFFAItems.end())
738 {
739 for (QuestItemList::const_iterator iter = itr->second->begin(); iter != itr->second->end(); ++iter)
740 if (iter->index == lootSlot)
741 {
742 QuestItem* ffaitem2 = (QuestItem*)&(*iter);
743 if (ffaitem)
744 *ffaitem = ffaitem2;
745 is_looted = ffaitem2->is_looted;
746 break;
747 }
748 }
749 }
750 else if (!item->conditions.empty())
751 {
752 QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
754 {
755 for (QuestItemList::const_iterator iter = itr->second->begin(); iter != itr->second->end(); ++iter)
756 {
757 if (iter->index == lootSlot)
758 {
759 QuestItem* conditem2 = (QuestItem*)&(*iter);
760 if (conditem)
761 *conditem = conditem2;
762 is_looted = conditem2->is_looted;
763 break;
764 }
765 }
766 }
767 }
768 }
769
770 if (is_looted)
771 return NULL;
772
773 return item;
774}
775
777{
778 QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
779 return items.size() + (itr != PlayerQuestItems.end() ? itr->second->size() : 0);
780}
781
782// return true if there is any FFA, quest or conditional item for the player.
783bool Loot::hasItemFor(Player* player) const
784{
785 QuestItemMap const& lootPlayerQuestItems = GetPlayerQuestItems();
786 QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(player->GetGUIDLow());
787 if (q_itr != lootPlayerQuestItems.end())
788 {
789 QuestItemList* q_list = q_itr->second;
790 for (QuestItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi)
791 {
792 const LootItem& item = quest_items[qi->index];
793 if (!qi->is_looted && !item.is_looted)
794 return true;
795 }
796 }
797
798 QuestItemMap const& lootPlayerFFAItems = GetPlayerFFAItems();
799 QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(player->GetGUIDLow());
800 if (ffa_itr != lootPlayerFFAItems.end())
801 {
802 QuestItemList* ffa_list = ffa_itr->second;
803 for (QuestItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi)
804 {
805 const LootItem& item = items[fi->index];
806 if (!fi->is_looted && !item.is_looted)
807 return true;
808 }
809 }
810
811 QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems();
812 QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
813 if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
814 {
815 QuestItemList* conditional_list = nn_itr->second;
816 for (QuestItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci)
817 {
818 const LootItem& item = items[ci->index];
819 if (!ci->is_looted && !item.is_looted)
820 return true;
821 }
822 }
823
824 return false;
825}
826
827// return true if there is any item over the group threshold (i.e. not underthreshold).
829{
830 for (uint8 i = 0; i < items.size(); ++i)
831 {
832 if (!items[i].is_looted && !items[i].is_underthreshold && !items[i].freeforall)
833 return true;
834 }
835
836 return false;
837}
838
840{
841 bool hasSlotType = bool(SlotType);
842 buff->WriteBits(uint8(permission), 3);
843 buff->WriteBit(0); // canTradeToTapList
844 buff->WriteBit(!hasSlotType);
845 buff->WriteBit(0); // Contains Slot - Always sent
846 buff->WriteBits(0, 2); // Unk 2 bits
847}
848
850{
851 *buff << uint32(randomSuffix);
852 *buff << uint32(count);
853 *buff << uint32(itemid);
854 *buff << uint32(4); // Send situ size
855 *buff << uint32(0); // Blizz always send 0 uint32 as situ (read in packet handler)
856
857 bool hasSlotType = bool(SlotType);
858 if (hasSlotType)
859 *buff << uint8(SlotType);
860
861 *buff << uint32(randomPropertyId);
862 *buff << uint8(slot);
863 *buff << uint32(sObjectMgr->GetItemTemplate(itemid)->DisplayInfoID);
864}
865
866void LootView::WriteData(ObjectGuid guid, LootType lootType, WorldPacket* data, bool isAoE)
867{
868 ObjectGuid lootGuid = guid;
869
871 {
872 data->WriteBit(1); // Missing unk8
873 data->WriteBit(0); // lootType present
874 data->WriteBit(guid[4]);
875 data->WriteBits(0, 20);
876 data->WriteBit(lootGuid[2]);
877 data->WriteBit(lootGuid[3]);
878 data->WriteBit(lootGuid[7]);
879 data->WriteBit(lootGuid[1]);
880 data->WriteBit(guid[6]);
881 data->WriteBit(guid[7]);
882 data->WriteBit(1);
883 data->WriteBit(1); // isPersonalLooting
884 data->WriteBit(1); // Missing unk8
885 data->WriteBit(isAoE); // isAoELooting
886 data->WriteBit(guid[5]);
887 data->WriteBit(lootGuid[6]);
888 data->WriteBit(guid[1]);
889 data->WriteBit(guid[0]);
890 data->WriteBit(lootGuid[5]);
891 data->WriteBit(guid[3]);
892 data->WriteBit(lootGuid[4]);
893 data->WriteBit(1); // Missing unk8
894 data->WriteBit(guid[2]);
895 data->FlushBits();
896 data->WriteByteSeq(lootGuid[2]);
897 data->WriteByteSeq(lootGuid[7]);
898 data->WriteByteSeq(guid[5]);
899 data->WriteByteSeq(lootGuid[3]);
900 data->WriteByteSeq(lootGuid[4]);
901 *data << uint8(lootType);
902 data->WriteByteSeq(guid[4]);
903 data->WriteByteSeq(lootGuid[5]);
904 data->WriteByteSeq(guid[2]);
905 data->WriteByteSeq(guid[3]);
906 data->WriteByteSeq(lootGuid[1]);
907 data->WriteByteSeq(guid[0]);
908 data->WriteByteSeq(lootGuid[0]);
909 data->WriteByteSeq(guid[6]);
910 data->WriteByteSeq(guid[7]);
911 data->WriteByteSeq(guid[1]);
912 data->WriteByteSeq(lootGuid[6]);
913 return;
914 }
915
916 uint8 itemsShown = 0;
917 uint8 currenciesShown = 0;
918 ByteBuffer itemBuff;
919 ByteBuffer currencyBuff;
920
921 data->WriteBit(1); // Missing unk8
922 data->WriteBit(0); // lootType present
923 data->WriteBit(guid[4]);
924
925 size_t currencyCountPos = data->bitwpos();
926 data->WriteBits(0, 20);
927
928 data->WriteBit(lootGuid[2]);
929 data->WriteBit(lootGuid[3]);
930 data->WriteBit(lootGuid[7]);
931 data->WriteBit(lootGuid[1]);
932 data->WriteBit(guid[6]);
933 data->WriteBit(guid[7]);
934 data->WriteBit(!loot.gold);
935 data->WriteBit(1); // isPersonalLooting
936 data->WriteBit(1); // Missing unk8
937 data->WriteBit(isAoE); // isAoELooting
938 data->WriteBit(guid[5]);
939 data->WriteBit(lootGuid[6]);
940
941 size_t itemCountPos = data->bitwpos();
942 data->WriteBits(0, 19);
943
944 data->WriteBit(lootGuid[0]);
945
946 bool hasPermission = true;
947
948 switch (permission)
949 {
951 {
952 // if you are not the round-robin group looter, you can only see
953 // blocked rolled items and quest items, and !ffa items
954 for (uint8 i = 0; i < loot.items.size(); ++i)
955 {
956 if (!loot.items[i].is_looted && !loot.items[i].freeforall && loot.items[i].conditions.empty() && loot.items[i].AllowedForPlayer(viewer))
957 {
958 LootSlotType slotType;
959
960 if (loot.items[i].is_blocked)
962 else if (loot.roundRobinPlayer == 0 || !loot.items[i].is_underthreshold || viewer->GetGUID() == loot.roundRobinPlayer)
963 {
964 // no round robin owner or he has released the loot
965 // or it IS the round robin group owner
966 // => item is lootable
968 }
969 else
970 continue; // item shall not be displayed.
971
972 loot.items[i].WriteBitDataPart(permission, slotType, data);
973 loot.items[i].WriteBasicDataPart(slotType, i, &itemBuff);
974 ++itemsShown;
975 }
976 }
977 break;
978 }
980 {
981 for (uint8 i = 0; i < loot.items.size(); ++i)
982 {
983 if (!loot.items[i].is_looted && !loot.items[i].freeforall && loot.items[i].conditions.empty() && loot.items[i].AllowedForPlayer(viewer))
984 {
985 if (loot.roundRobinPlayer != 0 && viewer->GetGUID() != loot.roundRobinPlayer)
986 // item shall not be displayed.
987 continue;
988
989 loot.items[i].WriteBitDataPart(permission, LootSlotType::LOOT_SLOT_TYPE_ALLOW_LOOT, data);
990 loot.items[i].WriteBasicDataPart(LootSlotType::LOOT_SLOT_TYPE_ALLOW_LOOT, i, &itemBuff);
991 ++itemsShown;
992 }
993 }
994 break;
995 }
999 {
1001 switch (permission)
1002 {
1005 break;
1008 break;
1009 default:
1010 break;
1011 }
1012
1013 for (uint8 i = 0; i < loot.items.size(); ++i)
1014 {
1015 if (!loot.items[i].is_looted && !loot.items[i].freeforall && loot.items[i].conditions.empty() && loot.items[i].AllowedForPlayer(viewer))
1016 {
1017 loot.items[i].WriteBitDataPart(permission, slotType, data);
1018 loot.items[i].WriteBasicDataPart(slotType, i, &itemBuff);
1019 ++itemsShown;
1020 }
1021 }
1022 break;
1023 }
1024 default:
1025 hasPermission = false;
1026 break;
1027 }
1028
1029 if (hasPermission)
1030 {
1032 QuestItemMap const& lootPlayerQuestItems = loot.GetPlayerQuestItems();
1033 QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(viewer->GetGUIDLow());
1034 if (q_itr != lootPlayerQuestItems.end())
1035 {
1036 QuestItemList* q_list = q_itr->second;
1037 for (QuestItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi)
1038 {
1039 LootItem& item = loot.quest_items[qi->index];
1040 if (!qi->is_looted && !item.is_looted)
1041 {
1042 LootSlotType finalSlotType = slotType;
1043 uint8 index = loot.items.size() + (qi - q_list->begin());
1044
1045 if (item.follow_loot_rules)
1046 {
1047 switch (permission)
1048 {
1051 break;
1054 if (!item.is_blocked)
1056 else
1058 break;
1059 default:
1060 break;
1061 }
1062 }
1063
1064 item.WriteBitDataPart(permission, finalSlotType, data);
1065 item.WriteBasicDataPart(finalSlotType, index, &itemBuff);
1066 ++itemsShown;
1067 }
1068 }
1069 }
1070
1071 QuestItemMap const& lootPlayerFFAItems = loot.GetPlayerFFAItems();
1072 QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(viewer->GetGUIDLow());
1073 if (ffa_itr != lootPlayerFFAItems.end())
1074 {
1075 QuestItemList* ffa_list = ffa_itr->second;
1076 for (QuestItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi)
1077 {
1078 LootItem& item = loot.items[fi->index];
1079 if (!fi->is_looted && !item.is_looted)
1080 {
1082 item.WriteBasicDataPart(slotType, fi->index, &itemBuff);
1083 ++itemsShown;
1084 }
1085 }
1086 }
1087
1088 QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = loot.GetPlayerNonQuestNonFFAConditionalItems();
1089 QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(viewer->GetGUIDLow());
1090 if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
1091 {
1092 QuestItemList* conditional_list = nn_itr->second;
1093 for (QuestItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci)
1094 {
1095 LootItem& item = loot.items[ci->index];
1096 if (!ci->is_looted && !item.is_looted)
1097 {
1098 LootSlotType finalSlotType = slotType;
1099
1100 if (item.follow_loot_rules)
1101 {
1102 switch (permission)
1103 {
1106 break;
1109 if (!item.is_blocked)
1111 else
1113 break;
1114 default:
1115 break;
1116 }
1117 }
1118
1119 item.WriteBitDataPart(permission, finalSlotType, data);
1120 item.WriteBasicDataPart(finalSlotType, ci->index, &itemBuff);
1121 ++itemsShown;
1122 }
1123 }
1124 }
1125 }
1126
1127 data->WriteBit(guid[1]);
1128 data->WriteBit(guid[0]);
1129
1130 // currency permission loop
1131
1132 data->WriteBit(lootGuid[5]);
1133 data->WriteBit(guid[3]);
1134 data->WriteBit(lootGuid[4]);
1135 data->WriteBit(1); // Missing unk8
1136 data->WriteBit(guid[2]);
1137
1138 data->FlushBits();
1139
1140 //update number of items and currencies shown
1141 data->PutBits(itemCountPos, itemsShown, 19);
1142 data->PutBits(currencyCountPos, currenciesShown, 20);
1143
1144 data->append(itemBuff);
1145
1146 data->WriteByteSeq(lootGuid[2]);
1147
1148 if (loot.gold)
1149 *data << uint32(loot.gold);
1150
1151 data->WriteByteSeq(lootGuid[7]);
1152 data->WriteByteSeq(guid[5]);
1153 data->WriteByteSeq(lootGuid[3]);
1154 data->WriteByteSeq(lootGuid[4]);
1155 *data << uint8(lootType);
1156 data->WriteByteSeq(guid[4]);
1157 data->WriteByteSeq(lootGuid[5]);
1158
1159 data->append(currencyBuff);
1160
1161 data->WriteByteSeq(guid[2]);
1162 data->WriteByteSeq(guid[3]);
1163 data->WriteByteSeq(lootGuid[1]);
1164 data->WriteByteSeq(guid[0]);
1165 data->WriteByteSeq(lootGuid[0]);
1166 data->WriteByteSeq(guid[6]);
1167 data->WriteByteSeq(guid[7]);
1168 data->WriteByteSeq(guid[1]);
1169 data->WriteByteSeq(lootGuid[6]);
1170}
1171
1172//
1173// --------- LootTemplate::LootGroup ---------
1174//
1175
1177{
1178 while (!ExplicitlyChanced.empty())
1179 {
1180 delete ExplicitlyChanced.back();
1181 ExplicitlyChanced.pop_back();
1182 }
1183
1184 while (!EqualChanced.empty())
1185 {
1186 delete EqualChanced.back();
1187 EqualChanced.pop_back();
1188 }
1189}
1190
1191// Adds an entry to the group (at loading stage)
1193{
1194 if (item->chance != 0)
1195 ExplicitlyChanced.push_back(item);
1196 else
1197 EqualChanced.push_back(item);
1198}
1199
1200// Rolls an item from the group, returns NULL if all miss their chances
1202{
1203 LootStoreItemList possibleLoot = ExplicitlyChanced;
1204 possibleLoot.remove_if(LootGroupInvalidSelector(loot, lootMode));
1205
1206 if (!possibleLoot.empty()) // First explicitly chanced entries are checked
1207 {
1208 float roll = (float)rand_chance();
1209
1210 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.
1211 {
1212 LootStoreItem* item = *itr;
1213 if (item->chance >= 100.0f)
1214 return item;
1215
1216 roll -= item->chance;
1217 if (roll < 0)
1218 return item;
1219 }
1220 }
1221
1222 possibleLoot = EqualChanced;
1223 possibleLoot.remove_if(LootGroupInvalidSelector(loot, lootMode));
1224 if (!possibleLoot.empty()) // If nothing selected yet - an item is taken from equal-chanced part
1226
1227 return NULL; // Empty drop from the group
1228}
1229
1230// True if group includes at least 1 quest drop entry
1232{
1233 for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
1234 if ((*i)->needs_quest)
1235 return true;
1236
1237 for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
1238 if ((*i)->needs_quest)
1239 return true;
1240
1241 return false;
1242}
1243
1244// True if group includes at least 1 quest drop entry for active quests of the player
1246{
1247 for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
1248 if (player->HasQuestForItem((*i)->itemid))
1249 return true;
1250
1251 for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
1252 if (player->HasQuestForItem((*i)->itemid))
1253 return true;
1254
1255 return false;
1256}
1257
1259{
1260 for (LootStoreItemList::iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
1261 (*i)->conditions.clear();
1262
1263 for (LootStoreItemList::iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
1264 (*i)->conditions.clear();
1265}
1266
1267// Rolls an item from the group (if any takes its chance) and adds the item to the loot
1269{
1270 if (LootStoreItem const* item = Roll(loot, lootMode))
1271 loot.AddItem(*item);
1272}
1273
1274// Overall chance for the group without equal chanced items
1276{
1277 float result = 0;
1278
1279 for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
1280 if (!(*i)->needs_quest)
1281 result += (*i)->chance;
1282
1283 return result;
1284}
1285
1286// Overall chance for the group
1288{
1289 float result = RawTotalChance();
1290
1291 if (!EqualChanced.empty() && result < 100.0f)
1292 return 100.0f;
1293
1294 return result;
1295}
1296
1297void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const
1298{
1299 float chance = RawTotalChance();
1300 if (chance > 101.0f)
1301 SF_LOG_ERROR("sql.sql", "Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore.GetName(), id, group_id, chance);
1302
1303 if (chance >= 100.0f && !EqualChanced.empty())
1304 SF_LOG_ERROR("sql.sql", "Table '%s' entry %u group %d has items with chance=0%% but group total chance >= 100%% (%f)", lootstore.GetName(), id, group_id, chance);
1305}
1306
1308{
1309 for (LootStoreItemList::const_iterator ieItr = ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
1310 {
1311 LootStoreItem* item = *ieItr;
1312 if (item->mincountOrRef < 0)
1313 {
1314 if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef))
1315 LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef);
1316 else if (ref_set)
1317 ref_set->erase(-item->mincountOrRef);
1318 }
1319 }
1320
1321 for (LootStoreItemList::const_iterator ieItr = EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
1322 {
1323 LootStoreItem* item = *ieItr;
1324 if (item->mincountOrRef < 0)
1325 {
1326 if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef))
1327 LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef);
1328 else if (ref_set)
1329 ref_set->erase(-item->mincountOrRef);
1330 }
1331 }
1332}
1333
1334//
1335// --------- LootTemplate ---------
1336//
1337
1339{
1340 for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
1341 delete* i;
1342
1343 for (size_t i = 0; i < Groups.size(); ++i)
1344 delete Groups[i];
1345}
1346
1347// Adds an entry to the group (at loading stage)
1349{
1350 if (item->group > 0 && item->mincountOrRef > 0) // Group
1351 {
1352 if (item->group >= Groups.size())
1353 Groups.resize(item->group, NULL); // Adds new group the the loot template if needed
1354 if (!Groups[item->group - 1])
1355 Groups[item->group - 1] = new LootGroup();
1356
1357 Groups[item->group - 1]->AddEntry(item); // Adds new entry to the group
1358 }
1359 else // Non-grouped entries and references are stored together
1360 Entries.push_back(item);
1361}
1362
1364{
1365 for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
1366 (*i)->conditions.clear();
1367
1368 for (LootGroups::iterator i = Groups.begin(); i != Groups.end(); ++i)
1369 if (LootGroup* group = *i)
1370 group->CopyConditions(conditions);
1371}
1372
1374{
1375 // Copies the conditions list from a template item to a LootItem
1376 for (LootStoreItemList::const_iterator _iter = Entries.begin(); _iter != Entries.end(); ++_iter)
1377 {
1378 LootStoreItem* item = *_iter;
1379 if (item->itemid != li->itemid)
1380 continue;
1381
1382 li->conditions = item->conditions;
1383 break;
1384 }
1385}
1386
1387// Rolls for every item in the template and adds the rolled items the the loot
1388void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId) const
1389{
1390 if (groupId) // Group reference uses own processing of the group
1391 {
1392 if (groupId > Groups.size())
1393 return; // Error message already printed at loading stage
1394
1395 if (!Groups[groupId - 1])
1396 return;
1397
1398 Groups[groupId - 1]->Process(loot, lootMode);
1399 return;
1400 }
1401
1402 // Rolling non-grouped items
1403 for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
1404 {
1405 LootStoreItem* item = *i;
1406 if (!(item->lootmode & lootMode)) // Do not add if mode mismatch
1407 continue;
1408
1409 if (!item->Roll(rate))
1410 continue; // Bad luck for the entry
1411
1412 if (item->mincountOrRef < 0) // References processing
1413 {
1414 LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-item->mincountOrRef);
1415 if (!Referenced)
1416 continue; // Error message already printed at loading stage
1417
1418 uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(Rates::RATE_DROP_ITEM_REFERENCED_AMOUNT));
1419 for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
1420 Referenced->Process(loot, rate, lootMode, item->group);
1421 }
1422 else // Plain entries (not a reference, not grouped)
1423 loot.AddItem(*item); // Chance is already checked, just add
1424 }
1425
1426 // Now processing groups
1427 for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
1428 if (LootGroup* group = *i)
1429 group->Process(loot, lootMode);
1430}
1431
1432// True if template includes at least 1 quest drop entry
1433bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) const
1434{
1435 if (groupId) // Group reference
1436 {
1437 if (groupId > Groups.size())
1438 return false; // Error message [should be] already printed at loading stage
1439
1440 if (!Groups[groupId - 1])
1441 return false;
1442
1443 return Groups[groupId - 1]->HasQuestDrop();
1444 }
1445
1446 for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
1447 {
1448 LootStoreItem* item = *i;
1449 if (item->mincountOrRef < 0) // References
1450 {
1451 LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef);
1452 if (Referenced == store.end())
1453 continue; // Error message [should be] already printed at loading stage
1454 if (Referenced->second->HasQuestDrop(store, item->group))
1455 return true;
1456 }
1457 else if (item->needs_quest)
1458 return true; // quest drop found
1459 }
1460
1461 // Now processing groups
1462 for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
1463 if (LootGroup* group = *i)
1464 if (group->HasQuestDrop())
1465 return true;
1466
1467 return false;
1468}
1469
1470// True if template includes at least 1 quest drop for an active quest of the player
1471bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player const* player, uint8 groupId) const
1472{
1473 if (groupId) // Group reference
1474 {
1475 if (groupId > Groups.size())
1476 return false; // Error message already printed at loading stage
1477
1478 if (!Groups[groupId - 1])
1479 return false;
1480
1481 return Groups[groupId - 1]->HasQuestDropForPlayer(player);
1482 }
1483
1484 // Checking non-grouped entries
1485 for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
1486 {
1487 LootStoreItem* item = *i;
1488 if (item->mincountOrRef < 0) // References processing
1489 {
1490 LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef);
1491 if (Referenced == store.end())
1492 continue; // Error message already printed at loading stage
1493 if (Referenced->second->HasQuestDropForPlayer(store, player, item->group))
1494 return true;
1495 }
1496 else if (player->HasQuestForItem(item->itemid))
1497 return true; // active quest drop found
1498 }
1499
1500 // Now checking groups
1501 for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
1502 if (LootGroup* group = *i)
1503 if (group->HasQuestDropForPlayer(player))
1504 return true;
1505
1506 return false;
1507}
1508
1509// Checks integrity of the template
1510void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const
1511{
1512 // Checking group chances
1513 for (uint32 i = 0; i < Groups.size(); ++i)
1514 if (Groups[i])
1515 Groups[i]->Verify(lootstore, id, i + 1);
1516
1518}
1519
1521{
1522 for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
1523 {
1524 LootStoreItem* item = *ieItr;
1525 if (item->mincountOrRef < 0)
1526 {
1527 if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef))
1528 LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef);
1529 else if (ref_set)
1530 ref_set->erase(-item->mincountOrRef);
1531 }
1532 }
1533
1534 for (LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
1535 if (LootGroup* group = *grItr)
1536 group->CheckLootRefs(store, ref_set);
1537}
1538
1540{
1541 if (!cond || !cond->isLoaded())//should never happen, checked at loading
1542 {
1543 SF_LOG_ERROR("loot", "LootTemplate::addConditionItem: condition is null");
1544 return false;
1545 }
1546
1547 if (!Entries.empty())
1548 {
1549 for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
1550 {
1551 if ((*i)->itemid == uint32(cond->SourceEntry))
1552 {
1553 (*i)->conditions.push_back(cond);
1554 return true;
1555 }
1556 }
1557 }
1558
1559 if (!Groups.empty())
1560 {
1561 for (LootGroups::iterator groupItr = Groups.begin(); groupItr != Groups.end(); ++groupItr)
1562 {
1563 LootGroup* group = *groupItr;
1564 if (!group)
1565 continue;
1566
1568 if (!itemList->empty())
1569 {
1570 for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
1571 {
1572 if ((*i)->itemid == uint32(cond->SourceEntry))
1573 {
1574 (*i)->conditions.push_back(cond);
1575 return true;
1576 }
1577 }
1578 }
1579
1580 itemList = group->GetEqualChancedItemList();
1581 if (!itemList->empty())
1582 {
1583 for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
1584 {
1585 if ((*i)->itemid == uint32(cond->SourceEntry))
1586 {
1587 (*i)->conditions.push_back(cond);
1588 return true;
1589 }
1590 }
1591 }
1592 }
1593 }
1594 return false;
1595}
1596
1598{
1599 for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
1600 if ((*ieItr)->itemid == id && (*ieItr)->mincountOrRef < 0)
1601 return true;
1602
1603 return false;//not found or not reference
1604}
1605
1607{
1608 SF_LOG_INFO("server.loading", "Loading creature loot templates...");
1609
1610 uint32 oldMSTime = getMSTime();
1611
1612 LootIdSet lootIdSet, lootIdSetUsed;
1613 uint32 count = LootTemplates_Creature.LoadAndCollectLootIds(lootIdSet);
1614
1615 // Remove real entries and check loot existence
1616 CreatureTemplateContainer const* ctc = sObjectMgr->GetCreatureTemplates();
1617 for (CreatureTemplateContainer::const_iterator itr = ctc->begin(); itr != ctc->end(); ++itr)
1618 {
1619 if (uint32 lootid = itr->second.lootid)
1620 {
1621 if (lootIdSet.find(lootid) == lootIdSet.end())
1622 LootTemplates_Creature.ReportNotExistedId(lootid);
1623 else
1624 lootIdSetUsed.insert(lootid);
1625 }
1626 }
1627
1628 for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr)
1629 lootIdSet.erase(*itr);
1630
1631 // output error for any still listed (not referenced from appropriate table) ids
1632 LootTemplates_Creature.ReportUnusedIds(lootIdSet);
1633
1634 if (count)
1635 SF_LOG_INFO("server.loading", ">> Loaded %u creature loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1636 else
1637 SF_LOG_ERROR("server.loading", ">> Loaded 0 creature loot templates. DB table `creature_loot_template` is empty");
1638}
1639
1641{
1642 SF_LOG_INFO("server.loading", "Loading disenchanting loot templates...");
1643
1644 uint32 oldMSTime = getMSTime();
1645
1646 LootIdSet lootIdSet, lootIdSetUsed;
1647 uint32 count = LootTemplates_Disenchant.LoadAndCollectLootIds(lootIdSet);
1648
1649 for (uint32 i = 0; i < sItemDisenchantLootStore.GetNumRows(); ++i)
1650 {
1651 ItemDisenchantLootEntry const* disenchant = sItemDisenchantLootStore.LookupEntry(i);
1652 if (!disenchant)
1653 continue;
1654
1655 uint32 lootid = disenchant->Id;
1656 if (lootIdSet.find(lootid) == lootIdSet.end())
1657 LootTemplates_Disenchant.ReportNotExistedId(lootid);
1658 else
1659 lootIdSetUsed.insert(lootid);
1660 }
1661
1662 for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr)
1663 lootIdSet.erase(*itr);
1664
1665 // output error for any still listed (not referenced from appropriate table) ids
1666 LootTemplates_Disenchant.ReportUnusedIds(lootIdSet);
1667
1668 if (count)
1669 SF_LOG_INFO("server.loading", ">> Loaded %u disenchanting loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1670 else
1671 SF_LOG_ERROR("server.loading", ">> Loaded 0 disenchanting loot templates. DB table `disenchant_loot_template` is empty");
1672}
1673
1675{
1676 SF_LOG_INFO("server.loading", "Loading fishing loot templates...");
1677
1678 uint32 oldMSTime = getMSTime();
1679
1680 LootIdSet lootIdSet;
1681 uint32 count = LootTemplates_Fishing.LoadAndCollectLootIds(lootIdSet);
1682
1683 // remove real entries and check existence loot
1684 for (uint32 i = 1; i < sAreaStore.GetNumRows(); ++i)
1685 if (AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
1686 if (lootIdSet.find(areaEntry->m_ID) != lootIdSet.end())
1687 lootIdSet.erase(areaEntry->m_ID);
1688
1689 // output error for any still listed (not referenced from appropriate table) ids
1690 LootTemplates_Fishing.ReportUnusedIds(lootIdSet);
1691
1692 if (count)
1693 SF_LOG_INFO("server.loading", ">> Loaded %u fishing loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1694 else
1695 SF_LOG_ERROR("server.loading", ">> Loaded 0 fishing loot templates. DB table `fishing_loot_template` is empty");
1696}
1697
1699{
1700 SF_LOG_INFO("server.loading", "Loading gameobject loot templates...");
1701
1702 uint32 oldMSTime = getMSTime();
1703
1704 LootIdSet lootIdSet, lootIdSetUsed;
1705 uint32 count = LootTemplates_Gameobject.LoadAndCollectLootIds(lootIdSet);
1706
1707 // remove real entries and check existence loot
1708 GameObjectTemplateContainer const* gotc = sObjectMgr->GetGameObjectTemplates();
1709 for (GameObjectTemplateContainer::const_iterator itr = gotc->begin(); itr != gotc->end(); ++itr)
1710 {
1711 if (uint32 lootid = itr->second.GetLootId())
1712 {
1713 if (lootIdSet.find(lootid) == lootIdSet.end())
1714 LootTemplates_Gameobject.ReportNotExistedId(lootid);
1715 else
1716 lootIdSetUsed.insert(lootid);
1717 }
1718 }
1719
1720 for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr)
1721 lootIdSet.erase(*itr);
1722
1723 // output error for any still listed (not referenced from appropriate table) ids
1724 LootTemplates_Gameobject.ReportUnusedIds(lootIdSet);
1725
1726 if (count)
1727 SF_LOG_INFO("server.loading", ">> Loaded %u gameobject loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1728 else
1729 SF_LOG_ERROR("server.loading", ">> Loaded 0 gameobject loot templates. DB table `gameobject_loot_template` is empty");
1730}
1731
1733{
1734 SF_LOG_INFO("server.loading", "Loading item loot templates...");
1735
1736 uint32 oldMSTime = getMSTime();
1737
1738 LootIdSet lootIdSet;
1739 uint32 count = LootTemplates_Item.LoadAndCollectLootIds(lootIdSet);
1740
1741 // remove real entries and check existence loot
1742 ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
1743 for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
1744 if (lootIdSet.find(itr->second.ItemId) != lootIdSet.end() && itr->second.Flags & ITEM_PROTO_FLAG_OPENABLE)
1745 lootIdSet.erase(itr->second.ItemId);
1746
1747 // output error for any still listed (not referenced from appropriate table) ids
1748 LootTemplates_Item.ReportUnusedIds(lootIdSet);
1749
1750 if (count)
1751 SF_LOG_INFO("server.loading", ">> Loaded %u item loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1752 else
1753 SF_LOG_ERROR("server.loading", ">> Loaded 0 item loot templates. DB table `item_loot_template` is empty");
1754}
1755
1757{
1758 SF_LOG_INFO("server.loading", "Loading milling loot templates...");
1759
1760 uint32 oldMSTime = getMSTime();
1761
1762 LootIdSet lootIdSet;
1763 uint32 count = LootTemplates_Milling.LoadAndCollectLootIds(lootIdSet);
1764
1765 // remove real entries and check existence loot
1766 ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
1767 for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
1768 {
1769 if (!(itr->second.Flags & ITEM_PROTO_FLAG_MILLABLE))
1770 continue;
1771
1772 if (lootIdSet.find(itr->second.ItemId) != lootIdSet.end())
1773 lootIdSet.erase(itr->second.ItemId);
1774 }
1775
1776 // output error for any still listed (not referenced from appropriate table) ids
1777 LootTemplates_Milling.ReportUnusedIds(lootIdSet);
1778
1779 if (count)
1780 SF_LOG_INFO("server.loading", ">> Loaded %u milling loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1781 else
1782 SF_LOG_ERROR("server.loading", ">> Loaded 0 milling loot templates. DB table `milling_loot_template` is empty");
1783}
1784
1786{
1787 SF_LOG_INFO("server.loading", "Loading pickpocketing loot templates...");
1788
1789 uint32 oldMSTime = getMSTime();
1790
1791 LootIdSet lootIdSet, lootIdSetUsed;
1792 uint32 count = LootTemplates_Pickpocketing.LoadAndCollectLootIds(lootIdSet);
1793
1794 // Remove real entries and check loot existence
1795 CreatureTemplateContainer const* ctc = sObjectMgr->GetCreatureTemplates();
1796 for (CreatureTemplateContainer::const_iterator itr = ctc->begin(); itr != ctc->end(); ++itr)
1797 {
1798 if (uint32 lootid = itr->second.pickpocketLootId)
1799 {
1800 if (lootIdSet.find(lootid) == lootIdSet.end())
1801 LootTemplates_Pickpocketing.ReportNotExistedId(lootid);
1802 else
1803 lootIdSetUsed.insert(lootid);
1804 }
1805 }
1806
1807 for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr)
1808 lootIdSet.erase(*itr);
1809
1810 // output error for any still listed (not referenced from appropriate table) ids
1811 LootTemplates_Pickpocketing.ReportUnusedIds(lootIdSet);
1812
1813 if (count)
1814 SF_LOG_INFO("server.loading", ">> Loaded %u pickpocketing loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1815 else
1816 SF_LOG_ERROR("server.loading", ">> Loaded 0 pickpocketing loot templates. DB table `pickpocketing_loot_template` is empty");
1817}
1818
1820{
1821 SF_LOG_INFO("server.loading", "Loading prospecting loot templates...");
1822
1823 uint32 oldMSTime = getMSTime();
1824
1825 LootIdSet lootIdSet;
1826 uint32 count = LootTemplates_Prospecting.LoadAndCollectLootIds(lootIdSet);
1827
1828 // remove real entries and check existence loot
1829 ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
1830 for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
1831 {
1832 if (!(itr->second.Flags & ITEM_PROTO_FLAG_PROSPECTABLE))
1833 continue;
1834
1835 if (lootIdSet.find(itr->second.ItemId) != lootIdSet.end())
1836 lootIdSet.erase(itr->second.ItemId);
1837 }
1838
1839 // output error for any still listed (not referenced from appropriate table) ids
1840 LootTemplates_Prospecting.ReportUnusedIds(lootIdSet);
1841
1842 if (count)
1843 SF_LOG_INFO("server.loading", ">> Loaded %u prospecting loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1844 else
1845 SF_LOG_ERROR("server.loading", ">> Loaded 0 prospecting loot templates. DB table `prospecting_loot_template` is empty");
1846}
1847
1849{
1850 SF_LOG_INFO("server.loading", "Loading mail loot templates...");
1851
1852 uint32 oldMSTime = getMSTime();
1853
1854 LootIdSet lootIdSet;
1855 uint32 count = LootTemplates_Mail.LoadAndCollectLootIds(lootIdSet);
1856
1857 // remove real entries and check existence loot
1858 for (uint32 i = 1; i < sMailTemplateStore.GetNumRows(); ++i)
1859 if (sMailTemplateStore.LookupEntry(i))
1860 lootIdSet.erase(i);
1861
1862 // output error for any still listed (not referenced from appropriate table) ids
1863 LootTemplates_Mail.ReportUnusedIds(lootIdSet);
1864
1865 if (count)
1866 SF_LOG_INFO("server.loading", ">> Loaded %u mail loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1867 else
1868 SF_LOG_ERROR("server.loading", ">> Loaded 0 mail loot templates. DB table `mail_loot_template` is empty");
1869}
1870
1872{
1873 SF_LOG_INFO("server.loading", "Loading skinning loot templates...");
1874
1875 uint32 oldMSTime = getMSTime();
1876
1877 LootIdSet lootIdSet, lootIdSetUsed;
1878 uint32 count = LootTemplates_Skinning.LoadAndCollectLootIds(lootIdSet);
1879
1880 // remove real entries and check existence loot
1881 CreatureTemplateContainer const* ctc = sObjectMgr->GetCreatureTemplates();
1882 for (CreatureTemplateContainer::const_iterator itr = ctc->begin(); itr != ctc->end(); ++itr)
1883 {
1884 if (uint32 lootid = itr->second.SkinLootId)
1885 {
1886 if (lootIdSet.find(lootid) == lootIdSet.end())
1887 LootTemplates_Skinning.ReportNotExistedId(lootid);
1888 else
1889 lootIdSetUsed.insert(lootid);
1890 }
1891 }
1892
1893 for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr)
1894 lootIdSet.erase(*itr);
1895
1896 // output error for any still listed (not referenced from appropriate table) ids
1897 LootTemplates_Skinning.ReportUnusedIds(lootIdSet);
1898
1899 if (count)
1900 SF_LOG_INFO("server.loading", ">> Loaded %u skinning loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1901 else
1902 SF_LOG_ERROR("server.loading", ">> Loaded 0 skinning loot templates. DB table `skinning_loot_template` is empty");
1903}
1904
1906{
1907 SF_LOG_INFO("server.loading", "Loading spell loot templates...");
1908
1909 uint32 oldMSTime = getMSTime();
1910
1911 LootIdSet lootIdSet;
1912 uint32 count = LootTemplates_Spell.LoadAndCollectLootIds(lootIdSet);
1913
1914 // remove real entries and check existence loot
1915 for (uint32 spell_id = 1; spell_id < sSpellMgr->GetSpellInfoStoreSize(); ++spell_id)
1916 {
1917 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
1918 if (!spellInfo)
1919 continue;
1920
1921 // possible cases
1922 if (!spellInfo->IsLootCrafting())
1923 continue;
1924
1925 if (lootIdSet.find(spell_id) == lootIdSet.end())
1926 {
1927 // not report about not trainable spells (optionally supported by DB)
1928 // ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
1929 if (!(spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR0_TRADESPELL))
1930 {
1931 LootTemplates_Spell.ReportNotExistedId(spell_id);
1932 }
1933 }
1934 else
1935 lootIdSet.erase(spell_id);
1936 }
1937
1938 // output error for any still listed (not referenced from appropriate table) ids
1939 LootTemplates_Spell.ReportUnusedIds(lootIdSet);
1940
1941 if (count)
1942 SF_LOG_INFO("server.loading", ">> Loaded %u spell loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1943 else
1944 SF_LOG_ERROR("server.loading", ">> Loaded 0 spell loot templates. DB table `spell_loot_template` is empty");
1945}
1946
1948{
1949 SF_LOG_INFO("server.loading", "Loading reference loot templates...");
1950
1951 uint32 oldMSTime = getMSTime();
1952
1953 LootIdSet lootIdSet;
1954 LootTemplates_Reference.LoadAndCollectLootIds(lootIdSet);
1955
1956 // check references and remove used
1957 LootTemplates_Creature.CheckLootRefs(&lootIdSet);
1958 LootTemplates_Fishing.CheckLootRefs(&lootIdSet);
1959 LootTemplates_Gameobject.CheckLootRefs(&lootIdSet);
1960 LootTemplates_Item.CheckLootRefs(&lootIdSet);
1961 LootTemplates_Milling.CheckLootRefs(&lootIdSet);
1962 LootTemplates_Pickpocketing.CheckLootRefs(&lootIdSet);
1963 LootTemplates_Skinning.CheckLootRefs(&lootIdSet);
1964 LootTemplates_Disenchant.CheckLootRefs(&lootIdSet);
1965 LootTemplates_Prospecting.CheckLootRefs(&lootIdSet);
1966 LootTemplates_Mail.CheckLootRefs(&lootIdSet);
1967 LootTemplates_Reference.CheckLootRefs(&lootIdSet);
1968
1969 // output error for any still listed ids (not referenced from any loot table)
1970 LootTemplates_Reference.ReportUnusedIds(lootIdSet);
1971
1972 SF_LOG_INFO("server.loading", ">> Loaded refence loot templates in %u ms", GetMSTimeDiffToNow(oldMSTime));
1973}
@ CHAR_DEL_ITEMCONTAINER_MONEY
@ CHAR_DEL_ITEMCONTAINER_ITEM
#define sConditionMgr
std::list< Condition * > ConditionList
UNORDERED_MAP< uint32, CreatureTemplate > CreatureTemplateContainer
Definition Creature.h:187
DBCStorage< AreaTableEntry > sAreaStore(AreaTableEntryfmt)
DBCStorage< MailTemplateEntry > sMailTemplateStore(MailTemplateEntryfmt)
DBCStorage< ItemDisenchantLootEntry > sItemDisenchantLootStore(ItemDisenchantLootfmt)
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
std::uint16_t uint16
Definition Define.h:78
UNORDERED_MAP< uint32, GameObjectTemplate > GameObjectTemplateContainer
Definition GameObject.h:529
uint32 GenerateEnchSuffixFactor(uint32 item_id)
UNORDERED_MAP< uint32, ItemTemplate > ItemTemplateContainer
@ ITEM_PROTO_FLAG_SMART_LOOT
@ ITEM_PROTO_FLAG_MILLABLE
@ ITEM_PROTO_FLAG_PROSPECTABLE
@ ITEM_PROTO_FLAG_PARTY_LOOT
@ ITEM_PROTO_FLAG_OPENABLE
@ ITEM_FLAGS_EXTRA_ALLIANCE_ONLY
@ ITEM_FLAGS_EXTRA_HORDE_ONLY
@ ITEM_FLAGS_CU_FOLLOW_LOOT_RULES
@ ITEM_FLAGS_CU_IGNORE_QUEST_STATUS
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
#define SF_LOG_INFO(filterType__,...)
Definition Log.h:137
LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false)
LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true)
LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject entry", true)
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)
static Rates const qualityToRate[MAX_ITEM_QUALITY]
Definition LootMgr.cpp:19
LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true)
LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket lootid", true)
LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false)
LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true)
void LoadLootTemplates_Pickpocketing()
Definition LootMgr.cpp:1785
PermissionTypes
Definition LootMgr.h:56
@ ROUND_ROBIN_PERMISSION
Definition LootMgr.h:60
void LoadLootTemplates_Spell()
Definition LootMgr.cpp:1905
void LoadLootTemplates_Milling()
Definition LootMgr.cpp:1756
void LoadLootTemplates_Gameobject()
Definition LootMgr.cpp:1698
#define MAX_NR_QUEST_ITEMS
Definition LootMgr.h:43
LootStore LootTemplates_Reference
void LoadLootTemplates_Creature()
Definition LootMgr.cpp:1606
std::map< uint32, QuestItemList * > QuestItemMap
Definition LootMgr.h:169
void LoadLootTemplates_Fishing()
Definition LootMgr.cpp:1674
LootSlotType
Definition LootMgr.h:82
@ LOOT_SLOT_TYPE_ROLL_ONGOING
Definition LootMgr.h:83
@ LOOT_SLOT_TYPE_MASTER
Definition LootMgr.h:85
@ LOOT_SLOT_TYPE_OWNER
Definition LootMgr.h:87
@ LOOT_SLOT_TYPE_ALLOW_LOOT
Definition LootMgr.h:86
void LoadLootTemplates_Reference()
Definition LootMgr.cpp:1947
void LoadLootTemplates_Prospecting()
Definition LootMgr.cpp:1819
void LoadLootTemplates_Mail()
Definition LootMgr.cpp:1848
void LoadLootTemplates_Disenchant()
Definition LootMgr.cpp:1640
#define MAX_NR_LOOT_ITEMS
Definition LootMgr.h:41
void LoadLootTemplates_Item()
Definition LootMgr.cpp:1732
@ ROUND_ROBIN
Definition LootMgr.h:49
@ GROUP_LOOT
Definition LootMgr.h:51
@ MASTER_LOOT
Definition LootMgr.h:50
std::set< uint32 > LootIdSet
Definition LootMgr.h:173
UNORDERED_MAP< uint32, LootTemplate * > LootTemplateMap
Definition LootMgr.h:171
std::list< LootStoreItem * > LootStoreItemList
Definition LootMgr.h:170
LootType
Definition LootMgr.h:66
void LoadLootTemplates_Skinning()
Definition LootMgr.cpp:1871
std::vector< QuestItem > QuestItemList
Definition LootMgr.h:167
#define sObjectMgr
Definition ObjectMgr.h:1617
Skyfire::AutoPtr< ResultSet, Skyfire::Mutex > QueryResult
Definition QueryResult.h:48
@ QUEST_STATUS_NONE
Definition QuestDef.h:86
@ SPELL_ATTR0_TRADESPELL
@ SPELL_ATTR0_NOT_SHAPESHIFT
#define MAX_ITEM_QUALITY
@ ALLIANCE
@ HORDE
#define sSpellMgr
Definition SpellMgr.h:744
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:22
uint32 getMSTime()
Definition Timer.h:12
#define SF_UNARY_FUNCTION
double rand_chance(void)
Definition Util.cpp:55
bool roll_chance_f(float chance)
Definition Util.h:83
bool WriteBit(uint32 bit)
Definition ByteBuffer.h:164
size_t bitwpos() const
Returns position of last written bit.
Definition ByteBuffer.h:492
void append(T value)
Definition ByteBuffer.h:147
void PutBits(size_t pos, T value, uint32 bitCount)
Definition ByteBuffer.h:283
void WriteBits(T value, size_t bits)
Definition ByteBuffer.h:192
void WriteByteSeq(uint8 b)
Definition ByteBuffer.h:227
void FlushBits()
Definition ByteBuffer.h:154
Definition Field.h:16
uint8 GetUInt8() const
Definition Field.h:26
uint16 GetUInt16() const
Definition Field.h:69
float GetFloat() const
Definition Field.h:177
uint32 GetUInt32() const
Definition Field.h:105
int32 GetInt32() const
Definition Field.h:123
Definition Group.h:147
ItemQualities GetLootThreshold() const
Definition Group.cpp:2598
LootMethod GetLootMethod() const
Definition Group.cpp:2588
GroupReference * GetFirstMember()
Definition Group.h:225
uint64 GetLooterGuid() const
Definition Group.cpp:2593
GroupReference * next()
static int32 GenerateItemRandomPropertyId(uint32 item_id)
Definition Item.cpp:575
uint32 LoadLootTable()
Definition LootMgr.cpp:116
uint32 LoadAndCollectLootIds(LootIdSet &ids_set)
Definition LootMgr.cpp:237
void ResetConditions()
Definition LootMgr.cpp:208
LootTemplate const * GetLootFor(uint32 loot_id) const
Definition LootMgr.cpp:217
LootTemplateMap m_LootTemplates
Definition LootMgr.h:205
char const * GetEntryName() const
Definition LootMgr.h:199
bool HaveQuestLootForPlayer(uint32 loot_id, Player *player) const
Definition LootMgr.cpp:198
void CheckLootRefs(LootIdSet *ref_set=NULL) const
Definition LootMgr.cpp:247
bool HaveQuestLootFor(uint32 loot_id) const
Definition LootMgr.cpp:188
LootTemplate * GetLootForConditionFill(uint32 loot_id)
Definition LootMgr.cpp:227
bool IsRatesAllowed() const
Definition LootMgr.h:200
void Clear()
Definition LootMgr.cpp:99
char const * GetName() const
Definition LootMgr.h:198
void ReportNotExistedId(uint32 id) const
Definition LootMgr.cpp:260
void ReportUnusedIds(LootIdSet const &ids_set) const
Definition LootMgr.cpp:253
void Verify() const
Definition LootMgr.cpp:108
LootGroup(LootGroup const &)
void CheckLootRefs(LootTemplateMap const &store, LootIdSet *ref_set) const
Definition LootMgr.cpp:1307
LootStoreItemList ExplicitlyChanced
Definition LootMgr.cpp:88
LootStoreItemList * GetEqualChancedItemList()
Definition LootMgr.cpp:85
void CollectLootIds(LootIdSet &set) const
LootStoreItemList EqualChanced
Definition LootMgr.cpp:89
void Verify(LootStore const &lootstore, uint32 id, uint8 group_id) const
Definition LootMgr.cpp:1297
void CopyConditions(ConditionList conditions)
Definition LootMgr.cpp:1258
LootStoreItemList * GetExplicitlyChancedItemList()
Definition LootMgr.cpp:84
float RawTotalChance() const
Definition LootMgr.cpp:1275
void AddEntry(LootStoreItem *item)
Definition LootMgr.cpp:1192
bool HasQuestDropForPlayer(Player const *player) const
Definition LootMgr.cpp:1245
LootGroup & operator=(LootGroup const &)
void Process(Loot &loot, uint16 lootMode) const
Definition LootMgr.cpp:1268
float TotalChance() const
Definition LootMgr.cpp:1287
LootStoreItem const * Roll(Loot &loot, uint16 lootMode) const
Definition LootMgr.cpp:1201
bool HasQuestDrop() const
Definition LootMgr.cpp:1231
void Process(Loot &loot, bool rate, uint16 lootMode, uint8 groupId=0) const
Definition LootMgr.cpp:1388
void CopyConditions(const ConditionList &conditions)
Definition LootMgr.cpp:1363
void CheckLootRefs(LootTemplateMap const &store, LootIdSet *ref_set) const
Definition LootMgr.cpp:1520
bool isReference(uint32 id)
Definition LootMgr.cpp:1597
void AddEntry(LootStoreItem *item)
Definition LootMgr.cpp:1348
bool HasQuestDropForPlayer(LootTemplateMap const &store, Player const *player, uint8 groupId=0) const
Definition LootMgr.cpp:1471
LootStoreItemList Entries
Definition LootMgr.h:239
void Verify(LootStore const &store, uint32 Id) const
Definition LootMgr.cpp:1510
LootGroups Groups
Definition LootMgr.h:240
bool HasQuestDrop(LootTemplateMap const &store, uint8 groupId=0) const
Definition LootMgr.cpp:1433
bool addConditionItem(Condition *cond)
Definition LootMgr.cpp:1539
static Player * FindPlayer(uint64)
uint64 GetGUID() const
Definition Object.h:119
uint32 GetGUIDLow() const
Definition Object.h:120
uint32 GetTeam() const
Definition Player.h:2527
bool HasQuestForItem(uint32 itemId) const
bool HasSkill(uint32 skill) const
Definition Player.cpp:6542
Group * GetGroup()
Definition Player.h:2972
void StoreLootItem(uint8 lootSlot, Loot *loot, uint64 lootGuid=0)
Definition Player.cpp:20681
QuestStatus GetQuestStatus(uint32 quest_id) const
bool HasSpell(uint32 spell) const override
Definition Player.cpp:4674
void setUInt32(const uint8 index, const uint32 value)
bool IsLootCrafting() const
uint32 Attributes
Definition SpellInfo.h:164
CharacterDatabaseWorkerPool CharacterDatabase
Accessor to the character database.
Definition Main.cpp:41
WorldDatabaseWorkerPool WorldDatabase
Accessor to the world database.
Definition Main.cpp:40
#define sWorld
Definition World.h:910
Rates
Server rates.
Definition World.h:375
@ RATE_DROP_ITEM_ARTIFACT
Definition World.h:393
@ RATE_DROP_ITEM_NORMAL
Definition World.h:388
@ RATE_DROP_ITEM_REFERENCED
Definition World.h:394
@ RATE_DROP_ITEM_LEGENDARY
Definition World.h:392
@ RATE_DROP_ITEM_REFERENCED_AMOUNT
Definition World.h:395
@ RATE_DROP_ITEM_POOR
Definition World.h:387
@ RATE_DROP_ITEM_RARE
Definition World.h:390
@ RATE_DROP_MONEY
Definition World.h:396
@ RATE_DROP_ITEM_UNCOMMON
Definition World.h:389
@ RATE_DROP_ITEM_EPIC
Definition World.h:391
C::value_type const & SelectRandomContainerElement(C const &container)
Definition Containers.h:48
int32 SpellId
bool isLoaded() const
int32 SourceEntry
uint32 Id
uint32 RequiredSkill
uint32 GetMaxStackSize() const
_Spell Spells[MAX_ITEM_PROTO_SPELLS]
bool operator()(LootStoreItem *item) const
Definition LootMgr.cpp:48
LootGroupInvalidSelector(Loot const &loot, uint16 lootMode)
Definition LootMgr.cpp:46
QuestItemList * FillQuestLoot(Player *player)
Definition LootMgr.cpp:523
uint32 GetMaxSlotInLootFor(Player *player) const
Definition LootMgr.cpp:776
QuestItemMap PlayerNonQuestNonFFAConditionalItems
Definition LootMgr.h:361
std::set< uint64 > PlayersLooting
Definition LootMgr.h:358
bool hasItemFor(Player *player) const
Definition LootMgr.cpp:783
bool hasOverThresholdItem() const
Definition LootMgr.cpp:828
bool FillLoot(uint32 lootId, LootStore const &store, Player *lootOwner, bool personal, bool noEmptyError=false, uint16 lootMode=LOOT_MODE_DEFAULT)
Definition LootMgr.cpp:418
void NotifyQuestItemRemoved(uint8 questIndex, ObjectGuid lootGuid=0)
Definition LootMgr.cpp:636
QuestItemMap PlayerQuestItems
Definition LootMgr.h:359
uint8 unlootedCount
Definition LootMgr.h:285
void AddItem(LootStoreItem const &item)
Definition LootMgr.cpp:390
uint64 roundRobinPlayer
Definition LootMgr.h:286
void NotifyMoneyRemoved(ObjectGuid lootGuid=0)
Definition LootMgr.cpp:618
void NotifyItemRemoved(uint8 lootIndex, ObjectGuid lootGuid=0)
Definition LootMgr.cpp:599
QuestItemList * FillNonQuestNonFFAConditionalLoot(Player *player, bool presentAtLooting)
Definition LootMgr.cpp:563
uint32 containerID
Definition LootMgr.h:292
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
Definition LootMgr.cpp:673
uint32 gold
Definition LootMgr.h:284
QuestItemMap PlayerFFAItems
Definition LootMgr.h:360
LootItem * LootItemInSlot(uint32 lootslot, Player *player, QuestItem **qitem=NULL, QuestItem **ffaitem=NULL, QuestItem **conditem=NULL)
Definition LootMgr.cpp:713
QuestItemMap const & GetPlayerQuestItems() const
Definition LootMgr.h:278
void DeleteLootItemFromContainerItemDB(uint32 itemID)
Definition LootMgr.cpp:686
std::vector< LootItem > items
Definition LootMgr.h:282
QuestItemMap const & GetPlayerFFAItems() const
Definition LootMgr.h:279
QuestItemList * FillFFALoot(Player *player)
Definition LootMgr.cpp:500
QuestItemMap const & GetPlayerNonQuestNonFFAConditionalItems() const
Definition LootMgr.h:280
void DeleteLootMoneyFromContainerItemDB()
Definition LootMgr.cpp:705
void FillNotNormalLootFor(Player *player, bool presentAtLooting)
Definition LootMgr.cpp:462
std::vector< LootItem > quest_items
Definition LootMgr.h:283
uint32 itemid
Definition LootMgr.h:120
AllowedLooterSet allowedGUIDs
Definition LootMgr.h:124
bool is_blocked
Definition LootMgr.h:127
bool canSave
Definition LootMgr.h:133
void AddAllowedLooter(Player const *player)
Definition LootMgr.cpp:380
bool needs_quest
Definition LootMgr.h:131
bool follow_loot_rules
Definition LootMgr.h:132
void WriteBitDataPart(PermissionTypes permission, LootSlotType hasSlotType, ByteBuffer *buff)
Definition LootMgr.cpp:839
bool is_underthreshold
Definition LootMgr.h:129
int32 randomPropertyId
Definition LootMgr.h:122
uint8 count
Definition LootMgr.h:125
bool is_looted
Definition LootMgr.h:126
bool AllowedForPlayer(Player const *player) const
Definition LootMgr.cpp:352
LootItem()
Definition LootMgr.h:140
void WriteBasicDataPart(LootSlotType slotType, uint8 slot, ByteBuffer *buff)
Definition LootMgr.cpp:849
ConditionList conditions
Definition LootMgr.h:123
bool freeforall
Definition LootMgr.h:128
uint32 randomSuffix
Definition LootMgr.h:121
bool is_counted
Definition LootMgr.h:130
float chance
Definition LootMgr.h:96
int32 mincountOrRef
Definition LootMgr.h:97
uint8 group
Definition LootMgr.h:99
bool Roll(bool rate) const
Definition LootMgr.cpp:271
bool needs_quest
Definition LootMgr.h:100
uint32 itemid
Definition LootMgr.h:95
ConditionList conditions
Definition LootMgr.h:102
uint8 maxcount
Definition LootMgr.h:101
uint16 lootmode
Definition LootMgr.h:98
bool IsValid(LootStore const &store, uint32 entry) const
Definition LootMgr.cpp:287
void WriteData(ObjectGuid guid, LootType lootType, WorldPacket *data, bool isAoE=false)
Definition LootMgr.cpp:866
PermissionTypes permission
Definition LootMgr.h:371
Loot & loot
Definition LootMgr.h:369
Player * viewer
Definition LootMgr.h:370
uint8 index
Definition LootMgr.h:154
bool is_looted
Definition LootMgr.h:155