[7297] Fixed profession spells sorting in trainer spell list at client.
[getmangos.git] / src / game / LootMgr.cpp
blob05b08eb8a92fba00780766ea536f169e87df00af
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, bool personal)
371 // Must be provided
372 if(!loot_owner)
373 return;
375 LootTemplate const* tab = store.GetLootFor(loot_id);
377 if (!tab)
379 sLog.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.",store.GetName(),loot_id);
380 return;
383 items.reserve(MAX_NR_LOOT_ITEMS);
384 quest_items.reserve(MAX_NR_QUEST_ITEMS);
386 tab->Process(*this, store,store.IsRatesAllowed ()); // Processing is done there, callback via Loot::AddItem()
388 // Setting access rights for group loot case
389 Group * pGroup=loot_owner->GetGroup();
390 if(!personal && pGroup)
392 for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
393 if(Player* pl = itr->getSource())
394 FillNotNormalLootFor(pl);
396 // ... for personal loot
397 else
398 FillNotNormalLootFor(loot_owner);
401 void Loot::FillNotNormalLootFor(Player* pl)
403 uint32 plguid = pl->GetGUIDLow();
405 QuestItemMap::iterator qmapitr = PlayerQuestItems.find(plguid);
406 if (qmapitr == PlayerQuestItems.end())
407 FillQuestLoot(pl);
409 qmapitr = PlayerFFAItems.find(plguid);
410 if (qmapitr == PlayerFFAItems.end())
411 FillFFALoot(pl);
413 qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
414 if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
415 FillNonQuestNonFFAConditionalLoot(pl);
418 QuestItemList* Loot::FillFFALoot(Player* player)
420 QuestItemList *ql = new QuestItemList();
422 for(uint8 i = 0; i < items.size(); i++)
424 LootItem &item = items[i];
425 if(!item.is_looted && item.freeforall && item.AllowedForPlayer(player) )
427 ql->push_back(QuestItem(i));
428 ++unlootedCount;
431 if (ql->empty())
433 delete ql;
434 return NULL;
437 PlayerFFAItems[player->GetGUIDLow()] = ql;
438 return ql;
441 QuestItemList* Loot::FillQuestLoot(Player* player)
443 if (items.size() == MAX_NR_LOOT_ITEMS) return NULL;
444 QuestItemList *ql = new QuestItemList();
446 for(uint8 i = 0; i < quest_items.size(); i++)
448 LootItem &item = quest_items[i];
449 if(!item.is_looted && item.AllowedForPlayer(player) )
451 ql->push_back(QuestItem(i));
453 // questitems get blocked when they first apper in a
454 // player's quest vector
456 // increase once if one looter only, looter-times if free for all
457 if (item.freeforall || !item.is_blocked)
458 ++unlootedCount;
460 item.is_blocked = true;
462 if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS)
463 break;
466 if (ql->empty())
468 delete ql;
469 return NULL;
472 PlayerQuestItems[player->GetGUIDLow()] = ql;
473 return ql;
476 QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player)
478 QuestItemList *ql = new QuestItemList();
480 for(uint8 i = 0; i < items.size(); ++i)
482 LootItem &item = items[i];
483 if(!item.is_looted && !item.freeforall && item.conditionId && item.AllowedForPlayer(player))
485 ql->push_back(QuestItem(i));
486 if(!item.is_counted)
488 ++unlootedCount;
489 item.is_counted=true;
493 if (ql->empty())
495 delete ql;
496 return NULL;
499 PlayerNonQuestNonFFAConditionalItems[player->GetGUIDLow()] = ql;
500 return ql;
503 //===================================================
505 void Loot::NotifyItemRemoved(uint8 lootIndex)
507 // notify all players that are looting this that the item was removed
508 // convert the index to the slot the player sees
509 std::set<uint64>::iterator i_next;
510 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
512 i_next = i;
513 ++i_next;
514 if(Player* pl = ObjectAccessor::FindPlayer(*i))
515 pl->SendNotifyLootItemRemoved(lootIndex);
516 else
517 PlayersLooting.erase(i);
521 void Loot::NotifyMoneyRemoved()
523 // notify all players that are looting this that the money was removed
524 std::set<uint64>::iterator i_next;
525 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
527 i_next = i;
528 ++i_next;
529 if(Player* pl = ObjectAccessor::FindPlayer(*i))
530 pl->SendNotifyLootMoneyRemoved();
531 else
532 PlayersLooting.erase(i);
536 void Loot::NotifyQuestItemRemoved(uint8 questIndex)
538 // when a free for all questitem is looted
539 // all players will get notified of it being removed
540 // (other questitems can be looted by each group member)
541 // bit inefficient but isnt called often
543 std::set<uint64>::iterator i_next;
544 for(std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
546 i_next = i;
547 ++i_next;
548 if(Player* pl = ObjectAccessor::FindPlayer(*i))
550 QuestItemMap::iterator pq = PlayerQuestItems.find(pl->GetGUIDLow());
551 if (pq != PlayerQuestItems.end() && pq->second)
553 // find where/if the player has the given item in it's vector
554 QuestItemList& pql = *pq->second;
556 uint8 j;
557 for (j = 0; j < pql.size(); ++j)
558 if (pql[j].index == questIndex)
559 break;
561 if (j < pql.size())
562 pl->SendNotifyLootItemRemoved(items.size()+j);
565 else
566 PlayersLooting.erase(i);
570 void Loot::generateMoneyLoot( uint32 minAmount, uint32 maxAmount )
572 if (maxAmount > 0)
574 if (maxAmount <= minAmount)
575 gold = uint32(maxAmount * sWorld.getRate(RATE_DROP_MONEY));
576 else if ((maxAmount - minAmount) < 32700)
577 gold = uint32(urand(minAmount, maxAmount) * sWorld.getRate(RATE_DROP_MONEY));
578 else
579 gold = uint32(urand(minAmount >> 8, maxAmount >> 8) * sWorld.getRate(RATE_DROP_MONEY)) << 8;
583 LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qitem, QuestItem **ffaitem, QuestItem **conditem)
585 LootItem* item = NULL;
586 bool is_looted = true;
587 if (lootSlot >= items.size())
589 uint32 questSlot = lootSlot - items.size();
590 QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
591 if (itr != PlayerQuestItems.end() && questSlot < itr->second->size())
593 QuestItem *qitem2 = &itr->second->at(questSlot);
594 if(qitem)
595 *qitem = qitem2;
596 item = &quest_items[qitem2->index];
597 is_looted = qitem2->is_looted;
600 else
602 item = &items[lootSlot];
603 is_looted = item->is_looted;
604 if(item->freeforall)
606 QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUIDLow());
607 if (itr != PlayerFFAItems.end())
609 for(QuestItemList::iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
610 if(iter->index==lootSlot)
612 QuestItem *ffaitem2 = (QuestItem*)&(*iter);
613 if(ffaitem)
614 *ffaitem = ffaitem2;
615 is_looted = ffaitem2->is_looted;
616 break;
620 else if(item->conditionId)
622 QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
623 if (itr != PlayerNonQuestNonFFAConditionalItems.end())
625 for(QuestItemList::iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
627 if(iter->index==lootSlot)
629 QuestItem *conditem2 = (QuestItem*)&(*iter);
630 if(conditem)
631 *conditem = conditem2;
632 is_looted = conditem2->is_looted;
633 break;
640 if(is_looted)
641 return NULL;
643 return item;
646 uint32 Loot::GetMaxSlotInLootFor(Player* player) const
648 QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
649 return items.size() + (itr != PlayerQuestItems.end() ? itr->second->size() : 0);
652 ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
654 b << uint32(li.itemid);
655 b << uint32(li.count); // nr of items of this type
656 b << uint32(objmgr.GetItemPrototype(li.itemid)->DisplayInfoID);
657 b << uint32(li.randomSuffix);
658 b << uint32(li.randomPropertyId);
659 //b << uint8(0); // slot type - will send after this function call
660 return b;
663 ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
665 if (lv.permission == NONE_PERMISSION)
667 b << uint32(0); //gold
668 b << uint8(0); // item count
669 return b; // nothing output more
672 Loot &l = lv.loot;
674 uint8 itemsShown = 0;
676 //gold
677 b << uint32(l.gold);
679 size_t count_pos = b.wpos(); // pos of item count byte
680 b << uint8(0); // item count placeholder
682 switch (lv.permission)
684 case GROUP_PERMISSION:
686 // You are not the items proprietary, so you can only see
687 // blocked rolled items and quest items, and !ffa items
688 for (uint8 i = 0; i < l.items.size(); ++i)
690 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
692 uint8 slot_type = (l.items[i].is_blocked || l.items[i].is_underthreshold) ? 0 : 1;
694 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
695 b << uint8(slot_type); // 0 - get 1 - look only
696 ++itemsShown;
699 break;
701 case ALL_PERMISSION:
702 case MASTER_PERMISSION:
704 uint8 slot_type = (lv.permission==MASTER_PERMISSION) ? 2 : 0;
705 for (uint8 i = 0; i < l.items.size(); ++i)
707 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
709 b << uint8(i) << l.items[i]; //only send one-player loot items now, free for all will be sent later
710 b << uint8(slot_type); // 0 - get 2 - master selection
711 ++itemsShown;
714 break;
716 default:
717 return b; // nothing output more
720 QuestItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems();
721 QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUIDLow());
722 if (q_itr != lootPlayerQuestItems.end())
724 QuestItemList *q_list = q_itr->second;
725 for (QuestItemList::iterator qi = q_list->begin() ; qi != q_list->end(); ++qi)
727 LootItem &item = l.quest_items[qi->index];
728 if (!qi->is_looted && !item.is_looted)
730 b << uint8(l.items.size() + (qi - q_list->begin()));
731 b << item;
732 b << uint8(0); // allow loot
733 ++itemsShown;
738 QuestItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems();
739 QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUIDLow());
740 if (ffa_itr != lootPlayerFFAItems.end())
742 QuestItemList *ffa_list = ffa_itr->second;
743 for (QuestItemList::iterator fi = ffa_list->begin() ; fi != ffa_list->end(); ++fi)
745 LootItem &item = l.items[fi->index];
746 if (!fi->is_looted && !item.is_looted)
748 b << uint8(fi->index) << item;
749 b << uint8(0); // allow loot
750 ++itemsShown;
755 QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems();
756 QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUIDLow());
757 if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
759 QuestItemList *conditional_list = nn_itr->second;
760 for (QuestItemList::iterator ci = conditional_list->begin() ; ci != conditional_list->end(); ++ci)
762 LootItem &item = l.items[ci->index];
763 if (!ci->is_looted && !item.is_looted)
765 b << uint8(ci->index) << item;
766 b << uint8(0); // allow loot
767 ++itemsShown;
772 //update number of items shown
773 b.put<uint8>(count_pos,itemsShown);
775 return b;
779 // --------- LootTemplate::LootGroup ---------
782 // Adds an entry to the group (at loading stage)
783 void LootTemplate::LootGroup::AddEntry(LootStoreItem& item)
785 if (item.chance != 0)
786 ExplicitlyChanced.push_back(item);
787 else
788 EqualChanced.push_back(item);
791 // Rolls an item from the group, returns NULL if all miss their chances
792 LootStoreItem const * LootTemplate::LootGroup::Roll(bool rate) const
794 if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked
796 float Roll = rand_chance();
798 for (uint32 i=0; i<ExplicitlyChanced.size(); ++i) //check each explicitly chanced entry in the template and modify its chance based on quality.
800 if(ExplicitlyChanced[i].chance>=100.f)
801 return &ExplicitlyChanced[i];
803 ItemPrototype const *pProto = objmgr.GetItemPrototype(ExplicitlyChanced[i].itemid);
804 float qualityMultiplier = pProto && rate ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
805 Roll -= ExplicitlyChanced[i].chance * qualityMultiplier;
806 if (Roll < 0)
807 return &ExplicitlyChanced[i];
810 if (!EqualChanced.empty()) // If nothing selected yet - an item is taken from equal-chanced part
811 return &EqualChanced[irand(0, EqualChanced.size()-1)];
813 return NULL; // Empty drop from the group
816 // True if group includes at least 1 quest drop entry
817 bool LootTemplate::LootGroup::HasQuestDrop() const
819 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
820 if (i->needs_quest)
821 return true;
822 for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
823 if (i->needs_quest)
824 return true;
825 return false;
828 // True if group includes at least 1 quest drop entry for active quests of the player
829 bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const
831 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
832 if (player->HasQuestForItem(i->itemid))
833 return true;
834 for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
835 if (player->HasQuestForItem(i->itemid))
836 return true;
837 return false;
840 // Rolls an item from the group (if any takes its chance) and adds the item to the loot
841 void LootTemplate::LootGroup::Process(Loot& loot, bool rate) const
843 LootStoreItem const * item = Roll(rate);
844 if (item != NULL)
845 loot.AddItem(*item);
848 // Overall chance for the group without equal chanced items
849 float LootTemplate::LootGroup::RawTotalChance() const
851 float result = 0;
853 for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
854 if ( !i->needs_quest )
855 result += i->chance;
857 return result;
860 // Overall chance for the group
861 float LootTemplate::LootGroup::TotalChance() const
863 float result = RawTotalChance();
865 if (!EqualChanced.empty() && result < 100.0f)
866 return 100.0f;
868 return result;
871 void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint32 group_id) const
873 float chance = RawTotalChance();
874 if (chance > 101.0f) // TODO: replace with 100% when DBs will be ready
876 sLog.outErrorDb("Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore.GetName(), id, group_id, chance);
879 if(chance >= 100.0f && !EqualChanced.empty())
881 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);
885 void LootTemplate::LootGroup::CheckLootRefs(LootIdSet* ref_set) const
887 for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
889 if(ieItr->mincountOrRef < 0)
891 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
892 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
893 else if(ref_set)
894 ref_set->erase(-ieItr->mincountOrRef);
898 for (LootStoreItemList::const_iterator ieItr=EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
900 if(ieItr->mincountOrRef < 0)
902 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
903 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
904 else if(ref_set)
905 ref_set->erase(-ieItr->mincountOrRef);
911 // --------- LootTemplate ---------
914 // Adds an entry to the group (at loading stage)
915 void LootTemplate::AddEntry(LootStoreItem& item)
917 if (item.group > 0 && item.mincountOrRef > 0) // Group
919 if (item.group >= Groups.size())
920 Groups.resize(item.group); // Adds new group the the loot template if needed
921 Groups[item.group-1].AddEntry(item); // Adds new entry to the group
923 else // Non-grouped entries and references are stored together
924 Entries.push_back(item);
927 // Rolls for every item in the template and adds the rolled items the the loot
928 void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8 groupId) const
930 if (groupId) // Group reference uses own processing of the group
932 if (groupId > Groups.size())
933 return; // Error message already printed at loading stage
935 Groups[groupId-1].Process(loot,rate);
936 return;
939 // Rolling non-grouped items
940 for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i )
942 if (!i->Roll(rate))
943 continue; // Bad luck for the entry
945 if (i->mincountOrRef < 0) // References processing
947 LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef);
949 if(!Referenced)
950 continue; // Error message already printed at loading stage
952 for (uint32 loop=0; loop < i->maxcount; ++loop )// Ref multiplicator
953 Referenced->Process(loot, store, rate, i->group);
955 else // Plain entries (not a reference, not grouped)
956 loot.AddItem(*i); // Chance is already checked, just add
959 // Now processing groups
960 for (LootGroups::const_iterator i = Groups.begin( ) ; i != Groups.end( ) ; ++i )
961 i->Process(loot,rate);
964 // True if template includes at least 1 quest drop entry
965 bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) const
967 if (groupId) // Group reference
969 if (groupId > Groups.size())
970 return false; // Error message [should be] already printed at loading stage
971 return Groups[groupId-1].HasQuestDrop();
974 for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i )
976 if (i->mincountOrRef < 0) // References
978 LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
979 if( Referenced ==store.end() )
980 continue; // Error message [should be] already printed at loading stage
981 if (Referenced->second->HasQuestDrop(store, i->group) )
982 return true;
984 else if ( i->needs_quest )
985 return true; // quest drop found
988 // Now processing groups
989 for (LootGroups::const_iterator i = Groups.begin() ; i != Groups.end() ; ++i )
990 if (i->HasQuestDrop())
991 return true;
993 return false;
996 // True if template includes at least 1 quest drop for an active quest of the player
997 bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player const* player, uint8 groupId) const
999 if (groupId) // Group reference
1001 if (groupId > Groups.size())
1002 return false; // Error message already printed at loading stage
1003 return Groups[groupId-1].HasQuestDropForPlayer(player);
1006 // Checking non-grouped entries
1007 for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i )
1009 if (i->mincountOrRef < 0) // References processing
1011 LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
1012 if (Referenced == store.end() )
1013 continue; // Error message already printed at loading stage
1014 if (Referenced->second->HasQuestDropForPlayer(store, player, i->group) )
1015 return true;
1017 else if ( player->HasQuestForItem(i->itemid) )
1018 return true; // active quest drop found
1021 // Now checking groups
1022 for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i )
1023 if (i->HasQuestDropForPlayer(player))
1024 return true;
1026 return false;
1029 // Checks integrity of the template
1030 void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const
1032 // Checking group chances
1033 for (uint32 i=0; i < Groups.size(); ++i)
1034 Groups[i].Verify(lootstore,id,i+1);
1036 // TODO: References validity checks
1039 void LootTemplate::CheckLootRefs(LootIdSet* ref_set) const
1041 for(LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
1043 if(ieItr->mincountOrRef < 0)
1045 if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
1046 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
1047 else if(ref_set)
1048 ref_set->erase(-ieItr->mincountOrRef);
1052 for(LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
1053 grItr->CheckLootRefs(ref_set);
1056 void LoadLootTemplates_Creature()
1058 LootIdSet ids_set, ids_setUsed;
1059 LootTemplates_Creature.LoadAndCollectLootIds(ids_set);
1061 // remove real entries and check existence loot
1062 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1064 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1066 if(uint32 lootid = cInfo->lootid)
1068 if(!ids_set.count(lootid))
1069 LootTemplates_Creature.ReportNotExistedId(lootid);
1070 else
1071 ids_setUsed.insert(lootid);
1075 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1076 ids_set.erase(*itr);
1078 // output error for any still listed (not referenced from appropriate table) ids
1079 LootTemplates_Creature.ReportUnusedIds(ids_set);
1082 void LoadLootTemplates_Disenchant()
1084 LootIdSet ids_set, ids_setUsed;
1085 LootTemplates_Disenchant.LoadAndCollectLootIds(ids_set);
1087 // remove real entries and check existence loot
1088 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1090 if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
1092 if(uint32 lootid = proto->DisenchantID)
1094 if(!ids_set.count(lootid))
1095 LootTemplates_Disenchant.ReportNotExistedId(lootid);
1096 else
1097 ids_setUsed.insert(lootid);
1101 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1102 ids_set.erase(*itr);
1103 // output error for any still listed (not referenced from appropriate table) ids
1104 LootTemplates_Disenchant.ReportUnusedIds(ids_set);
1107 void LoadLootTemplates_Fishing()
1109 LootIdSet ids_set;
1110 LootTemplates_Fishing.LoadAndCollectLootIds(ids_set);
1112 // remove real entries and check existence loot
1113 for(uint32 i = 1; i < sAreaStore.GetNumRows(); ++i )
1115 if(AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
1116 if(ids_set.count(areaEntry->ID))
1117 ids_set.erase(areaEntry->ID);
1120 // output error for any still listed (not referenced from appropriate table) ids
1121 LootTemplates_Fishing.ReportUnusedIds(ids_set);
1124 void LoadLootTemplates_Gameobject()
1126 LootIdSet ids_set, ids_setUsed;
1127 LootTemplates_Gameobject.LoadAndCollectLootIds(ids_set);
1129 // remove real entries and check existence loot
1130 for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i )
1132 if(GameObjectInfo const* gInfo = sGOStorage.LookupEntry<GameObjectInfo>(i))
1134 if(uint32 lootid = GameObject::GetLootId(gInfo))
1136 if(!ids_set.count(lootid))
1137 LootTemplates_Gameobject.ReportNotExistedId(lootid);
1138 else
1139 ids_setUsed.insert(lootid);
1143 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1144 ids_set.erase(*itr);
1146 // output error for any still listed (not referenced from appropriate table) ids
1147 LootTemplates_Gameobject.ReportUnusedIds(ids_set);
1150 void LoadLootTemplates_Item()
1152 LootIdSet ids_set;
1153 LootTemplates_Item.LoadAndCollectLootIds(ids_set);
1155 // remove real entries and check existence loot
1156 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1157 if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
1158 if(ids_set.count(proto->ItemId))
1159 ids_set.erase(proto->ItemId);
1161 // output error for any still listed (not referenced from appropriate table) ids
1162 LootTemplates_Item.ReportUnusedIds(ids_set);
1165 void LoadLootTemplates_Milling()
1167 LootIdSet ids_set;
1168 LootTemplates_Milling.LoadAndCollectLootIds(ids_set);
1170 // remove real entries and check existence loot
1171 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1173 ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i);
1174 if(!proto)
1175 continue;
1177 if((proto->BagFamily & BAG_FAMILY_MASK_HERBS)==0)
1178 continue;
1180 if(ids_set.count(proto->ItemId))
1181 ids_set.erase(proto->ItemId);
1184 // output error for any still listed (not referenced from appropriate table) ids
1185 LootTemplates_Milling.ReportUnusedIds(ids_set);
1188 void LoadLootTemplates_Pickpocketing()
1190 LootIdSet ids_set, ids_setUsed;
1191 LootTemplates_Pickpocketing.LoadAndCollectLootIds(ids_set);
1193 // remove real entries and check existence loot
1194 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1196 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1198 if(uint32 lootid = cInfo->pickpocketLootId)
1200 if(!ids_set.count(lootid))
1201 LootTemplates_Pickpocketing.ReportNotExistedId(lootid);
1202 else
1203 ids_setUsed.insert(lootid);
1207 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1208 ids_set.erase(*itr);
1210 // output error for any still listed (not referenced from appropriate table) ids
1211 LootTemplates_Pickpocketing.ReportUnusedIds(ids_set);
1214 void LoadLootTemplates_Prospecting()
1216 LootIdSet ids_set;
1217 LootTemplates_Prospecting.LoadAndCollectLootIds(ids_set);
1219 // remove real entries and check existence loot
1220 for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
1222 ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i);
1223 if(!proto)
1224 continue;
1226 if((proto->BagFamily & BAG_FAMILY_MASK_MINING_SUPP)==0)
1227 continue;
1229 if(ids_set.count(proto->ItemId))
1230 ids_set.erase(proto->ItemId);
1233 // output error for any still listed (not referenced from appropriate table) ids
1234 LootTemplates_Prospecting.ReportUnusedIds(ids_set);
1237 void LoadLootTemplates_QuestMail()
1239 LootIdSet ids_set;
1240 LootTemplates_QuestMail.LoadAndCollectLootIds(ids_set);
1242 // remove real entries and check existence loot
1243 ObjectMgr::QuestMap const& questMap = objmgr.GetQuestTemplates();
1244 for(ObjectMgr::QuestMap::const_iterator itr = questMap.begin(); itr != questMap.end(); ++itr )
1246 if(!itr->second->GetRewMailTemplateId())
1247 continue;
1249 if(ids_set.count(itr->first))
1250 ids_set.erase(itr->first);
1251 /* disabled reporting: some quest mails not include items
1252 else
1253 LootTemplates_QuestMail.ReportNotExistedId(itr->first);
1257 // output error for any still listed (not referenced from appropriate table) ids
1258 LootTemplates_QuestMail.ReportUnusedIds(ids_set);
1261 void LoadLootTemplates_Skinning()
1263 LootIdSet ids_set, ids_setUsed;
1264 LootTemplates_Skinning.LoadAndCollectLootIds(ids_set);
1266 // remove real entries and check existence loot
1267 for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i )
1269 if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
1271 if(uint32 lootid = cInfo->SkinLootId)
1273 if(!ids_set.count(lootid))
1274 LootTemplates_Skinning.ReportNotExistedId(lootid);
1275 else
1276 ids_setUsed.insert(lootid);
1280 for(LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
1281 ids_set.erase(*itr);
1283 // output error for any still listed (not referenced from appropriate table) ids
1284 LootTemplates_Skinning.ReportUnusedIds(ids_set);
1287 void LoadLootTemplates_Spell()
1289 LootIdSet ids_set;
1290 LootTemplates_Spell.LoadAndCollectLootIds(ids_set);
1292 // remove real entries and check existence loot
1293 for(uint32 spell_id = 1; spell_id < sSpellStore.GetNumRows(); ++spell_id)
1295 SpellEntry const* spellInfo = sSpellStore.LookupEntry (spell_id);
1296 if(!spellInfo)
1297 continue;
1299 // possible cases
1300 if( !IsLootCraftingSpell(spellInfo))
1301 continue;
1303 if(!ids_set.count(spell_id))
1305 // not report about not trainable spells (optionally supported by DB) except with SPELL_ATTR_EX2_UNK14 (clams)
1306 // 61756 (Northrend Inscription Research (FAST QA VERSION) for example
1307 if ((spellInfo->Attributes & SPELL_ATTR_UNK5) || (spellInfo->AttributesEx2 & SPELL_ATTR_EX2_UNK14))
1308 LootTemplates_Spell.ReportNotExistedId(spell_id);
1310 else
1311 ids_set.erase(spell_id);
1314 // output error for any still listed (not referenced from appropriate table) ids
1315 LootTemplates_QuestMail.ReportUnusedIds(ids_set);
1318 void LoadLootTemplates_Reference()
1320 LootIdSet ids_set;
1321 LootTemplates_Reference.LoadAndCollectLootIds(ids_set);
1323 // check references and remove used
1324 LootTemplates_Creature.CheckLootRefs(&ids_set);
1325 LootTemplates_Fishing.CheckLootRefs(&ids_set);
1326 LootTemplates_Gameobject.CheckLootRefs(&ids_set);
1327 LootTemplates_Item.CheckLootRefs(&ids_set);
1328 LootTemplates_Milling.CheckLootRefs(&ids_set);
1329 LootTemplates_Pickpocketing.CheckLootRefs(&ids_set);
1330 LootTemplates_Skinning.CheckLootRefs(&ids_set);
1331 LootTemplates_Disenchant.CheckLootRefs(&ids_set);
1332 LootTemplates_Prospecting.CheckLootRefs(&ids_set);
1333 LootTemplates_QuestMail.CheckLootRefs(&ids_set);
1334 LootTemplates_Reference.CheckLootRefs(&ids_set);
1336 // output error for any still listed ids (not referenced from any loot table)
1337 LootTemplates_Reference.ReportUnusedIds(ids_set);