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"
27 static Rates
const qualityToRate
[MAX_ITEM_QUALITY
] = {
28 RATE_DROP_ITEM_POOR
, // ITEM_QUALITY_POOR
29 RATE_DROP_ITEM_NORMAL
, // ITEM_QUALITY_NORMAL
30 RATE_DROP_ITEM_UNCOMMON
, // ITEM_QUALITY_UNCOMMON
31 RATE_DROP_ITEM_RARE
, // ITEM_QUALITY_RARE
32 RATE_DROP_ITEM_EPIC
, // ITEM_QUALITY_EPIC
33 RATE_DROP_ITEM_LEGENDARY
, // ITEM_QUALITY_LEGENDARY
34 RATE_DROP_ITEM_ARTIFACT
, // ITEM_QUALITY_ARTIFACT
37 LootStore
LootTemplates_Creature( "creature_loot_template", "creature entry", true);
38 LootStore
LootTemplates_Disenchant( "disenchant_loot_template", "item disenchant id", true);
39 LootStore
LootTemplates_Fishing( "fishing_loot_template", "area id", true);
40 LootStore
LootTemplates_Gameobject( "gameobject_loot_template", "gameobject entry", true);
41 LootStore
LootTemplates_Item( "item_loot_template", "item entry", true);
42 LootStore
LootTemplates_Milling( "milling_loot_template", "item entry (herb)", true);
43 LootStore
LootTemplates_Pickpocketing("pickpocketing_loot_template","creature pickpocket lootid", true);
44 LootStore
LootTemplates_Prospecting( "prospecting_loot_template", "item entry (ore)", true);
45 LootStore
LootTemplates_QuestMail( "quest_mail_loot_template", "quest id (with mail template)",false);
46 LootStore
LootTemplates_Reference( "reference_loot_template", "reference id", false);
47 LootStore
LootTemplates_Skinning( "skinning_loot_template", "creature skinning id", true);
49 class LootTemplate::LootGroup
// A set of loot definitions for items (refs are not allowed)
52 void AddEntry(LootStoreItem
& item
); // Adds an entry to the group (at loading stage)
53 bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
54 bool HasQuestDropForPlayer(Player
const * player
) const;
55 // The same for active quests of the player
56 void Process(Loot
& loot
, bool rate
) const; // Rolls an item from the group (if any) and adds the item to the loot
57 float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
58 float TotalChance() const; // Overall chance for the group
60 void Verify(LootStore
const& lootstore
, uint32 id
, uint32 group_id
) const;
61 void CollectLootIds(LootIdSet
& set
) const;
62 void CheckLootRefs(LootIdSet
* ref_set
) const;
64 LootStoreItemList ExplicitlyChanced
; // Entries with chances defined in DB
65 LootStoreItemList EqualChanced
; // Zero chances - every entry takes the same chance
67 LootStoreItem
const * Roll(bool rate
) const; // Rolls an item from the group, returns NULL if all miss their chances
70 //Remove all data and free all memory
71 void LootStore::Clear()
73 for (LootTemplateMap::const_iterator itr
=m_LootTemplates
.begin(); itr
!= m_LootTemplates
.end(); ++itr
)
75 m_LootTemplates
.clear();
78 // Checks validity of the loot store
79 // Actual checks are done within LootTemplate::Verify() which is called for every template
80 void LootStore::Verify() const
82 for (LootTemplateMap::const_iterator i
= m_LootTemplates
.begin(); i
!= m_LootTemplates
.end(); ++i
)
83 i
->second
->Verify(*this, i
->first
);
86 // Loads a *_loot_template DB table into loot store
87 // All checks of the loaded template are called from here, no error reports at loot generation required
88 void LootStore::LoadLootTable()
90 LootTemplateMap::iterator tab
;
93 // Clearing store (for reloading case)
96 sLog
.outString( "%s :", GetName());
99 QueryResult
*result
= WorldDatabase
.PQuery("SELECT entry, item, ChanceOrQuestChance, groupid, mincountOrRef, maxcount, lootcondition, condition_value1, condition_value2 FROM %s",GetName());
103 barGoLink
bar(result
->GetRowCount());
107 Field
*fields
= result
->Fetch();
110 uint32 entry
= fields
[0].GetUInt32();
111 uint32 item
= fields
[1].GetUInt32();
112 float chanceOrQuestChance
= fields
[2].GetFloat();
113 uint8 group
= fields
[3].GetUInt8();
114 int32 mincountOrRef
= fields
[4].GetInt32();
115 uint8 maxcount
= fields
[5].GetUInt8();
116 ConditionType condition
= (ConditionType
)fields
[6].GetUInt8();
117 uint32 cond_value1
= fields
[7].GetUInt32();
118 uint32 cond_value2
= fields
[8].GetUInt32();
120 if(!PlayerCondition::IsValid(condition
,cond_value1
, cond_value2
))
122 sLog
.outErrorDb("... in table '%s' entry %u item %u", GetName(), entry
, item
);
123 continue; // error already printed to log/console.
126 // (condition + cond_value1/2) are converted into single conditionId
127 uint16 conditionId
= objmgr
.GetConditionId(condition
, cond_value1
, cond_value2
);
129 LootStoreItem storeitem
= LootStoreItem(item
, chanceOrQuestChance
, group
, conditionId
, mincountOrRef
, maxcount
);
131 if (!storeitem
.IsValid(*this,entry
)) // Validity checks
134 // Looking for the template of the entry
135 // often entries are put together
136 if (m_LootTemplates
.empty() || tab
->first
!= entry
)
138 // Searching the template (in case template Id changed)
139 tab
= m_LootTemplates
.find(entry
);
140 if ( tab
== m_LootTemplates
.end() )
142 std::pair
< LootTemplateMap::iterator
, bool > pr
= m_LootTemplates
.insert(LootTemplateMap::value_type(entry
, new LootTemplate
));
146 // else is empty - template Id and iter are the same
147 // finally iter refers to already existed or just created <entry, LootTemplate>
149 // Adds current row to the template
150 tab
->second
->AddEntry(storeitem
);
153 } while (result
->NextRow());
157 Verify(); // Checks validity of the loot store
160 sLog
.outString( ">> Loaded %u loot definitions (%d templates)", count
, m_LootTemplates
.size());
165 sLog
.outErrorDb( ">> Loaded 0 loot definitions. DB table `%s` is empty.",GetName() );
169 bool LootStore::HaveQuestLootFor(uint32 loot_id
) const
171 LootTemplateMap::const_iterator itr
= m_LootTemplates
.find(loot_id
);
172 if(itr
== m_LootTemplates
.end())
175 // scan loot for quest items
176 return itr
->second
->HasQuestDrop(m_LootTemplates
);
179 bool LootStore::HaveQuestLootForPlayer(uint32 loot_id
,Player
* player
) const
181 LootTemplateMap::const_iterator tab
= m_LootTemplates
.find(loot_id
);
182 if (tab
!= m_LootTemplates
.end())
183 if (tab
->second
->HasQuestDropForPlayer(m_LootTemplates
, player
))
189 LootTemplate
const* LootStore::GetLootFor(uint32 loot_id
) const
191 LootTemplateMap::const_iterator tab
= m_LootTemplates
.find(loot_id
);
193 if (tab
== m_LootTemplates
.end())
199 void LootStore::LoadAndCollectLootIds(LootIdSet
& ids_set
)
203 for(LootTemplateMap::const_iterator tab
= m_LootTemplates
.begin(); tab
!= m_LootTemplates
.end(); ++tab
)
204 ids_set
.insert(tab
->first
);
207 void LootStore::CheckLootRefs(LootIdSet
* ref_set
) const
209 for(LootTemplateMap::const_iterator ltItr
= m_LootTemplates
.begin(); ltItr
!= m_LootTemplates
.end(); ++ltItr
)
210 ltItr
->second
->CheckLootRefs(ref_set
);
213 void LootStore::ReportUnusedIds(LootIdSet
const& ids_set
) const
215 // all still listed ids isn't referenced
216 for(LootIdSet::const_iterator itr
= ids_set
.begin(); itr
!= ids_set
.end(); ++itr
)
217 sLog
.outErrorDb("Table '%s' entry %d isn't %s and not referenced from loot, and then useless.", GetName(), *itr
,GetEntryName());
220 void LootStore::ReportNotExistedId(uint32 id
) const
222 sLog
.outErrorDb("Table '%s' entry %d (%s) not exist but used as loot id in DB.", GetName(), id
,GetEntryName());
226 // --------- LootStoreItem ---------
229 // Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
230 // RATE_DROP_ITEMS is no longer used for all types of entries
231 bool LootStoreItem::Roll(bool rate
) const
236 if(mincountOrRef
< 0) // reference case
237 return roll_chance_f(chance
* (rate
? sWorld
.getRate(RATE_DROP_ITEM_REFERENCED
) : 1.0f
));
239 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype(itemid
);
241 float qualityModifier
= pProto
&& rate
? sWorld
.getRate(qualityToRate
[pProto
->Quality
]) : 1.0f
;
243 return roll_chance_f(chance
*qualityModifier
);
246 // Checks correctness of values
247 bool LootStoreItem::IsValid(LootStore
const& store
, uint32 entry
) const
249 if (mincountOrRef
== 0)
251 sLog
.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store
.GetName(), entry
, itemid
, mincountOrRef
);
255 if( mincountOrRef
> 0 ) // item (quest or non-quest) entry, maybe grouped
257 ItemPrototype
const *proto
= objmgr
.GetItemPrototype(itemid
);
260 sLog
.outErrorDb("Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store
.GetName(), entry
, itemid
);
264 if( chance
== 0 && group
== 0) // Zero chance is allowed for grouped entries only
266 sLog
.outErrorDb("Table '%s' entry %d item %d: equal-chanced grouped entry, but group not defined - skipped", store
.GetName(), entry
, itemid
);
270 if( chance
!= 0 && chance
< 0.000001f
) // loot with low chance
272 sLog
.outErrorDb("Table '%s' entry %d item %d: low chance (%f) - skipped",
273 store
.GetName(), entry
, itemid
, chance
);
277 else // mincountOrRef < 0
280 sLog
.outErrorDb("Table '%s' entry %d item %d: quest chance will be treated as non-quest chance", store
.GetName(), entry
, itemid
);
281 else if( chance
== 0 ) // no chance for the reference
283 sLog
.outErrorDb("Table '%s' entry %d item %d: zero chance is specified for a reference, skipped", store
.GetName(), entry
, itemid
);
287 return true; // Referenced template existence is checked at whole store level
291 // --------- LootItem ---------
294 // Constructor, copies most fields from LootStoreItem and generates random count
295 LootItem::LootItem(LootStoreItem
const& li
)
298 conditionId
= li
.conditionId
;
300 ItemPrototype
const* proto
= objmgr
.GetItemPrototype(itemid
);
301 freeforall
= proto
&& (proto
->Flags
& ITEM_FLAGS_PARTY_LOOT
);
303 needs_quest
= li
.needs_quest
;
305 count
= urand(li
.mincountOrRef
, li
.maxcount
); // constructor called for mincountOrRef > 0 only
306 randomSuffix
= GenerateEnchSuffixFactor(itemid
);
307 randomPropertyId
= Item::GenerateItemRandomPropertyId(itemid
);
310 is_underthreshold
= 0;
314 // Basic checks for player/item compatibility - if false no chance to see the item in the loot
315 bool LootItem::AllowedForPlayer(Player
const * player
) const
317 // DB conditions check
318 if ( !objmgr
.IsPlayerMeetToCondition(player
,conditionId
) )
323 // Checking quests for quest-only drop (check only quests requirements in this case)
324 if( !player
->HasQuestForItem(itemid
) )
329 // Not quest only drop (check quest starting items for already accepted non-repeatable quests)
330 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype(itemid
);
331 if (pProto
&& pProto
->StartQuest
&& player
->GetQuestStatus(pProto
->StartQuest
) != QUEST_STATUS_NONE
&& !player
->HasQuestForItem(itemid
))
339 // --------- Loot ---------
342 // Inserts the item into the loot (called by LootTemplate processors)
343 void Loot::AddItem(LootStoreItem
const & item
)
345 if (item
.needs_quest
) // Quest drop
347 if (quest_items
.size() < MAX_NR_QUEST_ITEMS
)
348 quest_items
.push_back(LootItem(item
));
350 else if (items
.size() < MAX_NR_LOOT_ITEMS
) // Non-quest drop
352 items
.push_back(LootItem(item
));
354 // non-conditional one-player only items are counted here,
355 // free for all items are counted in FillFFALoot(),
356 // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
357 if( !item
.conditionId
)
359 ItemPrototype
const* proto
= objmgr
.GetItemPrototype(item
.itemid
);
360 if( !proto
|| (proto
->Flags
& ITEM_FLAGS_PARTY_LOOT
)==0 )
366 // Calls processor of corresponding LootTemplate (which handles everything including references)
367 void Loot::FillLoot(uint32 loot_id
, LootStore
const& store
, Player
* loot_owner
)
369 LootTemplate
const* tab
= store
.GetLootFor(loot_id
);
373 sLog
.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.",store
.GetName(),loot_id
);
377 items
.reserve(MAX_NR_LOOT_ITEMS
);
378 quest_items
.reserve(MAX_NR_QUEST_ITEMS
);
380 tab
->Process(*this, store
,store
.IsRatesAllowed ()); // Processing is done there, callback via Loot::AddItem()
382 // Setting access rights fow group-looting case
385 Group
* pGroup
=loot_owner
->GetGroup();
388 for(GroupReference
*itr
= pGroup
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
390 //fill the quest item map for every player in the recipient's group
391 Player
* pl
= itr
->getSource();
394 uint32 plguid
= pl
->GetGUIDLow();
395 QuestItemMap::iterator qmapitr
= PlayerQuestItems
.find(plguid
);
396 if (qmapitr
== PlayerQuestItems
.end())
400 qmapitr
= PlayerFFAItems
.find(plguid
);
401 if (qmapitr
== PlayerFFAItems
.end())
405 qmapitr
= PlayerNonQuestNonFFAConditionalItems
.find(plguid
);
406 if (qmapitr
== PlayerNonQuestNonFFAConditionalItems
.end())
408 FillNonQuestNonFFAConditionalLoot(pl
);
413 QuestItemList
* Loot::FillFFALoot(Player
* player
)
415 QuestItemList
*ql
= new QuestItemList();
417 for(uint8 i
= 0; i
< items
.size(); i
++)
419 LootItem
&item
= items
[i
];
420 if(!item
.is_looted
&& item
.freeforall
&& item
.AllowedForPlayer(player
) )
422 ql
->push_back(QuestItem(i
));
432 PlayerFFAItems
[player
->GetGUIDLow()] = ql
;
436 QuestItemList
* Loot::FillQuestLoot(Player
* player
)
438 if (items
.size() == MAX_NR_LOOT_ITEMS
) return NULL
;
439 QuestItemList
*ql
= new QuestItemList();
441 for(uint8 i
= 0; i
< quest_items
.size(); i
++)
443 LootItem
&item
= quest_items
[i
];
444 if(!item
.is_looted
&& item
.AllowedForPlayer(player
) )
446 ql
->push_back(QuestItem(i
));
448 // questitems get blocked when they first apper in a
449 // player's quest vector
451 // increase once if one looter only, looter-times if free for all
452 if (item
.freeforall
|| !item
.is_blocked
)
455 item
.is_blocked
= true;
457 if (items
.size() + ql
->size() == MAX_NR_LOOT_ITEMS
)
467 PlayerQuestItems
[player
->GetGUIDLow()] = ql
;
471 QuestItemList
* Loot::FillNonQuestNonFFAConditionalLoot(Player
* player
)
473 QuestItemList
*ql
= new QuestItemList();
475 for(uint8 i
= 0; i
< items
.size(); ++i
)
477 LootItem
&item
= items
[i
];
478 if(!item
.is_looted
&& !item
.freeforall
&& item
.conditionId
&& item
.AllowedForPlayer(player
))
480 ql
->push_back(QuestItem(i
));
484 item
.is_counted
=true;
494 PlayerNonQuestNonFFAConditionalItems
[player
->GetGUIDLow()] = ql
;
498 //===================================================
500 void Loot::NotifyItemRemoved(uint8 lootIndex
)
502 // notify all players that are looting this that the item was removed
503 // convert the index to the slot the player sees
504 std::set
<uint64
>::iterator i_next
;
505 for(std::set
<uint64
>::iterator i
= PlayersLooting
.begin(); i
!= PlayersLooting
.end(); i
= i_next
)
509 if(Player
* pl
= ObjectAccessor::FindPlayer(*i
))
510 pl
->SendNotifyLootItemRemoved(lootIndex
);
512 PlayersLooting
.erase(i
);
516 void Loot::NotifyMoneyRemoved()
518 // notify all players that are looting this that the money was removed
519 std::set
<uint64
>::iterator i_next
;
520 for(std::set
<uint64
>::iterator i
= PlayersLooting
.begin(); i
!= PlayersLooting
.end(); i
= i_next
)
524 if(Player
* pl
= ObjectAccessor::FindPlayer(*i
))
525 pl
->SendNotifyLootMoneyRemoved();
527 PlayersLooting
.erase(i
);
531 void Loot::NotifyQuestItemRemoved(uint8 questIndex
)
533 // when a free for all questitem is looted
534 // all players will get notified of it being removed
535 // (other questitems can be looted by each group member)
536 // bit inefficient but isnt called often
538 std::set
<uint64
>::iterator i_next
;
539 for(std::set
<uint64
>::iterator i
= PlayersLooting
.begin(); i
!= PlayersLooting
.end(); i
= i_next
)
543 if(Player
* pl
= ObjectAccessor::FindPlayer(*i
))
545 QuestItemMap::iterator pq
= PlayerQuestItems
.find(pl
->GetGUIDLow());
546 if (pq
!= PlayerQuestItems
.end() && pq
->second
)
548 // find where/if the player has the given item in it's vector
549 QuestItemList
& pql
= *pq
->second
;
552 for (j
= 0; j
< pql
.size(); ++j
)
553 if (pql
[j
].index
== questIndex
)
557 pl
->SendNotifyLootItemRemoved(items
.size()+j
);
561 PlayersLooting
.erase(i
);
565 void Loot::generateMoneyLoot( uint32 minAmount
, uint32 maxAmount
)
569 if (maxAmount
<= minAmount
)
570 gold
= uint32(maxAmount
* sWorld
.getRate(RATE_DROP_MONEY
));
571 else if ((maxAmount
- minAmount
) < 32700)
572 gold
= uint32(urand(minAmount
, maxAmount
) * sWorld
.getRate(RATE_DROP_MONEY
));
574 gold
= uint32(urand(minAmount
>> 8, maxAmount
>> 8) * sWorld
.getRate(RATE_DROP_MONEY
)) << 8;
578 LootItem
* Loot::LootItemInSlot(uint32 lootSlot
, Player
* player
, QuestItem
**qitem
, QuestItem
**ffaitem
, QuestItem
**conditem
)
580 LootItem
* item
= NULL
;
581 bool is_looted
= true;
582 if (lootSlot
>= items
.size())
584 uint32 questSlot
= lootSlot
- items
.size();
585 QuestItemMap::const_iterator itr
= PlayerQuestItems
.find(player
->GetGUIDLow());
586 if (itr
!= PlayerQuestItems
.end() && questSlot
< itr
->second
->size())
588 QuestItem
*qitem2
= &itr
->second
->at(questSlot
);
591 item
= &quest_items
[qitem2
->index
];
592 is_looted
= qitem2
->is_looted
;
597 item
= &items
[lootSlot
];
598 is_looted
= item
->is_looted
;
601 QuestItemMap::const_iterator itr
= PlayerFFAItems
.find(player
->GetGUIDLow());
602 if (itr
!= PlayerFFAItems
.end())
604 for(QuestItemList::iterator iter
=itr
->second
->begin(); iter
!= itr
->second
->end(); ++iter
)
605 if(iter
->index
==lootSlot
)
607 QuestItem
*ffaitem2
= (QuestItem
*)&(*iter
);
610 is_looted
= ffaitem2
->is_looted
;
615 else if(item
->conditionId
)
617 QuestItemMap::const_iterator itr
= PlayerNonQuestNonFFAConditionalItems
.find(player
->GetGUIDLow());
618 if (itr
!= PlayerNonQuestNonFFAConditionalItems
.end())
620 for(QuestItemList::iterator iter
=itr
->second
->begin(); iter
!= itr
->second
->end(); ++iter
)
622 if(iter
->index
==lootSlot
)
624 QuestItem
*conditem2
= (QuestItem
*)&(*iter
);
626 *conditem
= conditem2
;
627 is_looted
= conditem2
->is_looted
;
641 ByteBuffer
& operator<<(ByteBuffer
& b
, LootItem
const& li
)
643 b
<< uint32(li
.itemid
);
644 b
<< uint32(li
.count
); // nr of items of this type
645 b
<< uint32(objmgr
.GetItemPrototype(li
.itemid
)->DisplayInfoID
);
646 b
<< uint32(li
.randomSuffix
);
647 b
<< uint32(li
.randomPropertyId
);
648 //b << uint8(0); // slot type - will send after this function call
652 ByteBuffer
& operator<<(ByteBuffer
& b
, LootView
const& lv
)
656 uint8 itemsShown
= 0;
659 b
<< uint32(lv
.permission
!=NONE_PERMISSION
? l
.gold
: 0);
661 size_t count_pos
= b
.wpos(); // pos of item count byte
662 b
<< uint8(0); // item count placeholder
664 switch (lv
.permission
)
666 case GROUP_PERMISSION
:
668 // You are not the items proprietary, so you can only see
669 // blocked rolled items and quest items, and !ffa items
670 for (uint8 i
= 0; i
< l
.items
.size(); ++i
)
672 if (!l
.items
[i
].is_looted
&& !l
.items
[i
].freeforall
&& !l
.items
[i
].conditionId
&& l
.items
[i
].AllowedForPlayer(lv
.viewer
))
674 uint8 slot_type
= (l
.items
[i
].is_blocked
|| l
.items
[i
].is_underthreshold
) ? 0 : 1;
676 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
677 b
<< uint8(slot_type
); // 0 - get 1 - look only
684 case MASTER_PERMISSION
:
686 uint8 slot_type
= (lv
.permission
==MASTER_PERMISSION
) ? 2 : 0;
687 for (uint8 i
= 0; i
< l
.items
.size(); ++i
)
689 if (!l
.items
[i
].is_looted
&& !l
.items
[i
].freeforall
&& !l
.items
[i
].conditionId
&& l
.items
[i
].AllowedForPlayer(lv
.viewer
))
691 b
<< uint8(i
) << l
.items
[i
]; //only send one-player loot items now, free for all will be sent later
692 b
<< uint8(slot_type
); // 0 - get 2 - master selection
698 case NONE_PERMISSION
:
700 return b
; // nothing output more
705 for (QuestItemList::iterator qi
= lv
.qlist
->begin() ; qi
!= lv
.qlist
->end(); ++qi
)
707 LootItem
&item
= l
.quest_items
[qi
->index
];
708 if (!qi
->is_looted
&& !item
.is_looted
)
710 b
<< uint8(l
.items
.size() + (qi
- lv
.qlist
->begin()));
712 b
<< uint8(0); // allow loot
720 for (QuestItemList::iterator fi
= lv
.ffalist
->begin() ; fi
!= lv
.ffalist
->end(); ++fi
)
722 LootItem
&item
= l
.items
[fi
->index
];
723 if (!fi
->is_looted
&& !item
.is_looted
)
725 b
<< uint8(fi
->index
) << item
;
726 b
<< uint8(0); // allow loot
732 if (lv
.conditionallist
)
734 for (QuestItemList::iterator ci
= lv
.conditionallist
->begin() ; ci
!= lv
.conditionallist
->end(); ++ci
)
736 LootItem
&item
= l
.items
[ci
->index
];
737 if (!ci
->is_looted
&& !item
.is_looted
)
739 b
<< uint8(ci
->index
) << item
;
740 b
<< uint8(0); // allow loot
746 //update number of items shown
747 b
.put
<uint8
>(count_pos
,itemsShown
);
753 // --------- LootTemplate::LootGroup ---------
756 // Adds an entry to the group (at loading stage)
757 void LootTemplate::LootGroup::AddEntry(LootStoreItem
& item
)
759 if (item
.chance
!= 0)
760 ExplicitlyChanced
.push_back(item
);
762 EqualChanced
.push_back(item
);
765 // Rolls an item from the group, returns NULL if all miss their chances
766 LootStoreItem
const * LootTemplate::LootGroup::Roll(bool rate
) const
768 if (!ExplicitlyChanced
.empty()) // First explicitly chanced entries are checked
770 float Roll
= rand_chance();
772 for (uint32 i
=0; i
<ExplicitlyChanced
.size(); ++i
) //check each explicitly chanced entry in the template and modify its chance based on quality.
774 if(ExplicitlyChanced
[i
].chance
>=100.f
)
775 return &ExplicitlyChanced
[i
];
777 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype(ExplicitlyChanced
[i
].itemid
);
778 float qualityMultiplier
= pProto
&& rate
? sWorld
.getRate(qualityToRate
[pProto
->Quality
]) : 1.0f
;
779 Roll
-= ExplicitlyChanced
[i
].chance
* qualityMultiplier
;
781 return &ExplicitlyChanced
[i
];
784 if (!EqualChanced
.empty()) // If nothing selected yet - an item is taken from equal-chanced part
785 return &EqualChanced
[irand(0, EqualChanced
.size()-1)];
787 return NULL
; // Empty drop from the group
790 // True if group includes at least 1 quest drop entry
791 bool LootTemplate::LootGroup::HasQuestDrop() const
793 for (LootStoreItemList::const_iterator i
=ExplicitlyChanced
.begin(); i
!= ExplicitlyChanced
.end(); ++i
)
796 for (LootStoreItemList::const_iterator i
=EqualChanced
.begin(); i
!= EqualChanced
.end(); ++i
)
802 // True if group includes at least 1 quest drop entry for active quests of the player
803 bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player
const * player
) const
805 for (LootStoreItemList::const_iterator i
=ExplicitlyChanced
.begin(); i
!= ExplicitlyChanced
.end(); ++i
)
806 if (player
->HasQuestForItem(i
->itemid
))
808 for (LootStoreItemList::const_iterator i
=EqualChanced
.begin(); i
!= EqualChanced
.end(); ++i
)
809 if (player
->HasQuestForItem(i
->itemid
))
814 // Rolls an item from the group (if any takes its chance) and adds the item to the loot
815 void LootTemplate::LootGroup::Process(Loot
& loot
, bool rate
) const
817 LootStoreItem
const * item
= Roll(rate
);
822 // Overall chance for the group without equal chanced items
823 float LootTemplate::LootGroup::RawTotalChance() const
827 for (LootStoreItemList::const_iterator i
=ExplicitlyChanced
.begin(); i
!= ExplicitlyChanced
.end(); ++i
)
828 if ( !i
->needs_quest
)
834 // Overall chance for the group
835 float LootTemplate::LootGroup::TotalChance() const
837 float result
= RawTotalChance();
839 if (!EqualChanced
.empty() && result
< 100.0f
)
845 void LootTemplate::LootGroup::Verify(LootStore
const& lootstore
, uint32 id
, uint32 group_id
) const
847 float chance
= RawTotalChance();
848 if (chance
> 101.0f
) // TODO: replace with 100% when DBs will be ready
850 sLog
.outErrorDb("Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore
.GetName(), id
, group_id
, chance
);
853 if(chance
>= 100.0f
&& !EqualChanced
.empty())
855 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
);
859 void LootTemplate::LootGroup::CheckLootRefs(LootIdSet
* ref_set
) const
861 for (LootStoreItemList::const_iterator ieItr
=ExplicitlyChanced
.begin(); ieItr
!= ExplicitlyChanced
.end(); ++ieItr
)
863 if(ieItr
->mincountOrRef
< 0)
865 if(!LootTemplates_Reference
.GetLootFor(-ieItr
->mincountOrRef
))
866 LootTemplates_Reference
.ReportNotExistedId(-ieItr
->mincountOrRef
);
868 ref_set
->erase(-ieItr
->mincountOrRef
);
872 for (LootStoreItemList::const_iterator ieItr
=EqualChanced
.begin(); ieItr
!= EqualChanced
.end(); ++ieItr
)
874 if(ieItr
->mincountOrRef
< 0)
876 if(!LootTemplates_Reference
.GetLootFor(-ieItr
->mincountOrRef
))
877 LootTemplates_Reference
.ReportNotExistedId(-ieItr
->mincountOrRef
);
879 ref_set
->erase(-ieItr
->mincountOrRef
);
885 // --------- LootTemplate ---------
888 // Adds an entry to the group (at loading stage)
889 void LootTemplate::AddEntry(LootStoreItem
& item
)
891 if (item
.group
> 0 && item
.mincountOrRef
> 0) // Group
893 if (item
.group
>= Groups
.size())
894 Groups
.resize(item
.group
); // Adds new group the the loot template if needed
895 Groups
[item
.group
-1].AddEntry(item
); // Adds new entry to the group
897 else // Non-grouped entries and references are stored together
898 Entries
.push_back(item
);
901 // Rolls for every item in the template and adds the rolled items the the loot
902 void LootTemplate::Process(Loot
& loot
, LootStore
const& store
, bool rate
, uint8 groupId
) const
904 if (groupId
) // Group reference uses own processing of the group
906 if (groupId
> Groups
.size())
907 return; // Error message already printed at loading stage
909 Groups
[groupId
-1].Process(loot
,rate
);
913 // Rolling non-grouped items
914 for (LootStoreItemList::const_iterator i
= Entries
.begin() ; i
!= Entries
.end() ; ++i
)
917 continue; // Bad luck for the entry
919 if (i
->mincountOrRef
< 0) // References processing
921 LootTemplate
const* Referenced
= LootTemplates_Reference
.GetLootFor(-i
->mincountOrRef
);
924 continue; // Error message already printed at loading stage
926 for (uint32 loop
=0; loop
< i
->maxcount
; ++loop
)// Ref multiplicator
927 Referenced
->Process(loot
, store
, rate
, i
->group
);
929 else // Plain entries (not a reference, not grouped)
930 loot
.AddItem(*i
); // Chance is already checked, just add
933 // Now processing groups
934 for (LootGroups::const_iterator i
= Groups
.begin( ) ; i
!= Groups
.end( ) ; ++i
)
935 i
->Process(loot
,rate
);
938 // True if template includes at least 1 quest drop entry
939 bool LootTemplate::HasQuestDrop(LootTemplateMap
const& store
, uint8 groupId
) const
941 if (groupId
) // Group reference
943 if (groupId
> Groups
.size())
944 return false; // Error message [should be] already printed at loading stage
945 return Groups
[groupId
-1].HasQuestDrop();
948 for (LootStoreItemList::const_iterator i
= Entries
.begin(); i
!= Entries
.end(); ++i
)
950 if (i
->mincountOrRef
< 0) // References
952 LootTemplateMap::const_iterator Referenced
= store
.find(-i
->mincountOrRef
);
953 if( Referenced
==store
.end() )
954 continue; // Error message [should be] already printed at loading stage
955 if (Referenced
->second
->HasQuestDrop(store
, i
->group
) )
958 else if ( i
->needs_quest
)
959 return true; // quest drop found
962 // Now processing groups
963 for (LootGroups::const_iterator i
= Groups
.begin() ; i
!= Groups
.end() ; ++i
)
964 if (i
->HasQuestDrop())
970 // True if template includes at least 1 quest drop for an active quest of the player
971 bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap
const& store
, Player
const* player
, uint8 groupId
) const
973 if (groupId
) // Group reference
975 if (groupId
> Groups
.size())
976 return false; // Error message already printed at loading stage
977 return Groups
[groupId
-1].HasQuestDropForPlayer(player
);
980 // Checking non-grouped entries
981 for (LootStoreItemList::const_iterator i
= Entries
.begin() ; i
!= Entries
.end() ; ++i
)
983 if (i
->mincountOrRef
< 0) // References processing
985 LootTemplateMap::const_iterator Referenced
= store
.find(-i
->mincountOrRef
);
986 if (Referenced
== store
.end() )
987 continue; // Error message already printed at loading stage
988 if (Referenced
->second
->HasQuestDropForPlayer(store
, player
, i
->group
) )
991 else if ( player
->HasQuestForItem(i
->itemid
) )
992 return true; // active quest drop found
995 // Now checking groups
996 for (LootGroups::const_iterator i
= Groups
.begin(); i
!= Groups
.end(); ++i
)
997 if (i
->HasQuestDrop())
1003 // Checks integrity of the template
1004 void LootTemplate::Verify(LootStore
const& lootstore
, uint32 id
) const
1006 // Checking group chances
1007 for (uint32 i
=0; i
< Groups
.size(); ++i
)
1008 Groups
[i
].Verify(lootstore
,id
,i
+1);
1010 // TODO: References validity checks
1013 void LootTemplate::CheckLootRefs(LootIdSet
* ref_set
) const
1015 for(LootStoreItemList::const_iterator ieItr
= Entries
.begin(); ieItr
!= Entries
.end(); ++ieItr
)
1017 if(ieItr
->mincountOrRef
< 0)
1019 if(!LootTemplates_Reference
.GetLootFor(-ieItr
->mincountOrRef
))
1020 LootTemplates_Reference
.ReportNotExistedId(-ieItr
->mincountOrRef
);
1022 ref_set
->erase(-ieItr
->mincountOrRef
);
1026 for(LootGroups::const_iterator grItr
= Groups
.begin(); grItr
!= Groups
.end(); ++grItr
)
1027 grItr
->CheckLootRefs(ref_set
);
1030 void LoadLootTemplates_Creature()
1032 LootIdSet ids_set
, ids_setUsed
;
1033 LootTemplates_Creature
.LoadAndCollectLootIds(ids_set
);
1035 // remove real entries and check existence loot
1036 for(uint32 i
= 1; i
< sCreatureStorage
.MaxEntry
; ++i
)
1038 if(CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(i
))
1040 if(uint32 lootid
= cInfo
->lootid
)
1042 if(!ids_set
.count(lootid
))
1043 LootTemplates_Creature
.ReportNotExistedId(lootid
);
1045 ids_setUsed
.insert(lootid
);
1049 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1050 ids_set
.erase(*itr
);
1052 // output error for any still listed (not referenced from appropriate table) ids
1053 LootTemplates_Creature
.ReportUnusedIds(ids_set
);
1056 void LoadLootTemplates_Disenchant()
1058 LootIdSet ids_set
, ids_setUsed
;
1059 LootTemplates_Disenchant
.LoadAndCollectLootIds(ids_set
);
1061 // remove real entries and check existence loot
1062 for(uint32 i
= 1; i
< sItemStorage
.MaxEntry
; ++i
)
1064 if(ItemPrototype
const* proto
= sItemStorage
.LookupEntry
<ItemPrototype
>(i
))
1066 if(uint32 lootid
= proto
->DisenchantID
)
1068 if(!ids_set
.count(lootid
))
1069 LootTemplates_Disenchant
.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
);
1077 // output error for any still listed (not referenced from appropriate table) ids
1078 LootTemplates_Disenchant
.ReportUnusedIds(ids_set
);
1081 void LoadLootTemplates_Fishing()
1084 LootTemplates_Fishing
.LoadAndCollectLootIds(ids_set
);
1086 // remove real entries and check existence loot
1087 for(uint32 i
= 1; i
< sAreaStore
.GetNumRows(); ++i
)
1089 if(AreaTableEntry
const* areaEntry
= sAreaStore
.LookupEntry(i
))
1090 if(ids_set
.count(areaEntry
->ID
))
1091 ids_set
.erase(areaEntry
->ID
);
1094 // output error for any still listed (not referenced from appropriate table) ids
1095 LootTemplates_Fishing
.ReportUnusedIds(ids_set
);
1098 void LoadLootTemplates_Gameobject()
1100 LootIdSet ids_set
, ids_setUsed
;
1101 LootTemplates_Gameobject
.LoadAndCollectLootIds(ids_set
);
1103 // remove real entries and check existence loot
1104 for(uint32 i
= 1; i
< sGOStorage
.MaxEntry
; ++i
)
1106 if(GameObjectInfo
const* gInfo
= sGOStorage
.LookupEntry
<GameObjectInfo
>(i
))
1108 if(uint32 lootid
= GameObject::GetLootId(gInfo
))
1110 if(!ids_set
.count(lootid
))
1111 LootTemplates_Gameobject
.ReportNotExistedId(lootid
);
1113 ids_setUsed
.insert(lootid
);
1117 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1118 ids_set
.erase(*itr
);
1120 // output error for any still listed (not referenced from appropriate table) ids
1121 LootTemplates_Gameobject
.ReportUnusedIds(ids_set
);
1124 void LoadLootTemplates_Item()
1127 LootTemplates_Item
.LoadAndCollectLootIds(ids_set
);
1129 // remove real entries and check existence loot
1130 for(uint32 i
= 1; i
< sItemStorage
.MaxEntry
; ++i
)
1131 if(ItemPrototype
const* proto
= sItemStorage
.LookupEntry
<ItemPrototype
>(i
))
1132 if(ids_set
.count(proto
->ItemId
))
1133 ids_set
.erase(proto
->ItemId
);
1135 // output error for any still listed (not referenced from appropriate table) ids
1136 LootTemplates_Item
.ReportUnusedIds(ids_set
);
1139 void LoadLootTemplates_Milling()
1142 LootTemplates_Milling
.LoadAndCollectLootIds(ids_set
);
1144 // remove real entries and check existence loot
1145 for(uint32 i
= 1; i
< sItemStorage
.MaxEntry
; ++i
)
1147 ItemPrototype
const* proto
= sItemStorage
.LookupEntry
<ItemPrototype
>(i
);
1151 if((proto
->BagFamily
& BAG_FAMILY_MASK_HERBS
)==0)
1154 if(ids_set
.count(proto
->ItemId
))
1155 ids_set
.erase(proto
->ItemId
);
1158 // output error for any still listed (not referenced from appropriate table) ids
1159 LootTemplates_Milling
.ReportUnusedIds(ids_set
);
1162 void LoadLootTemplates_Pickpocketing()
1164 LootIdSet ids_set
, ids_setUsed
;
1165 LootTemplates_Pickpocketing
.LoadAndCollectLootIds(ids_set
);
1167 // remove real entries and check existence loot
1168 for(uint32 i
= 1; i
< sCreatureStorage
.MaxEntry
; ++i
)
1170 if(CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(i
))
1172 if(uint32 lootid
= cInfo
->pickpocketLootId
)
1174 if(!ids_set
.count(lootid
))
1175 LootTemplates_Pickpocketing
.ReportNotExistedId(lootid
);
1177 ids_setUsed
.insert(lootid
);
1181 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1182 ids_set
.erase(*itr
);
1184 // output error for any still listed (not referenced from appropriate table) ids
1185 LootTemplates_Pickpocketing
.ReportUnusedIds(ids_set
);
1188 void LoadLootTemplates_Prospecting()
1191 LootTemplates_Prospecting
.LoadAndCollectLootIds(ids_set
);
1193 // remove real entries and check existence loot
1194 for(uint32 i
= 1; i
< sItemStorage
.MaxEntry
; ++i
)
1196 ItemPrototype
const* proto
= sItemStorage
.LookupEntry
<ItemPrototype
>(i
);
1200 if((proto
->BagFamily
& BAG_FAMILY_MASK_MINING_SUPP
)==0)
1203 if(ids_set
.count(proto
->ItemId
))
1204 ids_set
.erase(proto
->ItemId
);
1207 // output error for any still listed (not referenced from appropriate table) ids
1208 LootTemplates_Prospecting
.ReportUnusedIds(ids_set
);
1211 void LoadLootTemplates_QuestMail()
1214 LootTemplates_QuestMail
.LoadAndCollectLootIds(ids_set
);
1216 // remove real entries and check existence loot
1217 ObjectMgr::QuestMap
const& questMap
= objmgr
.GetQuestTemplates();
1218 for(ObjectMgr::QuestMap::const_iterator itr
= questMap
.begin(); itr
!= questMap
.end(); ++itr
)
1220 if(!itr
->second
->GetRewMailTemplateId())
1223 if(ids_set
.count(itr
->first
))
1224 ids_set
.erase(itr
->first
);
1225 /* disabled reporting: some quest mails not include items
1227 LootTemplates_QuestMail.ReportNotExistedId(itr->first);
1231 // output error for any still listed (not referenced from appropriate table) ids
1232 LootTemplates_QuestMail
.ReportUnusedIds(ids_set
);
1235 void LoadLootTemplates_Skinning()
1237 LootIdSet ids_set
, ids_setUsed
;
1238 LootTemplates_Skinning
.LoadAndCollectLootIds(ids_set
);
1240 // remove real entries and check existence loot
1241 for(uint32 i
= 1; i
< sCreatureStorage
.MaxEntry
; ++i
)
1243 if(CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(i
))
1245 if(uint32 lootid
= cInfo
->SkinLootId
)
1247 if(!ids_set
.count(lootid
))
1248 LootTemplates_Skinning
.ReportNotExistedId(lootid
);
1250 ids_setUsed
.insert(lootid
);
1254 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1255 ids_set
.erase(*itr
);
1257 // output error for any still listed (not referenced from appropriate table) ids
1258 LootTemplates_Skinning
.ReportUnusedIds(ids_set
);
1261 void LoadLootTemplates_Reference()
1264 LootTemplates_Reference
.LoadAndCollectLootIds(ids_set
);
1266 // check references and remove used
1267 LootTemplates_Creature
.CheckLootRefs(&ids_set
);
1268 LootTemplates_Fishing
.CheckLootRefs(&ids_set
);
1269 LootTemplates_Gameobject
.CheckLootRefs(&ids_set
);
1270 LootTemplates_Item
.CheckLootRefs(&ids_set
);
1271 LootTemplates_Milling
.CheckLootRefs(&ids_set
);
1272 LootTemplates_Pickpocketing
.CheckLootRefs(&ids_set
);
1273 LootTemplates_Skinning
.CheckLootRefs(&ids_set
);
1274 LootTemplates_Disenchant
.CheckLootRefs(&ids_set
);
1275 LootTemplates_Prospecting
.CheckLootRefs(&ids_set
);
1276 LootTemplates_QuestMail
.CheckLootRefs(&ids_set
);
1277 LootTemplates_Reference
.CheckLootRefs(&ids_set
);
1279 // output error for any still listed ids (not referenced from any loot table)
1280 LootTemplates_Reference
.ReportUnusedIds(ids_set
);