[7234] Now correct patch version: Use spell_loot_table for item creating in case...
[getmangos.git] / src / game / LootMgr.cpp
blobdeb9a26bd2f57148c0703f8e93318dd8429ebf6d
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 (explicitly discovering ability)",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, bool rate) 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(bool rate) 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::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 uint8 maxcount = fields[5].GetUInt8();
118 ConditionType condition = (ConditionType)fields[6].GetUInt8();
119 uint32 cond_value1 = fields[7].GetUInt32();
120 uint32 cond_value2 = fields[8].GetUInt32();
122 if(!PlayerCondition::IsValid(condition,cond_value1, cond_value2))
124 sLog.outErrorDb("... in table '%s' entry %u item %u", GetName(), entry, item);
125 continue; // error already printed to log/console.
128 // (condition + cond_value1/2) are converted into single conditionId
129 uint16 conditionId = objmgr.GetConditionId(condition, cond_value1, cond_value2);
131 LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, group, conditionId, mincountOrRef, maxcount);
133 if (!storeitem.IsValid(*this,entry)) // Validity checks
134 continue;
136 // Looking for the template of the entry
137 // often entries are put together
138 if (m_LootTemplates.empty() || tab->first != entry)
140 // Searching the template (in case template Id changed)
141 tab = m_LootTemplates.find(entry);
142 if ( tab == m_LootTemplates.end() )
144 std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate));
145 tab = pr.first;
148 // else is empty - template Id and iter are the same
149 // finally iter refers to already existed or just created <entry, LootTemplate>
151 // Adds current row to the template
152 tab->second->AddEntry(storeitem);
153 ++count;
155 } while (result->NextRow());
157 delete result;
159 Verify(); // Checks validity of the loot store
161 sLog.outString();
162 sLog.outString( ">> Loaded %u loot definitions (%d templates)", count, m_LootTemplates.size());
164 else
166 sLog.outString();
167 sLog.outErrorDb( ">> Loaded 0 loot definitions. DB table `%s` is empty.",GetName() );
171 bool LootStore::HaveQuestLootFor(uint32 loot_id) const
173 LootTemplateMap::const_iterator itr = m_LootTemplates.find(loot_id);
174 if(itr == m_LootTemplates.end())
175 return false;
177 // scan loot for quest items
178 return itr->second->HasQuestDrop(m_LootTemplates);
181 bool LootStore::HaveQuestLootForPlayer(uint32 loot_id,Player* player) const
183 LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
184 if (tab != m_LootTemplates.end())
185 if (tab->second->HasQuestDropForPlayer(m_LootTemplates, player))
186 return true;
188 return false;
191 LootTemplate const* LootStore::GetLootFor(uint32 loot_id) const
193 LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
195 if (tab == m_LootTemplates.end())
196 return NULL;
198 return tab->second;
201 void LootStore::LoadAndCollectLootIds(LootIdSet& ids_set)
203 LoadLootTable();
205 for(LootTemplateMap::const_iterator tab = m_LootTemplates.begin(); tab != m_LootTemplates.end(); ++tab)
206 ids_set.insert(tab->first);
209 void LootStore::CheckLootRefs(LootIdSet* ref_set) const
211 for(LootTemplateMap::const_iterator ltItr = m_LootTemplates.begin(); ltItr != m_LootTemplates.end(); ++ltItr)
212 ltItr->second->CheckLootRefs(ref_set);
215 void LootStore::ReportUnusedIds(LootIdSet const& ids_set) const
217 // all still listed ids isn't referenced
218 for(LootIdSet::const_iterator itr = ids_set.begin(); itr != ids_set.end(); ++itr)
219 sLog.outErrorDb("Table '%s' entry %d isn't %s and not referenced from loot, and then useless.", GetName(), *itr,GetEntryName());
222 void LootStore::ReportNotExistedId(uint32 id) const
224 sLog.outErrorDb("Table '%s' entry %d (%s) not exist but used as loot id in DB.", GetName(), id,GetEntryName());
228 // --------- LootStoreItem ---------
231 // Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
232 // RATE_DROP_ITEMS is no longer used for all types of entries
233 bool LootStoreItem::Roll(bool rate) const
235 if(chance>=100.f)
236 return true;
238 if(mincountOrRef < 0) // reference case
239 return roll_chance_f(chance* (rate ? sWorld.getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
241 ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid);
243 float qualityModifier = pProto && rate ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
245 return roll_chance_f(chance*qualityModifier);
248 // Checks correctness of values
249 bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
251 if (mincountOrRef == 0)
253 sLog.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincountOrRef);
254 return false;
257 if( mincountOrRef > 0 ) // item (quest or non-quest) entry, maybe grouped
259 ItemPrototype const *proto = objmgr.GetItemPrototype(itemid);
260 if(!proto)
262 sLog.outErrorDb("Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store.GetName(), entry, itemid);
263 return false;
266 if( chance == 0 && group == 0) // Zero chance is allowed for grouped entries only
268 sLog.outErrorDb("Table '%s' entry %d item %d: equal-chanced grouped entry, but group not defined - skipped", store.GetName(), entry, itemid);
269 return false;
272 if( chance != 0 && chance < 0.000001f ) // loot with low chance
274 sLog.outErrorDb("Table '%s' entry %d item %d: low chance (%f) - skipped",
275 store.GetName(), entry, itemid, chance);
276 return false;
279 else // mincountOrRef < 0
281 if (needs_quest)
282 sLog.outErrorDb("Table '%s' entry %d item %d: quest chance will be treated as non-quest chance", store.GetName(), entry, itemid);
283 else if( chance == 0 ) // no chance for the reference
285 sLog.outErrorDb("Table '%s' entry %d item %d: zero chance is specified for a reference, skipped", store.GetName(), entry, itemid);
286 return false;
289 return true; // Referenced template existence is checked at whole store level
293 // --------- LootItem ---------
296 // Constructor, copies most fields from LootStoreItem and generates random count
297 LootItem::LootItem(LootStoreItem const& li)
299 itemid = li.itemid;
300 conditionId = li.conditionId;
302 ItemPrototype const* proto = objmgr.GetItemPrototype(itemid);
303 freeforall = proto && (proto->Flags & ITEM_FLAGS_PARTY_LOOT);
305 needs_quest = li.needs_quest;
307 count = urand(li.mincountOrRef, li.maxcount); // constructor called for mincountOrRef > 0 only
308 randomSuffix = GenerateEnchSuffixFactor(itemid);
309 randomPropertyId = Item::GenerateItemRandomPropertyId(itemid);
310 is_looted = 0;
311 is_blocked = 0;
312 is_underthreshold = 0;
313 is_counted = 0;
316 // Basic checks for player/item compatibility - if false no chance to see the item in the loot
317 bool LootItem::AllowedForPlayer(Player const * player) const
319 // DB conditions check
320 if ( !objmgr.IsPlayerMeetToCondition(player,conditionId) )
321 return false;
323 if ( needs_quest )
325 // Checking quests for quest-only drop (check only quests requirements in this case)
326 if( !player->HasQuestForItem(itemid) )
327 return false;
329 else
331 // Not quest only drop (check quest starting items for already accepted non-repeatable quests)
332 ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid);
333 if (pProto && pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE && !player->HasQuestForItem(itemid))
334 return false;
337 return true;
341 // --------- Loot ---------
344 // Inserts the item into the loot (called by LootTemplate processors)
345 void Loot::AddItem(LootStoreItem const & item)
347 if (item.needs_quest) // Quest drop
349 if (quest_items.size() < MAX_NR_QUEST_ITEMS)
350 quest_items.push_back(LootItem(item));
352 else if (items.size() < MAX_NR_LOOT_ITEMS) // Non-quest drop
354 items.push_back(LootItem(item));
356 // non-conditional one-player only items are counted here,
357 // free for all items are counted in FillFFALoot(),
358 // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
359 if( !item.conditionId )
361 ItemPrototype const* proto = objmgr.GetItemPrototype(item.itemid);
362 if( !proto || (proto->Flags & ITEM_FLAGS_PARTY_LOOT)==0 )
363 ++unlootedCount;
368 // Calls processor of corresponding LootTemplate (which handles everything including references)
369 void Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner)
371 LootTemplate const* tab = store.GetLootFor(loot_id);
373 if (!tab)
375 sLog.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.",store.GetName(),loot_id);
376 return;
379 items.reserve(MAX_NR_LOOT_ITEMS);
380 quest_items.reserve(MAX_NR_QUEST_ITEMS);
382 tab->Process(*this, store,store.IsRatesAllowed ()); // Processing is done there, callback via Loot::AddItem()
384 // Setting access rights fow group-looting case
385 if(!loot_owner)
386 return;
387 Group * pGroup=loot_owner->GetGroup();
388 if(!pGroup)
389 return;
390 for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
392 //fill the quest item map for every player in the recipient's group
393 Player* pl = itr->getSource();
394 if(!pl)
395 continue;
396 uint32 plguid = pl->GetGUIDLow();
397 QuestItemMap::iterator qmapitr = PlayerQuestItems.find(plguid);
398 if (qmapitr == PlayerQuestItems.end())
400 FillQuestLoot(pl);
402 qmapitr = PlayerFFAItems.find(plguid);
403 if (qmapitr == PlayerFFAItems.end())
405 FillFFALoot(pl);
407 qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
408 if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
410 FillNonQuestNonFFAConditionalLoot(pl);
415 QuestItemList* Loot::FillFFALoot(Player* player)
417 QuestItemList *ql = new QuestItemList();
419 for(uint8 i = 0; i < items.size(); i++)
421 LootItem &item = items[i];
422 if(!item.is_looted && item.freeforall && item.AllowedForPlayer(player) )
424 ql->push_back(QuestItem(i));
425 ++unlootedCount;
428 if (ql->empty())
430 delete ql;
431 return NULL;
434 PlayerFFAItems[player->GetGUIDLow()] = ql;
435 return ql;
438 QuestItemList* Loot::FillQuestLoot(Player* player)
440 if (items.size() == MAX_NR_LOOT_ITEMS) return NULL;
441 QuestItemList *ql = new QuestItemList();
443 for(uint8 i = 0; i < quest_items.size(); i++)
445 LootItem &item = quest_items[i];
446 if(!item.is_looted && item.AllowedForPlayer(player) )
448 ql->push_back(QuestItem(i));
450 // questitems get blocked when they first apper in a
451 // player's quest vector
453 // increase once if one looter only, looter-times if free for all
454 if (item.freeforall || !item.is_blocked)
455 ++unlootedCount;
457 item.is_blocked = true;
459 if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS)
460 break;
463 if (ql->empty())
465 delete ql;
466 return NULL;
469 PlayerQuestItems[player->GetGUIDLow()] = ql;
470 return ql;
473 QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player)
475 QuestItemList *ql = new QuestItemList();
477 for(uint8 i = 0; i < items.size(); ++i)
479 LootItem &item = items[i];
480 if(!item.is_looted && !item.freeforall && item.conditionId && item.AllowedForPlayer(player))
482 ql->push_back(QuestItem(i));
483 if(!item.is_counted)
485 ++unlootedCount;
486 item.is_counted=true;
490 if (ql->empty())
492 delete ql;
493 return NULL;
496 PlayerNonQuestNonFFAConditionalItems[player->GetGUIDLow()] = ql;
497 return ql;
500 //===================================================
502 void Loot::NotifyItemRemoved(uint8 lootIndex)
504 // notify all players that are looting this that the item was removed
505 // convert the index to the slot the player sees
506 std::set<uint64>::iterator i_next;
507 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
509 i_next = i;
510 ++i_next;
511 if(Player* pl = ObjectAccessor::FindPlayer(*i))
512 pl->SendNotifyLootItemRemoved(lootIndex);
513 else
514 PlayersLooting.erase(i);
518 void Loot::NotifyMoneyRemoved()
520 // notify all players that are looting this that the money was removed
521 std::set<uint64>::iterator i_next;
522 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
524 i_next = i;
525 ++i_next;
526 if(Player* pl = ObjectAccessor::FindPlayer(*i))
527 pl->SendNotifyLootMoneyRemoved();
528 else
529 PlayersLooting.erase(i);
533 void Loot::NotifyQuestItemRemoved(uint8 questIndex)
535 // when a free for all questitem is looted
536 // all players will get notified of it being removed
537 // (other questitems can be looted by each group member)
538 // bit inefficient but isnt called often
540 std::set<uint64>::iterator i_next;
541 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
543 i_next = i;
544 ++i_next;
545 if(Player* pl = ObjectAccessor::FindPlayer(*i))
547 QuestItemMap::iterator pq = PlayerQuestItems.find(pl->GetGUIDLow());
548 if (pq != PlayerQuestItems.end() && pq->second)
550 // find where/if the player has the given item in it's vector
551 QuestItemList& pql = *pq->second;
553 uint8 j;
554 for (j = 0; j < pql.size(); ++j)
555 if (pql[j].index == questIndex)
556 break;
558 if (j < pql.size())
559 pl->SendNotifyLootItemRemoved(items.size()+j);
562 else
563 PlayersLooting.erase(i);
567 void Loot::generateMoneyLoot( uint32 minAmount, uint32 maxAmount )
569 if (maxAmount > 0)
571 if (maxAmount <= minAmount)
572 gold = uint32(maxAmount * sWorld.getRate(RATE_DROP_MONEY));
573 else if ((maxAmount - minAmount) < 32700)
574 gold = uint32(urand(minAmount, maxAmount) * sWorld.getRate(RATE_DROP_MONEY));
575 else
576 gold = uint32(urand(minAmount >> 8, maxAmount >> 8) * sWorld.getRate(RATE_DROP_MONEY)) << 8;
580 LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qitem, QuestItem **ffaitem, QuestItem **conditem)
582 LootItem* item = NULL;
583 bool is_looted = true;
584 if (lootSlot >= items.size())
586 uint32 questSlot = lootSlot - items.size();
587 QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
588 if (itr != PlayerQuestItems.end() && questSlot < itr->second->size())
590 QuestItem *qitem2 = &itr->second->at(questSlot);
591 if(qitem)
592 *qitem = qitem2;
593 item = &quest_items[qitem2->index];
594 is_looted = qitem2->is_looted;
597 else
599 item = &items[lootSlot];
600 is_looted = item->is_looted;
601 if(item->freeforall)
603 QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUIDLow());
604 if (itr != PlayerFFAItems.end())
606 for(QuestItemList::iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
607 if(iter->index==lootSlot)
609 QuestItem *ffaitem2 = (QuestItem*)&(*iter);
610 if(ffaitem)
611 *ffaitem = ffaitem2;
612 is_looted = ffaitem2->is_looted;
613 break;
617 else if(item->conditionId)
619 QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
620 if (itr != PlayerNonQuestNonFFAConditionalItems.end())
622 for(QuestItemList::iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
624 if(iter->index==lootSlot)
626 QuestItem *conditem2 = (QuestItem*)&(*iter);
627 if(conditem)
628 *conditem = conditem2;
629 is_looted = conditem2->is_looted;
630 break;
637 if(is_looted)
638 return NULL;
640 return item;
643 ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
645 b << uint32(li.itemid);
646 b << uint32(li.count); // nr of items of this type
647 b << uint32(objmgr.GetItemPrototype(li.itemid)->DisplayInfoID);
648 b << uint32(li.randomSuffix);
649 b << uint32(li.randomPropertyId);
650 //b << uint8(0); // slot type - will send after this function call
651 return b;
654 ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
656 Loot &l = lv.loot;
658 uint8 itemsShown = 0;
660 //gold
661 b << uint32(lv.permission!=NONE_PERMISSION ? l.gold : 0);
663 size_t count_pos = b.wpos(); // pos of item count byte
664 b << uint8(0); // item count placeholder
666 switch (lv.permission)
668 case GROUP_PERMISSION:
670 // You are not the items proprietary, so you can only see
671 // blocked rolled items and quest items, and !ffa items
672 for (uint8 i = 0; i < l.items.size(); ++i)
674 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
676 uint8 slot_type = (l.items[i].is_blocked || l.items[i].is_underthreshold) ? 0 : 1;
678 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
679 b << uint8(slot_type); // 0 - get 1 - look only
680 ++itemsShown;
683 break;
685 case ALL_PERMISSION:
686 case MASTER_PERMISSION:
688 uint8 slot_type = (lv.permission==MASTER_PERMISSION) ? 2 : 0;
689 for (uint8 i = 0; i < l.items.size(); ++i)
691 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
693 b << uint8(i) << l.items[i]; //only send one-player loot items now, free for all will be sent later
694 b << uint8(slot_type); // 0 - get 2 - master selection
695 ++itemsShown;
698 break;
700 case NONE_PERMISSION:
701 default:
702 return b; // nothing output more
705 if (lv.qlist)
707 for (QuestItemList::iterator qi = lv.qlist->begin() ; qi != lv.qlist->end(); ++qi)
709 LootItem &item = l.quest_items[qi->index];
710 if (!qi->is_looted && !item.is_looted)
712 b << uint8(l.items.size() + (qi - lv.qlist->begin()));
713 b << item;
714 b << uint8(0); // allow loot
715 ++itemsShown;
720 if (lv.ffalist)
722 for (QuestItemList::iterator fi = lv.ffalist->begin() ; fi != lv.ffalist->end(); ++fi)
724 LootItem &item = l.items[fi->index];
725 if (!fi->is_looted && !item.is_looted)
727 b << uint8(fi->index) << item;
728 b << uint8(0); // allow loot
729 ++itemsShown;
734 if (lv.conditionallist)
736 for (QuestItemList::iterator ci = lv.conditionallist->begin() ; ci != lv.conditionallist->end(); ++ci)
738 LootItem &item = l.items[ci->index];
739 if (!ci->is_looted && !item.is_looted)
741 b << uint8(ci->index) << item;
742 b << uint8(0); // allow loot
743 ++itemsShown;
748 //update number of items shown
749 b.put<uint8>(count_pos,itemsShown);
751 return b;
755 // --------- LootTemplate::LootGroup ---------
758 // Adds an entry to the group (at loading stage)
759 void LootTemplate::LootGroup::AddEntry(LootStoreItem& item)
761 if (item.chance != 0)
762 ExplicitlyChanced.push_back(item);
763 else
764 EqualChanced.push_back(item);
767 // Rolls an item from the group, returns NULL if all miss their chances
768 LootStoreItem const * LootTemplate::LootGroup::Roll(bool rate) const
770 if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked
772 float Roll = rand_chance();
774 for (uint32 i=0; i<ExplicitlyChanced.size(); ++i) //check each explicitly chanced entry in the template and modify its chance based on quality.
776 if(ExplicitlyChanced[i].chance>=100.f)
777 return &ExplicitlyChanced[i];
779 ItemPrototype const *pProto = objmgr.GetItemPrototype(ExplicitlyChanced[i].itemid);
780 float qualityMultiplier = pProto && rate ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
781 Roll -= ExplicitlyChanced[i].chance * qualityMultiplier;
782 if (Roll < 0)
783 return &ExplicitlyChanced[i];
786 if (!EqualChanced.empty()) // If nothing selected yet - an item is taken from equal-chanced part
787 return &EqualChanced[irand(0, EqualChanced.size()-1)];
789 return NULL; // Empty drop from the group
792 // True if group includes at least 1 quest drop entry
793 bool LootTemplate::LootGroup::HasQuestDrop() const
795 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
796 if (i->needs_quest)
797 return true;
798 for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
799 if (i->needs_quest)
800 return true;
801 return false;
804 // True if group includes at least 1 quest drop entry for active quests of the player
805 bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const
807 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
808 if (player->HasQuestForItem(i->itemid))
809 return true;
810 for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
811 if (player->HasQuestForItem(i->itemid))
812 return true;
813 return false;
816 // Rolls an item from the group (if any takes its chance) and adds the item to the loot
817 void LootTemplate::LootGroup::Process(Loot& loot, bool rate) const
819 LootStoreItem const * item = Roll(rate);
820 if (item != NULL)
821 loot.AddItem(*item);
824 // Overall chance for the group without equal chanced items
825 float LootTemplate::LootGroup::RawTotalChance() const
827 float result = 0;
829 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
830 if ( !i->needs_quest )
831 result += i->chance;
833 return result;
836 // Overall chance for the group
837 float LootTemplate::LootGroup::TotalChance() const
839 float result = RawTotalChance();
841 if (!EqualChanced.empty() && result < 100.0f)
842 return 100.0f;
844 return result;
847 void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint32 group_id) const
849 float chance = RawTotalChance();
850 if (chance > 101.0f) // TODO: replace with 100% when DBs will be ready
852 sLog.outErrorDb("Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore.GetName(), id, group_id, chance);
855 if(chance >= 100.0f && !EqualChanced.empty())
857 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);
861 void LootTemplate::LootGroup::CheckLootRefs(LootIdSet* ref_set) const
863 for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
865 if(ieItr->mincountOrRef < 0)
867 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
868 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
869 else if(ref_set)
870 ref_set->erase(-ieItr->mincountOrRef);
874 for (LootStoreItemList::const_iterator ieItr=EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
876 if(ieItr->mincountOrRef < 0)
878 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
879 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
880 else if(ref_set)
881 ref_set->erase(-ieItr->mincountOrRef);
887 // --------- LootTemplate ---------
890 // Adds an entry to the group (at loading stage)
891 void LootTemplate::AddEntry(LootStoreItem& item)
893 if (item.group > 0 && item.mincountOrRef > 0) // Group
895 if (item.group >= Groups.size())
896 Groups.resize(item.group); // Adds new group the the loot template if needed
897 Groups[item.group-1].AddEntry(item); // Adds new entry to the group
899 else // Non-grouped entries and references are stored together
900 Entries.push_back(item);
903 // Rolls for every item in the template and adds the rolled items the the loot
904 void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8 groupId) const
906 if (groupId) // Group reference uses own processing of the group
908 if (groupId > Groups.size())
909 return; // Error message already printed at loading stage
911 Groups[groupId-1].Process(loot,rate);
912 return;
915 // Rolling non-grouped items
916 for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i )
918 if (!i->Roll(rate))
919 continue; // Bad luck for the entry
921 if (i->mincountOrRef < 0) // References processing
923 LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef);
925 if(!Referenced)
926 continue; // Error message already printed at loading stage
928 for (uint32 loop=0; loop < i->maxcount; ++loop )// Ref multiplicator
929 Referenced->Process(loot, store, rate, i->group);
931 else // Plain entries (not a reference, not grouped)
932 loot.AddItem(*i); // Chance is already checked, just add
935 // Now processing groups
936 for (LootGroups::const_iterator i = Groups.begin( ) ; i != Groups.end( ) ; ++i )
937 i->Process(loot,rate);
940 // True if template includes at least 1 quest drop entry
941 bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) const
943 if (groupId) // Group reference
945 if (groupId > Groups.size())
946 return false; // Error message [should be] already printed at loading stage
947 return Groups[groupId-1].HasQuestDrop();
950 for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i )
952 if (i->mincountOrRef < 0) // References
954 LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
955 if( Referenced ==store.end() )
956 continue; // Error message [should be] already printed at loading stage
957 if (Referenced->second->HasQuestDrop(store, i->group) )
958 return true;
960 else if ( i->needs_quest )
961 return true; // quest drop found
964 // Now processing groups
965 for (LootGroups::const_iterator i = Groups.begin() ; i != Groups.end() ; ++i )
966 if (i->HasQuestDrop())
967 return true;
969 return false;
972 // True if template includes at least 1 quest drop for an active quest of the player
973 bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player const* player, uint8 groupId) const
975 if (groupId) // Group reference
977 if (groupId > Groups.size())
978 return false; // Error message already printed at loading stage
979 return Groups[groupId-1].HasQuestDropForPlayer(player);
982 // Checking non-grouped entries
983 for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i )
985 if (i->mincountOrRef < 0) // References processing
987 LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
988 if (Referenced == store.end() )
989 continue; // Error message already printed at loading stage
990 if (Referenced->second->HasQuestDropForPlayer(store, player, i->group) )
991 return true;
993 else if ( player->HasQuestForItem(i->itemid) )
994 return true; // active quest drop found
997 // Now checking groups
998 for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i )
999 if (i->HasQuestDropForPlayer(player))
1000 return true;
1002 return false;
1005 // Checks integrity of the template
1006 void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const
1008 // Checking group chances
1009 for (uint32 i=0; i < Groups.size(); ++i)
1010 Groups[i].Verify(lootstore,id,i+1);
1012 // TODO: References validity checks
1015 void LootTemplate::CheckLootRefs(LootIdSet* ref_set) const
1017 for(LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
1019 if(ieItr->mincountOrRef < 0)
1021 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
1022 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
1023 else if(ref_set)
1024 ref_set->erase(-ieItr->mincountOrRef);
1028 for(LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
1029 grItr->CheckLootRefs(ref_set);
1032 void LoadLootTemplates_Creature()
1034 LootIdSet ids_set, ids_setUsed;
1035 LootTemplates_Creature.LoadAndCollectLootIds(ids_set);
1037 // remove real entries and check existence loot
1038 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1040 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1042 if(uint32 lootid = cInfo->lootid)
1044 if(!ids_set.count(lootid))
1045 LootTemplates_Creature.ReportNotExistedId(lootid);
1046 else
1047 ids_setUsed.insert(lootid);
1051 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1052 ids_set.erase(*itr);
1054 // output error for any still listed (not referenced from appropriate table) ids
1055 LootTemplates_Creature.ReportUnusedIds(ids_set);
1058 void LoadLootTemplates_Disenchant()
1060 LootIdSet ids_set, ids_setUsed;
1061 LootTemplates_Disenchant.LoadAndCollectLootIds(ids_set);
1063 // remove real entries and check existence loot
1064 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1066 if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
1068 if(uint32 lootid = proto->DisenchantID)
1070 if(!ids_set.count(lootid))
1071 LootTemplates_Disenchant.ReportNotExistedId(lootid);
1072 else
1073 ids_setUsed.insert(lootid);
1077 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1078 ids_set.erase(*itr);
1079 // output error for any still listed (not referenced from appropriate table) ids
1080 LootTemplates_Disenchant.ReportUnusedIds(ids_set);
1083 void LoadLootTemplates_Fishing()
1085 LootIdSet ids_set;
1086 LootTemplates_Fishing.LoadAndCollectLootIds(ids_set);
1088 // remove real entries and check existence loot
1089 for(uint32 i = 1; i < sAreaStore.GetNumRows(); ++i )
1091 if(AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
1092 if(ids_set.count(areaEntry->ID))
1093 ids_set.erase(areaEntry->ID);
1096 // output error for any still listed (not referenced from appropriate table) ids
1097 LootTemplates_Fishing.ReportUnusedIds(ids_set);
1100 void LoadLootTemplates_Gameobject()
1102 LootIdSet ids_set, ids_setUsed;
1103 LootTemplates_Gameobject.LoadAndCollectLootIds(ids_set);
1105 // remove real entries and check existence loot
1106 for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i )
1108 if(GameObjectInfo const* gInfo = sGOStorage.LookupEntry<GameObjectInfo>(i))
1110 if(uint32 lootid = GameObject::GetLootId(gInfo))
1112 if(!ids_set.count(lootid))
1113 LootTemplates_Gameobject.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);
1122 // output error for any still listed (not referenced from appropriate table) ids
1123 LootTemplates_Gameobject.ReportUnusedIds(ids_set);
1126 void LoadLootTemplates_Item()
1128 LootIdSet ids_set;
1129 LootTemplates_Item.LoadAndCollectLootIds(ids_set);
1131 // remove real entries and check existence loot
1132 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1133 if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
1134 if(ids_set.count(proto->ItemId))
1135 ids_set.erase(proto->ItemId);
1137 // output error for any still listed (not referenced from appropriate table) ids
1138 LootTemplates_Item.ReportUnusedIds(ids_set);
1141 void LoadLootTemplates_Milling()
1143 LootIdSet ids_set;
1144 LootTemplates_Milling.LoadAndCollectLootIds(ids_set);
1146 // remove real entries and check existence loot
1147 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1149 ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i);
1150 if(!proto)
1151 continue;
1153 if((proto->BagFamily & BAG_FAMILY_MASK_HERBS)==0)
1154 continue;
1156 if(ids_set.count(proto->ItemId))
1157 ids_set.erase(proto->ItemId);
1160 // output error for any still listed (not referenced from appropriate table) ids
1161 LootTemplates_Milling.ReportUnusedIds(ids_set);
1164 void LoadLootTemplates_Pickpocketing()
1166 LootIdSet ids_set, ids_setUsed;
1167 LootTemplates_Pickpocketing.LoadAndCollectLootIds(ids_set);
1169 // remove real entries and check existence loot
1170 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1172 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1174 if(uint32 lootid = cInfo->pickpocketLootId)
1176 if(!ids_set.count(lootid))
1177 LootTemplates_Pickpocketing.ReportNotExistedId(lootid);
1178 else
1179 ids_setUsed.insert(lootid);
1183 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1184 ids_set.erase(*itr);
1186 // output error for any still listed (not referenced from appropriate table) ids
1187 LootTemplates_Pickpocketing.ReportUnusedIds(ids_set);
1190 void LoadLootTemplates_Prospecting()
1192 LootIdSet ids_set;
1193 LootTemplates_Prospecting.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_MINING_SUPP)==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_Prospecting.ReportUnusedIds(ids_set);
1213 void LoadLootTemplates_QuestMail()
1215 LootIdSet ids_set;
1216 LootTemplates_QuestMail.LoadAndCollectLootIds(ids_set);
1218 // remove real entries and check existence loot
1219 ObjectMgr::QuestMap const& questMap = objmgr.GetQuestTemplates();
1220 for(ObjectMgr::QuestMap::const_iterator itr = questMap.begin(); itr != questMap.end(); ++itr )
1222 if(!itr->second->GetRewMailTemplateId())
1223 continue;
1225 if(ids_set.count(itr->first))
1226 ids_set.erase(itr->first);
1227 /* disabled reporting: some quest mails not include items
1228 else
1229 LootTemplates_QuestMail.ReportNotExistedId(itr->first);
1233 // output error for any still listed (not referenced from appropriate table) ids
1234 LootTemplates_QuestMail.ReportUnusedIds(ids_set);
1237 void LoadLootTemplates_Skinning()
1239 LootIdSet ids_set, ids_setUsed;
1240 LootTemplates_Skinning.LoadAndCollectLootIds(ids_set);
1242 // remove real entries and check existence loot
1243 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1245 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1247 if(uint32 lootid = cInfo->SkinLootId)
1249 if(!ids_set.count(lootid))
1250 LootTemplates_Skinning.ReportNotExistedId(lootid);
1251 else
1252 ids_setUsed.insert(lootid);
1256 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1257 ids_set.erase(*itr);
1259 // output error for any still listed (not referenced from appropriate table) ids
1260 LootTemplates_Skinning.ReportUnusedIds(ids_set);
1263 void LoadLootTemplates_Spell()
1265 LootIdSet ids_set;
1266 LootTemplates_Spell.LoadAndCollectLootIds(ids_set);
1268 // remove real entries and check existence loot
1269 for(uint32 spell_id = 1; spell_id < sSpellStore.GetNumRows(); ++spell_id)
1271 SpellEntry const* spellInfo = sSpellStore.LookupEntry (spell_id);
1272 if(!spellInfo)
1273 continue;
1275 // possible cases
1276 if( !IsLootCraftingSpell(spellInfo))
1277 continue;
1279 if(!ids_set.count(spell_id))
1281 // not report about not trainable spells (optionally supported by DB) except with SPELL_ATTR_EX2_UNK14 (clams)
1282 // 61756 (Northrend Inscription Research (FAST QA VERSION) for example
1283 if ((spellInfo->Attributes & SPELL_ATTR_UNK5) || (spellInfo->AttributesEx2 & SPELL_ATTR_EX2_UNK14))
1284 LootTemplates_Spell.ReportNotExistedId(spell_id);
1286 else
1287 ids_set.erase(spell_id);
1290 // output error for any still listed (not referenced from appropriate table) ids
1291 LootTemplates_QuestMail.ReportUnusedIds(ids_set);
1294 void LoadLootTemplates_Reference()
1296 LootIdSet ids_set;
1297 LootTemplates_Reference.LoadAndCollectLootIds(ids_set);
1299 // check references and remove used
1300 LootTemplates_Creature.CheckLootRefs(&ids_set);
1301 LootTemplates_Fishing.CheckLootRefs(&ids_set);
1302 LootTemplates_Gameobject.CheckLootRefs(&ids_set);
1303 LootTemplates_Item.CheckLootRefs(&ids_set);
1304 LootTemplates_Milling.CheckLootRefs(&ids_set);
1305 LootTemplates_Pickpocketing.CheckLootRefs(&ids_set);
1306 LootTemplates_Skinning.CheckLootRefs(&ids_set);
1307 LootTemplates_Disenchant.CheckLootRefs(&ids_set);
1308 LootTemplates_Prospecting.CheckLootRefs(&ids_set);
1309 LootTemplates_QuestMail.CheckLootRefs(&ids_set);
1310 LootTemplates_Reference.CheckLootRefs(&ids_set);
1312 // output error for any still listed ids (not referenced from any loot table)
1313 LootTemplates_Reference.ReportUnusedIds(ids_set);