[6922] Whitespace and newline fixes
[getmangos.git] / src / game / LootMgr.cpp
blob44e9d59824e1b8bb48a935e2bef7b8dc2d03b8e6
1 /*
2 * Copyright (C) 2005-2008 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"
27 static Rates const qualityToRate[MAX_ITEM_QUALITY] = {
28 RATE_DROP_ITEM_POOR, // ITEM_QUALITY_POOR
29 RATE_DROP_ITEM_NORMAL, // ITEM_QUALITY_NORMAL
30 RATE_DROP_ITEM_UNCOMMON, // ITEM_QUALITY_UNCOMMON
31 RATE_DROP_ITEM_RARE, // ITEM_QUALITY_RARE
32 RATE_DROP_ITEM_EPIC, // ITEM_QUALITY_EPIC
33 RATE_DROP_ITEM_LEGENDARY, // ITEM_QUALITY_LEGENDARY
34 RATE_DROP_ITEM_ARTIFACT, // ITEM_QUALITY_ARTIFACT
37 LootStore LootTemplates_Creature( "creature_loot_template", "creature entry");
38 LootStore LootTemplates_Disenchant( "disenchant_loot_template", "item disenchant id");
39 LootStore LootTemplates_Fishing( "fishing_loot_template", "area id");
40 LootStore LootTemplates_Gameobject( "gameobject_loot_template", "gameobject entry");
41 LootStore LootTemplates_Item( "item_loot_template", "item entry");
42 LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template","creature pickpocket lootid");
43 LootStore LootTemplates_Prospecting( "prospecting_loot_template", "item entry");
44 LootStore LootTemplates_QuestMail( "quest_mail_loot_template", "quest id");
45 LootStore LootTemplates_Reference( "reference_loot_template", "reference id");
46 LootStore LootTemplates_Skinning( "skinning_loot_template", "creature skinning id");
48 class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed)
50 public:
51 void AddEntry(LootStoreItem& item); // Adds an entry to the group (at loading stage)
52 bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
53 bool HasQuestDropForPlayer(Player const * player) const;
54 // The same for active quests of the player
55 void Process(Loot& loot) const; // Rolls an item from the group (if any) and adds the item to the loot
56 float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
57 float TotalChance() const; // Overall chance for the group
59 void Verify(LootStore const& lootstore, uint32 id, uint32 group_id) const;
60 void CollectLootIds(LootIdSet& set) const;
61 void CheckLootRefs(LootIdSet* ref_set) const;
62 private:
63 LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
64 LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
66 LootStoreItem const * Roll() const; // Rolls an item from the group, returns NULL if all miss their chances
69 //Remove all data and free all memory
70 void LootStore::Clear()
72 for (LootTemplateMap::const_iterator itr=m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
73 delete itr->second;
74 m_LootTemplates.clear();
77 // Checks validity of the loot store
78 // Actual checks are done within LootTemplate::Verify() which is called for every template
79 void LootStore::Verify() const
81 for (LootTemplateMap::const_iterator i = m_LootTemplates.begin(); i != m_LootTemplates.end(); ++i )
82 i->second->Verify(*this, i->first);
85 // Loads a *_loot_template DB table into loot store
86 // All checks of the loaded template are called from here, no error reports at loot generation required
87 void LootStore::LoadLootTable()
89 LootTemplateMap::iterator tab;
90 uint32 count = 0;
92 // Clearing store (for reloading case)
93 Clear();
95 sLog.outString( "%s :", GetName());
97 // 0 1 2 3 4 5 6 7 8
98 QueryResult *result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, groupid, mincountOrRef, maxcount, lootcondition, condition_value1, condition_value2 FROM %s",GetName());
100 if (result)
102 barGoLink bar(result->GetRowCount());
106 Field *fields = result->Fetch();
107 bar.step();
109 uint32 entry = fields[0].GetUInt32();
110 uint32 item = fields[1].GetUInt32();
111 float chanceOrQuestChance = fields[2].GetFloat();
112 uint8 group = fields[3].GetUInt8();
113 int32 mincountOrRef = fields[4].GetInt32();
114 uint8 maxcount = fields[5].GetUInt8();
115 ConditionType condition = (ConditionType)fields[6].GetUInt8();
116 uint32 cond_value1 = fields[7].GetUInt32();
117 uint32 cond_value2 = fields[8].GetUInt32();
119 if(!PlayerCondition::IsValid(condition,cond_value1, cond_value2))
121 sLog.outErrorDb("... in table '%s' entry %u item %u", GetName(), entry, item);
122 continue; // error already printed to log/console.
125 // (condition + cond_value1/2) are converted into single conditionId
126 uint16 conditionId = objmgr.GetConditionId(condition, cond_value1, cond_value2);
128 LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, group, conditionId, mincountOrRef, maxcount);
130 if (!storeitem.IsValid(*this,entry)) // Validity checks
131 continue;
133 // Looking for the template of the entry
134 // often entries are put together
135 if (m_LootTemplates.empty() || tab->first != entry)
137 // Searching the template (in case template Id changed)
138 tab = m_LootTemplates.find(entry);
139 if ( tab == m_LootTemplates.end() )
141 std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate));
142 tab = pr.first;
145 // else is empty - template Id and iter are the same
146 // finally iter refers to already existed or just created <entry, LootTemplate>
148 // Adds current row to the template
149 tab->second->AddEntry(storeitem);
150 ++count;
152 } while (result->NextRow());
154 delete result;
156 Verify(); // Checks validity of the loot store
158 sLog.outString();
159 sLog.outString( ">> Loaded %u loot definitions (%d templates)", count, m_LootTemplates.size());
161 else
163 sLog.outString();
164 sLog.outErrorDb( ">> Loaded 0 loot definitions. DB table `%s` is empty.",GetName() );
168 bool LootStore::HaveQuestLootFor(uint32 loot_id) const
170 LootTemplateMap::const_iterator itr = m_LootTemplates.find(loot_id);
171 if(itr == m_LootTemplates.end())
172 return false;
174 // scan loot for quest items
175 return itr->second->HasQuestDrop(m_LootTemplates);
178 bool LootStore::HaveQuestLootForPlayer(uint32 loot_id,Player* player) const
180 LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
181 if (tab != m_LootTemplates.end())
182 if (tab->second->HasQuestDropForPlayer(m_LootTemplates, player))
183 return true;
185 return false;
188 LootTemplate const* LootStore::GetLootFor(uint32 loot_id) const
190 LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
192 if (tab == m_LootTemplates.end())
193 return NULL;
195 return tab->second;
198 void LootStore::LoadAndCollectLootIds(LootIdSet& ids_set)
200 LoadLootTable();
202 for(LootTemplateMap::const_iterator tab = m_LootTemplates.begin(); tab != m_LootTemplates.end(); ++tab)
203 ids_set.insert(tab->first);
206 void LootStore::CheckLootRefs(LootIdSet* ref_set) const
208 for(LootTemplateMap::const_iterator ltItr = m_LootTemplates.begin(); ltItr != m_LootTemplates.end(); ++ltItr)
209 ltItr->second->CheckLootRefs(ref_set);
212 void LootStore::ReportUnusedIds(LootIdSet const& ids_set) const
214 // all still listed ids isn't referenced
215 for(LootIdSet::const_iterator itr = ids_set.begin(); itr != ids_set.end(); ++itr)
216 sLog.outErrorDb("Table '%s' entry %d isn't %s and not referenced from loot, and then useless.", GetName(), *itr,GetEntryName());
219 void LootStore::ReportNotExistedId(uint32 id) const
221 sLog.outErrorDb("Table '%s' entry %d (%s) not exist but used as loot id in DB.", GetName(), id,GetEntryName());
225 // --------- LootStoreItem ---------
228 // Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
229 // RATE_DROP_ITEMS is no longer used for all types of entries
230 bool LootStoreItem::Roll() const
232 if(chance>=100.f)
233 return true;
235 if(mincountOrRef < 0) // reference case
236 return roll_chance_f(chance*sWorld.getRate(RATE_DROP_ITEM_REFERENCED));
238 ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid);
240 float qualityModifier = pProto ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
242 return roll_chance_f(chance*qualityModifier);
245 // Checks correctness of values
246 bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
248 if (mincountOrRef == 0)
250 sLog.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincountOrRef);
251 return false;
254 if( mincountOrRef > 0 ) // item (quest or non-quest) entry, maybe grouped
256 ItemPrototype const *proto = objmgr.GetItemPrototype(itemid);
257 if(!proto)
259 sLog.outErrorDb("Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store.GetName(), entry, itemid);
260 return false;
263 if( chance == 0 && group == 0) // Zero chance is allowed for grouped entries only
265 sLog.outErrorDb("Table '%s' entry %d item %d: equal-chanced grouped entry, but group not defined - skipped", store.GetName(), entry, itemid);
266 return false;
269 if( chance != 0 && chance < 0.000001f ) // loot with low chance
271 sLog.outErrorDb("Table '%s' entry %d item %d: low chance (%f) - skipped",
272 store.GetName(), entry, itemid, chance);
273 return false;
276 else // mincountOrRef < 0
278 if (needs_quest)
279 sLog.outErrorDb("Table '%s' entry %d item %d: quest chance will be treated as non-quest chance", store.GetName(), entry, itemid);
280 else if( chance == 0 ) // no chance for the reference
282 sLog.outErrorDb("Table '%s' entry %d item %d: zero chance is specified for a reference, skipped", store.GetName(), entry, itemid);
283 return false;
286 return true; // Referenced template existence is checked at whole store level
290 // --------- LootItem ---------
293 // Constructor, copies most fields from LootStoreItem and generates random count
294 LootItem::LootItem(LootStoreItem const& li)
296 itemid = li.itemid;
297 conditionId = li.conditionId;
299 ItemPrototype const* proto = objmgr.GetItemPrototype(itemid);
300 freeforall = proto && (proto->Flags & ITEM_FLAGS_PARTY_LOOT);
302 needs_quest = li.needs_quest;
304 count = urand(li.mincountOrRef, li.maxcount); // constructor called for mincountOrRef > 0 only
305 randomSuffix = GenerateEnchSuffixFactor(itemid);
306 randomPropertyId = Item::GenerateItemRandomPropertyId(itemid);
307 is_looted = 0;
308 is_blocked = 0;
309 is_underthreshold = 0;
310 is_counted = 0;
313 // Basic checks for player/item compatibility - if false no chance to see the item in the loot
314 bool LootItem::AllowedForPlayer(Player const * player) const
316 // DB conditions check
317 if ( !objmgr.IsPlayerMeetToCondition(player,conditionId) )
318 return false;
320 if ( needs_quest )
322 // Checking quests for quest-only drop (check only quests requirements in this case)
323 if( !player->HasQuestForItem(itemid) )
324 return false;
326 else
328 // Not quest only drop (check quest starting items for already accepted non-repeatable quests)
329 ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid);
330 if (pProto && pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE && !player->HasQuestForItem(itemid))
331 return false;
334 return true;
338 // --------- Loot ---------
341 // Inserts the item into the loot (called by LootTemplate processors)
342 void Loot::AddItem(LootStoreItem const & item)
344 if (item.needs_quest) // Quest drop
346 if (quest_items.size() < MAX_NR_QUEST_ITEMS)
347 quest_items.push_back(LootItem(item));
349 else if (items.size() < MAX_NR_LOOT_ITEMS) // Non-quest drop
351 items.push_back(LootItem(item));
353 // non-conditional one-player only items are counted here,
354 // free for all items are counted in FillFFALoot(),
355 // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
356 if( !item.conditionId )
358 ItemPrototype const* proto = objmgr.GetItemPrototype(item.itemid);
359 if( !proto || (proto->Flags & ITEM_FLAGS_PARTY_LOOT)==0 )
360 ++unlootedCount;
365 // Calls processor of corresponding LootTemplate (which handles everything including references)
366 void Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner)
368 LootTemplate const* tab = store.GetLootFor(loot_id);
370 if (!tab)
372 sLog.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.",store.GetName(),loot_id);
373 return;
376 items.reserve(MAX_NR_LOOT_ITEMS);
377 quest_items.reserve(MAX_NR_QUEST_ITEMS);
379 tab->Process(*this, store); // Processing is done there, callback via Loot::AddItem()
381 // Setting access rights fow group-looting case
382 if(!loot_owner)
383 return;
384 Group * pGroup=loot_owner->GetGroup();
385 if(!pGroup)
386 return;
387 for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
389 //fill the quest item map for every player in the recipient's group
390 Player* pl = itr->getSource();
391 if(!pl)
392 continue;
393 uint32 plguid = pl->GetGUIDLow();
394 QuestItemMap::iterator qmapitr = PlayerQuestItems.find(plguid);
395 if (qmapitr == PlayerQuestItems.end())
397 FillQuestLoot(pl);
399 qmapitr = PlayerFFAItems.find(plguid);
400 if (qmapitr == PlayerFFAItems.end())
402 FillFFALoot(pl);
404 qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
405 if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
407 FillNonQuestNonFFAConditionalLoot(pl);
412 QuestItemList* Loot::FillFFALoot(Player* player)
414 QuestItemList *ql = new QuestItemList();
416 for(uint8 i = 0; i < items.size(); i++)
418 LootItem &item = items[i];
419 if(!item.is_looted && item.freeforall && item.AllowedForPlayer(player) )
421 ql->push_back(QuestItem(i));
422 ++unlootedCount;
425 if (ql->empty())
427 delete ql;
428 return NULL;
431 PlayerFFAItems[player->GetGUIDLow()] = ql;
432 return ql;
435 QuestItemList* Loot::FillQuestLoot(Player* player)
437 if (items.size() == MAX_NR_LOOT_ITEMS) return NULL;
438 QuestItemList *ql = new QuestItemList();
440 for(uint8 i = 0; i < quest_items.size(); i++)
442 LootItem &item = quest_items[i];
443 if(!item.is_looted && item.AllowedForPlayer(player) )
445 ql->push_back(QuestItem(i));
447 // questitems get blocked when they first apper in a
448 // player's quest vector
450 // increase once if one looter only, looter-times if free for all
451 if (item.freeforall || !item.is_blocked)
452 ++unlootedCount;
454 item.is_blocked = true;
456 if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS)
457 break;
460 if (ql->empty())
462 delete ql;
463 return NULL;
466 PlayerQuestItems[player->GetGUIDLow()] = ql;
467 return ql;
470 QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player)
472 QuestItemList *ql = new QuestItemList();
474 for(uint8 i = 0; i < items.size(); ++i)
476 LootItem &item = items[i];
477 if(!item.is_looted && !item.freeforall && item.conditionId && item.AllowedForPlayer(player))
479 ql->push_back(QuestItem(i));
480 if(!item.is_counted)
482 ++unlootedCount;
483 item.is_counted=true;
487 if (ql->empty())
489 delete ql;
490 return NULL;
493 PlayerNonQuestNonFFAConditionalItems[player->GetGUIDLow()] = ql;
494 return ql;
497 //===================================================
499 void Loot::NotifyItemRemoved(uint8 lootIndex)
501 // notify all players that are looting this that the item was removed
502 // convert the index to the slot the player sees
503 std::set<uint64>::iterator i_next;
504 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
506 i_next = i;
507 ++i_next;
508 if(Player* pl = ObjectAccessor::FindPlayer(*i))
509 pl->SendNotifyLootItemRemoved(lootIndex);
510 else
511 PlayersLooting.erase(i);
515 void Loot::NotifyMoneyRemoved()
517 // notify all players that are looting this that the money was removed
518 std::set<uint64>::iterator i_next;
519 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
521 i_next = i;
522 ++i_next;
523 if(Player* pl = ObjectAccessor::FindPlayer(*i))
524 pl->SendNotifyLootMoneyRemoved();
525 else
526 PlayersLooting.erase(i);
530 void Loot::NotifyQuestItemRemoved(uint8 questIndex)
532 // when a free for all questitem is looted
533 // all players will get notified of it being removed
534 // (other questitems can be looted by each group member)
535 // bit inefficient but isnt called often
537 std::set<uint64>::iterator i_next;
538 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
540 i_next = i;
541 ++i_next;
542 if(Player* pl = ObjectAccessor::FindPlayer(*i))
544 QuestItemMap::iterator pq = PlayerQuestItems.find(pl->GetGUIDLow());
545 if (pq != PlayerQuestItems.end() && pq->second)
547 // find where/if the player has the given item in it's vector
548 QuestItemList& pql = *pq->second;
550 uint8 j;
551 for (j = 0; j < pql.size(); ++j)
552 if (pql[j].index == questIndex)
553 break;
555 if (j < pql.size())
556 pl->SendNotifyLootItemRemoved(items.size()+j);
559 else
560 PlayersLooting.erase(i);
564 void Loot::generateMoneyLoot( uint32 minAmount, uint32 maxAmount )
566 if (maxAmount > 0)
568 if (maxAmount <= minAmount)
569 gold = uint32(maxAmount * sWorld.getRate(RATE_DROP_MONEY));
570 else if ((maxAmount - minAmount) < 32700)
571 gold = uint32(urand(minAmount, maxAmount) * sWorld.getRate(RATE_DROP_MONEY));
572 else
573 gold = uint32(urand(minAmount >> 8, maxAmount >> 8) * sWorld.getRate(RATE_DROP_MONEY)) << 8;
577 LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qitem, QuestItem **ffaitem, QuestItem **conditem)
579 LootItem* item = NULL;
580 bool is_looted = true;
581 if (lootSlot >= items.size())
583 uint32 questSlot = lootSlot - items.size();
584 QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
585 if (itr != PlayerQuestItems.end() && questSlot < itr->second->size())
587 QuestItem *qitem2 = &itr->second->at(questSlot);
588 if(qitem)
589 *qitem = qitem2;
590 item = &quest_items[qitem2->index];
591 is_looted = qitem2->is_looted;
594 else
596 item = &items[lootSlot];
597 is_looted = item->is_looted;
598 if(item->freeforall)
600 QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUIDLow());
601 if (itr != PlayerFFAItems.end())
603 for(QuestItemList::iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
604 if(iter->index==lootSlot)
606 QuestItem *ffaitem2 = (QuestItem*)&(*iter);
607 if(ffaitem)
608 *ffaitem = ffaitem2;
609 is_looted = ffaitem2->is_looted;
610 break;
614 else if(item->conditionId)
616 QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
617 if (itr != PlayerNonQuestNonFFAConditionalItems.end())
619 for(QuestItemList::iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
621 if(iter->index==lootSlot)
623 QuestItem *conditem2 = (QuestItem*)&(*iter);
624 if(conditem)
625 *conditem = conditem2;
626 is_looted = conditem2->is_looted;
627 break;
634 if(is_looted)
635 return NULL;
637 return item;
640 ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
642 b << uint32(li.itemid);
643 b << uint32(li.count); // nr of items of this type
644 b << uint32(objmgr.GetItemPrototype(li.itemid)->DisplayInfoID);
645 b << uint32(li.randomSuffix);
646 b << uint32(li.randomPropertyId);
647 //b << uint8(0); // slot type - will send after this function call
648 return b;
651 ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
653 Loot &l = lv.loot;
655 uint8 itemsShown = 0;
657 //gold
658 b << uint32(lv.permission!=NONE_PERMISSION ? l.gold : 0);
660 size_t count_pos = b.wpos(); // pos of item count byte
661 b << uint8(0); // item count placeholder
663 switch (lv.permission)
665 case GROUP_PERMISSION:
667 // You are not the items proprietary, so you can only see
668 // blocked rolled items and quest items, and !ffa items
669 for (uint8 i = 0; i < l.items.size(); ++i)
671 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
673 uint8 slot_type = (l.items[i].is_blocked || l.items[i].is_underthreshold) ? 0 : 1;
675 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
676 b << uint8(slot_type); // 0 - get 1 - look only
677 ++itemsShown;
680 break;
682 case ALL_PERMISSION:
683 case MASTER_PERMISSION:
685 uint8 slot_type = (lv.permission==MASTER_PERMISSION) ? 2 : 0;
686 for (uint8 i = 0; i < l.items.size(); ++i)
688 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
690 b << uint8(i) << l.items[i]; //only send one-player loot items now, free for all will be sent later
691 b << uint8(slot_type); // 0 - get 2 - master selection
692 ++itemsShown;
695 break;
697 case NONE_PERMISSION:
698 default:
699 return b; // nothing output more
702 if (lv.qlist)
704 for (QuestItemList::iterator qi = lv.qlist->begin() ; qi != lv.qlist->end(); ++qi)
706 LootItem &item = l.quest_items[qi->index];
707 if (!qi->is_looted && !item.is_looted)
709 b << uint8(l.items.size() + (qi - lv.qlist->begin()));
710 b << item;
711 b << uint8(0); // allow loot
712 ++itemsShown;
717 if (lv.ffalist)
719 for (QuestItemList::iterator fi = lv.ffalist->begin() ; fi != lv.ffalist->end(); ++fi)
721 LootItem &item = l.items[fi->index];
722 if (!fi->is_looted && !item.is_looted)
724 b << uint8(fi->index) << item;
725 b << uint8(0); // allow loot
726 ++itemsShown;
731 if (lv.conditionallist)
733 for (QuestItemList::iterator ci = lv.conditionallist->begin() ; ci != lv.conditionallist->end(); ++ci)
735 LootItem &item = l.items[ci->index];
736 if (!ci->is_looted && !item.is_looted)
738 b << uint8(ci->index) << item;
739 b << uint8(0); // allow loot
740 ++itemsShown;
745 //update number of items shown
746 b.put<uint8>(count_pos,itemsShown);
748 return b;
752 // --------- LootTemplate::LootGroup ---------
755 // Adds an entry to the group (at loading stage)
756 void LootTemplate::LootGroup::AddEntry(LootStoreItem& item)
758 if (item.chance != 0)
759 ExplicitlyChanced.push_back(item);
760 else
761 EqualChanced.push_back(item);
764 // Rolls an item from the group, returns NULL if all miss their chances
765 LootStoreItem const * LootTemplate::LootGroup::Roll() const
767 if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked
769 float Roll = rand_chance();
771 for (uint32 i=0; i<ExplicitlyChanced.size(); ++i) //check each explicitly chanced entry in the template and modify its chance based on quality.
773 if(ExplicitlyChanced[i].chance>=100.f)
774 return &ExplicitlyChanced[i];
776 ItemPrototype const *pProto = objmgr.GetItemPrototype(ExplicitlyChanced[i].itemid);
777 float qualityMultiplier = pProto ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
778 Roll -= ExplicitlyChanced[i].chance * qualityMultiplier;
779 if (Roll < 0)
780 return &ExplicitlyChanced[i];
783 if (!EqualChanced.empty()) // If nothing selected yet - an item is taken from equal-chanced part
784 return &EqualChanced[irand(0, EqualChanced.size()-1)];
786 return NULL; // Empty drop from the group
789 // True if group includes at least 1 quest drop entry
790 bool LootTemplate::LootGroup::HasQuestDrop() const
792 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
793 if (i->needs_quest)
794 return true;
795 for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
796 if (i->needs_quest)
797 return true;
798 return false;
801 // True if group includes at least 1 quest drop entry for active quests of the player
802 bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const
804 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
805 if (player->HasQuestForItem(i->itemid))
806 return true;
807 for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
808 if (player->HasQuestForItem(i->itemid))
809 return true;
810 return false;
813 // Rolls an item from the group (if any takes its chance) and adds the item to the loot
814 void LootTemplate::LootGroup::Process(Loot& loot) const
816 LootStoreItem const * item = Roll();
817 if (item != NULL)
818 loot.AddItem(*item);
821 // Overall chance for the group without equal chanced items
822 float LootTemplate::LootGroup::RawTotalChance() const
824 float result = 0;
826 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
827 if ( !i->needs_quest )
828 result += i->chance;
830 return result;
833 // Overall chance for the group
834 float LootTemplate::LootGroup::TotalChance() const
836 float result = RawTotalChance();
838 if (!EqualChanced.empty() && result < 100.0f)
839 return 100.0f;
841 return result;
844 void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint32 group_id) const
846 float chance = RawTotalChance();
847 if (chance > 101.0f) // TODO: replace with 100% when DBs will be ready
849 sLog.outErrorDb("Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore.GetName(), id, group_id, chance);
852 if(chance >= 100.0f && !EqualChanced.empty())
854 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);
858 void LootTemplate::LootGroup::CheckLootRefs(LootIdSet* ref_set) const
860 for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
862 if(ieItr->mincountOrRef < 0)
864 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
865 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
866 else if(ref_set)
867 ref_set->erase(-ieItr->mincountOrRef);
871 for (LootStoreItemList::const_iterator ieItr=EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
873 if(ieItr->mincountOrRef < 0)
875 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
876 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
877 else if(ref_set)
878 ref_set->erase(-ieItr->mincountOrRef);
884 // --------- LootTemplate ---------
887 // Adds an entry to the group (at loading stage)
888 void LootTemplate::AddEntry(LootStoreItem& item)
890 if (item.group > 0 && item.mincountOrRef > 0) // Group
892 if (item.group >= Groups.size())
893 Groups.resize(item.group); // Adds new group the the loot template if needed
894 Groups[item.group-1].AddEntry(item); // Adds new entry to the group
896 else // Non-grouped entries and references are stored together
897 Entries.push_back(item);
900 // Rolls for every item in the template and adds the rolled items the the loot
901 void LootTemplate::Process(Loot& loot, LootStore const& store, uint8 groupId) const
903 if (groupId) // Group reference uses own processing of the group
905 if (groupId > Groups.size())
906 return; // Error message already printed at loading stage
908 Groups[groupId-1].Process(loot);
909 return;
912 // Rolling non-grouped items
913 for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i )
915 if ( !i->Roll() )
916 continue; // Bad luck for the entry
918 if (i->mincountOrRef < 0) // References processing
920 LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef);
922 if(!Referenced)
923 continue; // Error message already printed at loading stage
925 for (uint32 loop=0; loop < i->maxcount; ++loop )// Ref multiplicator
926 Referenced->Process(loot, store, i->group); // Ref processing
928 else // Plain entries (not a reference, not grouped)
929 loot.AddItem(*i); // Chance is already checked, just add
932 // Now processing groups
933 for (LootGroups::const_iterator i = Groups.begin( ) ; i != Groups.end( ) ; ++i )
934 i->Process(loot);
937 // True if template includes at least 1 quest drop entry
938 bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) const
940 if (groupId) // Group reference
942 if (groupId > Groups.size())
943 return false; // Error message [should be] already printed at loading stage
944 return Groups[groupId-1].HasQuestDrop();
947 for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i )
949 if (i->mincountOrRef < 0) // References
951 LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
952 if( Referenced ==store.end() )
953 continue; // Error message [should be] already printed at loading stage
954 if (Referenced->second->HasQuestDrop(store, i->group) )
955 return true;
957 else if ( i->needs_quest )
958 return true; // quest drop found
961 // Now processing groups
962 for (LootGroups::const_iterator i = Groups.begin() ; i != Groups.end() ; ++i )
963 if (i->HasQuestDrop())
964 return true;
966 return false;
969 // True if template includes at least 1 quest drop for an active quest of the player
970 bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player const* player, uint8 groupId) const
972 if (groupId) // Group reference
974 if (groupId > Groups.size())
975 return false; // Error message already printed at loading stage
976 return Groups[groupId-1].HasQuestDropForPlayer(player);
979 // Checking non-grouped entries
980 for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i )
982 if (i->mincountOrRef < 0) // References processing
984 LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
985 if (Referenced == store.end() )
986 continue; // Error message already printed at loading stage
987 if (Referenced->second->HasQuestDropForPlayer(store, player, i->group) )
988 return true;
990 else if ( player->HasQuestForItem(i->itemid) )
991 return true; // active quest drop found
994 // Now checking groups
995 for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i )
996 if (i->HasQuestDrop())
997 return true;
999 return false;
1002 // Checks integrity of the template
1003 void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const
1005 // Checking group chances
1006 for (uint32 i=0; i < Groups.size(); ++i)
1007 Groups[i].Verify(lootstore,id,i+1);
1009 // TODO: References validity checks
1012 void LootTemplate::CheckLootRefs(LootIdSet* ref_set) const
1014 for(LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
1016 if(ieItr->mincountOrRef < 0)
1018 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
1019 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
1020 else if(ref_set)
1021 ref_set->erase(-ieItr->mincountOrRef);
1025 for(LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
1026 grItr->CheckLootRefs(ref_set);
1029 void LoadLootTemplates_Creature()
1031 LootIdSet ids_set, ids_setUsed;
1032 LootTemplates_Creature.LoadAndCollectLootIds(ids_set);
1034 // remove real entries and check existence loot
1035 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1037 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1039 if(uint32 lootid = cInfo->lootid)
1041 if(!ids_set.count(lootid))
1042 LootTemplates_Creature.ReportNotExistedId(lootid);
1043 else
1044 ids_setUsed.insert(lootid);
1048 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1049 ids_set.erase(*itr);
1051 // output error for any still listed (not referenced from appropriate table) ids
1052 LootTemplates_Creature.ReportUnusedIds(ids_set);
1055 void LoadLootTemplates_Disenchant()
1057 LootIdSet ids_set, ids_setUsed;
1058 LootTemplates_Disenchant.LoadAndCollectLootIds(ids_set);
1060 // remove real entries and check existence loot
1061 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1063 if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
1065 if(uint32 lootid = proto->DisenchantID)
1067 if(!ids_set.count(lootid))
1068 LootTemplates_Disenchant.ReportNotExistedId(lootid);
1069 else
1070 ids_setUsed.insert(lootid);
1074 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1075 ids_set.erase(*itr);
1076 // output error for any still listed (not referenced from appropriate table) ids
1077 LootTemplates_Disenchant.ReportUnusedIds(ids_set);
1080 void LoadLootTemplates_Fishing()
1082 LootIdSet ids_set;
1083 LootTemplates_Fishing.LoadAndCollectLootIds(ids_set);
1085 // remove real entries and check existence loot
1086 for(uint32 i = 1; i < sAreaStore.GetNumRows(); ++i )
1088 if(AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
1089 if(ids_set.count(areaEntry->ID))
1090 ids_set.erase(areaEntry->ID);
1093 // output error for any still listed (not referenced from appropriate table) ids
1094 LootTemplates_Fishing.ReportUnusedIds(ids_set);
1097 void LoadLootTemplates_Gameobject()
1099 LootIdSet ids_set, ids_setUsed;
1100 LootTemplates_Gameobject.LoadAndCollectLootIds(ids_set);
1102 // remove real entries and check existence loot
1103 for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i )
1105 if(GameObjectInfo const* gInfo = sGOStorage.LookupEntry<GameObjectInfo>(i))
1107 if(uint32 lootid = GameObject::GetLootId(gInfo))
1109 if(!ids_set.count(lootid))
1110 LootTemplates_Gameobject.ReportNotExistedId(lootid);
1111 else
1112 ids_setUsed.insert(lootid);
1116 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1117 ids_set.erase(*itr);
1119 // output error for any still listed (not referenced from appropriate table) ids
1120 LootTemplates_Gameobject.ReportUnusedIds(ids_set);
1123 void LoadLootTemplates_Item()
1125 LootIdSet ids_set;
1126 LootTemplates_Item.LoadAndCollectLootIds(ids_set);
1128 // remove real entries and check existence loot
1129 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1130 if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
1131 if(ids_set.count(proto->ItemId))
1132 ids_set.erase(proto->ItemId);
1134 // output error for any still listed (not referenced from appropriate table) ids
1135 LootTemplates_Item.ReportUnusedIds(ids_set);
1138 void LoadLootTemplates_Pickpocketing()
1140 LootIdSet ids_set, ids_setUsed;
1141 LootTemplates_Pickpocketing.LoadAndCollectLootIds(ids_set);
1143 // remove real entries and check existence loot
1144 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1146 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1148 if(uint32 lootid = cInfo->pickpocketLootId)
1150 if(!ids_set.count(lootid))
1151 LootTemplates_Pickpocketing.ReportNotExistedId(lootid);
1152 else
1153 ids_setUsed.insert(lootid);
1157 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1158 ids_set.erase(*itr);
1160 // output error for any still listed (not referenced from appropriate table) ids
1161 LootTemplates_Pickpocketing.ReportUnusedIds(ids_set);
1164 void LoadLootTemplates_Prospecting()
1166 LootIdSet ids_set;
1167 LootTemplates_Prospecting.LoadAndCollectLootIds(ids_set);
1169 // remove real entries and check existence loot
1170 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1171 if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
1172 if(ids_set.count(proto->ItemId))
1173 ids_set.erase(proto->ItemId);
1175 // output error for any still listed (not referenced from appropriate table) ids
1176 LootTemplates_Prospecting.ReportUnusedIds(ids_set);
1179 void LoadLootTemplates_QuestMail()
1181 LootIdSet ids_set;
1182 LootTemplates_QuestMail.LoadAndCollectLootIds(ids_set);
1184 // remove real entries and check existence loot
1185 ObjectMgr::QuestMap const& questMap = objmgr.GetQuestTemplates();
1186 for(ObjectMgr::QuestMap::const_iterator itr = questMap.begin(); itr != questMap.end(); ++itr )
1187 if(ids_set.count(itr->first))
1188 ids_set.erase(itr->first);
1190 // output error for any still listed (not referenced from appropriate table) ids
1191 LootTemplates_QuestMail.ReportUnusedIds(ids_set);
1194 void LoadLootTemplates_Skinning()
1196 LootIdSet ids_set, ids_setUsed;
1197 LootTemplates_Skinning.LoadAndCollectLootIds(ids_set);
1199 // remove real entries and check existence loot
1200 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1202 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1204 if(uint32 lootid = cInfo->SkinLootId)
1206 if(!ids_set.count(lootid))
1207 LootTemplates_Skinning.ReportNotExistedId(lootid);
1208 else
1209 ids_setUsed.insert(lootid);
1213 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1214 ids_set.erase(*itr);
1216 // output error for any still listed (not referenced from appropriate table) ids
1217 LootTemplates_Skinning.ReportUnusedIds(ids_set);
1220 void LoadLootTemplates_Reference()
1222 LootIdSet ids_set;
1223 LootTemplates_Reference.LoadAndCollectLootIds(ids_set);
1225 // check references and remove used
1226 LootTemplates_Creature.CheckLootRefs(&ids_set);
1227 LootTemplates_Fishing.CheckLootRefs(&ids_set);
1228 LootTemplates_Gameobject.CheckLootRefs(&ids_set);
1229 LootTemplates_Item.CheckLootRefs(&ids_set);
1230 LootTemplates_Pickpocketing.CheckLootRefs(&ids_set);
1231 LootTemplates_Skinning.CheckLootRefs(&ids_set);
1232 LootTemplates_Disenchant.CheckLootRefs(&ids_set);
1233 LootTemplates_Prospecting.CheckLootRefs(&ids_set);
1234 LootTemplates_QuestMail.CheckLootRefs(&ids_set);
1235 LootTemplates_Reference.CheckLootRefs(&ids_set);
1237 // output error for any still listed ids (not referenced from any loot table)
1238 LootTemplates_Reference.ReportUnusedIds(ids_set);