Don't use singleton to access static functions.
[getmangos.git] / src / game / LootMgr.cpp
blob2efe2d619bf3d2368cfca61ee520f3bd23cec614
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "LootMgr.h"
20 #include "Log.h"
21 #include "ObjectMgr.h"
22 #include "ProgressBar.h"
23 #include "World.h"
24 #include "Util.h"
25 #include "SharedDefines.h"
26 #include "SpellMgr.h"
28 static Rates const qualityToRate[MAX_ITEM_QUALITY] = {
29 RATE_DROP_ITEM_POOR, // ITEM_QUALITY_POOR
30 RATE_DROP_ITEM_NORMAL, // ITEM_QUALITY_NORMAL
31 RATE_DROP_ITEM_UNCOMMON, // ITEM_QUALITY_UNCOMMON
32 RATE_DROP_ITEM_RARE, // ITEM_QUALITY_RARE
33 RATE_DROP_ITEM_EPIC, // ITEM_QUALITY_EPIC
34 RATE_DROP_ITEM_LEGENDARY, // ITEM_QUALITY_LEGENDARY
35 RATE_DROP_ITEM_ARTIFACT, // ITEM_QUALITY_ARTIFACT
38 LootStore LootTemplates_Creature( "creature_loot_template", "creature entry", true);
39 LootStore LootTemplates_Disenchant( "disenchant_loot_template", "item disenchant id", true);
40 LootStore LootTemplates_Fishing( "fishing_loot_template", "area id", true);
41 LootStore LootTemplates_Gameobject( "gameobject_loot_template", "gameobject entry", true);
42 LootStore LootTemplates_Item( "item_loot_template", "item entry", true);
43 LootStore LootTemplates_Mail( "mail_loot_template", "mail template id", false);
44 LootStore LootTemplates_Milling( "milling_loot_template", "item entry (herb)", true);
45 LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template","creature pickpocket lootid", true);
46 LootStore LootTemplates_Prospecting( "prospecting_loot_template", "item entry (ore)", true);
47 LootStore LootTemplates_Reference( "reference_loot_template", "reference id", false);
48 LootStore LootTemplates_Skinning( "skinning_loot_template", "creature skinning id", true);
49 LootStore LootTemplates_Spell( "spell_loot_template", "spell id (random item creating)",false);
51 class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed)
53 public:
54 void AddEntry(LootStoreItem& item); // Adds an entry to the group (at loading stage)
55 bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
56 bool HasQuestDropForPlayer(Player const * player) const;
57 // The same for active quests of the player
58 void Process(Loot& loot) const; // Rolls an item from the group (if any) and adds the item to the loot
59 float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
60 float TotalChance() const; // Overall chance for the group
62 void Verify(LootStore const& lootstore, uint32 id, uint32 group_id) const;
63 void CollectLootIds(LootIdSet& set) const;
64 void CheckLootRefs(LootIdSet* ref_set) const;
65 private:
66 LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
67 LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
69 LootStoreItem const * Roll() const; // Rolls an item from the group, returns NULL if all miss their chances
72 //Remove all data and free all memory
73 void LootStore::Clear()
75 for (LootTemplateMap::const_iterator itr=m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
76 delete itr->second;
77 m_LootTemplates.clear();
80 // Checks validity of the loot store
81 // Actual checks are done within LootTemplate::Verify() which is called for every template
82 void LootStore::Verify() const
84 for (LootTemplateMap::const_iterator i = m_LootTemplates.begin(); i != m_LootTemplates.end(); ++i )
85 i->second->Verify(*this, i->first);
88 // Loads a *_loot_template DB table into loot store
89 // All checks of the loaded template are called from here, no error reports at loot generation required
90 void LootStore::LoadLootTable()
92 LootTemplateMap::const_iterator tab;
93 uint32 count = 0;
95 // Clearing store (for reloading case)
96 Clear();
98 sLog.outString( "%s :", GetName());
100 // 0 1 2 3 4 5 6 7 8
101 QueryResult *result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, groupid, mincountOrRef, maxcount, lootcondition, condition_value1, condition_value2 FROM %s",GetName());
103 if (result)
105 barGoLink bar(result->GetRowCount());
109 Field *fields = result->Fetch();
110 bar.step();
112 uint32 entry = fields[0].GetUInt32();
113 uint32 item = fields[1].GetUInt32();
114 float chanceOrQuestChance = fields[2].GetFloat();
115 uint8 group = fields[3].GetUInt8();
116 int32 mincountOrRef = fields[4].GetInt32();
117 uint32 maxcount = fields[5].GetUInt32();
118 ConditionType condition = (ConditionType)fields[6].GetUInt8();
119 uint32 cond_value1 = fields[7].GetUInt32();
120 uint32 cond_value2 = fields[8].GetUInt32();
122 if(maxcount > std::numeric_limits<uint8>::max())
124 sLog.outErrorDb("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());
125 continue; // error already printed to log/console.
129 if(!PlayerCondition::IsValid(condition,cond_value1, cond_value2))
131 sLog.outErrorDb("... in table '%s' entry %u item %u", GetName(), entry, item);
132 continue; // error already printed to log/console.
135 // (condition + cond_value1/2) are converted into single conditionId
136 uint16 conditionId = objmgr.GetConditionId(condition, cond_value1, cond_value2);
138 LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, group, conditionId, mincountOrRef, maxcount);
140 if (!storeitem.IsValid(*this,entry)) // Validity checks
141 continue;
143 // Looking for the template of the entry
144 // often entries are put together
145 if (m_LootTemplates.empty() || tab->first != entry)
147 // Searching the template (in case template Id changed)
148 tab = m_LootTemplates.find(entry);
149 if ( tab == m_LootTemplates.end() )
151 std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate));
152 tab = pr.first;
155 // else is empty - template Id and iter are the same
156 // finally iter refers to already existed or just created <entry, LootTemplate>
158 // Adds current row to the template
159 tab->second->AddEntry(storeitem);
160 ++count;
162 } while (result->NextRow());
164 delete result;
166 Verify(); // Checks validity of the loot store
168 sLog.outString();
169 sLog.outString( ">> Loaded %u loot definitions (%lu templates)", count, (unsigned long)m_LootTemplates.size());
171 else
173 sLog.outString();
174 sLog.outErrorDb( ">> Loaded 0 loot definitions. DB table `%s` is empty.",GetName() );
178 bool LootStore::HaveQuestLootFor(uint32 loot_id) const
180 LootTemplateMap::const_iterator itr = m_LootTemplates.find(loot_id);
181 if(itr == m_LootTemplates.end())
182 return false;
184 // scan loot for quest items
185 return itr->second->HasQuestDrop(m_LootTemplates);
188 bool LootStore::HaveQuestLootForPlayer(uint32 loot_id,Player* player) const
190 LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
191 if (tab != m_LootTemplates.end())
192 if (tab->second->HasQuestDropForPlayer(m_LootTemplates, player))
193 return true;
195 return false;
198 LootTemplate const* LootStore::GetLootFor(uint32 loot_id) const
200 LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
202 if (tab == m_LootTemplates.end())
203 return NULL;
205 return tab->second;
208 void LootStore::LoadAndCollectLootIds(LootIdSet& ids_set)
210 LoadLootTable();
212 for(LootTemplateMap::const_iterator tab = m_LootTemplates.begin(); tab != m_LootTemplates.end(); ++tab)
213 ids_set.insert(tab->first);
216 void LootStore::CheckLootRefs(LootIdSet* ref_set) const
218 for(LootTemplateMap::const_iterator ltItr = m_LootTemplates.begin(); ltItr != m_LootTemplates.end(); ++ltItr)
219 ltItr->second->CheckLootRefs(ref_set);
222 void LootStore::ReportUnusedIds(LootIdSet const& ids_set) const
224 // all still listed ids isn't referenced
225 for(LootIdSet::const_iterator itr = ids_set.begin(); itr != ids_set.end(); ++itr)
226 sLog.outErrorDb("Table '%s' entry %d isn't %s and not referenced from loot, and then useless.", GetName(), *itr,GetEntryName());
229 void LootStore::ReportNotExistedId(uint32 id) const
231 sLog.outErrorDb("Table '%s' entry %d (%s) not exist but used as loot id in DB.", GetName(), id,GetEntryName());
235 // --------- LootStoreItem ---------
238 // Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
239 // RATE_DROP_ITEMS is no longer used for all types of entries
240 bool LootStoreItem::Roll(bool rate) const
242 if(chance>=100.0f)
243 return true;
245 if(mincountOrRef < 0) // reference case
246 return roll_chance_f(chance* (rate ? sWorld.getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
248 ItemPrototype const *pProto = ObjectMgr::GetItemPrototype(itemid);
250 float qualityModifier = pProto && rate ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
252 return roll_chance_f(chance*qualityModifier);
255 // Checks correctness of values
256 bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
258 if(group >= 1 << 7) // it stored in 7 bit field
260 sLog.outErrorDb("Table '%s' entry %d item %d: group (%u) must be less %u - skipped", store.GetName(), entry, itemid, group, 1 << 7);
261 return false;
264 if (mincountOrRef == 0)
266 sLog.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincountOrRef);
267 return false;
270 if( mincountOrRef > 0 ) // item (quest or non-quest) entry, maybe grouped
272 ItemPrototype const *proto = ObjectMgr::GetItemPrototype(itemid);
273 if(!proto)
275 sLog.outErrorDb("Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store.GetName(), entry, itemid);
276 return false;
279 if( chance == 0 && group == 0) // Zero chance is allowed for grouped entries only
281 sLog.outErrorDb("Table '%s' entry %d item %d: equal-chanced grouped entry, but group not defined - skipped", store.GetName(), entry, itemid);
282 return false;
285 if( chance != 0 && chance < 0.000001f ) // loot with low chance
287 sLog.outErrorDb("Table '%s' entry %d item %d: low chance (%f) - skipped",
288 store.GetName(), entry, itemid, chance);
289 return false;
292 if( maxcount < mincountOrRef) // wrong max count
294 sLog.outErrorDb("Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store.GetName(), entry, itemid, uint32(maxcount), mincountOrRef);
295 return false;
299 else // mincountOrRef < 0
301 if (needs_quest)
302 sLog.outErrorDb("Table '%s' entry %d item %d: quest chance will be treated as non-quest chance", store.GetName(), entry, itemid);
303 else if( chance == 0 ) // no chance for the reference
305 sLog.outErrorDb("Table '%s' entry %d item %d: zero chance is specified for a reference, skipped", store.GetName(), entry, itemid);
306 return false;
309 return true; // Referenced template existence is checked at whole store level
313 // --------- LootItem ---------
316 // Constructor, copies most fields from LootStoreItem and generates random count
317 LootItem::LootItem(LootStoreItem const& li)
319 itemid = li.itemid;
320 conditionId = li.conditionId;
322 ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemid);
323 freeforall = proto && (proto->Flags & ITEM_FLAGS_PARTY_LOOT);
325 needs_quest = li.needs_quest;
327 count = urand(li.mincountOrRef, li.maxcount); // constructor called for mincountOrRef > 0 only
328 randomSuffix = GenerateEnchSuffixFactor(itemid);
329 randomPropertyId = Item::GenerateItemRandomPropertyId(itemid);
330 is_looted = 0;
331 is_blocked = 0;
332 is_underthreshold = 0;
333 is_counted = 0;
336 // Basic checks for player/item compatibility - if false no chance to see the item in the loot
337 bool LootItem::AllowedForPlayer(Player const * player) const
339 // DB conditions check
340 if ( !objmgr.IsPlayerMeetToCondition(player,conditionId) )
341 return false;
343 if ( needs_quest )
345 // Checking quests for quest-only drop (check only quests requirements in this case)
346 if( !player->HasQuestForItem(itemid) )
347 return false;
349 else
351 // Not quest only drop (check quest starting items for already accepted non-repeatable quests)
352 ItemPrototype const *pProto = ObjectMgr::GetItemPrototype(itemid);
353 if (pProto && pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE && !player->HasQuestForItem(itemid))
354 return false;
357 return true;
361 // --------- Loot ---------
364 // Inserts the item into the loot (called by LootTemplate processors)
365 void Loot::AddItem(LootStoreItem const & item)
367 if (item.needs_quest) // Quest drop
369 if (quest_items.size() < MAX_NR_QUEST_ITEMS)
370 quest_items.push_back(LootItem(item));
372 else if (items.size() < MAX_NR_LOOT_ITEMS) // Non-quest drop
374 items.push_back(LootItem(item));
376 // non-conditional one-player only items are counted here,
377 // free for all items are counted in FillFFALoot(),
378 // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
379 if( !item.conditionId )
381 ItemPrototype const* proto = ObjectMgr::GetItemPrototype(item.itemid);
382 if( !proto || (proto->Flags & ITEM_FLAGS_PARTY_LOOT)==0 )
383 ++unlootedCount;
388 // Calls processor of corresponding LootTemplate (which handles everything including references)
389 bool Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner, bool personal, bool noEmptyError)
391 // Must be provided
392 if(!loot_owner)
393 return false;
395 LootTemplate const* tab = store.GetLootFor(loot_id);
397 if (!tab)
399 if (!noEmptyError)
400 sLog.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.",store.GetName(),loot_id);
401 return false;
404 items.reserve(MAX_NR_LOOT_ITEMS);
405 quest_items.reserve(MAX_NR_QUEST_ITEMS);
407 tab->Process(*this, store,store.IsRatesAllowed ()); // Processing is done there, callback via Loot::AddItem()
409 // Setting access rights for group loot case
410 Group * pGroup=loot_owner->GetGroup();
411 if(!personal && pGroup)
413 for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
414 if(Player* pl = itr->getSource())
415 FillNotNormalLootFor(pl);
417 // ... for personal loot
418 else
419 FillNotNormalLootFor(loot_owner);
421 return true;
424 void Loot::FillNotNormalLootFor(Player* pl)
426 uint32 plguid = pl->GetGUIDLow();
428 QuestItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid);
429 if (qmapitr == PlayerQuestItems.end())
430 FillQuestLoot(pl);
432 qmapitr = PlayerFFAItems.find(plguid);
433 if (qmapitr == PlayerFFAItems.end())
434 FillFFALoot(pl);
436 qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
437 if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
438 FillNonQuestNonFFAConditionalLoot(pl);
441 QuestItemList* Loot::FillFFALoot(Player* player)
443 QuestItemList *ql = new QuestItemList();
445 for(uint8 i = 0; i < items.size(); ++i)
447 LootItem &item = items[i];
448 if(!item.is_looted && item.freeforall && item.AllowedForPlayer(player) )
450 ql->push_back(QuestItem(i));
451 ++unlootedCount;
454 if (ql->empty())
456 delete ql;
457 return NULL;
460 PlayerFFAItems[player->GetGUIDLow()] = ql;
461 return ql;
464 QuestItemList* Loot::FillQuestLoot(Player* player)
466 if (items.size() == MAX_NR_LOOT_ITEMS) return NULL;
467 QuestItemList *ql = new QuestItemList();
469 for(uint8 i = 0; i < quest_items.size(); ++i)
471 LootItem &item = quest_items[i];
472 if(!item.is_looted && item.AllowedForPlayer(player) )
474 ql->push_back(QuestItem(i));
476 // questitems get blocked when they first apper in a
477 // player's quest vector
479 // increase once if one looter only, looter-times if free for all
480 if (item.freeforall || !item.is_blocked)
481 ++unlootedCount;
483 item.is_blocked = true;
485 if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS)
486 break;
489 if (ql->empty())
491 delete ql;
492 return NULL;
495 PlayerQuestItems[player->GetGUIDLow()] = ql;
496 return ql;
499 QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player)
501 QuestItemList *ql = new QuestItemList();
503 for(uint8 i = 0; i < items.size(); ++i)
505 LootItem &item = items[i];
506 if(!item.is_looted && !item.freeforall && item.conditionId && item.AllowedForPlayer(player))
508 ql->push_back(QuestItem(i));
509 if(!item.is_counted)
511 ++unlootedCount;
512 item.is_counted=true;
516 if (ql->empty())
518 delete ql;
519 return NULL;
522 PlayerNonQuestNonFFAConditionalItems[player->GetGUIDLow()] = ql;
523 return ql;
526 //===================================================
528 void Loot::NotifyItemRemoved(uint8 lootIndex)
530 // notify all players that are looting this that the item was removed
531 // convert the index to the slot the player sees
532 std::set<uint64>::iterator i_next;
533 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
535 i_next = i;
536 ++i_next;
537 if(Player* pl = ObjectAccessor::FindPlayer(*i))
538 pl->SendNotifyLootItemRemoved(lootIndex);
539 else
540 PlayersLooting.erase(i);
544 void Loot::NotifyMoneyRemoved()
546 // notify all players that are looting this that the money was removed
547 std::set<uint64>::iterator i_next;
548 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
550 i_next = i;
551 ++i_next;
552 if(Player* pl = ObjectAccessor::FindPlayer(*i))
553 pl->SendNotifyLootMoneyRemoved();
554 else
555 PlayersLooting.erase(i);
559 void Loot::NotifyQuestItemRemoved(uint8 questIndex)
561 // when a free for all questitem is looted
562 // all players will get notified of it being removed
563 // (other questitems can be looted by each group member)
564 // bit inefficient but isnt called often
566 std::set<uint64>::iterator i_next;
567 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
569 i_next = i;
570 ++i_next;
571 if(Player* pl = ObjectAccessor::FindPlayer(*i))
573 QuestItemMap::const_iterator pq = PlayerQuestItems.find(pl->GetGUIDLow());
574 if (pq != PlayerQuestItems.end() && pq->second)
576 // find where/if the player has the given item in it's vector
577 QuestItemList& pql = *pq->second;
579 uint8 j;
580 for (j = 0; j < pql.size(); ++j)
581 if (pql[j].index == questIndex)
582 break;
584 if (j < pql.size())
585 pl->SendNotifyLootItemRemoved(items.size()+j);
588 else
589 PlayersLooting.erase(i);
593 void Loot::generateMoneyLoot( uint32 minAmount, uint32 maxAmount )
595 if (maxAmount > 0)
597 if (maxAmount <= minAmount)
598 gold = uint32(maxAmount * sWorld.getRate(RATE_DROP_MONEY));
599 else if ((maxAmount - minAmount) < 32700)
600 gold = uint32(urand(minAmount, maxAmount) * sWorld.getRate(RATE_DROP_MONEY));
601 else
602 gold = uint32(urand(minAmount >> 8, maxAmount >> 8) * sWorld.getRate(RATE_DROP_MONEY)) << 8;
606 LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qitem, QuestItem **ffaitem, QuestItem **conditem)
608 LootItem* item = NULL;
609 bool is_looted = true;
610 if (lootSlot >= items.size())
612 uint32 questSlot = lootSlot - items.size();
613 QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
614 if (itr != PlayerQuestItems.end() && questSlot < itr->second->size())
616 QuestItem *qitem2 = &itr->second->at(questSlot);
617 if(qitem)
618 *qitem = qitem2;
619 item = &quest_items[qitem2->index];
620 is_looted = qitem2->is_looted;
623 else
625 item = &items[lootSlot];
626 is_looted = item->is_looted;
627 if(item->freeforall)
629 QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUIDLow());
630 if (itr != PlayerFFAItems.end())
632 for(QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
633 if(iter->index==lootSlot)
635 QuestItem *ffaitem2 = (QuestItem*)&(*iter);
636 if(ffaitem)
637 *ffaitem = ffaitem2;
638 is_looted = ffaitem2->is_looted;
639 break;
643 else if(item->conditionId)
645 QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
646 if (itr != PlayerNonQuestNonFFAConditionalItems.end())
648 for(QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
650 if(iter->index==lootSlot)
652 QuestItem *conditem2 = (QuestItem*)&(*iter);
653 if(conditem)
654 *conditem = conditem2;
655 is_looted = conditem2->is_looted;
656 break;
663 if(is_looted)
664 return NULL;
666 return item;
669 uint32 Loot::GetMaxSlotInLootFor(Player* player) const
671 QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
672 return items.size() + (itr != PlayerQuestItems.end() ? itr->second->size() : 0);
675 ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
677 b << uint32(li.itemid);
678 b << uint32(li.count); // nr of items of this type
679 b << uint32(ObjectMgr::GetItemPrototype(li.itemid)->DisplayInfoID);
680 b << uint32(li.randomSuffix);
681 b << uint32(li.randomPropertyId);
682 //b << uint8(0); // slot type - will send after this function call
683 return b;
686 ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
688 if (lv.permission == NONE_PERMISSION)
690 b << uint32(0); //gold
691 b << uint8(0); // item count
692 return b; // nothing output more
695 Loot &l = lv.loot;
697 uint8 itemsShown = 0;
699 //gold
700 b << uint32(l.gold);
702 size_t count_pos = b.wpos(); // pos of item count byte
703 b << uint8(0); // item count placeholder
705 switch (lv.permission)
707 case GROUP_PERMISSION:
709 // You are not the items proprietary, so you can only see
710 // blocked rolled items and quest items, and !ffa items
711 for (uint8 i = 0; i < l.items.size(); ++i)
713 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
715 uint8 slot_type = (l.items[i].is_blocked || l.items[i].is_underthreshold) ? 0 : 1;
717 b << uint8(i) << l.items[i]; //send the index and the item if it's not looted, and blocked or under threshold, free for all items will be sent later, only one-player loots here
718 b << uint8(slot_type); // 0 - get 1 - look only
719 ++itemsShown;
722 break;
724 case ALL_PERMISSION:
725 case MASTER_PERMISSION:
727 uint8 slot_type = (lv.permission==MASTER_PERMISSION) ? 2 : 0;
728 for (uint8 i = 0; i < l.items.size(); ++i)
730 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
732 b << uint8(i) << l.items[i]; //only send one-player loot items now, free for all will be sent later
733 b << uint8(slot_type); // 0 - get 2 - master selection
734 ++itemsShown;
737 break;
739 default:
740 return b; // nothing output more
743 QuestItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems();
744 QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUIDLow());
745 if (q_itr != lootPlayerQuestItems.end())
747 QuestItemList *q_list = q_itr->second;
748 for (QuestItemList::const_iterator qi = q_list->begin() ; qi != q_list->end(); ++qi)
750 LootItem &item = l.quest_items[qi->index];
751 if (!qi->is_looted && !item.is_looted)
753 b << uint8(l.items.size() + (qi - q_list->begin()));
754 b << item;
755 b << uint8(0); // allow loot
756 ++itemsShown;
761 QuestItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems();
762 QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUIDLow());
763 if (ffa_itr != lootPlayerFFAItems.end())
765 QuestItemList *ffa_list = ffa_itr->second;
766 for (QuestItemList::const_iterator fi = ffa_list->begin() ; fi != ffa_list->end(); ++fi)
768 LootItem &item = l.items[fi->index];
769 if (!fi->is_looted && !item.is_looted)
771 b << uint8(fi->index) << item;
772 b << uint8(0); // allow loot
773 ++itemsShown;
778 QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems();
779 QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUIDLow());
780 if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
782 QuestItemList *conditional_list = nn_itr->second;
783 for (QuestItemList::const_iterator ci = conditional_list->begin() ; ci != conditional_list->end(); ++ci)
785 LootItem &item = l.items[ci->index];
786 if (!ci->is_looted && !item.is_looted)
788 b << uint8(ci->index) << item;
789 b << uint8(0); // allow loot
790 ++itemsShown;
795 //update number of items shown
796 b.put<uint8>(count_pos,itemsShown);
798 return b;
802 // --------- LootTemplate::LootGroup ---------
805 // Adds an entry to the group (at loading stage)
806 void LootTemplate::LootGroup::AddEntry(LootStoreItem& item)
808 if (item.chance != 0)
809 ExplicitlyChanced.push_back(item);
810 else
811 EqualChanced.push_back(item);
814 // Rolls an item from the group, returns NULL if all miss their chances
815 LootStoreItem const * LootTemplate::LootGroup::Roll() const
817 if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked
819 float Roll = rand_chance();
821 for (uint32 i=0; i<ExplicitlyChanced.size(); ++i) //check each explicitly chanced entry in the template and modify its chance based on quality.
823 if(ExplicitlyChanced[i].chance>=100.0f)
824 return &ExplicitlyChanced[i];
826 Roll -= ExplicitlyChanced[i].chance;
827 if (Roll < 0)
828 return &ExplicitlyChanced[i];
831 if (!EqualChanced.empty()) // If nothing selected yet - an item is taken from equal-chanced part
832 return &EqualChanced[irand(0, EqualChanced.size()-1)];
834 return NULL; // Empty drop from the group
837 // True if group includes at least 1 quest drop entry
838 bool LootTemplate::LootGroup::HasQuestDrop() const
840 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
841 if (i->needs_quest)
842 return true;
843 for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
844 if (i->needs_quest)
845 return true;
846 return false;
849 // True if group includes at least 1 quest drop entry for active quests of the player
850 bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const
852 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
853 if (player->HasQuestForItem(i->itemid))
854 return true;
855 for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
856 if (player->HasQuestForItem(i->itemid))
857 return true;
858 return false;
861 // Rolls an item from the group (if any takes its chance) and adds the item to the loot
862 void LootTemplate::LootGroup::Process(Loot& loot) const
864 LootStoreItem const * item = Roll();
865 if (item != NULL)
866 loot.AddItem(*item);
869 // Overall chance for the group without equal chanced items
870 float LootTemplate::LootGroup::RawTotalChance() const
872 float result = 0;
874 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
875 if ( !i->needs_quest )
876 result += i->chance;
878 return result;
881 // Overall chance for the group
882 float LootTemplate::LootGroup::TotalChance() const
884 float result = RawTotalChance();
886 if (!EqualChanced.empty() && result < 100.0f)
887 return 100.0f;
889 return result;
892 void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint32 group_id) const
894 float chance = RawTotalChance();
895 if (chance > 101.0f) // TODO: replace with 100% when DBs will be ready
897 sLog.outErrorDb("Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore.GetName(), id, group_id, chance);
900 if(chance >= 100.0f && !EqualChanced.empty())
902 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);
906 void LootTemplate::LootGroup::CheckLootRefs(LootIdSet* ref_set) const
908 for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
910 if(ieItr->mincountOrRef < 0)
912 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
913 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
914 else if(ref_set)
915 ref_set->erase(-ieItr->mincountOrRef);
919 for (LootStoreItemList::const_iterator ieItr=EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
921 if(ieItr->mincountOrRef < 0)
923 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
924 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
925 else if(ref_set)
926 ref_set->erase(-ieItr->mincountOrRef);
932 // --------- LootTemplate ---------
935 // Adds an entry to the group (at loading stage)
936 void LootTemplate::AddEntry(LootStoreItem& item)
938 if (item.group > 0 && item.mincountOrRef > 0) // Group
940 if (item.group >= Groups.size())
941 Groups.resize(item.group); // Adds new group the the loot template if needed
942 Groups[item.group-1].AddEntry(item); // Adds new entry to the group
944 else // Non-grouped entries and references are stored together
945 Entries.push_back(item);
948 // Rolls for every item in the template and adds the rolled items the the loot
949 void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8 groupId) const
951 if (groupId) // Group reference uses own processing of the group
953 if (groupId > Groups.size())
954 return; // Error message already printed at loading stage
956 Groups[groupId-1].Process(loot);
957 return;
960 // Rolling non-grouped items
961 for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i )
963 if (!i->Roll(rate))
964 continue; // Bad luck for the entry
966 if (i->mincountOrRef < 0) // References processing
968 LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef);
970 if(!Referenced)
971 continue; // Error message already printed at loading stage
973 for (uint32 loop=0; loop < i->maxcount; ++loop )// Ref multiplicator
974 Referenced->Process(loot, store, rate, i->group);
976 else // Plain entries (not a reference, not grouped)
977 loot.AddItem(*i); // Chance is already checked, just add
980 // Now processing groups
981 for (LootGroups::const_iterator i = Groups.begin( ) ; i != Groups.end( ) ; ++i )
982 i->Process(loot);
985 // True if template includes at least 1 quest drop entry
986 bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) const
988 if (groupId) // Group reference
990 if (groupId > Groups.size())
991 return false; // Error message [should be] already printed at loading stage
992 return Groups[groupId-1].HasQuestDrop();
995 for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i )
997 if (i->mincountOrRef < 0) // References
999 LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
1000 if( Referenced ==store.end() )
1001 continue; // Error message [should be] already printed at loading stage
1002 if (Referenced->second->HasQuestDrop(store, i->group) )
1003 return true;
1005 else if ( i->needs_quest )
1006 return true; // quest drop found
1009 // Now processing groups
1010 for (LootGroups::const_iterator i = Groups.begin() ; i != Groups.end() ; ++i )
1011 if (i->HasQuestDrop())
1012 return true;
1014 return false;
1017 // True if template includes at least 1 quest drop for an active quest of the player
1018 bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player const* player, uint8 groupId) const
1020 if (groupId) // Group reference
1022 if (groupId > Groups.size())
1023 return false; // Error message already printed at loading stage
1024 return Groups[groupId-1].HasQuestDropForPlayer(player);
1027 // Checking non-grouped entries
1028 for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i )
1030 if (i->mincountOrRef < 0) // References processing
1032 LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
1033 if (Referenced == store.end() )
1034 continue; // Error message already printed at loading stage
1035 if (Referenced->second->HasQuestDropForPlayer(store, player, i->group) )
1036 return true;
1038 else if ( player->HasQuestForItem(i->itemid) )
1039 return true; // active quest drop found
1042 // Now checking groups
1043 for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i )
1044 if (i->HasQuestDropForPlayer(player))
1045 return true;
1047 return false;
1050 // Checks integrity of the template
1051 void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const
1053 // Checking group chances
1054 for (uint32 i=0; i < Groups.size(); ++i)
1055 Groups[i].Verify(lootstore,id,i+1);
1057 // TODO: References validity checks
1060 void LootTemplate::CheckLootRefs(LootIdSet* ref_set) const
1062 for(LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
1064 if(ieItr->mincountOrRef < 0)
1066 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
1067 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
1068 else if(ref_set)
1069 ref_set->erase(-ieItr->mincountOrRef);
1073 for(LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
1074 grItr->CheckLootRefs(ref_set);
1077 void LoadLootTemplates_Creature()
1079 LootIdSet ids_set, ids_setUsed;
1080 LootTemplates_Creature.LoadAndCollectLootIds(ids_set);
1082 // remove real entries and check existence loot
1083 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1085 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1087 if(uint32 lootid = cInfo->lootid)
1089 if(!ids_set.count(lootid))
1090 LootTemplates_Creature.ReportNotExistedId(lootid);
1091 else
1092 ids_setUsed.insert(lootid);
1096 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1097 ids_set.erase(*itr);
1099 // for alterac valley we've defined Player-loot inside creature_loot_template id=0
1100 // this hack is used, so that we won't need to create an extra table player_loot_template for just one case
1101 ids_set.erase(0);
1103 // output error for any still listed (not referenced from appropriate table) ids
1104 LootTemplates_Creature.ReportUnusedIds(ids_set);
1107 void LoadLootTemplates_Disenchant()
1109 LootIdSet ids_set, ids_setUsed;
1110 LootTemplates_Disenchant.LoadAndCollectLootIds(ids_set);
1112 // remove real entries and check existence loot
1113 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1115 if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
1117 if(uint32 lootid = proto->DisenchantID)
1119 if(!ids_set.count(lootid))
1120 LootTemplates_Disenchant.ReportNotExistedId(lootid);
1121 else
1122 ids_setUsed.insert(lootid);
1126 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1127 ids_set.erase(*itr);
1128 // output error for any still listed (not referenced from appropriate table) ids
1129 LootTemplates_Disenchant.ReportUnusedIds(ids_set);
1132 void LoadLootTemplates_Fishing()
1134 LootIdSet ids_set;
1135 LootTemplates_Fishing.LoadAndCollectLootIds(ids_set);
1137 // remove real entries and check existence loot
1138 for(uint32 i = 1; i < sAreaStore.GetNumRows(); ++i )
1140 if(AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
1141 if(ids_set.count(areaEntry->ID))
1142 ids_set.erase(areaEntry->ID);
1145 // output error for any still listed (not referenced from appropriate table) ids
1146 LootTemplates_Fishing.ReportUnusedIds(ids_set);
1149 void LoadLootTemplates_Gameobject()
1151 LootIdSet ids_set, ids_setUsed;
1152 LootTemplates_Gameobject.LoadAndCollectLootIds(ids_set);
1154 // remove real entries and check existence loot
1155 for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i )
1157 if(GameObjectInfo const* gInfo = sGOStorage.LookupEntry<GameObjectInfo>(i))
1159 if(uint32 lootid = gInfo->GetLootId())
1161 if(!ids_set.count(lootid))
1162 LootTemplates_Gameobject.ReportNotExistedId(lootid);
1163 else
1164 ids_setUsed.insert(lootid);
1168 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1169 ids_set.erase(*itr);
1171 // output error for any still listed (not referenced from appropriate table) ids
1172 LootTemplates_Gameobject.ReportUnusedIds(ids_set);
1175 void LoadLootTemplates_Item()
1177 LootIdSet ids_set;
1178 LootTemplates_Item.LoadAndCollectLootIds(ids_set);
1180 // remove real entries and check existence loot
1181 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1182 if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
1183 if(ids_set.count(proto->ItemId))
1184 ids_set.erase(proto->ItemId);
1186 // output error for any still listed (not referenced from appropriate table) ids
1187 LootTemplates_Item.ReportUnusedIds(ids_set);
1190 void LoadLootTemplates_Milling()
1192 LootIdSet ids_set;
1193 LootTemplates_Milling.LoadAndCollectLootIds(ids_set);
1195 // remove real entries and check existence loot
1196 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1198 ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i);
1199 if(!proto)
1200 continue;
1202 if((proto->BagFamily & BAG_FAMILY_MASK_HERBS)==0)
1203 continue;
1205 if(ids_set.count(proto->ItemId))
1206 ids_set.erase(proto->ItemId);
1209 // output error for any still listed (not referenced from appropriate table) ids
1210 LootTemplates_Milling.ReportUnusedIds(ids_set);
1213 void LoadLootTemplates_Pickpocketing()
1215 LootIdSet ids_set, ids_setUsed;
1216 LootTemplates_Pickpocketing.LoadAndCollectLootIds(ids_set);
1218 // remove real entries and check existence loot
1219 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1221 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1223 if(uint32 lootid = cInfo->pickpocketLootId)
1225 if(!ids_set.count(lootid))
1226 LootTemplates_Pickpocketing.ReportNotExistedId(lootid);
1227 else
1228 ids_setUsed.insert(lootid);
1232 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1233 ids_set.erase(*itr);
1235 // output error for any still listed (not referenced from appropriate table) ids
1236 LootTemplates_Pickpocketing.ReportUnusedIds(ids_set);
1239 void LoadLootTemplates_Prospecting()
1241 LootIdSet ids_set;
1242 LootTemplates_Prospecting.LoadAndCollectLootIds(ids_set);
1244 // remove real entries and check existence loot
1245 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1247 ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i);
1248 if(!proto)
1249 continue;
1251 if((proto->BagFamily & BAG_FAMILY_MASK_MINING_SUPP)==0)
1252 continue;
1254 if(ids_set.count(proto->ItemId))
1255 ids_set.erase(proto->ItemId);
1258 // output error for any still listed (not referenced from appropriate table) ids
1259 LootTemplates_Prospecting.ReportUnusedIds(ids_set);
1262 void LoadLootTemplates_Mail()
1264 LootIdSet ids_set;
1265 LootTemplates_Mail.LoadAndCollectLootIds(ids_set);
1267 // remove real entries and check existence loot
1268 for(uint32 i = 1; i < sMailTemplateStore.GetNumRows(); ++i )
1269 if(sMailTemplateStore.LookupEntry(i))
1270 if(ids_set.count(i))
1271 ids_set.erase(i);
1273 // output error for any still listed (not referenced from appropriate table) ids
1274 LootTemplates_Mail.ReportUnusedIds(ids_set);
1277 void LoadLootTemplates_Skinning()
1279 LootIdSet ids_set, ids_setUsed;
1280 LootTemplates_Skinning.LoadAndCollectLootIds(ids_set);
1282 // remove real entries and check existence loot
1283 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1285 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1287 if(uint32 lootid = cInfo->SkinLootId)
1289 if(!ids_set.count(lootid))
1290 LootTemplates_Skinning.ReportNotExistedId(lootid);
1291 else
1292 ids_setUsed.insert(lootid);
1296 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1297 ids_set.erase(*itr);
1299 // output error for any still listed (not referenced from appropriate table) ids
1300 LootTemplates_Skinning.ReportUnusedIds(ids_set);
1303 void LoadLootTemplates_Spell()
1305 LootIdSet ids_set;
1306 LootTemplates_Spell.LoadAndCollectLootIds(ids_set);
1308 // remove real entries and check existence loot
1309 for(uint32 spell_id = 1; spell_id < sSpellStore.GetNumRows(); ++spell_id)
1311 SpellEntry const* spellInfo = sSpellStore.LookupEntry (spell_id);
1312 if(!spellInfo)
1313 continue;
1315 // possible cases
1316 if( !IsLootCraftingSpell(spellInfo))
1317 continue;
1319 if(!ids_set.count(spell_id))
1321 // not report about not trainable spells (optionally supported by DB)
1322 // ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
1323 if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_TRADESPELL))
1325 LootTemplates_Spell.ReportNotExistedId(spell_id);
1328 else
1329 ids_set.erase(spell_id);
1332 // output error for any still listed (not referenced from appropriate table) ids
1333 LootTemplates_Spell.ReportUnusedIds(ids_set);
1336 void LoadLootTemplates_Reference()
1338 LootIdSet ids_set;
1339 LootTemplates_Reference.LoadAndCollectLootIds(ids_set);
1341 // check references and remove used
1342 LootTemplates_Creature.CheckLootRefs(&ids_set);
1343 LootTemplates_Fishing.CheckLootRefs(&ids_set);
1344 LootTemplates_Gameobject.CheckLootRefs(&ids_set);
1345 LootTemplates_Item.CheckLootRefs(&ids_set);
1346 LootTemplates_Milling.CheckLootRefs(&ids_set);
1347 LootTemplates_Pickpocketing.CheckLootRefs(&ids_set);
1348 LootTemplates_Skinning.CheckLootRefs(&ids_set);
1349 LootTemplates_Disenchant.CheckLootRefs(&ids_set);
1350 LootTemplates_Prospecting.CheckLootRefs(&ids_set);
1351 LootTemplates_Mail.CheckLootRefs(&ids_set);
1352 LootTemplates_Reference.CheckLootRefs(&ids_set);
1354 // output error for any still listed ids (not referenced from any loot table)
1355 LootTemplates_Reference.ReportUnusedIds(ids_set);