diff options
Diffstat (limited to 'src/game/LootMgr.cpp')
-rw-r--r-- | src/game/LootMgr.cpp | 1639 |
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); -} |