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
21 #include "ObjectMgr.h"
22 #include "ProgressBar.h"
25 #include "SharedDefines.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)
54 void AddEntry(LootStoreItem
& item
); // Adds an entry to the group (at loading stage)
55 bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
56 bool HasQuestDropForPlayer(Player
const * player
) const;
57 // The same for active quests of the player
58 void Process(Loot
& loot
) const; // Rolls an item from the group (if any) and adds the item to the loot
59 float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
60 float TotalChance() const; // Overall chance for the group
62 void Verify(LootStore
const& lootstore
, uint32 id
, uint32 group_id
) const;
63 void CollectLootIds(LootIdSet
& set
) const;
64 void CheckLootRefs(LootIdSet
* ref_set
) const;
66 LootStoreItemList ExplicitlyChanced
; // Entries with chances defined in DB
67 LootStoreItemList EqualChanced
; // Zero chances - every entry takes the same chance
69 LootStoreItem
const * Roll() const; // Rolls an item from the group, returns NULL if all miss their chances
72 //Remove all data and free all memory
73 void LootStore::Clear()
75 for (LootTemplateMap::const_iterator itr
=m_LootTemplates
.begin(); itr
!= m_LootTemplates
.end(); ++itr
)
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
;
95 // Clearing store (for reloading case)
98 sLog
.outString( "%s :", GetName());
101 QueryResult
*result
= WorldDatabase
.PQuery("SELECT entry, item, ChanceOrQuestChance, groupid, mincountOrRef, maxcount, lootcondition, condition_value1, condition_value2 FROM %s",GetName());
105 barGoLink
bar(result
->GetRowCount());
109 Field
*fields
= result
->Fetch();
112 uint32 entry
= fields
[0].GetUInt32();
113 uint32 item
= fields
[1].GetUInt32();
114 float chanceOrQuestChance
= fields
[2].GetFloat();
115 uint8 group
= fields
[3].GetUInt8();
116 int32 mincountOrRef
= fields
[4].GetInt32();
117 uint32 maxcount
= fields
[5].GetUInt32();
118 ConditionType condition
= (ConditionType
)fields
[6].GetUInt8();
119 uint32 cond_value1
= fields
[7].GetUInt32();
120 uint32 cond_value2
= fields
[8].GetUInt32();
122 if(maxcount
> std::numeric_limits
<uint8
>::max())
124 sLog
.outErrorDb("Table '%s' entry %d item %d: maxcount value (%u) to large. must be less %u - skipped", GetName(), entry
, item
, maxcount
,std::numeric_limits
<uint8
>::max());
125 continue; // error already printed to log/console.
129 if(!PlayerCondition::IsValid(condition
,cond_value1
, cond_value2
))
131 sLog
.outErrorDb("... in table '%s' entry %u item %u", GetName(), entry
, item
);
132 continue; // error already printed to log/console.
135 // (condition + cond_value1/2) are converted into single conditionId
136 uint16 conditionId
= objmgr
.GetConditionId(condition
, cond_value1
, cond_value2
);
138 LootStoreItem storeitem
= LootStoreItem(item
, chanceOrQuestChance
, group
, conditionId
, mincountOrRef
, maxcount
);
140 if (!storeitem
.IsValid(*this,entry
)) // Validity checks
143 // Looking for the template of the entry
144 // often entries are put together
145 if (m_LootTemplates
.empty() || tab
->first
!= entry
)
147 // Searching the template (in case template Id changed)
148 tab
= m_LootTemplates
.find(entry
);
149 if ( tab
== m_LootTemplates
.end() )
151 std::pair
< LootTemplateMap::iterator
, bool > pr
= m_LootTemplates
.insert(LootTemplateMap::value_type(entry
, new LootTemplate
));
155 // else is empty - template Id and iter are the same
156 // finally iter refers to already existed or just created <entry, LootTemplate>
158 // Adds current row to the template
159 tab
->second
->AddEntry(storeitem
);
162 } while (result
->NextRow());
166 Verify(); // Checks validity of the loot store
169 sLog
.outString( ">> Loaded %u loot definitions (%lu templates)", count
, (unsigned long)m_LootTemplates
.size());
174 sLog
.outErrorDb( ">> Loaded 0 loot definitions. DB table `%s` is empty.",GetName() );
178 bool LootStore::HaveQuestLootFor(uint32 loot_id
) const
180 LootTemplateMap::const_iterator itr
= m_LootTemplates
.find(loot_id
);
181 if(itr
== m_LootTemplates
.end())
184 // scan loot for quest items
185 return itr
->second
->HasQuestDrop(m_LootTemplates
);
188 bool LootStore::HaveQuestLootForPlayer(uint32 loot_id
,Player
* player
) const
190 LootTemplateMap::const_iterator tab
= m_LootTemplates
.find(loot_id
);
191 if (tab
!= m_LootTemplates
.end())
192 if (tab
->second
->HasQuestDropForPlayer(m_LootTemplates
, player
))
198 LootTemplate
const* LootStore::GetLootFor(uint32 loot_id
) const
200 LootTemplateMap::const_iterator tab
= m_LootTemplates
.find(loot_id
);
202 if (tab
== m_LootTemplates
.end())
208 void LootStore::LoadAndCollectLootIds(LootIdSet
& ids_set
)
212 for(LootTemplateMap::const_iterator tab
= m_LootTemplates
.begin(); tab
!= m_LootTemplates
.end(); ++tab
)
213 ids_set
.insert(tab
->first
);
216 void LootStore::CheckLootRefs(LootIdSet
* ref_set
) const
218 for(LootTemplateMap::const_iterator ltItr
= m_LootTemplates
.begin(); ltItr
!= m_LootTemplates
.end(); ++ltItr
)
219 ltItr
->second
->CheckLootRefs(ref_set
);
222 void LootStore::ReportUnusedIds(LootIdSet
const& ids_set
) const
224 // all still listed ids isn't referenced
225 for(LootIdSet::const_iterator itr
= ids_set
.begin(); itr
!= ids_set
.end(); ++itr
)
226 sLog
.outErrorDb("Table '%s' entry %d isn't %s and not referenced from loot, and then useless.", GetName(), *itr
,GetEntryName());
229 void LootStore::ReportNotExistedId(uint32 id
) const
231 sLog
.outErrorDb("Table '%s' entry %d (%s) not exist but used as loot id in DB.", GetName(), id
,GetEntryName());
235 // --------- LootStoreItem ---------
238 // Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
239 // RATE_DROP_ITEMS is no longer used for all types of entries
240 bool LootStoreItem::Roll(bool rate
) const
245 if(mincountOrRef
< 0) // reference case
246 return roll_chance_f(chance
* (rate
? sWorld
.getRate(RATE_DROP_ITEM_REFERENCED
) : 1.0f
));
248 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype(itemid
);
250 float qualityModifier
= pProto
&& rate
? sWorld
.getRate(qualityToRate
[pProto
->Quality
]) : 1.0f
;
252 return roll_chance_f(chance
*qualityModifier
);
255 // Checks correctness of values
256 bool LootStoreItem::IsValid(LootStore
const& store
, uint32 entry
) const
258 if(group
>= 1 << 7) // it stored in 7 bit field
260 sLog
.outErrorDb("Table '%s' entry %d item %d: group (%u) must be less %u - skipped", store
.GetName(), entry
, itemid
, group
, 1 << 7);
264 if (mincountOrRef
== 0)
266 sLog
.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store
.GetName(), entry
, itemid
, mincountOrRef
);
270 if( mincountOrRef
> 0 ) // item (quest or non-quest) entry, maybe grouped
272 ItemPrototype
const *proto
= objmgr
.GetItemPrototype(itemid
);
275 sLog
.outErrorDb("Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store
.GetName(), entry
, itemid
);
279 if( chance
== 0 && group
== 0) // Zero chance is allowed for grouped entries only
281 sLog
.outErrorDb("Table '%s' entry %d item %d: equal-chanced grouped entry, but group not defined - skipped", store
.GetName(), entry
, itemid
);
285 if( chance
!= 0 && chance
< 0.000001f
) // loot with low chance
287 sLog
.outErrorDb("Table '%s' entry %d item %d: low chance (%f) - skipped",
288 store
.GetName(), entry
, itemid
, chance
);
292 if( maxcount
< mincountOrRef
) // wrong max count
294 sLog
.outErrorDb("Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store
.GetName(), entry
, itemid
, uint32(maxcount
), mincountOrRef
);
299 else // mincountOrRef < 0
302 sLog
.outErrorDb("Table '%s' entry %d item %d: quest chance will be treated as non-quest chance", store
.GetName(), entry
, itemid
);
303 else if( chance
== 0 ) // no chance for the reference
305 sLog
.outErrorDb("Table '%s' entry %d item %d: zero chance is specified for a reference, skipped", store
.GetName(), entry
, itemid
);
309 return true; // Referenced template existence is checked at whole store level
313 // --------- LootItem ---------
316 // Constructor, copies most fields from LootStoreItem and generates random count
317 LootItem::LootItem(LootStoreItem
const& li
)
320 conditionId
= li
.conditionId
;
322 ItemPrototype
const* proto
= objmgr
.GetItemPrototype(itemid
);
323 freeforall
= proto
&& (proto
->Flags
& ITEM_FLAGS_PARTY_LOOT
);
325 needs_quest
= li
.needs_quest
;
327 count
= urand(li
.mincountOrRef
, li
.maxcount
); // constructor called for mincountOrRef > 0 only
328 randomSuffix
= GenerateEnchSuffixFactor(itemid
);
329 randomPropertyId
= Item::GenerateItemRandomPropertyId(itemid
);
332 is_underthreshold
= 0;
336 // Basic checks for player/item compatibility - if false no chance to see the item in the loot
337 bool LootItem::AllowedForPlayer(Player
const * player
) const
339 // DB conditions check
340 if ( !objmgr
.IsPlayerMeetToCondition(player
,conditionId
) )
345 // Checking quests for quest-only drop (check only quests requirements in this case)
346 if( !player
->HasQuestForItem(itemid
) )
351 // Not quest only drop (check quest starting items for already accepted non-repeatable quests)
352 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype(itemid
);
353 if (pProto
&& pProto
->StartQuest
&& player
->GetQuestStatus(pProto
->StartQuest
) != QUEST_STATUS_NONE
&& !player
->HasQuestForItem(itemid
))
361 // --------- Loot ---------
364 // Inserts the item into the loot (called by LootTemplate processors)
365 void Loot::AddItem(LootStoreItem
const & item
)
367 if (item
.needs_quest
) // Quest drop
369 if (quest_items
.size() < MAX_NR_QUEST_ITEMS
)
370 quest_items
.push_back(LootItem(item
));
372 else if (items
.size() < MAX_NR_LOOT_ITEMS
) // Non-quest drop
374 items
.push_back(LootItem(item
));
376 // non-conditional one-player only items are counted here,
377 // free for all items are counted in FillFFALoot(),
378 // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
379 if( !item
.conditionId
)
381 ItemPrototype
const* proto
= objmgr
.GetItemPrototype(item
.itemid
);
382 if( !proto
|| (proto
->Flags
& ITEM_FLAGS_PARTY_LOOT
)==0 )
388 // Calls processor of corresponding LootTemplate (which handles everything including references)
389 void Loot::FillLoot(uint32 loot_id
, LootStore
const& store
, Player
* loot_owner
, bool personal
)
395 LootTemplate
const* tab
= store
.GetLootFor(loot_id
);
399 sLog
.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.",store
.GetName(),loot_id
);
403 items
.reserve(MAX_NR_LOOT_ITEMS
);
404 quest_items
.reserve(MAX_NR_QUEST_ITEMS
);
406 tab
->Process(*this, store
,store
.IsRatesAllowed ()); // Processing is done there, callback via Loot::AddItem()
408 // Setting access rights for group loot case
409 Group
* pGroup
=loot_owner
->GetGroup();
410 if(!personal
&& pGroup
)
412 for(GroupReference
*itr
= pGroup
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
413 if(Player
* pl
= itr
->getSource())
414 FillNotNormalLootFor(pl
);
416 // ... for personal loot
418 FillNotNormalLootFor(loot_owner
);
421 void Loot::FillNotNormalLootFor(Player
* pl
)
423 uint32 plguid
= pl
->GetGUIDLow();
425 QuestItemMap::iterator qmapitr
= PlayerQuestItems
.find(plguid
);
426 if (qmapitr
== PlayerQuestItems
.end())
429 qmapitr
= PlayerFFAItems
.find(plguid
);
430 if (qmapitr
== PlayerFFAItems
.end())
433 qmapitr
= PlayerNonQuestNonFFAConditionalItems
.find(plguid
);
434 if (qmapitr
== PlayerNonQuestNonFFAConditionalItems
.end())
435 FillNonQuestNonFFAConditionalLoot(pl
);
438 QuestItemList
* Loot::FillFFALoot(Player
* player
)
440 QuestItemList
*ql
= new QuestItemList();
442 for(uint8 i
= 0; i
< items
.size(); i
++)
444 LootItem
&item
= items
[i
];
445 if(!item
.is_looted
&& item
.freeforall
&& item
.AllowedForPlayer(player
) )
447 ql
->push_back(QuestItem(i
));
457 PlayerFFAItems
[player
->GetGUIDLow()] = ql
;
461 QuestItemList
* Loot::FillQuestLoot(Player
* player
)
463 if (items
.size() == MAX_NR_LOOT_ITEMS
) return NULL
;
464 QuestItemList
*ql
= new QuestItemList();
466 for(uint8 i
= 0; i
< quest_items
.size(); i
++)
468 LootItem
&item
= quest_items
[i
];
469 if(!item
.is_looted
&& item
.AllowedForPlayer(player
) )
471 ql
->push_back(QuestItem(i
));
473 // questitems get blocked when they first apper in a
474 // player's quest vector
476 // increase once if one looter only, looter-times if free for all
477 if (item
.freeforall
|| !item
.is_blocked
)
480 item
.is_blocked
= true;
482 if (items
.size() + ql
->size() == MAX_NR_LOOT_ITEMS
)
492 PlayerQuestItems
[player
->GetGUIDLow()] = ql
;
496 QuestItemList
* Loot::FillNonQuestNonFFAConditionalLoot(Player
* player
)
498 QuestItemList
*ql
= new QuestItemList();
500 for(uint8 i
= 0; i
< items
.size(); ++i
)
502 LootItem
&item
= items
[i
];
503 if(!item
.is_looted
&& !item
.freeforall
&& item
.conditionId
&& item
.AllowedForPlayer(player
))
505 ql
->push_back(QuestItem(i
));
509 item
.is_counted
=true;
519 PlayerNonQuestNonFFAConditionalItems
[player
->GetGUIDLow()] = ql
;
523 //===================================================
525 void Loot::NotifyItemRemoved(uint8 lootIndex
)
527 // notify all players that are looting this that the item was removed
528 // convert the index to the slot the player sees
529 std::set
<uint64
>::iterator i_next
;
530 for(std::set
<uint64
>::iterator i
= PlayersLooting
.begin(); i
!= PlayersLooting
.end(); i
= i_next
)
534 if(Player
* pl
= ObjectAccessor::FindPlayer(*i
))
535 pl
->SendNotifyLootItemRemoved(lootIndex
);
537 PlayersLooting
.erase(i
);
541 void Loot::NotifyMoneyRemoved()
543 // notify all players that are looting this that the money was removed
544 std::set
<uint64
>::iterator i_next
;
545 for(std::set
<uint64
>::iterator i
= PlayersLooting
.begin(); i
!= PlayersLooting
.end(); i
= i_next
)
549 if(Player
* pl
= ObjectAccessor::FindPlayer(*i
))
550 pl
->SendNotifyLootMoneyRemoved();
552 PlayersLooting
.erase(i
);
556 void Loot::NotifyQuestItemRemoved(uint8 questIndex
)
558 // when a free for all questitem is looted
559 // all players will get notified of it being removed
560 // (other questitems can be looted by each group member)
561 // bit inefficient but isnt called often
563 std::set
<uint64
>::iterator i_next
;
564 for(std::set
<uint64
>::iterator i
= PlayersLooting
.begin(); i
!= PlayersLooting
.end(); i
= i_next
)
568 if(Player
* pl
= ObjectAccessor::FindPlayer(*i
))
570 QuestItemMap::iterator pq
= PlayerQuestItems
.find(pl
->GetGUIDLow());
571 if (pq
!= PlayerQuestItems
.end() && pq
->second
)
573 // find where/if the player has the given item in it's vector
574 QuestItemList
& pql
= *pq
->second
;
577 for (j
= 0; j
< pql
.size(); ++j
)
578 if (pql
[j
].index
== questIndex
)
582 pl
->SendNotifyLootItemRemoved(items
.size()+j
);
586 PlayersLooting
.erase(i
);
590 void Loot::generateMoneyLoot( uint32 minAmount
, uint32 maxAmount
)
594 if (maxAmount
<= minAmount
)
595 gold
= uint32(maxAmount
* sWorld
.getRate(RATE_DROP_MONEY
));
596 else if ((maxAmount
- minAmount
) < 32700)
597 gold
= uint32(urand(minAmount
, maxAmount
) * sWorld
.getRate(RATE_DROP_MONEY
));
599 gold
= uint32(urand(minAmount
>> 8, maxAmount
>> 8) * sWorld
.getRate(RATE_DROP_MONEY
)) << 8;
603 LootItem
* Loot::LootItemInSlot(uint32 lootSlot
, Player
* player
, QuestItem
**qitem
, QuestItem
**ffaitem
, QuestItem
**conditem
)
605 LootItem
* item
= NULL
;
606 bool is_looted
= true;
607 if (lootSlot
>= items
.size())
609 uint32 questSlot
= lootSlot
- items
.size();
610 QuestItemMap::const_iterator itr
= PlayerQuestItems
.find(player
->GetGUIDLow());
611 if (itr
!= PlayerQuestItems
.end() && questSlot
< itr
->second
->size())
613 QuestItem
*qitem2
= &itr
->second
->at(questSlot
);
616 item
= &quest_items
[qitem2
->index
];
617 is_looted
= qitem2
->is_looted
;
622 item
= &items
[lootSlot
];
623 is_looted
= item
->is_looted
;
626 QuestItemMap::const_iterator itr
= PlayerFFAItems
.find(player
->GetGUIDLow());
627 if (itr
!= PlayerFFAItems
.end())
629 for(QuestItemList::iterator iter
=itr
->second
->begin(); iter
!= itr
->second
->end(); ++iter
)
630 if(iter
->index
==lootSlot
)
632 QuestItem
*ffaitem2
= (QuestItem
*)&(*iter
);
635 is_looted
= ffaitem2
->is_looted
;
640 else if(item
->conditionId
)
642 QuestItemMap::const_iterator itr
= PlayerNonQuestNonFFAConditionalItems
.find(player
->GetGUIDLow());
643 if (itr
!= PlayerNonQuestNonFFAConditionalItems
.end())
645 for(QuestItemList::iterator iter
=itr
->second
->begin(); iter
!= itr
->second
->end(); ++iter
)
647 if(iter
->index
==lootSlot
)
649 QuestItem
*conditem2
= (QuestItem
*)&(*iter
);
651 *conditem
= conditem2
;
652 is_looted
= conditem2
->is_looted
;
666 uint32
Loot::GetMaxSlotInLootFor(Player
* player
) const
668 QuestItemMap::const_iterator itr
= PlayerQuestItems
.find(player
->GetGUIDLow());
669 return items
.size() + (itr
!= PlayerQuestItems
.end() ? itr
->second
->size() : 0);
672 ByteBuffer
& operator<<(ByteBuffer
& b
, LootItem
const& li
)
674 b
<< uint32(li
.itemid
);
675 b
<< uint32(li
.count
); // nr of items of this type
676 b
<< uint32(objmgr
.GetItemPrototype(li
.itemid
)->DisplayInfoID
);
677 b
<< uint32(li
.randomSuffix
);
678 b
<< uint32(li
.randomPropertyId
);
679 //b << uint8(0); // slot type - will send after this function call
683 ByteBuffer
& operator<<(ByteBuffer
& b
, LootView
const& lv
)
685 if (lv
.permission
== NONE_PERMISSION
)
687 b
<< uint32(0); //gold
688 b
<< uint8(0); // item count
689 return b
; // nothing output more
694 uint8 itemsShown
= 0;
699 size_t count_pos
= b
.wpos(); // pos of item count byte
700 b
<< uint8(0); // item count placeholder
702 switch (lv
.permission
)
704 case GROUP_PERMISSION
:
706 // You are not the items proprietary, so you can only see
707 // blocked rolled items and quest items, and !ffa items
708 for (uint8 i
= 0; i
< l
.items
.size(); ++i
)
710 if (!l
.items
[i
].is_looted
&& !l
.items
[i
].freeforall
&& !l
.items
[i
].conditionId
&& l
.items
[i
].AllowedForPlayer(lv
.viewer
))
712 uint8 slot_type
= (l
.items
[i
].is_blocked
|| l
.items
[i
].is_underthreshold
) ? 0 : 1;
714 b
<< uint8(i
) << l
.items
[i
]; //send the index and the item if it's not looted, and blocked or under threshold, free for all items will be sent later, only one-player loots here
715 b
<< uint8(slot_type
); // 0 - get 1 - look only
722 case MASTER_PERMISSION
:
724 uint8 slot_type
= (lv
.permission
==MASTER_PERMISSION
) ? 2 : 0;
725 for (uint8 i
= 0; i
< l
.items
.size(); ++i
)
727 if (!l
.items
[i
].is_looted
&& !l
.items
[i
].freeforall
&& !l
.items
[i
].conditionId
&& l
.items
[i
].AllowedForPlayer(lv
.viewer
))
729 b
<< uint8(i
) << l
.items
[i
]; //only send one-player loot items now, free for all will be sent later
730 b
<< uint8(slot_type
); // 0 - get 2 - master selection
737 return b
; // nothing output more
740 QuestItemMap
const& lootPlayerQuestItems
= l
.GetPlayerQuestItems();
741 QuestItemMap::const_iterator q_itr
= lootPlayerQuestItems
.find(lv
.viewer
->GetGUIDLow());
742 if (q_itr
!= lootPlayerQuestItems
.end())
744 QuestItemList
*q_list
= q_itr
->second
;
745 for (QuestItemList::iterator qi
= q_list
->begin() ; qi
!= q_list
->end(); ++qi
)
747 LootItem
&item
= l
.quest_items
[qi
->index
];
748 if (!qi
->is_looted
&& !item
.is_looted
)
750 b
<< uint8(l
.items
.size() + (qi
- q_list
->begin()));
752 b
<< uint8(0); // allow loot
758 QuestItemMap
const& lootPlayerFFAItems
= l
.GetPlayerFFAItems();
759 QuestItemMap::const_iterator ffa_itr
= lootPlayerFFAItems
.find(lv
.viewer
->GetGUIDLow());
760 if (ffa_itr
!= lootPlayerFFAItems
.end())
762 QuestItemList
*ffa_list
= ffa_itr
->second
;
763 for (QuestItemList::iterator fi
= ffa_list
->begin() ; fi
!= ffa_list
->end(); ++fi
)
765 LootItem
&item
= l
.items
[fi
->index
];
766 if (!fi
->is_looted
&& !item
.is_looted
)
768 b
<< uint8(fi
->index
) << item
;
769 b
<< uint8(0); // allow loot
775 QuestItemMap
const& lootPlayerNonQuestNonFFAConditionalItems
= l
.GetPlayerNonQuestNonFFAConditionalItems();
776 QuestItemMap::const_iterator nn_itr
= lootPlayerNonQuestNonFFAConditionalItems
.find(lv
.viewer
->GetGUIDLow());
777 if (nn_itr
!= lootPlayerNonQuestNonFFAConditionalItems
.end())
779 QuestItemList
*conditional_list
= nn_itr
->second
;
780 for (QuestItemList::iterator ci
= conditional_list
->begin() ; ci
!= conditional_list
->end(); ++ci
)
782 LootItem
&item
= l
.items
[ci
->index
];
783 if (!ci
->is_looted
&& !item
.is_looted
)
785 b
<< uint8(ci
->index
) << item
;
786 b
<< uint8(0); // allow loot
792 //update number of items shown
793 b
.put
<uint8
>(count_pos
,itemsShown
);
799 // --------- LootTemplate::LootGroup ---------
802 // Adds an entry to the group (at loading stage)
803 void LootTemplate::LootGroup::AddEntry(LootStoreItem
& item
)
805 if (item
.chance
!= 0)
806 ExplicitlyChanced
.push_back(item
);
808 EqualChanced
.push_back(item
);
811 // Rolls an item from the group, returns NULL if all miss their chances
812 LootStoreItem
const * LootTemplate::LootGroup::Roll() const
814 if (!ExplicitlyChanced
.empty()) // First explicitly chanced entries are checked
816 float Roll
= rand_chance();
818 for (uint32 i
=0; i
<ExplicitlyChanced
.size(); ++i
) //check each explicitly chanced entry in the template and modify its chance based on quality.
820 if(ExplicitlyChanced
[i
].chance
>=100.f
)
821 return &ExplicitlyChanced
[i
];
823 Roll
-= ExplicitlyChanced
[i
].chance
;
825 return &ExplicitlyChanced
[i
];
828 if (!EqualChanced
.empty()) // If nothing selected yet - an item is taken from equal-chanced part
829 return &EqualChanced
[irand(0, EqualChanced
.size()-1)];
831 return NULL
; // Empty drop from the group
834 // True if group includes at least 1 quest drop entry
835 bool LootTemplate::LootGroup::HasQuestDrop() const
837 for (LootStoreItemList::const_iterator i
=ExplicitlyChanced
.begin(); i
!= ExplicitlyChanced
.end(); ++i
)
840 for (LootStoreItemList::const_iterator i
=EqualChanced
.begin(); i
!= EqualChanced
.end(); ++i
)
846 // True if group includes at least 1 quest drop entry for active quests of the player
847 bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player
const * player
) const
849 for (LootStoreItemList::const_iterator i
=ExplicitlyChanced
.begin(); i
!= ExplicitlyChanced
.end(); ++i
)
850 if (player
->HasQuestForItem(i
->itemid
))
852 for (LootStoreItemList::const_iterator i
=EqualChanced
.begin(); i
!= EqualChanced
.end(); ++i
)
853 if (player
->HasQuestForItem(i
->itemid
))
858 // Rolls an item from the group (if any takes its chance) and adds the item to the loot
859 void LootTemplate::LootGroup::Process(Loot
& loot
) const
861 LootStoreItem
const * item
= Roll();
866 // Overall chance for the group without equal chanced items
867 float LootTemplate::LootGroup::RawTotalChance() const
871 for (LootStoreItemList::const_iterator i
=ExplicitlyChanced
.begin(); i
!= ExplicitlyChanced
.end(); ++i
)
872 if ( !i
->needs_quest
)
878 // Overall chance for the group
879 float LootTemplate::LootGroup::TotalChance() const
881 float result
= RawTotalChance();
883 if (!EqualChanced
.empty() && result
< 100.0f
)
889 void LootTemplate::LootGroup::Verify(LootStore
const& lootstore
, uint32 id
, uint32 group_id
) const
891 float chance
= RawTotalChance();
892 if (chance
> 101.0f
) // TODO: replace with 100% when DBs will be ready
894 sLog
.outErrorDb("Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore
.GetName(), id
, group_id
, chance
);
897 if(chance
>= 100.0f
&& !EqualChanced
.empty())
899 sLog
.outErrorDb("Table '%s' entry %u group %d has items with chance=0%% but group total chance >= 100%% (%f)", lootstore
.GetName(), id
, group_id
, chance
);
903 void LootTemplate::LootGroup::CheckLootRefs(LootIdSet
* ref_set
) const
905 for (LootStoreItemList::const_iterator ieItr
=ExplicitlyChanced
.begin(); ieItr
!= ExplicitlyChanced
.end(); ++ieItr
)
907 if(ieItr
->mincountOrRef
< 0)
909 if(!LootTemplates_Reference
.GetLootFor(-ieItr
->mincountOrRef
))
910 LootTemplates_Reference
.ReportNotExistedId(-ieItr
->mincountOrRef
);
912 ref_set
->erase(-ieItr
->mincountOrRef
);
916 for (LootStoreItemList::const_iterator ieItr
=EqualChanced
.begin(); ieItr
!= EqualChanced
.end(); ++ieItr
)
918 if(ieItr
->mincountOrRef
< 0)
920 if(!LootTemplates_Reference
.GetLootFor(-ieItr
->mincountOrRef
))
921 LootTemplates_Reference
.ReportNotExistedId(-ieItr
->mincountOrRef
);
923 ref_set
->erase(-ieItr
->mincountOrRef
);
929 // --------- LootTemplate ---------
932 // Adds an entry to the group (at loading stage)
933 void LootTemplate::AddEntry(LootStoreItem
& item
)
935 if (item
.group
> 0 && item
.mincountOrRef
> 0) // Group
937 if (item
.group
>= Groups
.size())
938 Groups
.resize(item
.group
); // Adds new group the the loot template if needed
939 Groups
[item
.group
-1].AddEntry(item
); // Adds new entry to the group
941 else // Non-grouped entries and references are stored together
942 Entries
.push_back(item
);
945 // Rolls for every item in the template and adds the rolled items the the loot
946 void LootTemplate::Process(Loot
& loot
, LootStore
const& store
, bool rate
, uint8 groupId
) const
948 if (groupId
) // Group reference uses own processing of the group
950 if (groupId
> Groups
.size())
951 return; // Error message already printed at loading stage
953 Groups
[groupId
-1].Process(loot
);
957 // Rolling non-grouped items
958 for (LootStoreItemList::const_iterator i
= Entries
.begin() ; i
!= Entries
.end() ; ++i
)
961 continue; // Bad luck for the entry
963 if (i
->mincountOrRef
< 0) // References processing
965 LootTemplate
const* Referenced
= LootTemplates_Reference
.GetLootFor(-i
->mincountOrRef
);
968 continue; // Error message already printed at loading stage
970 for (uint32 loop
=0; loop
< i
->maxcount
; ++loop
)// Ref multiplicator
971 Referenced
->Process(loot
, store
, rate
, i
->group
);
973 else // Plain entries (not a reference, not grouped)
974 loot
.AddItem(*i
); // Chance is already checked, just add
977 // Now processing groups
978 for (LootGroups::const_iterator i
= Groups
.begin( ) ; i
!= Groups
.end( ) ; ++i
)
982 // True if template includes at least 1 quest drop entry
983 bool LootTemplate::HasQuestDrop(LootTemplateMap
const& store
, uint8 groupId
) const
985 if (groupId
) // Group reference
987 if (groupId
> Groups
.size())
988 return false; // Error message [should be] already printed at loading stage
989 return Groups
[groupId
-1].HasQuestDrop();
992 for (LootStoreItemList::const_iterator i
= Entries
.begin(); i
!= Entries
.end(); ++i
)
994 if (i
->mincountOrRef
< 0) // References
996 LootTemplateMap::const_iterator Referenced
= store
.find(-i
->mincountOrRef
);
997 if( Referenced
==store
.end() )
998 continue; // Error message [should be] already printed at loading stage
999 if (Referenced
->second
->HasQuestDrop(store
, i
->group
) )
1002 else if ( i
->needs_quest
)
1003 return true; // quest drop found
1006 // Now processing groups
1007 for (LootGroups::const_iterator i
= Groups
.begin() ; i
!= Groups
.end() ; ++i
)
1008 if (i
->HasQuestDrop())
1014 // True if template includes at least 1 quest drop for an active quest of the player
1015 bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap
const& store
, Player
const* player
, uint8 groupId
) const
1017 if (groupId
) // Group reference
1019 if (groupId
> Groups
.size())
1020 return false; // Error message already printed at loading stage
1021 return Groups
[groupId
-1].HasQuestDropForPlayer(player
);
1024 // Checking non-grouped entries
1025 for (LootStoreItemList::const_iterator i
= Entries
.begin() ; i
!= Entries
.end() ; ++i
)
1027 if (i
->mincountOrRef
< 0) // References processing
1029 LootTemplateMap::const_iterator Referenced
= store
.find(-i
->mincountOrRef
);
1030 if (Referenced
== store
.end() )
1031 continue; // Error message already printed at loading stage
1032 if (Referenced
->second
->HasQuestDropForPlayer(store
, player
, i
->group
) )
1035 else if ( player
->HasQuestForItem(i
->itemid
) )
1036 return true; // active quest drop found
1039 // Now checking groups
1040 for (LootGroups::const_iterator i
= Groups
.begin(); i
!= Groups
.end(); ++i
)
1041 if (i
->HasQuestDropForPlayer(player
))
1047 // Checks integrity of the template
1048 void LootTemplate::Verify(LootStore
const& lootstore
, uint32 id
) const
1050 // Checking group chances
1051 for (uint32 i
=0; i
< Groups
.size(); ++i
)
1052 Groups
[i
].Verify(lootstore
,id
,i
+1);
1054 // TODO: References validity checks
1057 void LootTemplate::CheckLootRefs(LootIdSet
* ref_set
) const
1059 for(LootStoreItemList::const_iterator ieItr
= Entries
.begin(); ieItr
!= Entries
.end(); ++ieItr
)
1061 if(ieItr
->mincountOrRef
< 0)
1063 if(!LootTemplates_Reference
.GetLootFor(-ieItr
->mincountOrRef
))
1064 LootTemplates_Reference
.ReportNotExistedId(-ieItr
->mincountOrRef
);
1066 ref_set
->erase(-ieItr
->mincountOrRef
);
1070 for(LootGroups::const_iterator grItr
= Groups
.begin(); grItr
!= Groups
.end(); ++grItr
)
1071 grItr
->CheckLootRefs(ref_set
);
1074 void LoadLootTemplates_Creature()
1076 LootIdSet ids_set
, ids_setUsed
;
1077 LootTemplates_Creature
.LoadAndCollectLootIds(ids_set
);
1079 // remove real entries and check existence loot
1080 for(uint32 i
= 1; i
< sCreatureStorage
.MaxEntry
; ++i
)
1082 if(CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(i
))
1084 if(uint32 lootid
= cInfo
->lootid
)
1086 if(!ids_set
.count(lootid
))
1087 LootTemplates_Creature
.ReportNotExistedId(lootid
);
1089 ids_setUsed
.insert(lootid
);
1093 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1094 ids_set
.erase(*itr
);
1096 // output error for any still listed (not referenced from appropriate table) ids
1097 LootTemplates_Creature
.ReportUnusedIds(ids_set
);
1100 void LoadLootTemplates_Disenchant()
1102 LootIdSet ids_set
, ids_setUsed
;
1103 LootTemplates_Disenchant
.LoadAndCollectLootIds(ids_set
);
1105 // remove real entries and check existence loot
1106 for(uint32 i
= 1; i
< sItemStorage
.MaxEntry
; ++i
)
1108 if(ItemPrototype
const* proto
= sItemStorage
.LookupEntry
<ItemPrototype
>(i
))
1110 if(uint32 lootid
= proto
->DisenchantID
)
1112 if(!ids_set
.count(lootid
))
1113 LootTemplates_Disenchant
.ReportNotExistedId(lootid
);
1115 ids_setUsed
.insert(lootid
);
1119 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1120 ids_set
.erase(*itr
);
1121 // output error for any still listed (not referenced from appropriate table) ids
1122 LootTemplates_Disenchant
.ReportUnusedIds(ids_set
);
1125 void LoadLootTemplates_Fishing()
1128 LootTemplates_Fishing
.LoadAndCollectLootIds(ids_set
);
1130 // remove real entries and check existence loot
1131 for(uint32 i
= 1; i
< sAreaStore
.GetNumRows(); ++i
)
1133 if(AreaTableEntry
const* areaEntry
= sAreaStore
.LookupEntry(i
))
1134 if(ids_set
.count(areaEntry
->ID
))
1135 ids_set
.erase(areaEntry
->ID
);
1138 // output error for any still listed (not referenced from appropriate table) ids
1139 LootTemplates_Fishing
.ReportUnusedIds(ids_set
);
1142 void LoadLootTemplates_Gameobject()
1144 LootIdSet ids_set
, ids_setUsed
;
1145 LootTemplates_Gameobject
.LoadAndCollectLootIds(ids_set
);
1147 // remove real entries and check existence loot
1148 for(uint32 i
= 1; i
< sGOStorage
.MaxEntry
; ++i
)
1150 if(GameObjectInfo
const* gInfo
= sGOStorage
.LookupEntry
<GameObjectInfo
>(i
))
1152 if(uint32 lootid
= GameObject::GetLootId(gInfo
))
1154 if(!ids_set
.count(lootid
))
1155 LootTemplates_Gameobject
.ReportNotExistedId(lootid
);
1157 ids_setUsed
.insert(lootid
);
1161 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1162 ids_set
.erase(*itr
);
1164 // output error for any still listed (not referenced from appropriate table) ids
1165 LootTemplates_Gameobject
.ReportUnusedIds(ids_set
);
1168 void LoadLootTemplates_Item()
1171 LootTemplates_Item
.LoadAndCollectLootIds(ids_set
);
1173 // remove real entries and check existence loot
1174 for(uint32 i
= 1; i
< sItemStorage
.MaxEntry
; ++i
)
1175 if(ItemPrototype
const* proto
= sItemStorage
.LookupEntry
<ItemPrototype
>(i
))
1176 if(ids_set
.count(proto
->ItemId
))
1177 ids_set
.erase(proto
->ItemId
);
1179 // output error for any still listed (not referenced from appropriate table) ids
1180 LootTemplates_Item
.ReportUnusedIds(ids_set
);
1183 void LoadLootTemplates_Milling()
1186 LootTemplates_Milling
.LoadAndCollectLootIds(ids_set
);
1188 // remove real entries and check existence loot
1189 for(uint32 i
= 1; i
< sItemStorage
.MaxEntry
; ++i
)
1191 ItemPrototype
const* proto
= sItemStorage
.LookupEntry
<ItemPrototype
>(i
);
1195 if((proto
->BagFamily
& BAG_FAMILY_MASK_HERBS
)==0)
1198 if(ids_set
.count(proto
->ItemId
))
1199 ids_set
.erase(proto
->ItemId
);
1202 // output error for any still listed (not referenced from appropriate table) ids
1203 LootTemplates_Milling
.ReportUnusedIds(ids_set
);
1206 void LoadLootTemplates_Pickpocketing()
1208 LootIdSet ids_set
, ids_setUsed
;
1209 LootTemplates_Pickpocketing
.LoadAndCollectLootIds(ids_set
);
1211 // remove real entries and check existence loot
1212 for(uint32 i
= 1; i
< sCreatureStorage
.MaxEntry
; ++i
)
1214 if(CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(i
))
1216 if(uint32 lootid
= cInfo
->pickpocketLootId
)
1218 if(!ids_set
.count(lootid
))
1219 LootTemplates_Pickpocketing
.ReportNotExistedId(lootid
);
1221 ids_setUsed
.insert(lootid
);
1225 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1226 ids_set
.erase(*itr
);
1228 // output error for any still listed (not referenced from appropriate table) ids
1229 LootTemplates_Pickpocketing
.ReportUnusedIds(ids_set
);
1232 void LoadLootTemplates_Prospecting()
1235 LootTemplates_Prospecting
.LoadAndCollectLootIds(ids_set
);
1237 // remove real entries and check existence loot
1238 for(uint32 i
= 1; i
< sItemStorage
.MaxEntry
; ++i
)
1240 ItemPrototype
const* proto
= sItemStorage
.LookupEntry
<ItemPrototype
>(i
);
1244 if((proto
->BagFamily
& BAG_FAMILY_MASK_MINING_SUPP
)==0)
1247 if(ids_set
.count(proto
->ItemId
))
1248 ids_set
.erase(proto
->ItemId
);
1251 // output error for any still listed (not referenced from appropriate table) ids
1252 LootTemplates_Prospecting
.ReportUnusedIds(ids_set
);
1255 void LoadLootTemplates_QuestMail()
1258 LootTemplates_QuestMail
.LoadAndCollectLootIds(ids_set
);
1260 // remove real entries and check existence loot
1261 ObjectMgr::QuestMap
const& questMap
= objmgr
.GetQuestTemplates();
1262 for(ObjectMgr::QuestMap::const_iterator itr
= questMap
.begin(); itr
!= questMap
.end(); ++itr
)
1264 if(!itr
->second
->GetRewMailTemplateId())
1267 if(ids_set
.count(itr
->first
))
1268 ids_set
.erase(itr
->first
);
1269 /* disabled reporting: some quest mails not include items
1271 LootTemplates_QuestMail.ReportNotExistedId(itr->first);
1275 // output error for any still listed (not referenced from appropriate table) ids
1276 LootTemplates_QuestMail
.ReportUnusedIds(ids_set
);
1279 void LoadLootTemplates_Skinning()
1281 LootIdSet ids_set
, ids_setUsed
;
1282 LootTemplates_Skinning
.LoadAndCollectLootIds(ids_set
);
1284 // remove real entries and check existence loot
1285 for(uint32 i
= 1; i
< sCreatureStorage
.MaxEntry
; ++i
)
1287 if(CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(i
))
1289 if(uint32 lootid
= cInfo
->SkinLootId
)
1291 if(!ids_set
.count(lootid
))
1292 LootTemplates_Skinning
.ReportNotExistedId(lootid
);
1294 ids_setUsed
.insert(lootid
);
1298 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1299 ids_set
.erase(*itr
);
1301 // output error for any still listed (not referenced from appropriate table) ids
1302 LootTemplates_Skinning
.ReportUnusedIds(ids_set
);
1305 void LoadLootTemplates_Spell()
1308 LootTemplates_Spell
.LoadAndCollectLootIds(ids_set
);
1310 // remove real entries and check existence loot
1311 for(uint32 spell_id
= 1; spell_id
< sSpellStore
.GetNumRows(); ++spell_id
)
1313 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry (spell_id
);
1318 if( !IsLootCraftingSpell(spellInfo
))
1321 if(!ids_set
.count(spell_id
))
1323 // not report about not trainable spells (optionally supported by DB) except with SPELL_ATTR_EX2_UNK14 (clams)
1324 // 61756 (Northrend Inscription Research (FAST QA VERSION) for example
1325 if ((spellInfo
->Attributes
& SPELL_ATTR_UNK5
) || (spellInfo
->AttributesEx2
& SPELL_ATTR_EX2_UNK14
))
1326 LootTemplates_Spell
.ReportNotExistedId(spell_id
);
1329 ids_set
.erase(spell_id
);
1332 // output error for any still listed (not referenced from appropriate table) ids
1333 LootTemplates_QuestMail
.ReportUnusedIds(ids_set
);
1336 void LoadLootTemplates_Reference()
1339 LootTemplates_Reference
.LoadAndCollectLootIds(ids_set
);
1341 // check references and remove used
1342 LootTemplates_Creature
.CheckLootRefs(&ids_set
);
1343 LootTemplates_Fishing
.CheckLootRefs(&ids_set
);
1344 LootTemplates_Gameobject
.CheckLootRefs(&ids_set
);
1345 LootTemplates_Item
.CheckLootRefs(&ids_set
);
1346 LootTemplates_Milling
.CheckLootRefs(&ids_set
);
1347 LootTemplates_Pickpocketing
.CheckLootRefs(&ids_set
);
1348 LootTemplates_Skinning
.CheckLootRefs(&ids_set
);
1349 LootTemplates_Disenchant
.CheckLootRefs(&ids_set
);
1350 LootTemplates_Prospecting
.CheckLootRefs(&ids_set
);
1351 LootTemplates_QuestMail
.CheckLootRefs(&ids_set
);
1352 LootTemplates_Reference
.CheckLootRefs(&ids_set
);
1354 // output error for any still listed ids (not referenced from any loot table)
1355 LootTemplates_Reference
.ReportUnusedIds(ids_set
);