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
, 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;
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
)
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 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
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
));
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
);
155 } while (result
->NextRow());
159 Verify(); // Checks validity of the loot store
162 sLog
.outString( ">> Loaded %u loot definitions (%d templates)", count
, m_LootTemplates
.size());
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())
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
))
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())
201 void LootStore::LoadAndCollectLootIds(LootIdSet
& ids_set
)
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
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
);
257 if( mincountOrRef
> 0 ) // item (quest or non-quest) entry, maybe grouped
259 ItemPrototype
const *proto
= objmgr
.GetItemPrototype(itemid
);
262 sLog
.outErrorDb("Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store
.GetName(), entry
, itemid
);
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
);
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
);
279 else // mincountOrRef < 0
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
);
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
)
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
);
312 is_underthreshold
= 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
) )
325 // Checking quests for quest-only drop (check only quests requirements in this case)
326 if( !player
->HasQuestForItem(itemid
) )
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
))
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 )
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
)
375 LootTemplate
const* tab
= store
.GetLootFor(loot_id
);
379 sLog
.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.",store
.GetName(),loot_id
);
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
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())
409 qmapitr
= PlayerFFAItems
.find(plguid
);
410 if (qmapitr
== PlayerFFAItems
.end())
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
));
437 PlayerFFAItems
[player
->GetGUIDLow()] = 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
)
460 item
.is_blocked
= true;
462 if (items
.size() + ql
->size() == MAX_NR_LOOT_ITEMS
)
472 PlayerQuestItems
[player
->GetGUIDLow()] = 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
));
489 item
.is_counted
=true;
499 PlayerNonQuestNonFFAConditionalItems
[player
->GetGUIDLow()] = 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
)
514 if(Player
* pl
= ObjectAccessor::FindPlayer(*i
))
515 pl
->SendNotifyLootItemRemoved(lootIndex
);
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
)
529 if(Player
* pl
= ObjectAccessor::FindPlayer(*i
))
530 pl
->SendNotifyLootMoneyRemoved();
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
)
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
;
557 for (j
= 0; j
< pql
.size(); ++j
)
558 if (pql
[j
].index
== questIndex
)
562 pl
->SendNotifyLootItemRemoved(items
.size()+j
);
566 PlayersLooting
.erase(i
);
570 void Loot::generateMoneyLoot( uint32 minAmount
, uint32 maxAmount
)
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
));
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
);
596 item
= &quest_items
[qitem2
->index
];
597 is_looted
= qitem2
->is_looted
;
602 item
= &items
[lootSlot
];
603 is_looted
= item
->is_looted
;
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
);
615 is_looted
= ffaitem2
->is_looted
;
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
);
631 *conditem
= conditem2
;
632 is_looted
= conditem2
->is_looted
;
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
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
674 uint8 itemsShown
= 0;
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
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
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()));
732 b
<< uint8(0); // allow loot
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
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
772 //update number of items shown
773 b
.put
<uint8
>(count_pos
,itemsShown
);
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
);
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
;
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
)
822 for (LootStoreItemList::const_iterator i
=EqualChanced
.begin(); i
!= EqualChanced
.end(); ++i
)
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
))
834 for (LootStoreItemList::const_iterator i
=EqualChanced
.begin(); i
!= EqualChanced
.end(); ++i
)
835 if (player
->HasQuestForItem(i
->itemid
))
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
);
848 // Overall chance for the group without equal chanced items
849 float LootTemplate::LootGroup::RawTotalChance() const
853 for (LootStoreItemList::const_iterator i
=ExplicitlyChanced
.begin(); i
!= ExplicitlyChanced
.end(); ++i
)
854 if ( !i
->needs_quest
)
860 // Overall chance for the group
861 float LootTemplate::LootGroup::TotalChance() const
863 float result
= RawTotalChance();
865 if (!EqualChanced
.empty() && result
< 100.0f
)
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
);
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
);
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
);
939 // Rolling non-grouped items
940 for (LootStoreItemList::const_iterator i
= Entries
.begin() ; i
!= Entries
.end() ; ++i
)
943 continue; // Bad luck for the entry
945 if (i
->mincountOrRef
< 0) // References processing
947 LootTemplate
const* Referenced
= LootTemplates_Reference
.GetLootFor(-i
->mincountOrRef
);
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
) )
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())
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
) )
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
))
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
);
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
);
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
);
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()
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
);
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()
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()
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
);
1177 if((proto
->BagFamily
& BAG_FAMILY_MASK_HERBS
)==0)
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
);
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()
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
);
1226 if((proto
->BagFamily
& BAG_FAMILY_MASK_MINING_SUPP
)==0)
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()
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())
1249 if(ids_set
.count(itr
->first
))
1250 ids_set
.erase(itr
->first
);
1251 /* disabled reporting: some quest mails not include items
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
);
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()
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
);
1300 if( !IsLootCraftingSpell(spellInfo
))
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
);
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()
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
);