[8449] Deprecate healing/damage item mods and merge internal data in to spell power.
[getmangos.git] / src / game / LootMgr.cpp
blob70c386605920f59db02dbbb8ae73f2fd33b8a4a8
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_Milling( "milling_loot_template", "item entry (herb)", true);
44 LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template","creature pickpocket lootid", true);
45 LootStore LootTemplates_Prospecting( "prospecting_loot_template", "item entry (ore)", true);
46 LootStore LootTemplates_QuestMail( "quest_mail_loot_template", "quest id (with mail template)",false);
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 = objmgr.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 = objmgr.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 = objmgr.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 = objmgr.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 = objmgr.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 void Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner, bool personal)
391 // Must be provided
392 if(!loot_owner)
393 return;
395 LootTemplate const* tab = store.GetLootFor(loot_id);
397 if (!tab)
399 sLog.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.",store.GetName(),loot_id);
400 return;
403 items.reserve(MAX_NR_LOOT_ITEMS);
404 quest_items.reserve(MAX_NR_QUEST_ITEMS);
406 tab->Process(*this, store,store.IsRatesAllowed ()); // Processing is done there, callback via Loot::AddItem()
408 // Setting access rights for group loot case
409 Group * pGroup=loot_owner->GetGroup();
410 if(!personal && pGroup)
412 for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
413 if(Player* pl = itr->getSource())
414 FillNotNormalLootFor(pl);
416 // ... for personal loot
417 else
418 FillNotNormalLootFor(loot_owner);
421 void Loot::FillNotNormalLootFor(Player* pl)
423 uint32 plguid = pl->GetGUIDLow();
425 QuestItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid);
426 if (qmapitr == PlayerQuestItems.end())
427 FillQuestLoot(pl);
429 qmapitr = PlayerFFAItems.find(plguid);
430 if (qmapitr == PlayerFFAItems.end())
431 FillFFALoot(pl);
433 qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
434 if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
435 FillNonQuestNonFFAConditionalLoot(pl);
438 QuestItemList* Loot::FillFFALoot(Player* player)
440 QuestItemList *ql = new QuestItemList();
442 for(uint8 i = 0; i < items.size(); ++i)
444 LootItem &item = items[i];
445 if(!item.is_looted && item.freeforall && item.AllowedForPlayer(player) )
447 ql->push_back(QuestItem(i));
448 ++unlootedCount;
451 if (ql->empty())
453 delete ql;
454 return NULL;
457 PlayerFFAItems[player->GetGUIDLow()] = ql;
458 return ql;
461 QuestItemList* Loot::FillQuestLoot(Player* player)
463 if (items.size() == MAX_NR_LOOT_ITEMS) return NULL;
464 QuestItemList *ql = new QuestItemList();
466 for(uint8 i = 0; i < quest_items.size(); ++i)
468 LootItem &item = quest_items[i];
469 if(!item.is_looted && item.AllowedForPlayer(player) )
471 ql->push_back(QuestItem(i));
473 // questitems get blocked when they first apper in a
474 // player's quest vector
476 // increase once if one looter only, looter-times if free for all
477 if (item.freeforall || !item.is_blocked)
478 ++unlootedCount;
480 item.is_blocked = true;
482 if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS)
483 break;
486 if (ql->empty())
488 delete ql;
489 return NULL;
492 PlayerQuestItems[player->GetGUIDLow()] = ql;
493 return ql;
496 QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player)
498 QuestItemList *ql = new QuestItemList();
500 for(uint8 i = 0; i < items.size(); ++i)
502 LootItem &item = items[i];
503 if(!item.is_looted && !item.freeforall && item.conditionId && item.AllowedForPlayer(player))
505 ql->push_back(QuestItem(i));
506 if(!item.is_counted)
508 ++unlootedCount;
509 item.is_counted=true;
513 if (ql->empty())
515 delete ql;
516 return NULL;
519 PlayerNonQuestNonFFAConditionalItems[player->GetGUIDLow()] = ql;
520 return ql;
523 //===================================================
525 void Loot::NotifyItemRemoved(uint8 lootIndex)
527 // notify all players that are looting this that the item was removed
528 // convert the index to the slot the player sees
529 std::set<uint64>::iterator i_next;
530 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
532 i_next = i;
533 ++i_next;
534 if(Player* pl = ObjectAccessor::FindPlayer(*i))
535 pl->SendNotifyLootItemRemoved(lootIndex);
536 else
537 PlayersLooting.erase(i);
541 void Loot::NotifyMoneyRemoved()
543 // notify all players that are looting this that the money was removed
544 std::set<uint64>::iterator i_next;
545 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
547 i_next = i;
548 ++i_next;
549 if(Player* pl = ObjectAccessor::FindPlayer(*i))
550 pl->SendNotifyLootMoneyRemoved();
551 else
552 PlayersLooting.erase(i);
556 void Loot::NotifyQuestItemRemoved(uint8 questIndex)
558 // when a free for all questitem is looted
559 // all players will get notified of it being removed
560 // (other questitems can be looted by each group member)
561 // bit inefficient but isnt called often
563 std::set<uint64>::iterator i_next;
564 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
566 i_next = i;
567 ++i_next;
568 if(Player* pl = ObjectAccessor::FindPlayer(*i))
570 QuestItemMap::const_iterator pq = PlayerQuestItems.find(pl->GetGUIDLow());
571 if (pq != PlayerQuestItems.end() && pq->second)
573 // find where/if the player has the given item in it's vector
574 QuestItemList& pql = *pq->second;
576 uint8 j;
577 for (j = 0; j < pql.size(); ++j)
578 if (pql[j].index == questIndex)
579 break;
581 if (j < pql.size())
582 pl->SendNotifyLootItemRemoved(items.size()+j);
585 else
586 PlayersLooting.erase(i);
590 void Loot::generateMoneyLoot( uint32 minAmount, uint32 maxAmount )
592 if (maxAmount > 0)
594 if (maxAmount <= minAmount)
595 gold = uint32(maxAmount * sWorld.getRate(RATE_DROP_MONEY));
596 else if ((maxAmount - minAmount) < 32700)
597 gold = uint32(urand(minAmount, maxAmount) * sWorld.getRate(RATE_DROP_MONEY));
598 else
599 gold = uint32(urand(minAmount >> 8, maxAmount >> 8) * sWorld.getRate(RATE_DROP_MONEY)) << 8;
603 LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qitem, QuestItem **ffaitem, QuestItem **conditem)
605 LootItem* item = NULL;
606 bool is_looted = true;
607 if (lootSlot >= items.size())
609 uint32 questSlot = lootSlot - items.size();
610 QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
611 if (itr != PlayerQuestItems.end() && questSlot < itr->second->size())
613 QuestItem *qitem2 = &itr->second->at(questSlot);
614 if(qitem)
615 *qitem = qitem2;
616 item = &quest_items[qitem2->index];
617 is_looted = qitem2->is_looted;
620 else
622 item = &items[lootSlot];
623 is_looted = item->is_looted;
624 if(item->freeforall)
626 QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUIDLow());
627 if (itr != PlayerFFAItems.end())
629 for(QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
630 if(iter->index==lootSlot)
632 QuestItem *ffaitem2 = (QuestItem*)&(*iter);
633 if(ffaitem)
634 *ffaitem = ffaitem2;
635 is_looted = ffaitem2->is_looted;
636 break;
640 else if(item->conditionId)
642 QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
643 if (itr != PlayerNonQuestNonFFAConditionalItems.end())
645 for(QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
647 if(iter->index==lootSlot)
649 QuestItem *conditem2 = (QuestItem*)&(*iter);
650 if(conditem)
651 *conditem = conditem2;
652 is_looted = conditem2->is_looted;
653 break;
660 if(is_looted)
661 return NULL;
663 return item;
666 uint32 Loot::GetMaxSlotInLootFor(Player* player) const
668 QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
669 return items.size() + (itr != PlayerQuestItems.end() ? itr->second->size() : 0);
672 ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
674 b << uint32(li.itemid);
675 b << uint32(li.count); // nr of items of this type
676 b << uint32(objmgr.GetItemPrototype(li.itemid)->DisplayInfoID);
677 b << uint32(li.randomSuffix);
678 b << uint32(li.randomPropertyId);
679 //b << uint8(0); // slot type - will send after this function call
680 return b;
683 ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
685 if (lv.permission == NONE_PERMISSION)
687 b << uint32(0); //gold
688 b << uint8(0); // item count
689 return b; // nothing output more
692 Loot &l = lv.loot;
694 uint8 itemsShown = 0;
696 //gold
697 b << uint32(l.gold);
699 size_t count_pos = b.wpos(); // pos of item count byte
700 b << uint8(0); // item count placeholder
702 switch (lv.permission)
704 case GROUP_PERMISSION:
706 // You are not the items proprietary, so you can only see
707 // blocked rolled items and quest items, and !ffa items
708 for (uint8 i = 0; i < l.items.size(); ++i)
710 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
712 uint8 slot_type = (l.items[i].is_blocked || l.items[i].is_underthreshold) ? 0 : 1;
714 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
715 b << uint8(slot_type); // 0 - get 1 - look only
716 ++itemsShown;
719 break;
721 case ALL_PERMISSION:
722 case MASTER_PERMISSION:
724 uint8 slot_type = (lv.permission==MASTER_PERMISSION) ? 2 : 0;
725 for (uint8 i = 0; i < l.items.size(); ++i)
727 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
729 b << uint8(i) << l.items[i]; //only send one-player loot items now, free for all will be sent later
730 b << uint8(slot_type); // 0 - get 2 - master selection
731 ++itemsShown;
734 break;
736 default:
737 return b; // nothing output more
740 QuestItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems();
741 QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUIDLow());
742 if (q_itr != lootPlayerQuestItems.end())
744 QuestItemList *q_list = q_itr->second;
745 for (QuestItemList::const_iterator qi = q_list->begin() ; qi != q_list->end(); ++qi)
747 LootItem &item = l.quest_items[qi->index];
748 if (!qi->is_looted && !item.is_looted)
750 b << uint8(l.items.size() + (qi - q_list->begin()));
751 b << item;
752 b << uint8(0); // allow loot
753 ++itemsShown;
758 QuestItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems();
759 QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUIDLow());
760 if (ffa_itr != lootPlayerFFAItems.end())
762 QuestItemList *ffa_list = ffa_itr->second;
763 for (QuestItemList::const_iterator fi = ffa_list->begin() ; fi != ffa_list->end(); ++fi)
765 LootItem &item = l.items[fi->index];
766 if (!fi->is_looted && !item.is_looted)
768 b << uint8(fi->index) << item;
769 b << uint8(0); // allow loot
770 ++itemsShown;
775 QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems();
776 QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUIDLow());
777 if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
779 QuestItemList *conditional_list = nn_itr->second;
780 for (QuestItemList::const_iterator ci = conditional_list->begin() ; ci != conditional_list->end(); ++ci)
782 LootItem &item = l.items[ci->index];
783 if (!ci->is_looted && !item.is_looted)
785 b << uint8(ci->index) << item;
786 b << uint8(0); // allow loot
787 ++itemsShown;
792 //update number of items shown
793 b.put<uint8>(count_pos,itemsShown);
795 return b;
799 // --------- LootTemplate::LootGroup ---------
802 // Adds an entry to the group (at loading stage)
803 void LootTemplate::LootGroup::AddEntry(LootStoreItem& item)
805 if (item.chance != 0)
806 ExplicitlyChanced.push_back(item);
807 else
808 EqualChanced.push_back(item);
811 // Rolls an item from the group, returns NULL if all miss their chances
812 LootStoreItem const * LootTemplate::LootGroup::Roll() const
814 if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked
816 float Roll = rand_chance();
818 for (uint32 i=0; i<ExplicitlyChanced.size(); ++i) //check each explicitly chanced entry in the template and modify its chance based on quality.
820 if(ExplicitlyChanced[i].chance>=100.0f)
821 return &ExplicitlyChanced[i];
823 Roll -= ExplicitlyChanced[i].chance;
824 if (Roll < 0)
825 return &ExplicitlyChanced[i];
828 if (!EqualChanced.empty()) // If nothing selected yet - an item is taken from equal-chanced part
829 return &EqualChanced[irand(0, EqualChanced.size()-1)];
831 return NULL; // Empty drop from the group
834 // True if group includes at least 1 quest drop entry
835 bool LootTemplate::LootGroup::HasQuestDrop() const
837 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
838 if (i->needs_quest)
839 return true;
840 for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
841 if (i->needs_quest)
842 return true;
843 return false;
846 // True if group includes at least 1 quest drop entry for active quests of the player
847 bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const
849 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
850 if (player->HasQuestForItem(i->itemid))
851 return true;
852 for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
853 if (player->HasQuestForItem(i->itemid))
854 return true;
855 return false;
858 // Rolls an item from the group (if any takes its chance) and adds the item to the loot
859 void LootTemplate::LootGroup::Process(Loot& loot) const
861 LootStoreItem const * item = Roll();
862 if (item != NULL)
863 loot.AddItem(*item);
866 // Overall chance for the group without equal chanced items
867 float LootTemplate::LootGroup::RawTotalChance() const
869 float result = 0;
871 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
872 if ( !i->needs_quest )
873 result += i->chance;
875 return result;
878 // Overall chance for the group
879 float LootTemplate::LootGroup::TotalChance() const
881 float result = RawTotalChance();
883 if (!EqualChanced.empty() && result < 100.0f)
884 return 100.0f;
886 return result;
889 void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint32 group_id) const
891 float chance = RawTotalChance();
892 if (chance > 101.0f) // TODO: replace with 100% when DBs will be ready
894 sLog.outErrorDb("Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore.GetName(), id, group_id, chance);
897 if(chance >= 100.0f && !EqualChanced.empty())
899 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);
903 void LootTemplate::LootGroup::CheckLootRefs(LootIdSet* ref_set) const
905 for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
907 if(ieItr->mincountOrRef < 0)
909 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
910 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
911 else if(ref_set)
912 ref_set->erase(-ieItr->mincountOrRef);
916 for (LootStoreItemList::const_iterator ieItr=EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
918 if(ieItr->mincountOrRef < 0)
920 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
921 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
922 else if(ref_set)
923 ref_set->erase(-ieItr->mincountOrRef);
929 // --------- LootTemplate ---------
932 // Adds an entry to the group (at loading stage)
933 void LootTemplate::AddEntry(LootStoreItem& item)
935 if (item.group > 0 && item.mincountOrRef > 0) // Group
937 if (item.group >= Groups.size())
938 Groups.resize(item.group); // Adds new group the the loot template if needed
939 Groups[item.group-1].AddEntry(item); // Adds new entry to the group
941 else // Non-grouped entries and references are stored together
942 Entries.push_back(item);
945 // Rolls for every item in the template and adds the rolled items the the loot
946 void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8 groupId) const
948 if (groupId) // Group reference uses own processing of the group
950 if (groupId > Groups.size())
951 return; // Error message already printed at loading stage
953 Groups[groupId-1].Process(loot);
954 return;
957 // Rolling non-grouped items
958 for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i )
960 if (!i->Roll(rate))
961 continue; // Bad luck for the entry
963 if (i->mincountOrRef < 0) // References processing
965 LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef);
967 if(!Referenced)
968 continue; // Error message already printed at loading stage
970 for (uint32 loop=0; loop < i->maxcount; ++loop )// Ref multiplicator
971 Referenced->Process(loot, store, rate, i->group);
973 else // Plain entries (not a reference, not grouped)
974 loot.AddItem(*i); // Chance is already checked, just add
977 // Now processing groups
978 for (LootGroups::const_iterator i = Groups.begin( ) ; i != Groups.end( ) ; ++i )
979 i->Process(loot);
982 // True if template includes at least 1 quest drop entry
983 bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) const
985 if (groupId) // Group reference
987 if (groupId > Groups.size())
988 return false; // Error message [should be] already printed at loading stage
989 return Groups[groupId-1].HasQuestDrop();
992 for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i )
994 if (i->mincountOrRef < 0) // References
996 LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
997 if( Referenced ==store.end() )
998 continue; // Error message [should be] already printed at loading stage
999 if (Referenced->second->HasQuestDrop(store, i->group) )
1000 return true;
1002 else if ( i->needs_quest )
1003 return true; // quest drop found
1006 // Now processing groups
1007 for (LootGroups::const_iterator i = Groups.begin() ; i != Groups.end() ; ++i )
1008 if (i->HasQuestDrop())
1009 return true;
1011 return false;
1014 // True if template includes at least 1 quest drop for an active quest of the player
1015 bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player const* player, uint8 groupId) const
1017 if (groupId) // Group reference
1019 if (groupId > Groups.size())
1020 return false; // Error message already printed at loading stage
1021 return Groups[groupId-1].HasQuestDropForPlayer(player);
1024 // Checking non-grouped entries
1025 for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i )
1027 if (i->mincountOrRef < 0) // References processing
1029 LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
1030 if (Referenced == store.end() )
1031 continue; // Error message already printed at loading stage
1032 if (Referenced->second->HasQuestDropForPlayer(store, player, i->group) )
1033 return true;
1035 else if ( player->HasQuestForItem(i->itemid) )
1036 return true; // active quest drop found
1039 // Now checking groups
1040 for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i )
1041 if (i->HasQuestDropForPlayer(player))
1042 return true;
1044 return false;
1047 // Checks integrity of the template
1048 void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const
1050 // Checking group chances
1051 for (uint32 i=0; i < Groups.size(); ++i)
1052 Groups[i].Verify(lootstore,id,i+1);
1054 // TODO: References validity checks
1057 void LootTemplate::CheckLootRefs(LootIdSet* ref_set) const
1059 for(LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
1061 if(ieItr->mincountOrRef < 0)
1063 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
1064 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
1065 else if(ref_set)
1066 ref_set->erase(-ieItr->mincountOrRef);
1070 for(LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
1071 grItr->CheckLootRefs(ref_set);
1074 void LoadLootTemplates_Creature()
1076 LootIdSet ids_set, ids_setUsed;
1077 LootTemplates_Creature.LoadAndCollectLootIds(ids_set);
1079 // remove real entries and check existence loot
1080 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1082 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1084 if(uint32 lootid = cInfo->lootid)
1086 if(!ids_set.count(lootid))
1087 LootTemplates_Creature.ReportNotExistedId(lootid);
1088 else
1089 ids_setUsed.insert(lootid);
1093 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1094 ids_set.erase(*itr);
1096 // output error for any still listed (not referenced from appropriate table) ids
1097 LootTemplates_Creature.ReportUnusedIds(ids_set);
1100 void LoadLootTemplates_Disenchant()
1102 LootIdSet ids_set, ids_setUsed;
1103 LootTemplates_Disenchant.LoadAndCollectLootIds(ids_set);
1105 // remove real entries and check existence loot
1106 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1108 if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
1110 if(uint32 lootid = proto->DisenchantID)
1112 if(!ids_set.count(lootid))
1113 LootTemplates_Disenchant.ReportNotExistedId(lootid);
1114 else
1115 ids_setUsed.insert(lootid);
1119 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1120 ids_set.erase(*itr);
1121 // output error for any still listed (not referenced from appropriate table) ids
1122 LootTemplates_Disenchant.ReportUnusedIds(ids_set);
1125 void LoadLootTemplates_Fishing()
1127 LootIdSet ids_set;
1128 LootTemplates_Fishing.LoadAndCollectLootIds(ids_set);
1130 // remove real entries and check existence loot
1131 for(uint32 i = 1; i < sAreaStore.GetNumRows(); ++i )
1133 if(AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
1134 if(ids_set.count(areaEntry->ID))
1135 ids_set.erase(areaEntry->ID);
1138 // output error for any still listed (not referenced from appropriate table) ids
1139 LootTemplates_Fishing.ReportUnusedIds(ids_set);
1142 void LoadLootTemplates_Gameobject()
1144 LootIdSet ids_set, ids_setUsed;
1145 LootTemplates_Gameobject.LoadAndCollectLootIds(ids_set);
1147 // remove real entries and check existence loot
1148 for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i )
1150 if(GameObjectInfo const* gInfo = sGOStorage.LookupEntry<GameObjectInfo>(i))
1152 if(uint32 lootid = gInfo->GetLootId())
1154 if(!ids_set.count(lootid))
1155 LootTemplates_Gameobject.ReportNotExistedId(lootid);
1156 else
1157 ids_setUsed.insert(lootid);
1161 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1162 ids_set.erase(*itr);
1164 // output error for any still listed (not referenced from appropriate table) ids
1165 LootTemplates_Gameobject.ReportUnusedIds(ids_set);
1168 void LoadLootTemplates_Item()
1170 LootIdSet ids_set;
1171 LootTemplates_Item.LoadAndCollectLootIds(ids_set);
1173 // remove real entries and check existence loot
1174 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1175 if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
1176 if(ids_set.count(proto->ItemId))
1177 ids_set.erase(proto->ItemId);
1179 // output error for any still listed (not referenced from appropriate table) ids
1180 LootTemplates_Item.ReportUnusedIds(ids_set);
1183 void LoadLootTemplates_Milling()
1185 LootIdSet ids_set;
1186 LootTemplates_Milling.LoadAndCollectLootIds(ids_set);
1188 // remove real entries and check existence loot
1189 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1191 ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i);
1192 if(!proto)
1193 continue;
1195 if((proto->BagFamily & BAG_FAMILY_MASK_HERBS)==0)
1196 continue;
1198 if(ids_set.count(proto->ItemId))
1199 ids_set.erase(proto->ItemId);
1202 // output error for any still listed (not referenced from appropriate table) ids
1203 LootTemplates_Milling.ReportUnusedIds(ids_set);
1206 void LoadLootTemplates_Pickpocketing()
1208 LootIdSet ids_set, ids_setUsed;
1209 LootTemplates_Pickpocketing.LoadAndCollectLootIds(ids_set);
1211 // remove real entries and check existence loot
1212 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1214 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1216 if(uint32 lootid = cInfo->pickpocketLootId)
1218 if(!ids_set.count(lootid))
1219 LootTemplates_Pickpocketing.ReportNotExistedId(lootid);
1220 else
1221 ids_setUsed.insert(lootid);
1225 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1226 ids_set.erase(*itr);
1228 // output error for any still listed (not referenced from appropriate table) ids
1229 LootTemplates_Pickpocketing.ReportUnusedIds(ids_set);
1232 void LoadLootTemplates_Prospecting()
1234 LootIdSet ids_set;
1235 LootTemplates_Prospecting.LoadAndCollectLootIds(ids_set);
1237 // remove real entries and check existence loot
1238 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1240 ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i);
1241 if(!proto)
1242 continue;
1244 if((proto->BagFamily & BAG_FAMILY_MASK_MINING_SUPP)==0)
1245 continue;
1247 if(ids_set.count(proto->ItemId))
1248 ids_set.erase(proto->ItemId);
1251 // output error for any still listed (not referenced from appropriate table) ids
1252 LootTemplates_Prospecting.ReportUnusedIds(ids_set);
1255 void LoadLootTemplates_QuestMail()
1257 LootIdSet ids_set;
1258 LootTemplates_QuestMail.LoadAndCollectLootIds(ids_set);
1260 // remove real entries and check existence loot
1261 ObjectMgr::QuestMap const& questMap = objmgr.GetQuestTemplates();
1262 for(ObjectMgr::QuestMap::const_iterator itr = questMap.begin(); itr != questMap.end(); ++itr )
1264 if(!itr->second->GetRewMailTemplateId())
1265 continue;
1267 if(ids_set.count(itr->first))
1268 ids_set.erase(itr->first);
1269 /* disabled reporting: some quest mails not include items
1270 else
1271 LootTemplates_QuestMail.ReportNotExistedId(itr->first);
1275 // output error for any still listed (not referenced from appropriate table) ids
1276 LootTemplates_QuestMail.ReportUnusedIds(ids_set);
1279 void LoadLootTemplates_Skinning()
1281 LootIdSet ids_set, ids_setUsed;
1282 LootTemplates_Skinning.LoadAndCollectLootIds(ids_set);
1284 // remove real entries and check existence loot
1285 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1287 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1289 if(uint32 lootid = cInfo->SkinLootId)
1291 if(!ids_set.count(lootid))
1292 LootTemplates_Skinning.ReportNotExistedId(lootid);
1293 else
1294 ids_setUsed.insert(lootid);
1298 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1299 ids_set.erase(*itr);
1301 // output error for any still listed (not referenced from appropriate table) ids
1302 LootTemplates_Skinning.ReportUnusedIds(ids_set);
1305 void LoadLootTemplates_Spell()
1307 LootIdSet ids_set;
1308 LootTemplates_Spell.LoadAndCollectLootIds(ids_set);
1310 // remove real entries and check existence loot
1311 for(uint32 spell_id = 1; spell_id < sSpellStore.GetNumRows(); ++spell_id)
1313 SpellEntry const* spellInfo = sSpellStore.LookupEntry (spell_id);
1314 if(!spellInfo)
1315 continue;
1317 // possible cases
1318 if( !IsLootCraftingSpell(spellInfo))
1319 continue;
1321 if(!ids_set.count(spell_id))
1323 // not report about not trainable spells (optionally supported by DB)
1324 // ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
1325 if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_TRADESPELL))
1327 LootTemplates_Spell.ReportNotExistedId(spell_id);
1330 else
1331 ids_set.erase(spell_id);
1334 // output error for any still listed (not referenced from appropriate table) ids
1335 LootTemplates_Spell.ReportUnusedIds(ids_set);
1338 void LoadLootTemplates_Reference()
1340 LootIdSet ids_set;
1341 LootTemplates_Reference.LoadAndCollectLootIds(ids_set);
1343 // check references and remove used
1344 LootTemplates_Creature.CheckLootRefs(&ids_set);
1345 LootTemplates_Fishing.CheckLootRefs(&ids_set);
1346 LootTemplates_Gameobject.CheckLootRefs(&ids_set);
1347 LootTemplates_Item.CheckLootRefs(&ids_set);
1348 LootTemplates_Milling.CheckLootRefs(&ids_set);
1349 LootTemplates_Pickpocketing.CheckLootRefs(&ids_set);
1350 LootTemplates_Skinning.CheckLootRefs(&ids_set);
1351 LootTemplates_Disenchant.CheckLootRefs(&ids_set);
1352 LootTemplates_Prospecting.CheckLootRefs(&ids_set);
1353 LootTemplates_QuestMail.CheckLootRefs(&ids_set);
1354 LootTemplates_Reference.CheckLootRefs(&ids_set);
1356 // output error for any still listed ids (not referenced from any loot table)
1357 LootTemplates_Reference.ReportUnusedIds(ids_set);