aboutsummaryrefslogtreecommitdiff
path: root/src/game/LootMgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/LootMgr.cpp')
-rw-r--r--src/game/LootMgr.cpp1639
1 files changed, 0 insertions, 1639 deletions
diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp
deleted file mode 100644
index 2137c8872b5..00000000000
--- a/src/game/LootMgr.cpp
+++ /dev/null
@@ -1,1639 +0,0 @@
-/*
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "LootMgr.h"
-#include "Log.h"
-#include "ObjectMgr.h"
-#include "ProgressBar.h"
-#include "World.h"
-#include "Util.h"
-#include "SharedDefines.h"
-#include "SpellMgr.h"
-
-static Rates const qualityToRate[MAX_ITEM_QUALITY] = {
- RATE_DROP_ITEM_POOR, // ITEM_QUALITY_POOR
- RATE_DROP_ITEM_NORMAL, // ITEM_QUALITY_NORMAL
- RATE_DROP_ITEM_UNCOMMON, // ITEM_QUALITY_UNCOMMON
- RATE_DROP_ITEM_RARE, // ITEM_QUALITY_RARE
- RATE_DROP_ITEM_EPIC, // ITEM_QUALITY_EPIC
- RATE_DROP_ITEM_LEGENDARY, // ITEM_QUALITY_LEGENDARY
- RATE_DROP_ITEM_ARTIFACT, // ITEM_QUALITY_ARTIFACT
-};
-
-LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true);
-LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true);
-LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true);
-LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject entry", true);
-LootStore LootTemplates_Item("item_loot_template", "item entry", true);
-LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false);
-LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true);
-LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template","creature pickpocket lootid", true);
-LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true);
-LootStore LootTemplates_Reference("reference_loot_template", "reference id", false);
-LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true);
-LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)",false);
-
-class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed)
-{
- public:
- void AddEntry(LootStoreItem& item); // Adds an entry to the group (at loading stage)
- bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
- bool HasQuestDropForPlayer(Player const * player) const;
- // The same for active quests of the player
- void Process(Loot& loot, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot
- float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
- float TotalChance() const; // Overall chance for the group
-
- void Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const;
- void CollectLootIds(LootIdSet& set) const;
- void CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const;
- LootStoreItemList * GetExplicitlyChancedItemList() { return &ExplicitlyChanced; }
- LootStoreItemList * GetEqualChancedItemList() { return &EqualChanced; }
- void CopyConditions(ConditionList conditions);
- private:
- LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
- LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
-
- LootStoreItem const * Roll() const; // Rolls an item from the group, returns NULL if all miss their chances
-};
-
-//Remove all data and free all memory
-void LootStore::Clear()
-{
- for (LootTemplateMap::const_iterator itr=m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
- delete itr->second;
- m_LootTemplates.clear();
-}
-
-// Checks validity of the loot store
-// Actual checks are done within LootTemplate::Verify() which is called for every template
-void LootStore::Verify() const
-{
- for (LootTemplateMap::const_iterator i = m_LootTemplates.begin(); i != m_LootTemplates.end(); ++i)
- i->second->Verify(*this, i->first);
-}
-
-// Loads a *_loot_template DB table into loot store
-// All checks of the loaded template are called from here, no error reports at loot generation required
-void LootStore::LoadLootTable()
-{
- LootTemplateMap::const_iterator tab;
- uint32 count = 0;
-
- // Clearing store (for reloading case)
- Clear();
-
- sLog.outString("%s :", GetName());
-
- // 0 1 2 3 4 5 6
- QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, lootmode, groupid, mincountOrRef, maxcount FROM %s",GetName());
-
- if (result)
- {
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 entry = fields[0].GetUInt32();
- uint32 item = fields[1].GetUInt32();
- float chanceOrQuestChance = fields[2].GetFloat();
- uint16 lootmode = fields[3].GetUInt16();
- uint8 group = fields[4].GetUInt8();
- int32 mincountOrRef = fields[5].GetInt32();
- int32 maxcount = fields[6].GetInt32();
-
- if (maxcount > std::numeric_limits<uint8>::max())
- {
- sLog.outErrorDb("Table '%s' entry %d item %d: maxcount value (%u) to large. must be less %u - skipped", GetName(), entry, item, maxcount,std::numeric_limits<uint8>::max());
- continue; // error already printed to log/console.
- }
-
- LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount);
-
- if (!storeitem.IsValid(*this,entry)) // Validity checks
- continue;
-
- // Looking for the template of the entry
- // often entries are put together
- if (m_LootTemplates.empty() || tab->first != entry)
- {
- // Searching the template (in case template Id changed)
- tab = m_LootTemplates.find(entry);
- if (tab == m_LootTemplates.end())
- {
- std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate));
- tab = pr.first;
- }
- }
- // else is empty - template Id and iter are the same
- // finally iter refers to already existed or just created <entry, LootTemplate>
-
- // Adds current row to the template
- tab->second->AddEntry(storeitem);
- ++count;
-
- } while (result->NextRow());
-
- Verify(); // Checks validity of the loot store
-
- sLog.outString();
- sLog.outString(">> Loaded %u loot definitions (%lu templates)", count, (unsigned long)m_LootTemplates.size());
- }
- else
- {
- sLog.outString();
- sLog.outErrorDb(">> Loaded 0 loot definitions. DB table `%s` is empty.",GetName());
- }
-}
-
-bool LootStore::HaveQuestLootFor(uint32 loot_id) const
-{
- LootTemplateMap::const_iterator itr = m_LootTemplates.find(loot_id);
- if (itr == m_LootTemplates.end())
- return false;
-
- // scan loot for quest items
- return itr->second->HasQuestDrop(m_LootTemplates);
-}
-
-bool LootStore::HaveQuestLootForPlayer(uint32 loot_id,Player* player) const
-{
- LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
- if (tab != m_LootTemplates.end())
- if (tab->second->HasQuestDropForPlayer(m_LootTemplates, player))
- return true;
-
- return false;
-}
-
-void LootStore::ResetConditions()
-{
- LootTemplateMap m_LootTemplates;
- for (LootTemplateMap::iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
- {
- ConditionList empty;
- (*itr).second->CopyConditions(empty);
- }
-}
-
-LootTemplate const* LootStore::GetLootFor(uint32 loot_id) const
-{
- LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
-
- if (tab == m_LootTemplates.end())
- return NULL;
-
- return tab->second;
-}
-
-LootTemplate* LootStore::GetLootForConditionFill(uint32 loot_id)
-{
- LootTemplateMap::iterator tab = m_LootTemplates.find(loot_id);
-
- if (tab == m_LootTemplates.end())
- return NULL;
-
- return tab->second;
-}
-
-void LootStore::LoadAndCollectLootIds(LootIdSet& ids_set)
-{
- LoadLootTable();
-
- for (LootTemplateMap::const_iterator tab = m_LootTemplates.begin(); tab != m_LootTemplates.end(); ++tab)
- ids_set.insert(tab->first);
-}
-
-void LootStore::CheckLootRefs(LootIdSet* ref_set) const
-{
- for (LootTemplateMap::const_iterator ltItr = m_LootTemplates.begin(); ltItr != m_LootTemplates.end(); ++ltItr)
- ltItr->second->CheckLootRefs(m_LootTemplates,ref_set);
-}
-
-void LootStore::ReportUnusedIds(LootIdSet const& ids_set) const
-{
- // all still listed ids isn't referenced
- for (LootIdSet::const_iterator itr = ids_set.begin(); itr != ids_set.end(); ++itr)
- sLog.outErrorDb("Table '%s' entry %d isn't %s and not referenced from loot, and then useless.", GetName(), *itr,GetEntryName());
-}
-
-void LootStore::ReportNotExistedId(uint32 id) const
-{
- sLog.outErrorDb("Table '%s' entry %d (%s) not exist but used as loot id in DB.", GetName(), id,GetEntryName());
-}
-
-//
-// --------- LootStoreItem ---------
-//
-
-// Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
-// RATE_DROP_ITEMS is no longer used for all types of entries
-bool LootStoreItem::Roll(bool rate) const
-{
- if (chance >= 100.0f)
- return true;
-
- if (mincountOrRef < 0) // reference case
- return roll_chance_f(chance* (rate ? sWorld.getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
-
- ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid);
-
- float qualityModifier = pProto && rate ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
-
- return roll_chance_f(chance*qualityModifier);
-}
-
-// Checks correctness of values
-bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
-{
- if (group >= 1 << 7) // it stored in 7 bit field
- {
- sLog.outErrorDb("Table '%s' entry %d item %d: group (%u) must be less %u - skipped", store.GetName(), entry, itemid, group, 1 << 7);
- return false;
- }
-
- if (mincountOrRef == 0)
- {
- sLog.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincountOrRef);
- return false;
- }
-
- if (mincountOrRef > 0) // item (quest or non-quest) entry, maybe grouped
- {
- ItemPrototype const *proto = objmgr.GetItemPrototype(itemid);
- if (!proto)
- {
- sLog.outErrorDb("Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store.GetName(), entry, itemid);
- return false;
- }
-
- if (chance == 0 && group == 0) // Zero chance is allowed for grouped entries only
- {
- sLog.outErrorDb("Table '%s' entry %d item %d: equal-chanced grouped entry, but group not defined - skipped", store.GetName(), entry, itemid);
- return false;
- }
-
- if (chance != 0 && chance < 0.000001f) // loot with low chance
- {
- sLog.outErrorDb("Table '%s' entry %d item %d: low chance (%f) - skipped",
- store.GetName(), entry, itemid, chance);
- return false;
- }
-
- if (maxcount < mincountOrRef) // wrong max count
- {
- sLog.outErrorDb("Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store.GetName(), entry, itemid, int32(maxcount), mincountOrRef);
- return false;
- }
-
- }
- else // mincountOrRef < 0
- {
- if (needs_quest)
- sLog.outErrorDb("Table '%s' entry %d item %d: quest chance will be treated as non-quest chance", store.GetName(), entry, itemid);
- else if (chance == 0) // no chance for the reference
- {
- sLog.outErrorDb("Table '%s' entry %d item %d: zero chance is specified for a reference, skipped", store.GetName(), entry, itemid);
- return false;
- }
- }
- return true; // Referenced template existence is checked at whole store level
-}
-
-//
-// --------- LootItem ---------
-//
-
-// Constructor, copies most fields from LootStoreItem and generates random count
-LootItem::LootItem(LootStoreItem const& li)
-{
- itemid = li.itemid;
- conditions = li.conditions;
-
- ItemPrototype const* proto = objmgr.GetItemPrototype(itemid);
- freeforall = proto && (proto->Flags & ITEM_FLAGS_PARTY_LOOT);
-
- needs_quest = li.needs_quest;
-
- count = urand(li.mincountOrRef, li.maxcount); // constructor called for mincountOrRef > 0 only
- randomSuffix = GenerateEnchSuffixFactor(itemid);
- randomPropertyId = Item::GenerateItemRandomPropertyId(itemid);
- is_looted = 0;
- is_blocked = 0;
- is_underthreshold = 0;
- is_counted = 0;
-}
-
-// Basic checks for player/item compatibility - if false no chance to see the item in the loot
-bool LootItem::AllowedForPlayer(Player const * player) const
-{
- // DB conditions check
- if (!sConditionMgr.IsPlayerMeetToConditions(const_cast<Player*>(player), conditions))
- return false;
-
- if (needs_quest)
- {
- // Checking quests for quest-only drop (check only quests requirements in this case)
- if (!player->HasQuestForItem(itemid))
- return false;
- }
- else
- {
- // Not quest only drop (check quest starting items for already accepted non-repeatable quests)
- if (ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid))
- if (pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE && !player->HasQuestForItem(itemid))
- return false;
- }
-
- return true;
-}
-
-//
-// --------- Loot ---------
-//
-
-// Inserts the item into the loot (called by LootTemplate processors)
-void Loot::AddItem(LootStoreItem const & item)
-{
- if (item.needs_quest) // Quest drop
- {
- if (quest_items.size() < MAX_NR_QUEST_ITEMS)
- quest_items.push_back(LootItem(item));
- }
- else if (items.size() < MAX_NR_LOOT_ITEMS) // Non-quest drop
- {
- items.push_back(LootItem(item));
-
- // non-conditional one-player only items are counted here,
- // free for all items are counted in FillFFALoot(),
- // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
- if (item.conditions.empty())
- {
- ItemPrototype const* proto = objmgr.GetItemPrototype(item.itemid);
- if (!proto || (proto->Flags & ITEM_FLAGS_PARTY_LOOT) == 0)
- ++unlootedCount;
- }
- }
-}
-
-// Calls processor of corresponding LootTemplate (which handles everything including references)
-bool Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner, bool personal, bool noEmptyError, uint16 lootMode /*= LOOT_MODE_DEFAULT*/)
-{
- // Must be provided
- if (!loot_owner)
- return false;
-
- LootTemplate const* tab = store.GetLootFor(loot_id);
-
- if (!tab)
- {
- if (!noEmptyError)
- sLog.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.",store.GetName(),loot_id);
- return false;
- }
-
- items.reserve(MAX_NR_LOOT_ITEMS);
- quest_items.reserve(MAX_NR_QUEST_ITEMS);
-
- tab->Process(*this, store, store.IsRatesAllowed(), lootMode); // Processing is done there, callback via Loot::AddItem()
-
- // Setting access rights for group loot case
- Group * pGroup = loot_owner->GetGroup();
- if (!personal && pGroup)
- {
- roundRobinPlayer = loot_owner->GetGUID();
-
- for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
- if (Player* pl = itr->getSource())
- FillNotNormalLootFor(pl);
-
- for (uint8 i = 0; i < items.size(); ++i)
- {
- if (ItemPrototype const *proto = sItemStorage.LookupEntry<ItemPrototype>(items[i].itemid))
- if (proto->Quality < uint32(pGroup->GetLootThreshold()))
- items[i].is_underthreshold = true;
- }
- }
- // ... for personal loot
- else
- FillNotNormalLootFor(loot_owner);
-
- return true;
-}
-
-void Loot::FillNotNormalLootFor(Player* pl)
-{
- uint32 plguid = pl->GetGUIDLow();
-
- QuestItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid);
- if (qmapitr == PlayerQuestItems.end())
- FillQuestLoot(pl);
-
- qmapitr = PlayerFFAItems.find(plguid);
- if (qmapitr == PlayerFFAItems.end())
- FillFFALoot(pl);
-
- qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
- if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
- FillNonQuestNonFFAConditionalLoot(pl);
-}
-
-QuestItemList* Loot::FillFFALoot(Player* player)
-{
- QuestItemList *ql = new QuestItemList();
-
- for (uint8 i = 0; i < items.size(); ++i)
- {
- LootItem &item = items[i];
- if (!item.is_looted && item.freeforall && item.AllowedForPlayer(player))
- {
- ql->push_back(QuestItem(i));
- ++unlootedCount;
- }
- }
- if (ql->empty())
- {
- delete ql;
- return NULL;
- }
-
- PlayerFFAItems[player->GetGUIDLow()] = ql;
- return ql;
-}
-
-QuestItemList* Loot::FillQuestLoot(Player* player)
-{
- if (items.size() == MAX_NR_LOOT_ITEMS) return NULL;
- QuestItemList *ql = new QuestItemList();
-
- for (uint8 i = 0; i < quest_items.size(); ++i)
- {
- LootItem &item = quest_items[i];
- if (!item.is_looted && item.AllowedForPlayer(player))
- {
- ql->push_back(QuestItem(i));
-
- // questitems get blocked when they first appear in a
- // player's quest vector
- //
- // increase once if one looter only, looter-times if free for all
- if (item.freeforall || !item.is_blocked)
- ++unlootedCount;
-
- item.is_blocked = true;
-
- if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS)
- break;
- }
- }
- if (ql->empty())
- {
- delete ql;
- return NULL;
- }
-
- PlayerQuestItems[player->GetGUIDLow()] = ql;
- return ql;
-}
-
-QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player)
-{
- QuestItemList *ql = new QuestItemList();
-
- for (uint8 i = 0; i < items.size(); ++i)
- {
- LootItem &item = items[i];
- if (!item.is_looted && !item.freeforall && !item.conditions.empty() && item.AllowedForPlayer(player))
- {
- ql->push_back(QuestItem(i));
- if (!item.is_counted)
- {
- ++unlootedCount;
- item.is_counted = true;
- }
- }
- }
- if (ql->empty())
- {
- delete ql;
- return NULL;
- }
-
- PlayerNonQuestNonFFAConditionalItems[player->GetGUIDLow()] = ql;
- return ql;
-}
-
-//===================================================
-
-void Loot::NotifyItemRemoved(uint8 lootIndex)
-{
- // notify all players that are looting this that the item was removed
- // convert the index to the slot the player sees
- std::set<uint64>::iterator i_next;
- for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
- {
- i_next = i;
- ++i_next;
- if (Player* pl = ObjectAccessor::FindPlayer(*i))
- pl->SendNotifyLootItemRemoved(lootIndex);
- else
- PlayersLooting.erase(i);
- }
-}
-
-void Loot::NotifyMoneyRemoved()
-{
- // notify all players that are looting this that the money was removed
- std::set<uint64>::iterator i_next;
- for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
- {
- i_next = i;
- ++i_next;
- if (Player* pl = ObjectAccessor::FindPlayer(*i))
- pl->SendNotifyLootMoneyRemoved();
- else
- PlayersLooting.erase(i);
- }
-}
-
-void Loot::NotifyQuestItemRemoved(uint8 questIndex)
-{
- // when a free for all questitem is looted
- // all players will get notified of it being removed
- // (other questitems can be looted by each group member)
- // bit inefficient but isn't called often
-
- std::set<uint64>::iterator i_next;
- for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
- {
- i_next = i;
- ++i_next;
- if (Player* pl = ObjectAccessor::FindPlayer(*i))
- {
- QuestItemMap::const_iterator pq = PlayerQuestItems.find(pl->GetGUIDLow());
- if (pq != PlayerQuestItems.end() && pq->second)
- {
- // find where/if the player has the given item in it's vector
- QuestItemList& pql = *pq->second;
-
- uint8 j;
- for (j = 0; j < pql.size(); ++j)
- if (pql[j].index == questIndex)
- break;
-
- if (j < pql.size())
- pl->SendNotifyLootItemRemoved(items.size()+j);
- }
- }
- else
- PlayersLooting.erase(i);
- }
-}
-
-void Loot::generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
-{
- if (maxAmount > 0)
- {
- if (maxAmount <= minAmount)
- gold = uint32(maxAmount * sWorld.getRate(RATE_DROP_MONEY));
- else if ((maxAmount - minAmount) < 32700)
- gold = uint32(urand(minAmount, maxAmount) * sWorld.getRate(RATE_DROP_MONEY));
- else
- gold = uint32(urand(minAmount >> 8, maxAmount >> 8) * sWorld.getRate(RATE_DROP_MONEY)) << 8;
- }
-}
-
-LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qitem, QuestItem **ffaitem, QuestItem **conditem)
-{
- LootItem* item = NULL;
- bool is_looted = true;
- if (lootSlot >= items.size())
- {
- uint32 questSlot = lootSlot - items.size();
- QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
- if (itr != PlayerQuestItems.end() && questSlot < itr->second->size())
- {
- QuestItem *qitem2 = &itr->second->at(questSlot);
- if (qitem)
- *qitem = qitem2;
- item = &quest_items[qitem2->index];
- is_looted = qitem2->is_looted;
- }
- }
- else
- {
- item = &items[lootSlot];
- is_looted = item->is_looted;
- if (item->freeforall)
- {
- QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUIDLow());
- if (itr != PlayerFFAItems.end())
- {
- for (QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
- if (iter->index == lootSlot)
- {
- QuestItem *ffaitem2 = (QuestItem*)&(*iter);
- if (ffaitem)
- *ffaitem = ffaitem2;
- is_looted = ffaitem2->is_looted;
- break;
- }
- }
- }
- else if (!item->conditions.empty())
- {
- QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
- if (itr != PlayerNonQuestNonFFAConditionalItems.end())
- {
- for (QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
- {
- if (iter->index == lootSlot)
- {
- QuestItem *conditem2 = (QuestItem*)&(*iter);
- if (conditem)
- *conditem = conditem2;
- is_looted = conditem2->is_looted;
- break;
- }
- }
- }
- }
- }
-
- if (is_looted)
- return NULL;
-
- return item;
-}
-
-uint32 Loot::GetMaxSlotInLootFor(Player* player) const
-{
- QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
- return items.size() + (itr != PlayerQuestItems.end() ? itr->second->size() : 0);
-}
-
-// return true if there is any FFA, quest or conditional item for the player.
-bool Loot::hasItemFor(Player* player) const
-{
- QuestItemMap const& lootPlayerQuestItems = GetPlayerQuestItems();
- QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(player->GetGUIDLow());
- if (q_itr != lootPlayerQuestItems.end())
- {
- QuestItemList *q_list = q_itr->second;
- for (QuestItemList::const_iterator qi = q_list->begin() ; qi != q_list->end(); ++qi)
- {
- const LootItem &item = quest_items[qi->index];
- if (!qi->is_looted && !item.is_looted)
- return true;
- }
- }
-
- QuestItemMap const& lootPlayerFFAItems = GetPlayerFFAItems();
- QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(player->GetGUIDLow());
- if (ffa_itr != lootPlayerFFAItems.end())
- {
- QuestItemList *ffa_list = ffa_itr->second;
- for (QuestItemList::const_iterator fi = ffa_list->begin() ; fi != ffa_list->end(); ++fi)
- {
- const LootItem &item = items[fi->index];
- if (!fi->is_looted && !item.is_looted)
- return true;
- }
- }
-
- QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems();
- QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
- if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
- {
- QuestItemList *conditional_list = nn_itr->second;
- for (QuestItemList::const_iterator ci = conditional_list->begin() ; ci != conditional_list->end(); ++ci)
- {
- const LootItem &item = items[ci->index];
- if (!ci->is_looted && !item.is_looted)
- return true;
- }
- }
-
- return false;
-}
-
-// return true if there is any item over the group threshold (i.e. not underthreshold).
-bool Loot::hasOverThresholdItem() const
-{
- for (uint8 i = 0; i < items.size(); ++i)
- {
- if (!items[i].is_looted && !items[i].is_underthreshold && !items[i].freeforall)
- return true;
- }
-
- return false;
-}
-
-ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
-{
- b << uint32(li.itemid);
- b << uint32(li.count); // nr of items of this type
- b << uint32(objmgr.GetItemPrototype(li.itemid)->DisplayInfoID);
- b << uint32(li.randomSuffix);
- b << uint32(li.randomPropertyId);
- //b << uint8(0); // slot type - will send after this function call
- return b;
-}
-
-ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
-{
- if (lv.permission == NONE_PERMISSION)
- {
- b << uint32(0); //gold
- b << uint8(0); // item count
- return b; // nothing output more
- }
-
- Loot &l = lv.loot;
-
- uint8 itemsShown = 0;
-
- //gold
- b << uint32(l.gold);
-
- size_t count_pos = b.wpos(); // pos of item count byte
- b << uint8(0); // item count placeholder
-
- switch (lv.permission)
- {
- case GROUP_PERMISSION:
- {
- // if you are not the round-robin group looter, you can only see
- // blocked rolled items and quest items, and !ffa items
- for (uint8 i = 0; i < l.items.size(); ++i)
- {
- if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer))
- {
- uint8 slot_type;
-
- if (l.items[i].is_blocked)
- slot_type = LOOT_SLOT_TYPE_ROLL_ONGOING;
- else if (l.roundRobinPlayer == 0 || !l.items[i].is_underthreshold || lv.viewer->GetGUID() == l.roundRobinPlayer)
- {
- // no round robin owner or he has released the loot
- // or it IS the round robin group owner
- // => item is lootable
- slot_type = LOOT_SLOT_TYPE_ALLOW_LOOT;
- }
- else
- // item shall not be displayed.
- continue;
-
- b << uint8(i) << l.items[i];
- b << uint8(slot_type);
- ++itemsShown;
- }
- }
- break;
- }
- case ROUND_ROBIN_PERMISSION:
- {
- for (uint8 i = 0; i < l.items.size(); ++i)
- {
- if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer))
- {
- if (l.roundRobinPlayer != 0 && lv.viewer->GetGUID() != l.roundRobinPlayer)
- // item shall not be displayed.
- continue;
-
- b << uint8(i) << l.items[i];
- b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT);
- ++itemsShown;
- }
- }
- break;
- }
- case ALL_PERMISSION:
- case MASTER_PERMISSION:
- {
- uint8 slot_type = (lv.permission == MASTER_PERMISSION) ? LOOT_SLOT_TYPE_MASTER : LOOT_SLOT_TYPE_ALLOW_LOOT;
- for (uint8 i = 0; i < l.items.size(); ++i)
- {
- if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer))
- {
- b << uint8(i) << l.items[i];
- b << uint8(slot_type);
- ++itemsShown;
- }
- }
- break;
- }
- default:
- return b; // nothing output more
- }
-
- QuestItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems();
- QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUIDLow());
- if (q_itr != lootPlayerQuestItems.end())
- {
- QuestItemList *q_list = q_itr->second;
- for (QuestItemList::const_iterator qi = q_list->begin() ; qi != q_list->end(); ++qi)
- {
- LootItem &item = l.quest_items[qi->index];
- if (!qi->is_looted && !item.is_looted)
- {
- b << uint8(l.items.size() + (qi - q_list->begin()));
- b << item;
- b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT);
- ++itemsShown;
- }
- }
- }
-
- QuestItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems();
- QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUIDLow());
- if (ffa_itr != lootPlayerFFAItems.end())
- {
- QuestItemList *ffa_list = ffa_itr->second;
- for (QuestItemList::const_iterator fi = ffa_list->begin() ; fi != ffa_list->end(); ++fi)
- {
- LootItem &item = l.items[fi->index];
- if (!fi->is_looted && !item.is_looted)
- {
- b << uint8(fi->index) << item;
- b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT);
- ++itemsShown;
- }
- }
- }
-
- QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems();
- QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUIDLow());
- if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
- {
- QuestItemList *conditional_list = nn_itr->second;
- for (QuestItemList::const_iterator ci = conditional_list->begin() ; ci != conditional_list->end(); ++ci)
- {
- LootItem &item = l.items[ci->index];
- if (!ci->is_looted && !item.is_looted)
- {
- b << uint8(ci->index) << item;
- b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT);
- ++itemsShown;
- }
- }
- }
-
- //update number of items shown
- b.put<uint8>(count_pos,itemsShown);
-
- return b;
-}
-
-//
-// --------- LootTemplate::LootGroup ---------
-//
-
-// Adds an entry to the group (at loading stage)
-void LootTemplate::LootGroup::AddEntry(LootStoreItem& item)
-{
- if (item.chance != 0)
- ExplicitlyChanced.push_back(item);
- else
- EqualChanced.push_back(item);
-}
-
-// Rolls an item from the group, returns NULL if all miss their chances
-LootStoreItem const * LootTemplate::LootGroup::Roll() const
-{
- if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked
- {
- float Roll = rand_chance();
-
- for (uint32 i = 0; i < ExplicitlyChanced.size(); ++i) // check each explicitly chanced entry in the template and modify its chance based on quality.
- {
- if (ExplicitlyChanced[i].chance >= 100.0f)
- return &ExplicitlyChanced[i];
-
- Roll -= ExplicitlyChanced[i].chance;
- if (Roll < 0)
- return &ExplicitlyChanced[i];
- }
- }
- if (!EqualChanced.empty()) // If nothing selected yet - an item is taken from equal-chanced part
- return &EqualChanced[irand(0, EqualChanced.size()-1)];
-
- return NULL; // Empty drop from the group
-}
-
-// True if group includes at least 1 quest drop entry
-bool LootTemplate::LootGroup::HasQuestDrop() const
-{
- for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
- if (i->needs_quest)
- return true;
- for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
- if (i->needs_quest)
- return true;
- return false;
-}
-
-// True if group includes at least 1 quest drop entry for active quests of the player
-bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const
-{
- for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
- if (player->HasQuestForItem(i->itemid))
- return true;
- for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
- if (player->HasQuestForItem(i->itemid))
- return true;
- return false;
-}
-
-void LootTemplate::LootGroup::CopyConditions(ConditionList conditions)
-{
- for (LootStoreItemList::iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
- {
- i->conditions = conditions;
- }
- for (LootStoreItemList::iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
- {
- i->conditions = conditions;
- }
-}
-
-// Rolls an item from the group (if any takes its chance) and adds the item to the loot
-void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const
-{
- // build up list of possible drops
- LootStoreItemList EqualPossibleDrops = EqualChanced;
- LootStoreItemList ExplicitPossibleDrops = ExplicitlyChanced;
-
- uint8 uiAttemptCount = 0;
- const uint8 uiMaxAttempts = ExplicitlyChanced.size() + EqualChanced.size();
-
- while (!ExplicitPossibleDrops.empty() || !EqualPossibleDrops.empty())
- {
- if (uiAttemptCount == uiMaxAttempts) // already tried rolling too many times, just abort
- return;
-
- LootStoreItem *item = NULL;
-
- // begin rolling (normally called via Roll())
- LootStoreItemList::iterator itr;
- uint8 itemSource = 0;
- if (!ExplicitPossibleDrops.empty()) // First explicitly chanced entries are checked
- {
- itemSource = 1;
- float Roll = rand_chance();
- // check each explicitly chanced entry in the template and modify its chance based on quality
- for (itr = ExplicitPossibleDrops.begin(); itr != ExplicitPossibleDrops.end(); itr = ExplicitPossibleDrops.erase(itr))
- {
- if (itr->chance >= 100.0f)
- {
- item = &*itr;
- break;
- }
-
- Roll -= itr->chance;
- if (Roll < 0)
- {
- item = &*itr;
- break;
- }
- }
- }
- if (item == NULL && !EqualPossibleDrops.empty()) // If nothing selected yet - an item is taken from equal-chanced part
- {
- itemSource = 2;
- itr = EqualPossibleDrops.begin();
- std::advance(itr, irand(0, EqualPossibleDrops.size()-1));
- item = &*itr;
- }
- // finish rolling
-
- ++uiAttemptCount;
-
- if (item != NULL && item->lootmode & lootMode) // only add this item if roll succeeds and the mode matches
- {
- bool duplicate = false;
- if (ItemPrototype const *_proto = sItemStorage.LookupEntry<ItemPrototype>(item->itemid))
- {
- uint8 _item_counter = 0;
- for (LootItemList::const_iterator _item = loot.items.begin(); _item != loot.items.end(); ++_item)
- if (_item->itemid == item->itemid) // search through the items that have already dropped
- {
- ++_item_counter;
- if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops
- duplicate = true;
- else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop
- duplicate = true;
- }
- }
- if (duplicate) // if item->itemid is a duplicate, remove it
- switch (itemSource)
- {
- case 1: // item came from ExplicitPossibleDrops
- ExplicitPossibleDrops.erase(itr);
- break;
- case 2: // item came from EqualPossibleDrops
- EqualPossibleDrops.erase(itr);
- break;
- }
- else // otherwise, add the item and exit the function
- {
- loot.AddItem(*item);
- return;
- }
- }
- }
-}
-
-// Overall chance for the group without equal chanced items
-float LootTemplate::LootGroup::RawTotalChance() const
-{
- float result = 0;
-
- for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
- if (!i->needs_quest)
- result += i->chance;
-
- return result;
-}
-
-// Overall chance for the group
-float LootTemplate::LootGroup::TotalChance() const
-{
- float result = RawTotalChance();
-
- if (!EqualChanced.empty() && result < 100.0f)
- return 100.0f;
-
- return result;
-}
-
-void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const
-{
- float chance = RawTotalChance();
- if (chance > 101.0f) // TODO: replace with 100% when DBs will be ready
- {
- sLog.outErrorDb("Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore.GetName(), id, group_id, chance);
- }
-
- if (chance >= 100.0f && !EqualChanced.empty())
- {
- 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);
- }
-}
-
-void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const
-{
- for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
- {
- if (ieItr->mincountOrRef < 0)
- {
- if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
- LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
- else if (ref_set)
- ref_set->erase(-ieItr->mincountOrRef);
- }
- }
-
- for (LootStoreItemList::const_iterator ieItr=EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
- {
- if (ieItr->mincountOrRef < 0)
- {
- if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
- LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
- else if (ref_set)
- ref_set->erase(-ieItr->mincountOrRef);
- }
- }
-}
-
-//
-// --------- LootTemplate ---------
-//
-
-// Adds an entry to the group (at loading stage)
-void LootTemplate::AddEntry(LootStoreItem& item)
-{
- if (item.group > 0 && item.mincountOrRef > 0) // Group
- {
- if (item.group >= Groups.size())
- Groups.resize(item.group); // Adds new group the the loot template if needed
- Groups[item.group-1].AddEntry(item); // Adds new entry to the group
- }
- else // Non-grouped entries and references are stored together
- Entries.push_back(item);
-}
-
-void LootTemplate::CopyConditions(ConditionList conditions)
-{
- for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
- i->conditions = conditions;
-
- for (LootGroups::iterator i = Groups.begin(); i != Groups.end(); ++i)
- i->CopyConditions(conditions);
-}
-
-// Rolls for every item in the template and adds the rolled items the the loot
-void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint16 lootMode, uint8 groupId) const
-{
- if (groupId) // Group reference uses own processing of the group
- {
- if (groupId > Groups.size())
- return; // Error message already printed at loading stage
-
- Groups[groupId-1].Process(loot, lootMode);
- return;
- }
-
- // Rolling non-grouped items
- for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
- {
- if (i->lootmode &~ lootMode) // Do not add if mode mismatch
- continue;
-
- if (!i->Roll(rate))
- continue; // Bad luck for the entry
-
- if (ItemPrototype const *_proto = sItemStorage.LookupEntry<ItemPrototype>(i->itemid))
- {
- uint8 _item_counter = 0;
- LootItemList::const_iterator _item = loot.items.begin();
- for (; _item != loot.items.end(); ++_item)
- if (_item->itemid == i->itemid) // search through the items that have already dropped
- {
- ++_item_counter;
- if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops
- continue;
- else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop
- continue;
- }
- if (_item != loot.items.end())
- continue;
- }
-
- if (i->mincountOrRef < 0) // References processing
- {
- LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef);
-
- if (!Referenced)
- continue; // Error message already printed at loading stage
-
- const_cast<LootTemplate*>(Referenced)->CopyConditions(i->conditions);//copy conditions from referer template
-
- for (uint32 loop = 0; loop < i->maxcount; ++loop) // Ref multiplicator
- Referenced->Process(loot, store, rate, lootMode, i->group);
- }
- else // Plain entries (not a reference, not grouped)
- loot.AddItem(*i); // Chance is already checked, just add
- }
-
- // Now processing groups
- for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
- i->Process(loot, lootMode);
-}
-
-// True if template includes at least 1 quest drop entry
-bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) const
-{
- if (groupId) // Group reference
- {
- if (groupId > Groups.size())
- return false; // Error message [should be] already printed at loading stage
- return Groups[groupId-1].HasQuestDrop();
- }
-
- for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
- {
- if (i->mincountOrRef < 0) // References
- {
- LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
- if (Referenced == store.end())
- continue; // Error message [should be] already printed at loading stage
- if (Referenced->second->HasQuestDrop(store, i->group))
- return true;
- }
- else if (i->needs_quest)
- return true; // quest drop found
- }
-
- // Now processing groups
- for (LootGroups::const_iterator i = Groups.begin() ; i != Groups.end(); ++i)
- if (i->HasQuestDrop())
- return true;
-
- return false;
-}
-
-// True if template includes at least 1 quest drop for an active quest of the player
-bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player const* player, uint8 groupId) const
-{
- if (groupId) // Group reference
- {
- if (groupId > Groups.size())
- return false; // Error message already printed at loading stage
- return Groups[groupId-1].HasQuestDropForPlayer(player);
- }
-
- // Checking non-grouped entries
- for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end(); ++i)
- {
- if (i->mincountOrRef < 0) // References processing
- {
- LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
- if (Referenced == store.end())
- continue; // Error message already printed at loading stage
- if (Referenced->second->HasQuestDropForPlayer(store, player, i->group))
- return true;
- }
- else if (player->HasQuestForItem(i->itemid))
- return true; // active quest drop found
- }
-
- // Now checking groups
- for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
- if (i->HasQuestDropForPlayer(player))
- return true;
-
- return false;
-}
-
-// Checks integrity of the template
-void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const
-{
- // Checking group chances
- for (uint32 i=0; i < Groups.size(); ++i)
- Groups[i].Verify(lootstore,id,i+1);
-
- // TODO: References validity checks
-}
-
-void LootTemplate::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const
-{
- for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
- {
- if (ieItr->mincountOrRef < 0)
- {
- if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
- LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
- else if (ref_set)
- ref_set->erase(-ieItr->mincountOrRef);
- }
- }
-
- for (LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
- grItr->CheckLootRefs(store,ref_set);
-}
-bool LootTemplate::addConditionItem(Condition* cond)
-{
- if (!cond || !cond->isLoaded())//should never happen, checked at loading
- {
- sLog.outError("LootTemplate::addConditionItem: condition is null");
- return false;
- }
- if (!Entries.empty())
- {
- for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
- {
- if (i->itemid == cond->mSourceEntry)
- {
- i->conditions.push_back(cond);
- return true;
- }
- }
- }
- if (!Groups.empty())
- {
- for (LootGroups::iterator groupItr = Groups.begin(); groupItr != Groups.end(); ++groupItr)
- {
- LootStoreItemList* itemList = (*groupItr).GetExplicitlyChancedItemList();
- if (!itemList->empty())
- {
- for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
- {
- if ((*i).itemid == cond->mSourceEntry)
- {
- (*i).conditions.push_back(cond);
- return true;
- }
- }
- }
- itemList = (*groupItr).GetEqualChancedItemList();
- if (!itemList->empty())
- {
- for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
- {
- if ((*i).itemid == cond->mSourceEntry)
- {
- (*i).conditions.push_back(cond);
- return true;
- }
- }
- }
- }
- }
- return false;
-}
-
-bool LootTemplate::isReference(uint32 id)
-{
- for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
- {
- if (ieItr->itemid == id && ieItr->mincountOrRef < 0)
- return true;
- }
- return false;//not found or not reference
-}
-
-void LoadLootTemplates_Creature()
-{
- LootIdSet ids_set, ids_setUsed;
- LootTemplates_Creature.LoadAndCollectLootIds(ids_set);
-
- // remove real entries and check existence loot
- for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
- {
- if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
- {
- if (uint32 lootid = cInfo->lootid)
- {
- if (ids_set.find(lootid) == ids_set.end())
- LootTemplates_Creature.ReportNotExistedId(lootid);
- else
- ids_setUsed.insert(lootid);
- }
- }
- }
- for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
- ids_set.erase(*itr);
-
- // output error for any still listed (not referenced from appropriate table) ids
- LootTemplates_Creature.ReportUnusedIds(ids_set);
-}
-
-void LoadLootTemplates_Disenchant()
-{
- LootIdSet ids_set, ids_setUsed;
- LootTemplates_Disenchant.LoadAndCollectLootIds(ids_set);
-
- // remove real entries and check existence loot
- for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
- {
- if (ItemPrototype const *proto = sItemStorage.LookupEntry<ItemPrototype>(i))
- {
- if (uint32 lootid = proto->DisenchantID)
- {
- if (ids_set.find(lootid) == ids_set.end())
- LootTemplates_Disenchant.ReportNotExistedId(lootid);
- else
- ids_setUsed.insert(lootid);
- }
- }
- }
- for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
- ids_set.erase(*itr);
- // output error for any still listed (not referenced from appropriate table) ids
- LootTemplates_Disenchant.ReportUnusedIds(ids_set);
-}
-
-void LoadLootTemplates_Fishing()
-{
- LootIdSet ids_set;
- LootTemplates_Fishing.LoadAndCollectLootIds(ids_set);
-
- // remove real entries and check existence loot
- for (uint32 i = 1; i < sAreaStore.GetNumRows(); ++i)
- if (AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
- if (ids_set.find(areaEntry->ID) != ids_set.end())
- ids_set.erase(areaEntry->ID);
-
- // output error for any still listed (not referenced from appropriate table) ids
- LootTemplates_Fishing.ReportUnusedIds(ids_set);
-}
-
-void LoadLootTemplates_Gameobject()
-{
- LootIdSet ids_set, ids_setUsed;
- LootTemplates_Gameobject.LoadAndCollectLootIds(ids_set);
-
- // remove real entries and check existence loot
- for (uint32 i = 1; i < sGOStorage.MaxEntry; ++i)
- {
- if (GameObjectInfo const* gInfo = sGOStorage.LookupEntry<GameObjectInfo>(i))
- {
- if (uint32 lootid = gInfo->GetLootId())
- {
- if (objmgr.IsGoOfSpecificEntrySpawned(gInfo->id) && ids_set.find(lootid) == ids_set.end())
- LootTemplates_Gameobject.ReportNotExistedId(lootid);
- else
- ids_setUsed.insert(lootid);
- }
- }
- }
- for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
- ids_set.erase(*itr);
-
- // output error for any still listed (not referenced from appropriate table) ids
- LootTemplates_Gameobject.ReportUnusedIds(ids_set);
-}
-
-void LoadLootTemplates_Item()
-{
- LootIdSet ids_set;
- LootTemplates_Item.LoadAndCollectLootIds(ids_set);
-
- // remove real entries and check existence loot
- for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
- if (ItemPrototype const *proto = sItemStorage.LookupEntry<ItemPrototype>(i))
- if (ids_set.find(proto->ItemId) != ids_set.end())
- ids_set.erase(proto->ItemId);
-
- // output error for any still listed (not referenced from appropriate table) ids
- LootTemplates_Item.ReportUnusedIds(ids_set);
-}
-
-void LoadLootTemplates_Milling()
-{
- LootIdSet ids_set;
- LootTemplates_Milling.LoadAndCollectLootIds(ids_set);
-
- // remove real entries and check existence loot
- for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
- {
- ItemPrototype const *proto = sItemStorage.LookupEntry<ItemPrototype>(i);
- if (!proto)
- continue;
-
- if ((proto->BagFamily & BAG_FAMILY_MASK_HERBS) == 0)
- continue;
-
- if (ids_set.find(proto->ItemId) != ids_set.end())
- ids_set.erase(proto->ItemId);
- }
-
- // output error for any still listed (not referenced from appropriate table) ids
- LootTemplates_Milling.ReportUnusedIds(ids_set);
-}
-
-void LoadLootTemplates_Pickpocketing()
-{
- LootIdSet ids_set, ids_setUsed;
- LootTemplates_Pickpocketing.LoadAndCollectLootIds(ids_set);
-
- // remove real entries and check existence loot
- for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
- {
- if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
- {
- if (uint32 lootid = cInfo->pickpocketLootId)
- {
- if (ids_set.find(lootid) == ids_set.end())
- LootTemplates_Pickpocketing.ReportNotExistedId(lootid);
- else
- ids_setUsed.insert(lootid);
- }
- }
- }
- for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
- ids_set.erase(*itr);
-
- // output error for any still listed (not referenced from appropriate table) ids
- LootTemplates_Pickpocketing.ReportUnusedIds(ids_set);
-}
-
-void LoadLootTemplates_Prospecting()
-{
- LootIdSet ids_set;
- LootTemplates_Prospecting.LoadAndCollectLootIds(ids_set);
-
- // remove real entries and check existence loot
- for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
- {
- ItemPrototype const *proto = sItemStorage.LookupEntry<ItemPrototype>(i);
- if (!proto)
- continue;
-
- if ((proto->BagFamily & BAG_FAMILY_MASK_MINING_SUPP) == 0)
- continue;
-
- if (ids_set.find(proto->ItemId) != ids_set.end())
- ids_set.erase(proto->ItemId);
- }
-
- // output error for any still listed (not referenced from appropriate table) ids
- LootTemplates_Prospecting.ReportUnusedIds(ids_set);
-}
-
-void LoadLootTemplates_Mail()
-{
- LootIdSet ids_set;
- LootTemplates_Mail.LoadAndCollectLootIds(ids_set);
-
- // remove real entries and check existence loot
- for (uint32 i = 1; i < sMailTemplateStore.GetNumRows(); ++i)
- if (sMailTemplateStore.LookupEntry(i))
- if (ids_set.find(i) != ids_set.end())
- ids_set.erase(i);
-
- // output error for any still listed (not referenced from appropriate table) ids
- LootTemplates_Mail.ReportUnusedIds(ids_set);
-}
-
-void LoadLootTemplates_Skinning()
-{
- LootIdSet ids_set, ids_setUsed;
- LootTemplates_Skinning.LoadAndCollectLootIds(ids_set);
-
- // remove real entries and check existence loot
- for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
- {
- if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
- {
- if (uint32 lootid = cInfo->SkinLootId)
- {
- if (ids_set.find(lootid) == ids_set.end())
- LootTemplates_Skinning.ReportNotExistedId(lootid);
- else
- ids_setUsed.insert(lootid);
- }
- }
- }
- for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
- ids_set.erase(*itr);
-
- // output error for any still listed (not referenced from appropriate table) ids
- LootTemplates_Skinning.ReportUnusedIds(ids_set);
-}
-
-void LoadLootTemplates_Spell()
-{
- LootIdSet ids_set;
- LootTemplates_Spell.LoadAndCollectLootIds(ids_set);
-
- // remove real entries and check existence loot
- for (uint32 spell_id = 1; spell_id < sSpellStore.GetNumRows(); ++spell_id)
- {
- SpellEntry const* spellInfo = sSpellStore.LookupEntry (spell_id);
- if (!spellInfo)
- continue;
-
- // possible cases
- if (!IsLootCraftingSpell(spellInfo))
- continue;
-
- if (ids_set.find(spell_id) == ids_set.end())
- {
- // not report about not trainable spells (optionally supported by DB)
- // ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
- if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_TRADESPELL))
- {
- LootTemplates_Spell.ReportNotExistedId(spell_id);
- }
- }
- else
- ids_set.erase(spell_id);
- }
-
- // output error for any still listed (not referenced from appropriate table) ids
- LootTemplates_Spell.ReportUnusedIds(ids_set);
-}
-
-void LoadLootTemplates_Reference()
-{
- LootIdSet ids_set;
- LootTemplates_Reference.LoadAndCollectLootIds(ids_set);
-
- // check references and remove used
- LootTemplates_Creature.CheckLootRefs(&ids_set);
- LootTemplates_Fishing.CheckLootRefs(&ids_set);
- LootTemplates_Gameobject.CheckLootRefs(&ids_set);
- LootTemplates_Item.CheckLootRefs(&ids_set);
- LootTemplates_Milling.CheckLootRefs(&ids_set);
- LootTemplates_Pickpocketing.CheckLootRefs(&ids_set);
- LootTemplates_Skinning.CheckLootRefs(&ids_set);
- LootTemplates_Disenchant.CheckLootRefs(&ids_set);
- LootTemplates_Prospecting.CheckLootRefs(&ids_set);
- LootTemplates_Mail.CheckLootRefs(&ids_set);
- LootTemplates_Reference.CheckLootRefs(&ids_set);
-
- // output error for any still listed ids (not referenced from any loot table)
- LootTemplates_Reference.ReportUnusedIds(ids_set);
-}