OregonCore  revision 3611e8a-git
Your Favourite TBC server
LootMgr.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore 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 "Log.h"
20 #include "ObjectMgr.h"
21 #include "World.h"
22 #include "Util.h"
23 #include "SharedDefines.h"
24 
25 static Rates const qualityToRate[MAX_ITEM_QUALITY] =
26 {
27  RATE_DROP_ITEM_POOR, // ITEM_QUALITY_POOR
28  RATE_DROP_ITEM_NORMAL, // ITEM_QUALITY_NORMAL
29  RATE_DROP_ITEM_UNCOMMON, // ITEM_QUALITY_UNCOMMON
30  RATE_DROP_ITEM_RARE, // ITEM_QUALITY_RARE
31  RATE_DROP_ITEM_EPIC, // ITEM_QUALITY_EPIC
32  RATE_DROP_ITEM_LEGENDARY, // ITEM_QUALITY_LEGENDARY
33  RATE_DROP_ITEM_ARTIFACT, // ITEM_QUALITY_ARTIFACT
34 };
35 
36 LootStore LootTemplates_Creature( "creature_loot_template", "creature entry" );
37 LootStore LootTemplates_Disenchant( "disenchant_loot_template", "item disenchant id" );
38 LootStore LootTemplates_Fishing( "fishing_loot_template", "area id" );
39 LootStore LootTemplates_Gameobject( "gameobject_loot_template", "gameobject entry" );
40 LootStore LootTemplates_Item( "item_loot_template", "item entry" );
41 LootStore LootTemplates_Mail( "mail_loot_template", "mail template id" );
42 LootStore LootTemplates_Pickpocketing( "pickpocketing_loot_template", "creature pickpocket lootid" );
43 LootStore LootTemplates_Prospecting( "prospecting_loot_template", "item entry (ore)" );
44 LootStore LootTemplates_Reference( "reference_loot_template", "reference id" );
45 LootStore LootTemplates_Skinning( "skinning_loot_template", "creature skinning id" );
46 
47 class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed)
48 {
49  public:
50  void AddEntry(LootStoreItem& item); // Adds an entry to the group (at loading stage)
51  bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
52  bool HasQuestDropForPlayer(Player const* player) const;
53  // The same for active quests of the player
54  void Process(Loot& loot) const; // Rolls an item from the group (if any) and adds the item to the loot
55  float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
56  float TotalChance() const; // Overall chance for the group
57 
58  void Verify(LootStore const& lootstore, uint32 id, uint32 group_id) const;
59  void CollectLootIds(LootIdSet& set) const;
60  void CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const;
63  void CopyConditions(ConditionList conditions);
64  private:
65  LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
66  LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
67 
68  LootStoreItem const* Roll() const; // Rolls an item from the group, returns NULL if all miss their chances
69 };
70 
71 //Remove all data and free all memory
73 {
74  for (LootTemplateMap::const_iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
75  delete itr->second;
76  m_LootTemplates.clear();
77 }
78 
79 // Checks validity of the loot store
80 // Actual checks are done within LootTemplate::Verify() which is called for every template
81 void LootStore::Verify() const
82 {
83  for (LootTemplateMap::const_iterator i = m_LootTemplates.begin(); i != m_LootTemplates.end(); ++i)
84  i->second->Verify(*this, i->first);
85 }
86 
87 // Loads a *_loot_template DB table into loot store
88 // All checks of the loaded template are called from here, no error reports at loot generation required
90 {
91  LootTemplateMap::iterator tab;
92  uint64 count = 0;
93 
94  // Clearing store (for reloading case)
95  Clear();
96 
97  // 0 1 2 3 4 5 6
98  QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT Entry, Item, Reference, Chance, QuestRequired, GroupId, MinCount, MaxCount FROM %s", GetName());
99 
100  if (result)
101  {
102  do
103  {
104  Field* fields = result->Fetch();
105 
106  uint32 entry = fields[0].GetUInt32();
107  uint32 item = fields[1].GetUInt32();
108  uint32 reference = fields[2].GetUInt32();
109  float chance = fields[3].GetFloat();
110  bool needsquest = fields[4].GetBool();
111  uint8 groupid = fields[5].GetUInt8();
112  int32 mincount = fields[6].GetUInt8();
113  int32 maxcount = fields[7].GetUInt8();
114 
115  LootStoreItem storeitem = LootStoreItem(item, reference, chance, needsquest, groupid, mincount, maxcount);
116 
117  if (!storeitem.IsValid(*this, entry)) // Validity checks
118  continue;
119 
120  // Looking for the template of the entry
121  // often entries are put together
122  if (m_LootTemplates.empty() || tab->first != entry)
123  {
124  // Searching the template (in case template Id changed)
125  tab = m_LootTemplates.find(entry);
126  if (tab == m_LootTemplates.end())
127  {
128  std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate));
129  tab = pr.first;
130  }
131  }
132  // else is empty - template Id and iter are the same
133  // finally iter refers to already existed or just created <entry, LootTemplate>
134 
135  // Adds current row to the template
136  tab->second->AddEntry(storeitem);
137  ++count;
138 
139  }
140  while (result->NextRow());
141 
142  Verify(); // Checks validity of the loot store
143 
144  sLog.outString(">> Loaded " UI64FMTD " loot definitions (%lu templates)", count, m_LootTemplates.size());
145  }
146  else
147  sLog.outErrorDb(">> Loaded 0 loot definitions. DB table %s is empty.", GetName());
148 }
149 
151 {
152  LootTemplateMap::const_iterator itr = m_LootTemplates.find(loot_id);
153  if (itr == m_LootTemplates.end())
154  return false;
155 
156  // scan loot for quest items
157  return itr->second->HasQuestDrop(m_LootTemplates);
158 }
159 
160 bool LootStore::HaveQuestLootForPlayer(uint32 loot_id, Player* player) const
161 {
162  LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
163  if (tab != m_LootTemplates.end())
164  if (tab->second->HasQuestDropForPlayer(m_LootTemplates, player))
165  return true;
166 
167  return false;
168 }
169 
171 {
172  for (LootTemplateMap::iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
173  {
174  ConditionList empty;
175  (*itr).second->CopyConditions(empty);
176  }
177 }
178 
180 {
181  LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
182 
183  if (tab == m_LootTemplates.end())
184  return NULL;
185 
186  return tab->second;
187 }
188 
190 {
191  LootTemplateMap::iterator tab = m_LootTemplates.find(loot_id);
192 
193  if (tab == m_LootTemplates.end())
194  return NULL;
195 
196  return tab->second;
197 }
198 
200 {
201  LoadLootTable();
202 
203  for (LootTemplateMap::const_iterator tab = m_LootTemplates.begin(); tab != m_LootTemplates.end(); ++tab)
204  ids_set.insert(tab->first);
205 }
206 
208 {
209  for (LootTemplateMap::const_iterator ltItr = m_LootTemplates.begin(); ltItr != m_LootTemplates.end(); ++ltItr)
210  ltItr->second->CheckLootRefs(m_LootTemplates, ref_set);
211 }
212 
213 void LootStore::ReportUnusedIds(LootIdSet const& ids_set) const
214 {
215  // all still listed ids isn't referenced
216  for (LootIdSet::const_iterator itr = ids_set.begin(); itr != ids_set.end(); ++itr)
217  sLog.outErrorDb("Table '%s' Entry %d isn't %s and not referenced from loot, and then useless.", GetName(), *itr, GetEntryName());
218 }
219 
221 {
222  sLog.outErrorDb("Table '%s' Entry %d (%s) not exist but used as loot id in DB.", GetName(), id, GetEntryName());
223 }
224 
225 //
226 // --------- LootStoreItem ---------
227 //
228 
229 // Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
230 // RATE_DROP_ITEMS is no longer used for all types of entries
232 {
233  if (chance >= 100.f)
234  return true;
235 
236  if (reference > 0) // reference case
237  return roll_chance_f(chance * sWorld.getRate(RATE_DROP_ITEM_REFERENCED));
238 
239  ItemTemplate const* pProto = sObjectMgr.GetItemTemplate(itemid);
240 
241  float qualityModifier = pProto ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
242 
243  return roll_chance_f(chance * qualityModifier);
244 }
245 
246 // Checks correctness of values
247 bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
248 {
249  if (mincount == 0)
250  {
251  sLog.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincount);
252  return false;
253  }
254 
255  if (reference == 0) // item (quest or non-quest) entry, maybe grouped
256  {
257  ItemTemplate const* proto = sObjectMgr.GetItemTemplate(itemid);
258  if (!proto)
259  {
260  sLog.outErrorDb("Table '%s' Entry %d Item %d: item entry not listed in item_template - skipped", store.GetName(), entry, itemid);
261  return false;
262  }
263 
264  if (chance == 0 && groupid == 0) // Zero chance is allowed for grouped entries only
265  {
266  sLog.outErrorDb("Table '%s' Entry %d Item %d: equal-chanced grouped entry, but group not defined - skipped", store.GetName(), entry, itemid);
267  return false;
268  }
269 
270  if (chance != 0 && chance < 0.000001f) // loot with low chance
271  {
272  sLog.outErrorDb("Table '%s' Entry %d Item %d: low chance (%f) - skipped",
273  store.GetName(), entry, itemid, chance);
274  return false;
275  }
276 
277  if (maxcount < mincount) // wrong max count
278  {
279  sLog.outErrorDb("Table '%s' Entry %d Item %d: MaxCount (%u) less that MinCount (%i) - skipped",
280  store.GetName(), entry, itemid, int32(maxcount), mincount);
281  return false;
282  }
283  }
284  else // if reference loot
285  {
286  if (needs_quest)
287  sLog.outErrorDb("Table '%s' Entry %d Item %d: quest required will be ignored", store.GetName(), entry, itemid);
288  else if (chance == 0) // no chance for the reference
289  {
290  sLog.outErrorDb("Table '%s' Entry %d Item %d: zero chance is specified for a reference, skipped", store.GetName(), entry, itemid);
291  return false;
292  }
293  }
294  return true; // Referenced template existence is checked at whole store level
295 }
296 
297 //
298 // --------- LootItem ---------
299 //
300 
301 // Constructor, copies most fields from LootStoreItem and generates random count
303 {
304  itemid = li.itemid;
305  conditions = li.conditions;
306 
307  ItemTemplate const* proto = sObjectMgr.GetItemTemplate(itemid);
308  freeforall = proto && (proto->Flags & ITEM_PROTO_FLAG_MULTI_DROP);
309 
310  needs_quest = li.needs_quest;
311 
312  count = urand(li.mincount, li.maxcount); // constructor called for mincountOrRef > 0 only
313  randomSuffix = GenerateEnchSuffixFactor(itemid);
314  randomPropertyId = Item::GenerateItemRandomPropertyId(itemid);
315  is_looted = 0;
316  is_blocked = 0;
317  is_underthreshold = 0;
318  is_counted = 0;
319 }
320 
321 // Basic checks for player/item compatibility - if false no chance to see the item in the loot
322 bool LootItem::AllowedForPlayer(Player const* player) const
323 {
324  // DB conditions check
325  if (!sConditionMgr.IsObjectMeetToConditions(const_cast<Player*>(player), conditions))
326  return false;
327 
328  ItemTemplate const* pProto = sObjectMgr.GetItemTemplate(itemid);
329  if (!pProto)
330  return false;
331 
332  // not show loot for players without profession or those who already know the recipe
333  if ((pProto->Flags & ITEM_PROTO_FLAG_SMART_LOOT) && (!player->HasSkill(pProto->RequiredSkill) || player->HasSpell(pProto->Spells[1].SpellId)))
334  return false;
335 
336  // check quest requirements
337  if (((needs_quest || (pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE)) && !player->HasQuestForItem(itemid)))
338  return false;
339 
340  return true;
341 }
342 
343 //
344 // --------- Loot ---------
345 //
346 
347 // Inserts the item into the loot (called by LootTemplate processors)
348 void Loot::AddItem(LootStoreItem const& item)
349 {
350  ItemTemplate const* proto = sObjectMgr.GetItemTemplate(item.itemid);
351  if (!proto)
352  return;
353 
354  if (item.needs_quest) // Quest drop
355  {
356  if (quest_items.size() < MAX_NR_QUEST_ITEMS)
357  quest_items.push_back(LootItem(item));
358  }
359  else if (items.size() < MAX_NR_LOOT_ITEMS) // Non-quest drop
360  {
361  items.push_back(LootItem(item));
362 
363  // non-conditional one-player only items are counted here,
364  // free for all items are counted in FillFFALoot(),
365  // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
366  if (item.conditions.empty())
367  {
368  if ((proto->Flags & ITEM_PROTO_FLAG_MULTI_DROP) == 0)
369  ++unlootedCount;
370  }
371  }
372 }
373 
374 // Calls processor of corresponding LootTemplate (which handles everything including references)
375 void Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner, bool personal)
376 {
377  // Must be provided
378  if (!loot_owner)
379  return;
380 
381  LootTemplate const* tab = store.GetLootFor(loot_id);
382 
383  if (!tab)
384  {
385  sLog.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.", store.GetName(), loot_id);
386  return;
387  }
388 
389  items.reserve(MAX_NR_LOOT_ITEMS);
390  quest_items.reserve(MAX_NR_QUEST_ITEMS);
391 
392  tab->Process(*this, store); // Processing is done there, callback via Loot::AddItem()
393 
394  Group* group = loot_owner->GetGroup();
395  if (!personal && group)
396  {
397  roundRobinPlayer = loot_owner->GetGUID();
398 
399  for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
400  if (Player* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter
401  if (player->IsInMap(loot_owner))
402  FillNotNormalLootFor(player);
403 
404  for (uint8 i = 0; i < items.size(); ++i)
405  {
406  if (ItemTemplate const* proto = sObjectMgr.GetItemTemplate(items[i].itemid))
407  if (proto->Quality < uint32(group->GetLootThreshold()))
408  items[i].is_underthreshold = true;
409  }
410  }
411  // ... for personal loot
412  else
413  FillNotNormalLootFor(loot_owner);
414 }
415 
417 {
418  uint32 plguid = player->GetGUIDLow();
419 
420  QuestItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid);
421  if (qmapitr == PlayerQuestItems.end())
422  FillQuestLoot(player);
423 
424  qmapitr = PlayerFFAItems.find(plguid);
425  if (qmapitr == PlayerFFAItems.end())
426  FillFFALoot(player);
427 
428  qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
429  if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
430  FillNonQuestNonFFAConditionalLoot(player);
431 
432  // Process currency items
433  uint32 max_slot = GetMaxSlotInLootFor(player);
434  LootItem const* item = NULL;
435  uint32 itemsSize = uint32(items.size());
436  for (uint32 i = 0; i < max_slot; ++i)
437  {
438  if (i < items.size())
439  item = &items[i];
440  else
441  item = &quest_items[i-itemsSize];
442  }
443 }
444 
446 {
447  QuestItemList* ql = new QuestItemList();
448 
449  for (uint8 i = 0; i < items.size(); i++)
450  {
451  LootItem& item = items[i];
452  if (!item.is_looted && item.freeforall && item.AllowedForPlayer(player))
453  {
454  ql->push_back(QuestItem(i));
455  ++unlootedCount;
456  }
457  }
458  if (ql->empty())
459  {
460  delete ql;
461  return NULL;
462  }
463 
464  PlayerFFAItems[player->GetGUIDLow()] = ql;
465  return ql;
466 }
467 
469 {
470  if (items.size() == MAX_NR_LOOT_ITEMS)
471  return NULL;
472 
473  QuestItemList* ql = new QuestItemList();
474 
475  for (uint8 i = 0; i < quest_items.size(); i++)
476  {
477  LootItem& item = quest_items[i];
478  if (!item.is_looted && item.AllowedForPlayer(player))
479  {
480  ql->push_back(QuestItem(i));
481 
482  // quest items get blocked when they first appear in a
483  // player's quest vector
484  //
485  // increase once if one looter only, looter-times if free for all
486  if (item.freeforall || !item.is_blocked)
487  ++unlootedCount;
488  if (!player->GetGroup() || (player->GetGroup()->GetLootMethod() != GROUP_LOOT && player->GetGroup()->GetLootMethod() != ROUND_ROBIN))
489  item.is_blocked = true;
490 
491  if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS)
492  break;
493  }
494  }
495  if (ql->empty())
496  {
497  delete ql;
498  return NULL;
499  }
500 
501  PlayerQuestItems[player->GetGUIDLow()] = ql;
502  return ql;
503 }
504 
506 {
507  QuestItemList* ql = new QuestItemList();
508 
509  for (uint8 i = 0; i < items.size(); ++i)
510  {
511  LootItem& item = items[i];
512  if (!item.is_looted && !item.freeforall && !item.conditions.empty() && item.AllowedForPlayer(player))
513  {
514  ql->push_back(QuestItem(i));
515  if (!item.is_counted)
516  {
517  ++unlootedCount;
518  item.is_counted = true;
519  }
520  }
521  }
522  if (ql->empty())
523  {
524  delete ql;
525  return NULL;
526  }
527 
528  PlayerNonQuestNonFFAConditionalItems[player->GetGUIDLow()] = ql;
529  return ql;
530 }
531 
532 //===================================================
533 
535 {
536  // notify all players that are looting this that the item was removed
537  // convert the index to the slot the player sees
538  std::set<uint64>::iterator i_next;
539  for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
540  {
541  i_next = i;
542  ++i_next;
543  if (Player* player = ObjectAccessor::FindPlayer(*i))
544  player->SendNotifyLootItemRemoved(lootIndex);
545  else
546  PlayersLooting.erase(i);
547  }
548 }
549 
551 {
552  // notify all players that are looting this that the money was removed
553  std::set<uint64>::iterator i_next;
554  for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
555  {
556  i_next = i;
557  ++i_next;
558  if (Player* player = ObjectAccessor::FindPlayer(*i))
559  player->SendNotifyLootMoneyRemoved();
560  else
561  PlayersLooting.erase(i);
562  }
563 }
564 
566 {
567  // when a free for all questitem is looted
568  // all players will get notified of it being removed
569  // (other questitems can be looted by each group member)
570  // bit inefficient but isn't called often
571 
572  std::set<uint64>::iterator i_next;
573  for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
574  {
575  i_next = i;
576  ++i_next;
577  if (Player* player = ObjectAccessor::FindPlayer(*i))
578  {
579  QuestItemMap::const_iterator pq = PlayerQuestItems.find(player->GetGUIDLow());
580  if (pq != PlayerQuestItems.end() && pq->second)
581  {
582  // find where/if the player has the given item in it's vector
583  QuestItemList& pql = *pq->second;
584 
585  uint8 j;
586  for (j = 0; j < pql.size(); ++j)
587  if (pql[j].index == questIndex)
588  break;
589 
590  if (j < pql.size())
591  player->SendNotifyLootItemRemoved(items.size()+j);
592  }
593  }
594  else
595  PlayersLooting.erase(i);
596  }
597 }
598 
599 void Loot::generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
600 {
601  if (maxAmount > 0)
602  {
603  if (maxAmount <= minAmount)
604  gold = uint32(maxAmount * sWorld.getRate(RATE_DROP_MONEY));
605  else if ((maxAmount - minAmount) < 32700)
606  gold = uint32(urand(minAmount, maxAmount) * sWorld.getRate(RATE_DROP_MONEY));
607  else
608  gold = uint32(urand(minAmount >> 8, maxAmount >> 8) * sWorld.getRate(RATE_DROP_MONEY)) << 8;
609  }
610 }
611 
612 LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem** qitem, QuestItem** ffaitem, QuestItem** conditem)
613 {
614  LootItem* item = NULL;
615  bool is_looted = true;
616  if (lootSlot >= items.size())
617  {
618  uint32 questSlot = lootSlot - items.size();
619  QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
620  if (itr != PlayerQuestItems.end() && questSlot < itr->second->size())
621  {
622  QuestItem* qitem2 = &itr->second->at(questSlot);
623  if (qitem)
624  *qitem = qitem2;
625  item = &quest_items[qitem2->index];
626  is_looted = qitem2->is_looted;
627  }
628  }
629  else
630  {
631  item = &items[lootSlot];
632  is_looted = item->is_looted;
633  if (item->freeforall)
634  {
635  QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUIDLow());
636  if (itr != PlayerFFAItems.end())
637  {
638  for (QuestItemList::iterator iter = itr->second->begin(); iter != itr->second->end(); ++iter)
639  if (iter->index == lootSlot)
640  {
641  QuestItem* ffaitem2 = (QuestItem*) & (*iter);
642  if (ffaitem)
643  *ffaitem = ffaitem2;
644  is_looted = ffaitem2->is_looted;
645  break;
646  }
647  }
648  }
649  else if (!item->conditions.empty())
650  {
651  QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
652  if (itr != PlayerNonQuestNonFFAConditionalItems.end())
653  {
654  for (QuestItemList::iterator iter = itr->second->begin(); iter != itr->second->end(); ++iter)
655  {
656  if (iter->index == lootSlot)
657  {
658  QuestItem* conditem2 = (QuestItem*) & (*iter);
659  if (conditem)
660  *conditem = conditem2;
661  is_looted = conditem2->is_looted;
662  break;
663  }
664  }
665  }
666  }
667  }
668 
669  if (is_looted)
670  return NULL;
671 
672  return item;
673 }
674 
676 {
677  QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
678  return items.size() + (itr != PlayerQuestItems.end() ? itr->second->size() : 0);
679 }
680 
681 // return true if there is any item that is lootable for any player (not quest item, FFA or conditional)
683 {
684  // Gold is always lootable
685  if (gold)
686  return true;
687 
688  for (LootItem const& item : items)
689  if (!item.is_looted && !item.freeforall && item.conditions.empty())
690  return true;
691  return false;
692 }
693 
694 // return true if there is any FFA, quest or conditional item for the player.
695 bool Loot::hasItemFor(Player* player) const
696 {
697  QuestItemMap const& lootPlayerQuestItems = GetPlayerQuestItems();
698  QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(player->GetGUIDLow());
699  if (q_itr != lootPlayerQuestItems.end())
700  {
701  QuestItemList* q_list = q_itr->second;
702  for (QuestItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi)
703  {
704  const LootItem &item = quest_items[qi->index];
705  if (!qi->is_looted && !item.is_looted)
706  return true;
707  }
708  }
709 
710  QuestItemMap const& lootPlayerFFAItems = GetPlayerFFAItems();
711  QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(player->GetGUIDLow());
712  if (ffa_itr != lootPlayerFFAItems.end())
713  {
714  QuestItemList* ffa_list = ffa_itr->second;
715  for (QuestItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi)
716  {
717  const LootItem &item = items[fi->index];
718  if (!fi->is_looted && !item.is_looted)
719  return true;
720  }
721  }
722 
723  QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems();
724  QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
725  if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
726  {
727  QuestItemList* conditional_list = nn_itr->second;
728  for (QuestItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci)
729  {
730  const LootItem &item = items[ci->index];
731  if (!ci->is_looted && !item.is_looted)
732  return true;
733  }
734  }
735 
736  return false;
737 }
738 
739 // return true if there is any item over the group threshold (i.e. not underthreshold).
741 {
742  for (uint8 i = 0; i < items.size(); ++i)
743  {
744  if (!items[i].is_looted && !items[i].is_underthreshold && !items[i].freeforall)
745  return true;
746  }
747 
748  return false;
749 }
750 
752 {
753  b << uint32(li.itemid);
754  b << uint32(li.count); // nr of items of this type
755  b << uint32(sObjectMgr.GetItemTemplate(li.itemid)->DisplayInfoID);
756  b << uint32(li.randomSuffix);
757  b << uint32(li.randomPropertyId);
758  //b << uint8(0); // slot type - will send after this function call
759  return b;
760 }
761 
763 {
764  if (lv.permission == NONE_PERMISSION)
765  {
766  b << uint32(0); // gold
767  b << uint8(0); // item count
768  return b;
769  }
770 
771  Loot &l = lv.loot;
772 
773  uint8 itemsShown = 0;
774 
775  b << uint32(l.gold); //gold
776 
777  size_t count_pos = b.wpos(); // pos of item count byte
778  b << uint8(0); // item count placeholder
779 
780  switch (lv.permission)
781  {
782  case GROUP_PERMISSION:
783  case MASTER_PERMISSION:
785  {
786  // if you are not the round-robin group looter, you can only see
787  // blocked rolled items and quest items, and !ffa items
788  for (uint8 i = 0; i < l.items.size(); ++i)
789  {
790  if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer))
791  {
792  uint8 slot_type;
793 
794  if (l.items[i].is_blocked) // for ML & restricted is_blocked = !is_underthreshold
795  {
796  switch (lv.permission)
797  {
798  case GROUP_PERMISSION:
799  slot_type = LOOT_SLOT_TYPE_ROLL_ONGOING;
800  break;
801  case MASTER_PERMISSION:
802  {
803  if (lv.viewer->GetGroup() && lv.viewer->GetGroup()->GetMasterLooterGuid() == lv.viewer->GetGUID())
804  slot_type = LOOT_SLOT_TYPE_MASTER;
805  else
806  slot_type = LOOT_SLOT_TYPE_LOCKED;
807  break;
808  }
810  slot_type = LOOT_SLOT_TYPE_LOCKED;
811  break;
812  default:
813  continue;
814  }
815  }
816  else if (!l.roundRobinPlayer || lv.viewer->GetGUID() == l.roundRobinPlayer || !l.items[i].is_underthreshold)
817  {
818  // no round robin owner or he has released the loot
819  // or it IS the round robin group owner
820  // => item is lootable
821  slot_type = LOOT_SLOT_TYPE_ALLOW_LOOT;
822  }
823  else
824  // item shall not be displayed.
825  continue;
826 
827  b << uint8(i) << l.items[i];
828  b << uint8(slot_type);
829  ++itemsShown;
830  }
831  }
832  break;
833  }
835  {
836  for (uint8 i = 0; i < l.items.size(); ++i)
837  {
838  if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer))
839  {
840  if (l.roundRobinPlayer && lv.viewer->GetGUID() != l.roundRobinPlayer)
841  // item shall not be displayed.
842  continue;
843 
844  b << uint8(i) << l.items[i];
846  ++itemsShown;
847  }
848  }
849  break;
850  }
851  case ALL_PERMISSION:
852  case OWNER_PERMISSION:
853  {
855  for (uint8 i = 0; i < l.items.size(); ++i)
856  {
857  if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer))
858  {
859  b << uint8(i) << l.items[i];
860  b << uint8(slot_type);
861  ++itemsShown;
862  }
863  }
864  break;
865  }
866  default:
867  return b;
868  }
869 
871  QuestItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems();
872  QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUIDLow());
873  if (q_itr != lootPlayerQuestItems.end())
874  {
875  QuestItemList* q_list = q_itr->second;
876  for (QuestItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi)
877  {
878  LootItem &item = l.quest_items[qi->index];
879  if (!qi->is_looted && !item.is_looted)
880  {
881  b << uint8(l.items.size() + (qi - q_list->begin()));
882  b << item;
883  b << uint8(slotType);
884  ++itemsShown;
885  }
886  }
887  }
888 
889  QuestItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems();
890  QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUIDLow());
891  if (ffa_itr != lootPlayerFFAItems.end())
892  {
893  QuestItemList* ffa_list = ffa_itr->second;
894  for (QuestItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi)
895  {
896  LootItem &item = l.items[fi->index];
897  if (!fi->is_looted && !item.is_looted)
898  {
899  b << uint8(fi->index);
900  b << item;
901  b << uint8(slotType);
902  ++itemsShown;
903  }
904  }
905  }
906 
907  QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems();
908  QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUIDLow());
909  if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
910  {
911  QuestItemList* conditional_list = nn_itr->second;
912  for (QuestItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci)
913  {
914  LootItem &item = l.items[ci->index];
915  if (!ci->is_looted && !item.is_looted)
916  {
917  b << uint8(ci->index);
918  b << item;
919  b << uint8(slotType);
920  ++itemsShown;
921  }
922  }
923  }
924 
925  //update number of items shown
926  b.put<uint8>(count_pos, itemsShown);
927 
928  return b;
929 }
930 
931 //
932 // --------- LootTemplate::LootGroup ---------
933 //
934 
935 // Adds an entry to the group (at loading stage)
937 {
938  if (item.chance != 0)
939  ExplicitlyChanced.push_back(item);
940  else
941  EqualChanced.push_back(item);
942 }
943 
944 // Rolls an item from the group, returns NULL if all miss their chances
946 {
947  if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked
948  {
949  float roll = (float)rand_chance();
950 
951  for (uint32 i = 0; i < ExplicitlyChanced.size(); ++i) //check each explicitly chanced entry in the template and modify its chance based on quality.
952  {
953  if (ExplicitlyChanced[i].chance >= 100.f)
954  return &ExplicitlyChanced[i];
955 
956  roll -= ExplicitlyChanced[i].chance;
957  if (roll < 0)
958  return &ExplicitlyChanced[i];
959  }
960  }
961  if (!EqualChanced.empty()) // If nothing selected yet - an item is taken from equal-chanced part
962  return &EqualChanced[irand(0, EqualChanced.size() - 1)];
963 
964  return NULL; // Empty drop from the group
965 }
966 
967 // True if group includes at least 1 quest drop entry
969 {
970  for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
971  if (i->needs_quest)
972  return true;
973 
974  for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
975  if (i->needs_quest)
976  return true;
977 
978  return false;
979 }
980 
981 // True if group includes at least 1 quest drop entry for active quests of the player
983 {
984  for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
985  if (player->HasQuestForItem(i->itemid))
986  return true;
987 
988  for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
989  if (player->HasQuestForItem(i->itemid))
990  return true;
991 
992  return false;
993 }
994 
996 {
997  for (LootStoreItemList::iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
998  i->conditions.clear();
999 
1000  for (LootStoreItemList::iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
1001  i->conditions.clear();
1002 }
1003 
1004 // Rolls an item from the group (if any takes its chance) and adds the item to the loot
1006 {
1007  LootStoreItem const* item = Roll();
1008  if (item != NULL)
1009  loot.AddItem(*item);
1010 }
1011 
1012 // Overall chance for the group without equal chanced items
1014 {
1015  float result = 0;
1016 
1017  for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
1018  if (!i->needs_quest)
1019  result += i->chance;
1020 
1021  return result;
1022 }
1023 
1024 // Overall chance for the group
1026 {
1027  float result = RawTotalChance();
1028 
1029  if (!EqualChanced.empty() && result < 100.0f)
1030  return 100.0f;
1031 
1032  return result;
1033 }
1034 
1035 void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint32 group_id) const
1036 {
1037  float chance = RawTotalChance();
1038  if (chance > 101.0f) // @todo replace with 100% when DBs will be ready
1039  sLog.outErrorDb("Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore.GetName(), id, group_id, chance);
1040 
1041  if (chance >= 100.0f && !EqualChanced.empty())
1042  sLog.outErrorDb("Table '%s' entry %u group %d has items with chance=0%% but group total chance >= 100%% (%f)", lootstore.GetName(), id, group_id, chance);
1043 }
1044 
1046 {
1047  for (LootStoreItemList::const_iterator ieItr = ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
1048  {
1049  if (ieItr->reference > 0)
1050  {
1051  if (!LootTemplates_Reference.GetLootFor(ieItr->reference))
1052  LootTemplates_Reference.ReportNonExistingId(ieItr->reference);
1053  else if (ref_set)
1054  ref_set->erase(ieItr->reference);
1055  }
1056  }
1057 
1058  for (LootStoreItemList::const_iterator ieItr = EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
1059  {
1060  if (ieItr->reference > 0)
1061  {
1062  if (!LootTemplates_Reference.GetLootFor(ieItr->reference))
1063  LootTemplates_Reference.ReportNonExistingId(ieItr->reference);
1064  else if (ref_set)
1065  ref_set->erase(ieItr->reference);
1066  }
1067  }
1068 }
1069 
1070 //
1071 // --------- LootTemplate ---------
1072 //
1073 
1074 // Adds an entry to the group (at loading stage)
1076 {
1077  if (item.groupid > 0 && item.reference == 0) // Group
1078  {
1079  if (item.groupid >= Groups.size())
1080  Groups.resize(item.groupid); // Adds new group the the loot template if needed
1081  Groups[item.groupid - 1].AddEntry(item); // Adds new entry to the group
1082  }
1083  else // Non-grouped entries and references are stored together
1084  Entries.push_back(item);
1085 }
1086 
1088 {
1089  for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
1090  i->conditions.clear();
1091 
1092  for (LootGroups::iterator i = Groups.begin(); i != Groups.end(); ++i)
1093  i->CopyConditions(conditions);
1094 }
1095 
1096 // Rolls for every item in the template and adds the rolled items the the loot
1097 void LootTemplate::Process(Loot& loot, LootStore const& store, uint8 groupId) const
1098 {
1099  if (groupId) // Group reference uses own processing of the group
1100  {
1101  if (groupId > Groups.size())
1102  return; // Error message already printed at loading stage
1103 
1104  Groups[groupId - 1].Process(loot);
1105  return;
1106  }
1107 
1108  // Rolling non-grouped items
1109  for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i)
1110  {
1111  if (!i->Roll())
1112  continue; // Bad luck for the entry
1113 
1114  if (i->reference > 0) // References processing
1115  {
1116  LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(i->reference);
1117 
1118  if (!Referenced)
1119  continue; // Error message already printed at loading stage
1120 
1121  for (uint32 loop = 0; loop < i->maxcount; ++loop) // Ref multiplicator
1122  Referenced->Process(loot, store, i->groupid); // Ref processing
1123  }
1124  else // Plain entries (not a reference, not grouped)
1125  loot.AddItem(*i); // Chance is already checked, just add
1126  }
1127 
1128  // Now processing groups
1129  for (LootGroups::const_iterator i = Groups.begin() ; i != Groups.end() ; ++i)
1130  i->Process(loot);
1131 }
1132 
1133 // True if template includes at least 1 quest drop entry
1134 bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) const
1135 {
1136  if (groupId) // Group reference
1137  {
1138  if (groupId > Groups.size())
1139  return false; // Error message [should be] already printed at loading stage
1140  return Groups[groupId - 1].HasQuestDrop();
1141  }
1142 
1143  for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
1144  {
1145  if (i->reference > 0) // References
1146  {
1147  LootTemplateMap::const_iterator Referenced = store.find(i->reference);
1148  if (Referenced == store.end())
1149  continue; // Error message [should be] already printed at loading stage
1150  if (Referenced->second->HasQuestDrop(store, i->groupid))
1151  return true;
1152  }
1153  else if (i->needs_quest)
1154  return true; // quest drop found
1155  }
1156 
1157  // Now processing groups
1158  for (LootGroups::const_iterator i = Groups.begin() ; i != Groups.end() ; ++i)
1159  if (i->HasQuestDrop())
1160  return true;
1161 
1162  return false;
1163 }
1164 
1165 // True if template includes at least 1 quest drop for an active quest of the player
1166 bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player const* player, uint8 groupId) const
1167 {
1168  if (groupId) // Group reference
1169  {
1170  if (groupId > Groups.size())
1171  return false; // Error message already printed at loading stage
1172  return Groups[groupId - 1].HasQuestDropForPlayer(player);
1173  }
1174 
1175  // Checking non-grouped entries
1176  for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i)
1177  {
1178  if (i->reference > 0) // References processing
1179  {
1180  LootTemplateMap::const_iterator Referenced = store.find(i->reference);
1181  if (Referenced == store.end())
1182  continue; // Error message already printed at loading stage
1183  if (Referenced->second->HasQuestDropForPlayer(store, player, i->groupid))
1184  return true;
1185  }
1186  else if (player->HasQuestForItem(i->itemid))
1187  return true; // active quest drop found
1188  }
1189 
1190  // Now checking groups
1191  for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
1192  if (i->HasQuestDropForPlayer(player))
1193  return true;
1194 
1195  return false;
1196 }
1197 
1198 // Checks integrity of the template
1199 void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const
1200 {
1201  // Checking group chances
1202  for (uint32 i = 0; i < Groups.size(); ++i)
1203  Groups[i].Verify(lootstore, id, i + 1);
1204 
1206 }
1207 
1208 void LootTemplate::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const
1209 {
1210  for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
1211  {
1212  if (ieItr->reference > 0)
1213  {
1214  if (!LootTemplates_Reference.GetLootFor(ieItr->reference))
1215  LootTemplates_Reference.ReportNonExistingId(ieItr->reference);
1216 
1217  else if (ref_set)
1218  ref_set->erase(ieItr->reference);
1219  }
1220  }
1221 
1222  for (LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
1223  grItr->CheckLootRefs(store, ref_set);
1224 }
1225 
1227 {
1228  if (!cond || !cond->isLoaded())//should never happen, checked at loading
1229  {
1230  sLog.outError("LootTemplate::addConditionItem: condition is null");
1231  return false;
1232  }
1233 
1234  if (!Entries.empty())
1235  {
1236  for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
1237  {
1238  if (i->itemid == uint32(cond->SourceEntry))
1239  {
1240  i->conditions.push_back(cond);
1241  return true;
1242  }
1243  }
1244  }
1245 
1246  if (!Groups.empty())
1247  {
1248  for (LootGroups::iterator groupItr = Groups.begin(); groupItr != Groups.end(); ++groupItr)
1249  {
1250  LootStoreItemList* itemList = (*groupItr).GetExplicitlyChancedItemList();
1251  if (!itemList->empty())
1252  {
1253  for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
1254  {
1255  if ((*i).itemid == uint32(cond->SourceEntry))
1256  {
1257  (*i).conditions.push_back(cond);
1258  return true;
1259  }
1260  }
1261  }
1262  itemList = (*groupItr).GetEqualChancedItemList();
1263  if (!itemList->empty())
1264  {
1265  for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
1266  {
1267  if ((*i).itemid == uint32(cond->SourceEntry))
1268  {
1269  (*i).conditions.push_back(cond);
1270  return true;
1271  }
1272  }
1273  }
1274  }
1275  }
1276  return false;
1277 }
1278 
1280 {
1281  for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
1282  if (ieItr->itemid == id && ieItr->reference > 0)
1283  return true;
1284 
1285  return false;//not found or not reference
1286 }
1287 
1289 {
1290  LootIdSet ids_set, ids_setUsed;
1292 
1293  // remove real entries and check existence loot
1294  for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
1295  {
1296  if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1297  {
1298  if (uint32 lootid = cInfo->lootid)
1299  {
1300  if (ids_set.find(lootid) == ids_set.end())
1302  else
1303  ids_setUsed.insert(lootid);
1304  }
1305  }
1306  }
1307  for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1308  ids_set.erase(*itr);
1309 
1310  // output error for any still listed (not referenced from appropriate table) ids
1312 }
1313 
1315 {
1316  LootIdSet ids_set, ids_setUsed;
1318 
1319  // remove real entries and check existence loot
1320  for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
1321  {
1322  if (ItemTemplate const* proto = sItemStorage.LookupEntry<ItemTemplate>(i))
1323  {
1324  if (uint32 lootid = proto->DisenchantID)
1325  {
1326  if (ids_set.find(lootid) == ids_set.end())
1328  else
1329  ids_setUsed.insert(lootid);
1330  }
1331  }
1332  }
1333  for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1334  ids_set.erase(*itr);
1335  // output error for any still listed (not referenced from appropriate table) ids
1337 }
1338 
1340 {
1341  LootIdSet ids_set;
1343 
1344  // remove real entries and check existence loot
1345  for (uint32 i = 1; i < sAreaStore.GetNumRows(); ++i)
1346  if (AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
1347  if (ids_set.find(areaEntry->ID) != ids_set.end())
1348  ids_set.erase(areaEntry->ID);
1349 
1350  // output error for any still listed (not referenced from appropriate table) ids
1352 }
1353 
1355 {
1356  LootIdSet ids_set, ids_setUsed;
1358 
1359  // remove real entries and check existence loot
1360  for (uint32 i = 1; i < sGOStorage.MaxEntry; ++i)
1361  {
1362  if (GameObjectInfo const* gInfo = sGOStorage.LookupEntry<GameObjectInfo>(i))
1363  {
1364  if (uint32 lootid = gInfo->GetLootId())
1365  {
1366  if (ids_set.find(lootid) == ids_set.end())
1368  else
1369  ids_setUsed.insert(lootid);
1370  }
1371  }
1372  }
1373  for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1374  ids_set.erase(*itr);
1375 
1376  // output error for any still listed (not referenced from appropriate table) ids
1378 }
1379 
1381 {
1382  LootIdSet ids_set;
1384 
1385  // remove real entries and check existence loot
1386  for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
1387  if (ItemTemplate const* proto = sItemStorage.LookupEntry<ItemTemplate>(i))
1388  if (ids_set.find(proto->ItemId) != ids_set.end() && proto->Flags & ITEM_PROTO_FLAG_HAS_LOOT)
1389  ids_set.erase(proto->ItemId);
1390 
1391  // output error for any still listed (not referenced from appropriate table) ids
1393 }
1394 
1396 {
1397  LootIdSet ids_set, ids_setUsed;
1399 
1400  // remove real entries and check existence loot
1401  for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
1402  {
1403  if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1404  {
1405  if (uint32 lootid = cInfo->pickpocketLootId)
1406  {
1407  if (ids_set.find(lootid) == ids_set.end())
1409  else
1410  ids_setUsed.insert(lootid);
1411  }
1412  }
1413  }
1414  for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1415  ids_set.erase(*itr);
1416 
1417  // output error for any still listed (not referenced from appropriate table) ids
1419 }
1420 
1422 {
1423  LootIdSet ids_set;
1425 
1426  // remove real entries and check existence loot
1427  for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
1428  if (ItemTemplate const* proto = sItemStorage.LookupEntry<ItemTemplate>(i))
1429  if (ids_set.find(proto->ItemId) != ids_set.end())
1430  ids_set.erase(proto->ItemId);
1431 
1432  // output error for any still listed (not referenced from appropriate table) ids
1434 }
1435 
1437 {
1438  LootIdSet ids_set;
1440 
1441  // remove real entries and check existence loot
1442  ObjectMgr::QuestMap const& questMap = sObjectMgr.GetQuestTemplates();
1443  for (ObjectMgr::QuestMap::const_iterator itr = questMap.begin(); itr != questMap.end(); ++itr)
1444  if (uint32 mail_template_id = itr->second->GetRewMailTemplateId())
1445  if (ids_set.find(mail_template_id) != ids_set.end())
1446  ids_set.erase(mail_template_id);
1447 
1448  // output error for any still listed (not referenced from appropriate table) ids
1450 }
1451 
1453 {
1454  LootIdSet ids_set, ids_setUsed;
1456 
1457  // remove real entries and check existence loot
1458  for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
1459  {
1460  if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1461  {
1462  if (uint32 lootid = cInfo->SkinLootId)
1463  {
1464  if (ids_set.find(lootid) == ids_set.end())
1466  else
1467  ids_setUsed.insert(lootid);
1468  }
1469  }
1470  }
1471  for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1472  ids_set.erase(*itr);
1473 
1474  // output error for any still listed (not referenced from appropriate table) ids
1476 }
1477 
1479 {
1480  LootIdSet ids_set;
1482 
1483  // check references and remove used
1494 
1495  // output error for any still listed ids (not referenced from any loot table)
1497 }
1498 
ConditionList conditions
Definition: LootMgr.h:129
#define MAX_NR_LOOT_ITEMS
Definition: LootMgr.h:29
void ResetConditions()
Definition: LootMgr.cpp:170
bool is_counted
Definition: LootMgr.h:135
void LoadLootTemplates_Creature()
Definition: LootMgr.cpp:1288
Group * GetGroup()
Definition: Player.h:2589
uint8 maxcount
Definition: LootMgr.h:110
void LoadLootTable()
Definition: LootMgr.cpp:89
LootStoreItemList EqualChanced
Definition: LootMgr.cpp:66
SQLStorage sCreatureStorage
Rates
Definition: World.h:270
void CheckLootRefs(LootTemplateMap const &store, LootIdSet *ref_set) const
Definition: LootMgr.cpp:1045
LootItem * LootItemInSlot(uint32 lootslot, Player *player, QuestItem **qitem=NULL, QuestItem **ffaitem=NULL, QuestItem **conditem=NULL)
Definition: LootMgr.cpp:612
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition: Player.cpp:13641
void LoadLootTemplates_Reference()
Definition: LootMgr.cpp:1478
LootItem(LootStoreItem const &li)
Definition: LootMgr.cpp:302
uint32 GetMaxSlotInLootFor(Player *player) const
Definition: LootMgr.cpp:675
bool freeforall
Definition: LootMgr.h:133
uint32 RequiredSkill
bool isReference(uint32 id)
Definition: LootMgr.cpp:1279
DatabaseType WorldDatabase
Accessor to the world database.
Definition: Main.cpp:53
bool is_looted
Definition: LootMgr.h:149
void Process(Loot &loot) const
Definition: LootMgr.cpp:1005
_Spell Spells[5]
void Verify(LootStore const &lootstore, uint32 id, uint32 group_id) const
Definition: LootMgr.cpp:1035
bool hasItemForAll() const
Definition: LootMgr.cpp:682
QueryResult_AutoPtr PQuery(const char *format,...) ATTR_PRINTF(2
Definition: Database.cpp:400
bool HasSkill(uint32 skill) const
Definition: Player.cpp:5536
LootStoreItemList ExplicitlyChanced
Definition: LootMgr.cpp:65
std::list< Condition * > ConditionList
Definition: ConditionMgr.h:223
Definition: Field.h:24
void ReportNonExistingId(uint32 id) const
Definition: LootMgr.cpp:220
void ReportUnusedIds(LootIdSet const &ids_set) const
Definition: LootMgr.cpp:213
float chance
Definition: LootMgr.h:106
LootStore LootTemplates_Gameobject("gameobject_loot_template","gameobject entry")
bool HasQuestForItem(uint32 itemid) const
Definition: Player.cpp:14081
void LoadLootTemplates_Pickpocketing()
Definition: LootMgr.cpp:1395
std::map< uint32, QuestItemList * > QuestItemMap
Definition: LootMgr.h:162
LootStoreItemList Entries
Definition: LootMgr.h:236
int32 irand(int32 min, int32 max)
Definition: Util.cpp:66
LootGroups Groups
Definition: LootMgr.h:237
bool roll_chance_f(float chance)
Definition: Util.h:67
#define sLog
Log class singleton.
Definition: Log.h:187
LootTemplate * GetLootForConditionFill(uint32 loot_id)
Definition: LootMgr.cpp:189
bool is_blocked
Definition: LootMgr.h:132
uint32 randomSuffix
Definition: LootMgr.h:127
ACE_INT32 int32
Definition: Define.h:67
std::vector< LootStoreItem > LootStoreItemList
Definition: LootMgr.h:163
#define MAX_ITEM_QUALITY
void LoadLootTemplates_Prospecting()
Definition: LootMgr.cpp:1421
uint32 itemid
Definition: LootMgr.h:103
uint32 SpellId
int32 SourceEntry
Definition: ConditionMgr.h:183
bool HasQuestDrop(LootTemplateMap const &store, uint8 GroupId=0) const
Definition: LootMgr.cpp:1134
float TotalChance() const
Definition: LootMgr.cpp:1025
void CheckLootRefs(LootTemplateMap const &store, LootIdSet *ref_set) const
Definition: LootMgr.cpp:1208
uint8 groupid
Definition: LootMgr.h:108
uint32 GetGUIDLow() const
Definition: Object.h:160
ConditionList conditions
Definition: LootMgr.h:111
bool isLoaded()
Definition: ConditionMgr.h:217
LootStore LootTemplates_Creature("creature_loot_template","creature entry")
bool is_looted
Definition: LootMgr.h:131
#define sObjectMgr
Definition: ObjectMgr.h:1285
void AddEntry(LootStoreItem &item)
Definition: LootMgr.cpp:936
bool HasQuestDropForPlayer(LootTemplateMap const &store, Player const *player, uint8 GroupId=0) const
Definition: LootMgr.cpp:1166
bool needs_quest
Definition: LootMgr.h:107
ItemQualities GetLootThreshold() const
Definition: Group.h:241
LootSlotType
Definition: LootMgr.h:88
void NotifyItemRemoved(uint8 lootIndex)
Definition: LootMgr.cpp:534
void LoadLootTemplates_Gameobject()
Definition: LootMgr.cpp:1354
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
Definition: LootMgr.cpp:599
bool HasSpell(uint32 spell) const override
Definition: Player.cpp:3813
LootTemplate const * GetLootFor(uint32 loot_id) const
Definition: LootMgr.cpp:179
PermissionTypes permission
Definition: LootMgr.h:404
int32 randomPropertyId
Definition: LootMgr.h:128
void FillLoot(uint32 loot_id, LootStore const &store, Player *loot_owner, bool personal)
Definition: LootMgr.cpp:375
QuestItemMap const & GetPlayerNonQuestNonFFAConditionalItems() const
Definition: LootMgr.h:302
void NotifyQuestItemRemoved(uint8 questIndex)
Definition: LootMgr.cpp:565
void Verify() const
Definition: LootMgr.cpp:81
bool HaveQuestLootForPlayer(uint32 loot_id, Player *player) const
Definition: LootMgr.cpp:160
size_t wpos() const
Definition: ByteBuffer.h:264
QuestItemMap const & GetPlayerQuestItems() const
Definition: LootMgr.h:294
QuestItemList * FillQuestLoot(Player *player)
Definition: LootMgr.cpp:468
ACE_UINT8 uint8
Definition: Define.h:73
#define UI64FMTD
Definition: Common.h:149
double rand_chance(void)
Definition: Util.cpp:91
uint64 GetMasterLooterGuid() const
Definition: Group.h:240
static int32 GenerateItemRandomPropertyId(uint32 item_id)
Definition: Item.cpp:569
QuestItemList * FillNonQuestNonFFAConditionalLoot(Player *player)
Definition: LootMgr.cpp:505
void LoadLootTemplates_Skinning()
Definition: LootMgr.cpp:1452
void FillNotNormalLootFor(Player *player)
Definition: LootMgr.cpp:416
Definition: LootMgr.h:290
uint8 index
Definition: LootMgr.h:148
void LoadLootTemplates_Item()
Definition: LootMgr.cpp:1380
void Verify(LootStore const &store, uint32 Id) const
Definition: LootMgr.cpp:1199
void put(size_t pos, T value)
Definition: ByteBuffer.h:79
void NotifyMoneyRemoved()
Definition: LootMgr.cpp:550
bool Roll() const
Definition: LootMgr.cpp:231
LootStore LootTemplates_Prospecting("prospecting_loot_template","item entry (ore)")
bool AllowedForPlayer(Player const *player) const
Definition: LootMgr.cpp:322
uint64 roundRobinPlayer
Definition: LootMgr.h:311
float RawTotalChance() const
Definition: LootMgr.cpp:1013
static Player * FindPlayer(uint64, bool force=false)
LootStore LootTemplates_Mail("mail_loot_template","mail template id")
void CheckLootRefs(LootIdSet *ref_set=NULL) const
Definition: LootMgr.cpp:207
void CopyConditions(ConditionList conditions)
Definition: LootMgr.cpp:1087
#define sConditionMgr
Definition: ConditionMgr.h:312
GroupReference * GetFirstMember()
Definition: Group.h:304
std::set< uint32 > LootIdSet
Definition: LootMgr.h:166
LootStore LootTemplates_Item("item_loot_template","item entry")
ByteBuffer & operator<<(ByteBuffer &b, LootItem const &li)
Definition: LootMgr.cpp:751
void Process(Loot &loot, LootStore const &store, uint8 GroupId=0) const
Definition: LootMgr.cpp:1097
Player * viewer
Definition: LootMgr.h:403
LootStoreItemList * GetEqualChancedItemList()
Definition: LootMgr.cpp:62
LootStoreItemList * GetExplicitlyChancedItemList()
Definition: LootMgr.cpp:61
SQLStorage sItemStorage
void CollectLootIds(LootIdSet &set) const
uint8 mincount
Definition: LootMgr.h:109
GroupReference * next()
char const * GetName() const
Definition: LootMgr.h:195
void Clear()
Definition: LootMgr.cpp:72
LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template","creature pickpocket lootid")
UNORDERED_MAP< uint32, Quest * > QuestMap
Definition: ObjectMgr.h:530
uint32 gold
Definition: LootMgr.h:309
void AddItem(LootStoreItem const &item)
Definition: LootMgr.cpp:348
LootStore LootTemplates_Reference("reference_loot_template","reference id")
ACE_UINT64 uint64
Definition: Define.h:70
bool IsValid(LootStore const &store, uint32 entry) const
Definition: LootMgr.cpp:247
T const * LookupEntry(uint32 id) const
Definition: SQLStorage.h:52
bool hasItemFor(Player *player) const
Definition: LootMgr.cpp:695
LootStore LootTemplates_Fishing("fishing_loot_template","area id")
std::vector< LootItem > items
Definition: LootMgr.h:307
UNORDERED_MAP< uint32, LootTemplate * > LootTemplateMap
Definition: LootMgr.h:164
ACE_Refcounted_Auto_Ptr< QueryResult, ACE_Null_Mutex > QueryResult_AutoPtr
Definition: QueryResult.h:113
bool HasQuestDrop() const
Definition: LootMgr.cpp:968
std::vector< QuestItem > QuestItemList
Definition: LootMgr.h:159
bool HasQuestDropForPlayer(Player const *player) const
Definition: LootMgr.cpp:982
bool hasOverThresholdItem() const
Definition: LootMgr.cpp:740
QuestItemMap const & GetPlayerFFAItems() const
Definition: LootMgr.h:298
LootMethod GetLootMethod() const
Definition: Group.h:230
void LoadLootTemplates_Fishing()
Definition: LootMgr.cpp:1339
void LoadAndCollectLootIds(LootIdSet &ids_set)
Definition: LootMgr.cpp:199
#define sWorld
Definition: World.h:860
uint8 count
Definition: LootMgr.h:130
Loot & loot
Definition: LootMgr.h:402
SQLStorage sGOStorage
uint32 MaxEntry
Definition: SQLStorage.h:62
uint32 GenerateEnchSuffixFactor(uint32 item_id)
ACE_UINT32 uint32
Definition: Define.h:71
LootStore LootTemplates_Skinning("skinning_loot_template","creature skinning id")
QuestItemList * FillFFALoot(Player *player)
Definition: LootMgr.cpp:445
void AddEntry(LootStoreItem &item)
Definition: LootMgr.cpp:1075
LootStore LootTemplates_Disenchant("disenchant_loot_template","item disenchant id")
uint32 itemid
Definition: LootMgr.h:126
Definition: Player.h:922
bool addConditionItem(Condition *cond)
Definition: LootMgr.cpp:1226
void LoadLootTemplates_Disenchant()
Definition: LootMgr.cpp:1314
void CopyConditions(ConditionList conditions)
Definition: LootMgr.cpp:995
LootStoreItem const * Roll() const
Definition: LootMgr.cpp:945
#define MAX_NR_QUEST_ITEMS
Definition: LootMgr.h:31
uint32 StartQuest
std::vector< LootItem > quest_items
Definition: LootMgr.h:308
uint32 reference
Definition: LootMgr.h:105
Definition: Group.h:154
uint32 urand(uint32 min, uint32 max)
Definition: Util.cpp:71
const uint64 & GetGUID() const
Definition: Object.h:156
DBCStorage< AreaTableEntry > sAreaStore(AreaTableEntryfmt)
void LoadLootTemplates_Mail()
Definition: LootMgr.cpp:1436
bool HaveQuestLootFor(uint32 loot_id) const
Definition: LootMgr.cpp:150