2 * Copyright (C) 2005-2008 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");
38 LootStore
LootTemplates_Disenchant( "disenchant_loot_template", "item disenchant id");
39 LootStore
LootTemplates_Fishing( "fishing_loot_template", "area id");
40 LootStore
LootTemplates_Gameobject( "gameobject_loot_template", "gameobject entry");
41 LootStore
LootTemplates_Item( "item_loot_template", "item entry");
42 LootStore
LootTemplates_Pickpocketing("pickpocketing_loot_template","creature pickpocket lootid");
43 LootStore
LootTemplates_Prospecting( "prospecting_loot_template", "item entry");
44 LootStore
LootTemplates_QuestMail( "quest_mail_loot_template", "quest id");
45 LootStore
LootTemplates_Reference( "reference_loot_template", "reference id");
46 LootStore
LootTemplates_Skinning( "skinning_loot_template", "creature skinning id");
48 class LootTemplate::LootGroup
// A set of loot definitions for items (refs are not allowed)
51 void AddEntry(LootStoreItem
& item
); // Adds an entry to the group (at loading stage)
52 bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
53 bool HasQuestDropForPlayer(Player
const * player
) const;
54 // The same for active quests of the player
55 void Process(Loot
& loot
) const; // Rolls an item from the group (if any) and adds the item to the loot
56 float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
57 float TotalChance() const; // Overall chance for the group
59 void Verify(LootStore
const& lootstore
, uint32 id
, uint32 group_id
) const;
60 void CollectLootIds(LootIdSet
& set
) const;
61 void CheckLootRefs(LootIdSet
* ref_set
) const;
63 LootStoreItemList ExplicitlyChanced
; // Entries with chances defined in DB
64 LootStoreItemList EqualChanced
; // Zero chances - every entry takes the same chance
66 LootStoreItem
const * Roll() const; // Rolls an item from the group, returns NULL if all miss their chances
69 //Remove all data and free all memory
70 void LootStore::Clear()
72 for (LootTemplateMap::const_iterator itr
=m_LootTemplates
.begin(); itr
!= m_LootTemplates
.end(); ++itr
)
74 m_LootTemplates
.clear();
77 // Checks validity of the loot store
78 // Actual checks are done within LootTemplate::Verify() which is called for every template
79 void LootStore::Verify() const
81 for (LootTemplateMap::const_iterator i
= m_LootTemplates
.begin(); i
!= m_LootTemplates
.end(); ++i
)
82 i
->second
->Verify(*this, i
->first
);
85 // Loads a *_loot_template DB table into loot store
86 // All checks of the loaded template are called from here, no error reports at loot generation required
87 void LootStore::LoadLootTable()
89 LootTemplateMap::iterator tab
;
92 // Clearing store (for reloading case)
95 sLog
.outString( "%s :", GetName());
98 QueryResult
*result
= WorldDatabase
.PQuery("SELECT entry, item, ChanceOrQuestChance, groupid, mincountOrRef, maxcount, lootcondition, condition_value1, condition_value2 FROM %s",GetName());
102 barGoLink
bar(result
->GetRowCount());
106 Field
*fields
= result
->Fetch();
109 uint32 entry
= fields
[0].GetUInt32();
110 uint32 item
= fields
[1].GetUInt32();
111 float chanceOrQuestChance
= fields
[2].GetFloat();
112 uint8 group
= fields
[3].GetUInt8();
113 int32 mincountOrRef
= fields
[4].GetInt32();
114 uint8 maxcount
= fields
[5].GetUInt8();
115 ConditionType condition
= (ConditionType
)fields
[6].GetUInt8();
116 uint32 cond_value1
= fields
[7].GetUInt32();
117 uint32 cond_value2
= fields
[8].GetUInt32();
119 if(!PlayerCondition::IsValid(condition
,cond_value1
, cond_value2
))
121 sLog
.outErrorDb("... in table '%s' entry %u item %u", GetName(), entry
, item
);
122 continue; // error already printed to log/console.
125 // (condition + cond_value1/2) are converted into single conditionId
126 uint16 conditionId
= objmgr
.GetConditionId(condition
, cond_value1
, cond_value2
);
128 LootStoreItem storeitem
= LootStoreItem(item
, chanceOrQuestChance
, group
, conditionId
, mincountOrRef
, maxcount
);
130 if (!storeitem
.IsValid(*this,entry
)) // Validity checks
133 // Looking for the template of the entry
134 // often entries are put together
135 if (m_LootTemplates
.empty() || tab
->first
!= entry
)
137 // Searching the template (in case template Id changed)
138 tab
= m_LootTemplates
.find(entry
);
139 if ( tab
== m_LootTemplates
.end() )
141 std::pair
< LootTemplateMap::iterator
, bool > pr
= m_LootTemplates
.insert(LootTemplateMap::value_type(entry
, new LootTemplate
));
145 // else is empty - template Id and iter are the same
146 // finally iter refers to already existed or just created <entry, LootTemplate>
148 // Adds current row to the template
149 tab
->second
->AddEntry(storeitem
);
152 } while (result
->NextRow());
156 Verify(); // Checks validity of the loot store
159 sLog
.outString( ">> Loaded %u loot definitions (%d templates)", count
, m_LootTemplates
.size());
164 sLog
.outErrorDb( ">> Loaded 0 loot definitions. DB table `%s` is empty.",GetName() );
168 bool LootStore::HaveQuestLootFor(uint32 loot_id
) const
170 LootTemplateMap::const_iterator itr
= m_LootTemplates
.find(loot_id
);
171 if(itr
== m_LootTemplates
.end())
174 // scan loot for quest items
175 return itr
->second
->HasQuestDrop(m_LootTemplates
);
178 bool LootStore::HaveQuestLootForPlayer(uint32 loot_id
,Player
* player
) const
180 LootTemplateMap::const_iterator tab
= m_LootTemplates
.find(loot_id
);
181 if (tab
!= m_LootTemplates
.end())
182 if (tab
->second
->HasQuestDropForPlayer(m_LootTemplates
, player
))
188 LootTemplate
const* LootStore::GetLootFor(uint32 loot_id
) const
190 LootTemplateMap::const_iterator tab
= m_LootTemplates
.find(loot_id
);
192 if (tab
== m_LootTemplates
.end())
198 void LootStore::LoadAndCollectLootIds(LootIdSet
& ids_set
)
202 for(LootTemplateMap::const_iterator tab
= m_LootTemplates
.begin(); tab
!= m_LootTemplates
.end(); ++tab
)
203 ids_set
.insert(tab
->first
);
206 void LootStore::CheckLootRefs(LootIdSet
* ref_set
) const
208 for(LootTemplateMap::const_iterator ltItr
= m_LootTemplates
.begin(); ltItr
!= m_LootTemplates
.end(); ++ltItr
)
209 ltItr
->second
->CheckLootRefs(ref_set
);
212 void LootStore::ReportUnusedIds(LootIdSet
const& ids_set
) const
214 // all still listed ids isn't referenced
215 for(LootIdSet::const_iterator itr
= ids_set
.begin(); itr
!= ids_set
.end(); ++itr
)
216 sLog
.outErrorDb("Table '%s' entry %d isn't %s and not referenced from loot, and then useless.", GetName(), *itr
,GetEntryName());
219 void LootStore::ReportNotExistedId(uint32 id
) const
221 sLog
.outErrorDb("Table '%s' entry %d (%s) not exist but used as loot id in DB.", GetName(), id
,GetEntryName());
225 // --------- LootStoreItem ---------
228 // Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
229 // RATE_DROP_ITEMS is no longer used for all types of entries
230 bool LootStoreItem::Roll() const
235 if(mincountOrRef
< 0) // reference case
236 return roll_chance_f(chance
*sWorld
.getRate(RATE_DROP_ITEM_REFERENCED
));
238 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype(itemid
);
240 float qualityModifier
= pProto
? sWorld
.getRate(qualityToRate
[pProto
->Quality
]) : 1.0f
;
242 return roll_chance_f(chance
*qualityModifier
);
245 // Checks correctness of values
246 bool LootStoreItem::IsValid(LootStore
const& store
, uint32 entry
) const
248 if (mincountOrRef
== 0)
250 sLog
.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store
.GetName(), entry
, itemid
, mincountOrRef
);
254 if( mincountOrRef
> 0 ) // item (quest or non-quest) entry, maybe grouped
256 ItemPrototype
const *proto
= objmgr
.GetItemPrototype(itemid
);
259 sLog
.outErrorDb("Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store
.GetName(), entry
, itemid
);
263 if( chance
== 0 && group
== 0) // Zero chance is allowed for grouped entries only
265 sLog
.outErrorDb("Table '%s' entry %d item %d: equal-chanced grouped entry, but group not defined - skipped", store
.GetName(), entry
, itemid
);
269 if( chance
!= 0 && chance
< 0.000001f
) // loot with low chance
271 sLog
.outErrorDb("Table '%s' entry %d item %d: low chance (%f) - skipped",
272 store
.GetName(), entry
, itemid
, chance
);
276 else // mincountOrRef < 0
279 sLog
.outErrorDb("Table '%s' entry %d item %d: quest chance will be treated as non-quest chance", store
.GetName(), entry
, itemid
);
280 else if( chance
== 0 ) // no chance for the reference
282 sLog
.outErrorDb("Table '%s' entry %d item %d: zero chance is specified for a reference, skipped", store
.GetName(), entry
, itemid
);
286 return true; // Referenced template existence is checked at whole store level
290 // --------- LootItem ---------
293 // Constructor, copies most fields from LootStoreItem and generates random count
294 LootItem::LootItem(LootStoreItem
const& li
)
297 conditionId
= li
.conditionId
;
299 ItemPrototype
const* proto
= objmgr
.GetItemPrototype(itemid
);
300 freeforall
= proto
&& (proto
->Flags
& ITEM_FLAGS_PARTY_LOOT
);
302 needs_quest
= li
.needs_quest
;
304 count
= urand(li
.mincountOrRef
, li
.maxcount
); // constructor called for mincountOrRef > 0 only
305 randomSuffix
= GenerateEnchSuffixFactor(itemid
);
306 randomPropertyId
= Item::GenerateItemRandomPropertyId(itemid
);
309 is_underthreshold
= 0;
313 // Basic checks for player/item compatibility - if false no chance to see the item in the loot
314 bool LootItem::AllowedForPlayer(Player
const * player
) const
316 // DB conditions check
317 if ( !objmgr
.IsPlayerMeetToCondition(player
,conditionId
) )
322 // Checking quests for quest-only drop (check only quests requirements in this case)
323 if( !player
->HasQuestForItem(itemid
) )
328 // Not quest only drop (check quest starting items for already accepted non-repeatable quests)
329 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype(itemid
);
330 if (pProto
&& pProto
->StartQuest
&& player
->GetQuestStatus(pProto
->StartQuest
) != QUEST_STATUS_NONE
&& !player
->HasQuestForItem(itemid
))
338 // --------- Loot ---------
341 // Inserts the item into the loot (called by LootTemplate processors)
342 void Loot::AddItem(LootStoreItem
const & item
)
344 if (item
.needs_quest
) // Quest drop
346 if (quest_items
.size() < MAX_NR_QUEST_ITEMS
)
347 quest_items
.push_back(LootItem(item
));
349 else if (items
.size() < MAX_NR_LOOT_ITEMS
) // Non-quest drop
351 items
.push_back(LootItem(item
));
353 // non-conditional one-player only items are counted here,
354 // free for all items are counted in FillFFALoot(),
355 // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
356 if( !item
.conditionId
)
358 ItemPrototype
const* proto
= objmgr
.GetItemPrototype(item
.itemid
);
359 if( !proto
|| (proto
->Flags
& ITEM_FLAGS_PARTY_LOOT
)==0 )
365 // Calls processor of corresponding LootTemplate (which handles everything including references)
366 void Loot::FillLoot(uint32 loot_id
, LootStore
const& store
, Player
* loot_owner
)
368 LootTemplate
const* tab
= store
.GetLootFor(loot_id
);
372 sLog
.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.",store
.GetName(),loot_id
);
376 items
.reserve(MAX_NR_LOOT_ITEMS
);
377 quest_items
.reserve(MAX_NR_QUEST_ITEMS
);
379 tab
->Process(*this, store
); // Processing is done there, callback via Loot::AddItem()
381 // Setting access rights fow group-looting case
384 Group
* pGroup
=loot_owner
->GetGroup();
387 for(GroupReference
*itr
= pGroup
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
389 //fill the quest item map for every player in the recipient's group
390 Player
* pl
= itr
->getSource();
393 uint32 plguid
= pl
->GetGUIDLow();
394 QuestItemMap::iterator qmapitr
= PlayerQuestItems
.find(plguid
);
395 if (qmapitr
== PlayerQuestItems
.end())
399 qmapitr
= PlayerFFAItems
.find(plguid
);
400 if (qmapitr
== PlayerFFAItems
.end())
404 qmapitr
= PlayerNonQuestNonFFAConditionalItems
.find(plguid
);
405 if (qmapitr
== PlayerNonQuestNonFFAConditionalItems
.end())
407 FillNonQuestNonFFAConditionalLoot(pl
);
412 QuestItemList
* Loot::FillFFALoot(Player
* player
)
414 QuestItemList
*ql
= new QuestItemList();
416 for(uint8 i
= 0; i
< items
.size(); i
++)
418 LootItem
&item
= items
[i
];
419 if(!item
.is_looted
&& item
.freeforall
&& item
.AllowedForPlayer(player
) )
421 ql
->push_back(QuestItem(i
));
431 PlayerFFAItems
[player
->GetGUIDLow()] = ql
;
435 QuestItemList
* Loot::FillQuestLoot(Player
* player
)
437 if (items
.size() == MAX_NR_LOOT_ITEMS
) return NULL
;
438 QuestItemList
*ql
= new QuestItemList();
440 for(uint8 i
= 0; i
< quest_items
.size(); i
++)
442 LootItem
&item
= quest_items
[i
];
443 if(!item
.is_looted
&& item
.AllowedForPlayer(player
) )
445 ql
->push_back(QuestItem(i
));
447 // questitems get blocked when they first apper in a
448 // player's quest vector
450 // increase once if one looter only, looter-times if free for all
451 if (item
.freeforall
|| !item
.is_blocked
)
454 item
.is_blocked
= true;
456 if (items
.size() + ql
->size() == MAX_NR_LOOT_ITEMS
)
466 PlayerQuestItems
[player
->GetGUIDLow()] = ql
;
470 QuestItemList
* Loot::FillNonQuestNonFFAConditionalLoot(Player
* player
)
472 QuestItemList
*ql
= new QuestItemList();
474 for(uint8 i
= 0; i
< items
.size(); ++i
)
476 LootItem
&item
= items
[i
];
477 if(!item
.is_looted
&& !item
.freeforall
&& item
.conditionId
&& item
.AllowedForPlayer(player
))
479 ql
->push_back(QuestItem(i
));
483 item
.is_counted
=true;
493 PlayerNonQuestNonFFAConditionalItems
[player
->GetGUIDLow()] = ql
;
497 //===================================================
499 void Loot::NotifyItemRemoved(uint8 lootIndex
)
501 // notify all players that are looting this that the item was removed
502 // convert the index to the slot the player sees
503 std::set
<uint64
>::iterator i_next
;
504 for(std::set
<uint64
>::iterator i
= PlayersLooting
.begin(); i
!= PlayersLooting
.end(); i
= i_next
)
508 if(Player
* pl
= ObjectAccessor::FindPlayer(*i
))
509 pl
->SendNotifyLootItemRemoved(lootIndex
);
511 PlayersLooting
.erase(i
);
515 void Loot::NotifyMoneyRemoved()
517 // notify all players that are looting this that the money was removed
518 std::set
<uint64
>::iterator i_next
;
519 for(std::set
<uint64
>::iterator i
= PlayersLooting
.begin(); i
!= PlayersLooting
.end(); i
= i_next
)
523 if(Player
* pl
= ObjectAccessor::FindPlayer(*i
))
524 pl
->SendNotifyLootMoneyRemoved();
526 PlayersLooting
.erase(i
);
530 void Loot::NotifyQuestItemRemoved(uint8 questIndex
)
532 // when a free for all questitem is looted
533 // all players will get notified of it being removed
534 // (other questitems can be looted by each group member)
535 // bit inefficient but isnt called often
537 std::set
<uint64
>::iterator i_next
;
538 for(std::set
<uint64
>::iterator i
= PlayersLooting
.begin(); i
!= PlayersLooting
.end(); i
= i_next
)
542 if(Player
* pl
= ObjectAccessor::FindPlayer(*i
))
544 QuestItemMap::iterator pq
= PlayerQuestItems
.find(pl
->GetGUIDLow());
545 if (pq
!= PlayerQuestItems
.end() && pq
->second
)
547 // find where/if the player has the given item in it's vector
548 QuestItemList
& pql
= *pq
->second
;
551 for (j
= 0; j
< pql
.size(); ++j
)
552 if (pql
[j
].index
== questIndex
)
556 pl
->SendNotifyLootItemRemoved(items
.size()+j
);
560 PlayersLooting
.erase(i
);
564 void Loot::generateMoneyLoot( uint32 minAmount
, uint32 maxAmount
)
568 if (maxAmount
<= minAmount
)
569 gold
= uint32(maxAmount
* sWorld
.getRate(RATE_DROP_MONEY
));
570 else if ((maxAmount
- minAmount
) < 32700)
571 gold
= uint32(urand(minAmount
, maxAmount
) * sWorld
.getRate(RATE_DROP_MONEY
));
573 gold
= uint32(urand(minAmount
>> 8, maxAmount
>> 8) * sWorld
.getRate(RATE_DROP_MONEY
)) << 8;
577 LootItem
* Loot::LootItemInSlot(uint32 lootSlot
, Player
* player
, QuestItem
**qitem
, QuestItem
**ffaitem
, QuestItem
**conditem
)
579 LootItem
* item
= NULL
;
580 bool is_looted
= true;
581 if (lootSlot
>= items
.size())
583 uint32 questSlot
= lootSlot
- items
.size();
584 QuestItemMap::const_iterator itr
= PlayerQuestItems
.find(player
->GetGUIDLow());
585 if (itr
!= PlayerQuestItems
.end() && questSlot
< itr
->second
->size())
587 QuestItem
*qitem2
= &itr
->second
->at(questSlot
);
590 item
= &quest_items
[qitem2
->index
];
591 is_looted
= qitem2
->is_looted
;
596 item
= &items
[lootSlot
];
597 is_looted
= item
->is_looted
;
600 QuestItemMap::const_iterator itr
= PlayerFFAItems
.find(player
->GetGUIDLow());
601 if (itr
!= PlayerFFAItems
.end())
603 for(QuestItemList::iterator iter
=itr
->second
->begin(); iter
!= itr
->second
->end(); ++iter
)
604 if(iter
->index
==lootSlot
)
606 QuestItem
*ffaitem2
= (QuestItem
*)&(*iter
);
609 is_looted
= ffaitem2
->is_looted
;
614 else if(item
->conditionId
)
616 QuestItemMap::const_iterator itr
= PlayerNonQuestNonFFAConditionalItems
.find(player
->GetGUIDLow());
617 if (itr
!= PlayerNonQuestNonFFAConditionalItems
.end())
619 for(QuestItemList::iterator iter
=itr
->second
->begin(); iter
!= itr
->second
->end(); ++iter
)
621 if(iter
->index
==lootSlot
)
623 QuestItem
*conditem2
= (QuestItem
*)&(*iter
);
625 *conditem
= conditem2
;
626 is_looted
= conditem2
->is_looted
;
640 ByteBuffer
& operator<<(ByteBuffer
& b
, LootItem
const& li
)
642 b
<< uint32(li
.itemid
);
643 b
<< uint32(li
.count
); // nr of items of this type
644 b
<< uint32(objmgr
.GetItemPrototype(li
.itemid
)->DisplayInfoID
);
645 b
<< uint32(li
.randomSuffix
);
646 b
<< uint32(li
.randomPropertyId
);
647 //b << uint8(0); // slot type - will send after this function call
651 ByteBuffer
& operator<<(ByteBuffer
& b
, LootView
const& lv
)
655 uint8 itemsShown
= 0;
658 b
<< uint32(lv
.permission
!=NONE_PERMISSION
? l
.gold
: 0);
660 size_t count_pos
= b
.wpos(); // pos of item count byte
661 b
<< uint8(0); // item count placeholder
663 switch (lv
.permission
)
665 case GROUP_PERMISSION
:
667 // You are not the items proprietary, so you can only see
668 // blocked rolled items and quest items, and !ffa items
669 for (uint8 i
= 0; i
< l
.items
.size(); ++i
)
671 if (!l
.items
[i
].is_looted
&& !l
.items
[i
].freeforall
&& !l
.items
[i
].conditionId
&& l
.items
[i
].AllowedForPlayer(lv
.viewer
))
673 uint8 slot_type
= (l
.items
[i
].is_blocked
|| l
.items
[i
].is_underthreshold
) ? 0 : 1;
675 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
676 b
<< uint8(slot_type
); // 0 - get 1 - look only
683 case MASTER_PERMISSION
:
685 uint8 slot_type
= (lv
.permission
==MASTER_PERMISSION
) ? 2 : 0;
686 for (uint8 i
= 0; i
< l
.items
.size(); ++i
)
688 if (!l
.items
[i
].is_looted
&& !l
.items
[i
].freeforall
&& !l
.items
[i
].conditionId
&& l
.items
[i
].AllowedForPlayer(lv
.viewer
))
690 b
<< uint8(i
) << l
.items
[i
]; //only send one-player loot items now, free for all will be sent later
691 b
<< uint8(slot_type
); // 0 - get 2 - master selection
697 case NONE_PERMISSION
:
699 return b
; // nothing output more
704 for (QuestItemList::iterator qi
= lv
.qlist
->begin() ; qi
!= lv
.qlist
->end(); ++qi
)
706 LootItem
&item
= l
.quest_items
[qi
->index
];
707 if (!qi
->is_looted
&& !item
.is_looted
)
709 b
<< uint8(l
.items
.size() + (qi
- lv
.qlist
->begin()));
711 b
<< uint8(0); // allow loot
719 for (QuestItemList::iterator fi
= lv
.ffalist
->begin() ; fi
!= lv
.ffalist
->end(); ++fi
)
721 LootItem
&item
= l
.items
[fi
->index
];
722 if (!fi
->is_looted
&& !item
.is_looted
)
724 b
<< uint8(fi
->index
) << item
;
725 b
<< uint8(0); // allow loot
731 if (lv
.conditionallist
)
733 for (QuestItemList::iterator ci
= lv
.conditionallist
->begin() ; ci
!= lv
.conditionallist
->end(); ++ci
)
735 LootItem
&item
= l
.items
[ci
->index
];
736 if (!ci
->is_looted
&& !item
.is_looted
)
738 b
<< uint8(ci
->index
) << item
;
739 b
<< uint8(0); // allow loot
745 //update number of items shown
746 b
.put
<uint8
>(count_pos
,itemsShown
);
752 // --------- LootTemplate::LootGroup ---------
755 // Adds an entry to the group (at loading stage)
756 void LootTemplate::LootGroup::AddEntry(LootStoreItem
& item
)
758 if (item
.chance
!= 0)
759 ExplicitlyChanced
.push_back(item
);
761 EqualChanced
.push_back(item
);
764 // Rolls an item from the group, returns NULL if all miss their chances
765 LootStoreItem
const * LootTemplate::LootGroup::Roll() const
767 if (!ExplicitlyChanced
.empty()) // First explicitly chanced entries are checked
769 float Roll
= rand_chance();
771 for (uint32 i
=0; i
<ExplicitlyChanced
.size(); ++i
) //check each explicitly chanced entry in the template and modify its chance based on quality.
773 if(ExplicitlyChanced
[i
].chance
>=100.f
)
774 return &ExplicitlyChanced
[i
];
776 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype(ExplicitlyChanced
[i
].itemid
);
777 float qualityMultiplier
= pProto
? sWorld
.getRate(qualityToRate
[pProto
->Quality
]) : 1.0f
;
778 Roll
-= ExplicitlyChanced
[i
].chance
* qualityMultiplier
;
780 return &ExplicitlyChanced
[i
];
783 if (!EqualChanced
.empty()) // If nothing selected yet - an item is taken from equal-chanced part
784 return &EqualChanced
[irand(0, EqualChanced
.size()-1)];
786 return NULL
; // Empty drop from the group
789 // True if group includes at least 1 quest drop entry
790 bool LootTemplate::LootGroup::HasQuestDrop() const
792 for (LootStoreItemList::const_iterator i
=ExplicitlyChanced
.begin(); i
!= ExplicitlyChanced
.end(); ++i
)
795 for (LootStoreItemList::const_iterator i
=EqualChanced
.begin(); i
!= EqualChanced
.end(); ++i
)
801 // True if group includes at least 1 quest drop entry for active quests of the player
802 bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player
const * player
) const
804 for (LootStoreItemList::const_iterator i
=ExplicitlyChanced
.begin(); i
!= ExplicitlyChanced
.end(); ++i
)
805 if (player
->HasQuestForItem(i
->itemid
))
807 for (LootStoreItemList::const_iterator i
=EqualChanced
.begin(); i
!= EqualChanced
.end(); ++i
)
808 if (player
->HasQuestForItem(i
->itemid
))
813 // Rolls an item from the group (if any takes its chance) and adds the item to the loot
814 void LootTemplate::LootGroup::Process(Loot
& loot
) const
816 LootStoreItem
const * item
= Roll();
821 // Overall chance for the group without equal chanced items
822 float LootTemplate::LootGroup::RawTotalChance() const
826 for (LootStoreItemList::const_iterator i
=ExplicitlyChanced
.begin(); i
!= ExplicitlyChanced
.end(); ++i
)
827 if ( !i
->needs_quest
)
833 // Overall chance for the group
834 float LootTemplate::LootGroup::TotalChance() const
836 float result
= RawTotalChance();
838 if (!EqualChanced
.empty() && result
< 100.0f
)
844 void LootTemplate::LootGroup::Verify(LootStore
const& lootstore
, uint32 id
, uint32 group_id
) const
846 float chance
= RawTotalChance();
847 if (chance
> 101.0f
) // TODO: replace with 100% when DBs will be ready
849 sLog
.outErrorDb("Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore
.GetName(), id
, group_id
, chance
);
852 if(chance
>= 100.0f
&& !EqualChanced
.empty())
854 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
);
858 void LootTemplate::LootGroup::CheckLootRefs(LootIdSet
* ref_set
) const
860 for (LootStoreItemList::const_iterator ieItr
=ExplicitlyChanced
.begin(); ieItr
!= ExplicitlyChanced
.end(); ++ieItr
)
862 if(ieItr
->mincountOrRef
< 0)
864 if(!LootTemplates_Reference
.GetLootFor(-ieItr
->mincountOrRef
))
865 LootTemplates_Reference
.ReportNotExistedId(-ieItr
->mincountOrRef
);
867 ref_set
->erase(-ieItr
->mincountOrRef
);
871 for (LootStoreItemList::const_iterator ieItr
=EqualChanced
.begin(); ieItr
!= EqualChanced
.end(); ++ieItr
)
873 if(ieItr
->mincountOrRef
< 0)
875 if(!LootTemplates_Reference
.GetLootFor(-ieItr
->mincountOrRef
))
876 LootTemplates_Reference
.ReportNotExistedId(-ieItr
->mincountOrRef
);
878 ref_set
->erase(-ieItr
->mincountOrRef
);
884 // --------- LootTemplate ---------
887 // Adds an entry to the group (at loading stage)
888 void LootTemplate::AddEntry(LootStoreItem
& item
)
890 if (item
.group
> 0 && item
.mincountOrRef
> 0) // Group
892 if (item
.group
>= Groups
.size())
893 Groups
.resize(item
.group
); // Adds new group the the loot template if needed
894 Groups
[item
.group
-1].AddEntry(item
); // Adds new entry to the group
896 else // Non-grouped entries and references are stored together
897 Entries
.push_back(item
);
900 // Rolls for every item in the template and adds the rolled items the the loot
901 void LootTemplate::Process(Loot
& loot
, LootStore
const& store
, uint8 groupId
) const
903 if (groupId
) // Group reference uses own processing of the group
905 if (groupId
> Groups
.size())
906 return; // Error message already printed at loading stage
908 Groups
[groupId
-1].Process(loot
);
912 // Rolling non-grouped items
913 for (LootStoreItemList::const_iterator i
= Entries
.begin() ; i
!= Entries
.end() ; ++i
)
916 continue; // Bad luck for the entry
918 if (i
->mincountOrRef
< 0) // References processing
920 LootTemplate
const* Referenced
= LootTemplates_Reference
.GetLootFor(-i
->mincountOrRef
);
923 continue; // Error message already printed at loading stage
925 for (uint32 loop
=0; loop
< i
->maxcount
; ++loop
)// Ref multiplicator
926 Referenced
->Process(loot
, store
, i
->group
); // Ref processing
928 else // Plain entries (not a reference, not grouped)
929 loot
.AddItem(*i
); // Chance is already checked, just add
932 // Now processing groups
933 for (LootGroups::const_iterator i
= Groups
.begin( ) ; i
!= Groups
.end( ) ; ++i
)
937 // True if template includes at least 1 quest drop entry
938 bool LootTemplate::HasQuestDrop(LootTemplateMap
const& store
, uint8 groupId
) const
940 if (groupId
) // Group reference
942 if (groupId
> Groups
.size())
943 return false; // Error message [should be] already printed at loading stage
944 return Groups
[groupId
-1].HasQuestDrop();
947 for (LootStoreItemList::const_iterator i
= Entries
.begin(); i
!= Entries
.end(); ++i
)
949 if (i
->mincountOrRef
< 0) // References
951 LootTemplateMap::const_iterator Referenced
= store
.find(-i
->mincountOrRef
);
952 if( Referenced
==store
.end() )
953 continue; // Error message [should be] already printed at loading stage
954 if (Referenced
->second
->HasQuestDrop(store
, i
->group
) )
957 else if ( i
->needs_quest
)
958 return true; // quest drop found
961 // Now processing groups
962 for (LootGroups::const_iterator i
= Groups
.begin() ; i
!= Groups
.end() ; ++i
)
963 if (i
->HasQuestDrop())
969 // True if template includes at least 1 quest drop for an active quest of the player
970 bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap
const& store
, Player
const* player
, uint8 groupId
) const
972 if (groupId
) // Group reference
974 if (groupId
> Groups
.size())
975 return false; // Error message already printed at loading stage
976 return Groups
[groupId
-1].HasQuestDropForPlayer(player
);
979 // Checking non-grouped entries
980 for (LootStoreItemList::const_iterator i
= Entries
.begin() ; i
!= Entries
.end() ; ++i
)
982 if (i
->mincountOrRef
< 0) // References processing
984 LootTemplateMap::const_iterator Referenced
= store
.find(-i
->mincountOrRef
);
985 if (Referenced
== store
.end() )
986 continue; // Error message already printed at loading stage
987 if (Referenced
->second
->HasQuestDropForPlayer(store
, player
, i
->group
) )
990 else if ( player
->HasQuestForItem(i
->itemid
) )
991 return true; // active quest drop found
994 // Now checking groups
995 for (LootGroups::const_iterator i
= Groups
.begin(); i
!= Groups
.end(); ++i
)
996 if (i
->HasQuestDrop())
1002 // Checks integrity of the template
1003 void LootTemplate::Verify(LootStore
const& lootstore
, uint32 id
) const
1005 // Checking group chances
1006 for (uint32 i
=0; i
< Groups
.size(); ++i
)
1007 Groups
[i
].Verify(lootstore
,id
,i
+1);
1009 // TODO: References validity checks
1012 void LootTemplate::CheckLootRefs(LootIdSet
* ref_set
) const
1014 for(LootStoreItemList::const_iterator ieItr
= Entries
.begin(); ieItr
!= Entries
.end(); ++ieItr
)
1016 if(ieItr
->mincountOrRef
< 0)
1018 if(!LootTemplates_Reference
.GetLootFor(-ieItr
->mincountOrRef
))
1019 LootTemplates_Reference
.ReportNotExistedId(-ieItr
->mincountOrRef
);
1021 ref_set
->erase(-ieItr
->mincountOrRef
);
1025 for(LootGroups::const_iterator grItr
= Groups
.begin(); grItr
!= Groups
.end(); ++grItr
)
1026 grItr
->CheckLootRefs(ref_set
);
1029 void LoadLootTemplates_Creature()
1031 LootIdSet ids_set
, ids_setUsed
;
1032 LootTemplates_Creature
.LoadAndCollectLootIds(ids_set
);
1034 // remove real entries and check existence loot
1035 for(uint32 i
= 1; i
< sCreatureStorage
.MaxEntry
; ++i
)
1037 if(CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(i
))
1039 if(uint32 lootid
= cInfo
->lootid
)
1041 if(!ids_set
.count(lootid
))
1042 LootTemplates_Creature
.ReportNotExistedId(lootid
);
1044 ids_setUsed
.insert(lootid
);
1048 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1049 ids_set
.erase(*itr
);
1051 // output error for any still listed (not referenced from appropriate table) ids
1052 LootTemplates_Creature
.ReportUnusedIds(ids_set
);
1055 void LoadLootTemplates_Disenchant()
1057 LootIdSet ids_set
, ids_setUsed
;
1058 LootTemplates_Disenchant
.LoadAndCollectLootIds(ids_set
);
1060 // remove real entries and check existence loot
1061 for(uint32 i
= 1; i
< sItemStorage
.MaxEntry
; ++i
)
1063 if(ItemPrototype
const* proto
= sItemStorage
.LookupEntry
<ItemPrototype
>(i
))
1065 if(uint32 lootid
= proto
->DisenchantID
)
1067 if(!ids_set
.count(lootid
))
1068 LootTemplates_Disenchant
.ReportNotExistedId(lootid
);
1070 ids_setUsed
.insert(lootid
);
1074 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1075 ids_set
.erase(*itr
);
1076 // output error for any still listed (not referenced from appropriate table) ids
1077 LootTemplates_Disenchant
.ReportUnusedIds(ids_set
);
1080 void LoadLootTemplates_Fishing()
1083 LootTemplates_Fishing
.LoadAndCollectLootIds(ids_set
);
1085 // remove real entries and check existence loot
1086 for(uint32 i
= 1; i
< sAreaStore
.GetNumRows(); ++i
)
1088 if(AreaTableEntry
const* areaEntry
= sAreaStore
.LookupEntry(i
))
1089 if(ids_set
.count(areaEntry
->ID
))
1090 ids_set
.erase(areaEntry
->ID
);
1093 // output error for any still listed (not referenced from appropriate table) ids
1094 LootTemplates_Fishing
.ReportUnusedIds(ids_set
);
1097 void LoadLootTemplates_Gameobject()
1099 LootIdSet ids_set
, ids_setUsed
;
1100 LootTemplates_Gameobject
.LoadAndCollectLootIds(ids_set
);
1102 // remove real entries and check existence loot
1103 for(uint32 i
= 1; i
< sGOStorage
.MaxEntry
; ++i
)
1105 if(GameObjectInfo
const* gInfo
= sGOStorage
.LookupEntry
<GameObjectInfo
>(i
))
1107 if(uint32 lootid
= GameObject::GetLootId(gInfo
))
1109 if(!ids_set
.count(lootid
))
1110 LootTemplates_Gameobject
.ReportNotExistedId(lootid
);
1112 ids_setUsed
.insert(lootid
);
1116 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1117 ids_set
.erase(*itr
);
1119 // output error for any still listed (not referenced from appropriate table) ids
1120 LootTemplates_Gameobject
.ReportUnusedIds(ids_set
);
1123 void LoadLootTemplates_Item()
1126 LootTemplates_Item
.LoadAndCollectLootIds(ids_set
);
1128 // remove real entries and check existence loot
1129 for(uint32 i
= 1; i
< sItemStorage
.MaxEntry
; ++i
)
1130 if(ItemPrototype
const* proto
= sItemStorage
.LookupEntry
<ItemPrototype
>(i
))
1131 if(ids_set
.count(proto
->ItemId
))
1132 ids_set
.erase(proto
->ItemId
);
1134 // output error for any still listed (not referenced from appropriate table) ids
1135 LootTemplates_Item
.ReportUnusedIds(ids_set
);
1138 void LoadLootTemplates_Pickpocketing()
1140 LootIdSet ids_set
, ids_setUsed
;
1141 LootTemplates_Pickpocketing
.LoadAndCollectLootIds(ids_set
);
1143 // remove real entries and check existence loot
1144 for(uint32 i
= 1; i
< sCreatureStorage
.MaxEntry
; ++i
)
1146 if(CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(i
))
1148 if(uint32 lootid
= cInfo
->pickpocketLootId
)
1150 if(!ids_set
.count(lootid
))
1151 LootTemplates_Pickpocketing
.ReportNotExistedId(lootid
);
1153 ids_setUsed
.insert(lootid
);
1157 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1158 ids_set
.erase(*itr
);
1160 // output error for any still listed (not referenced from appropriate table) ids
1161 LootTemplates_Pickpocketing
.ReportUnusedIds(ids_set
);
1164 void LoadLootTemplates_Prospecting()
1167 LootTemplates_Prospecting
.LoadAndCollectLootIds(ids_set
);
1169 // remove real entries and check existence loot
1170 for(uint32 i
= 1; i
< sItemStorage
.MaxEntry
; ++i
)
1171 if(ItemPrototype
const* proto
= sItemStorage
.LookupEntry
<ItemPrototype
>(i
))
1172 if(ids_set
.count(proto
->ItemId
))
1173 ids_set
.erase(proto
->ItemId
);
1175 // output error for any still listed (not referenced from appropriate table) ids
1176 LootTemplates_Prospecting
.ReportUnusedIds(ids_set
);
1179 void LoadLootTemplates_QuestMail()
1182 LootTemplates_QuestMail
.LoadAndCollectLootIds(ids_set
);
1184 // remove real entries and check existence loot
1185 ObjectMgr::QuestMap
const& questMap
= objmgr
.GetQuestTemplates();
1186 for(ObjectMgr::QuestMap::const_iterator itr
= questMap
.begin(); itr
!= questMap
.end(); ++itr
)
1187 if(ids_set
.count(itr
->first
))
1188 ids_set
.erase(itr
->first
);
1190 // output error for any still listed (not referenced from appropriate table) ids
1191 LootTemplates_QuestMail
.ReportUnusedIds(ids_set
);
1194 void LoadLootTemplates_Skinning()
1196 LootIdSet ids_set
, ids_setUsed
;
1197 LootTemplates_Skinning
.LoadAndCollectLootIds(ids_set
);
1199 // remove real entries and check existence loot
1200 for(uint32 i
= 1; i
< sCreatureStorage
.MaxEntry
; ++i
)
1202 if(CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(i
))
1204 if(uint32 lootid
= cInfo
->SkinLootId
)
1206 if(!ids_set
.count(lootid
))
1207 LootTemplates_Skinning
.ReportNotExistedId(lootid
);
1209 ids_setUsed
.insert(lootid
);
1213 for(LootIdSet::const_iterator itr
= ids_setUsed
.begin(); itr
!= ids_setUsed
.end(); ++itr
)
1214 ids_set
.erase(*itr
);
1216 // output error for any still listed (not referenced from appropriate table) ids
1217 LootTemplates_Skinning
.ReportUnusedIds(ids_set
);
1220 void LoadLootTemplates_Reference()
1223 LootTemplates_Reference
.LoadAndCollectLootIds(ids_set
);
1225 // check references and remove used
1226 LootTemplates_Creature
.CheckLootRefs(&ids_set
);
1227 LootTemplates_Fishing
.CheckLootRefs(&ids_set
);
1228 LootTemplates_Gameobject
.CheckLootRefs(&ids_set
);
1229 LootTemplates_Item
.CheckLootRefs(&ids_set
);
1230 LootTemplates_Pickpocketing
.CheckLootRefs(&ids_set
);
1231 LootTemplates_Skinning
.CheckLootRefs(&ids_set
);
1232 LootTemplates_Disenchant
.CheckLootRefs(&ids_set
);
1233 LootTemplates_Prospecting
.CheckLootRefs(&ids_set
);
1234 LootTemplates_QuestMail
.CheckLootRefs(&ids_set
);
1235 LootTemplates_Reference
.CheckLootRefs(&ids_set
);
1237 // output error for any still listed ids (not referenced from any loot table)
1238 LootTemplates_Reference
.ReportUnusedIds(ids_set
);