Recent Posts
None | 8 sec ago
PHP | 17 sec ago
None | 19 sec ago
None | 34 sec ago
None | 1 min ago
JavaScript | 1 min ago
Java | 1 min ago
Python | 1 min ago
None | 1 min ago
None | 1 min ago
Sitereport
Find cool info about any domain on the internet?
visit sitereport
Free Subdomains
Want a pastebin.com sub-domain for your community?
learn more...
What is pastebin?
Pastebin is a website that hosts all your text & code on dedicated servers for easy sharing.
learn more...
Learn a little bit about the new Pastebin.com on our help page. hide message
By Anonymous on the 9th of Feb 2010 06:58:34 PM Download | Raw | Embed | Report
  1. /*
  2.  * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
  3.  *
  4.  * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19.  */
  20.  
  21. #include "LootMgr.h"
  22. #include "Log.h"
  23. #include "ObjectMgr.h"
  24. #include "ProgressBar.h"
  25. #include "World.h"
  26. #include "Util.h"
  27. #include "SharedDefines.h"
  28. #include "SpellMgr.h"
  29.  
  30. static Rates const qualityToRate[MAX_ITEM_QUALITY] = {
  31.     RATE_DROP_ITEM_POOR,                                    // ITEM_QUALITY_POOR
  32.     RATE_DROP_ITEM_NORMAL,                                  // ITEM_QUALITY_NORMAL
  33.     RATE_DROP_ITEM_UNCOMMON,                                // ITEM_QUALITY_UNCOMMON
  34.     RATE_DROP_ITEM_RARE,                                    // ITEM_QUALITY_RARE
  35.     RATE_DROP_ITEM_EPIC,                                    // ITEM_QUALITY_EPIC
  36.     RATE_DROP_ITEM_LEGENDARY,                               // ITEM_QUALITY_LEGENDARY
  37.     RATE_DROP_ITEM_ARTIFACT,                                // ITEM_QUALITY_ARTIFACT
  38. };
  39.  
  40. LootStore LootTemplates_Creature(     "creature_loot_template",     "creature entry",               true);
  41. LootStore LootTemplates_Disenchant(   "disenchant_loot_template",   "item disenchant id",           true);
  42. LootStore LootTemplates_Fishing(      "fishing_loot_template",      "area id",                      true);
  43. LootStore LootTemplates_Gameobject(   "gameobject_loot_template",   "gameobject entry",             true);
  44. LootStore LootTemplates_Item(         "item_loot_template",         "item entry",                   true);
  45. LootStore LootTemplates_Mail(         "mail_loot_template",         "mail template id",             false);
  46. LootStore LootTemplates_Milling(      "milling_loot_template",      "item entry (herb)",            true);
  47. LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template","creature pickpocket lootid",   true);
  48. LootStore LootTemplates_Prospecting(  "prospecting_loot_template",  "item entry (ore)",             true);
  49. LootStore LootTemplates_Reference(    "reference_loot_template",    "reference id",                 false);
  50. LootStore LootTemplates_Skinning(     "skinning_loot_template",     "creature skinning id",         true);
  51. LootStore LootTemplates_Spell(        "spell_loot_template",        "spell id (random item creating)",false);
  52.  
  53. class LootTemplate::LootGroup                               // A set of loot definitions for items (refs are not allowed)
  54. {
  55.     public:
  56.         void AddEntry(LootStoreItem& item);                 // Adds an entry to the group (at loading stage)
  57.         bool HasQuestDrop() const;                          // True if group includes at least 1 quest drop entry
  58.         bool HasQuestDropForPlayer(Player const * player) const;
  59.                                                             // The same for active quests of the player
  60.         void Process(Loot& loot, uint16 lootMode) const;    // Rolls an item from the group (if any) and adds the item to the loot
  61.         float RawTotalChance() const;                       // Overall chance for the group (without equal chanced items)
  62.         float TotalChance() const;                          // Overall chance for the group
  63.  
  64.         void Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const;
  65.         void CollectLootIds(LootIdSet& set) const;
  66.         void CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const;
  67.     private:
  68.         LootStoreItemList ExplicitlyChanced;                // Entries with chances defined in DB
  69.         LootStoreItemList EqualChanced;                     // Zero chances - every entry takes the same chance
  70.  
  71.         LootStoreItem const * Roll() const;                 // Rolls an item from the group, returns NULL if all miss their chances
  72. };
  73.  
  74. //Remove all data and free all memory
  75. void LootStore::Clear()
  76. {
  77.     for (LootTemplateMap::const_iterator itr=m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
  78.         delete itr->second;
  79.     m_LootTemplates.clear();
  80. }
  81.  
  82. // Checks validity of the loot store
  83. // Actual checks are done within LootTemplate::Verify() which is called for every template
  84. void LootStore::Verify() const
  85. {
  86.     for (LootTemplateMap::const_iterator i = m_LootTemplates.begin(); i != m_LootTemplates.end(); ++i)
  87.         i->second->Verify(*this, i->first);
  88. }
  89.  
  90. // Loads a *_loot_template DB table into loot store
  91. // All checks of the loaded template are called from here, no error reports at loot generation required
  92. void LootStore::LoadLootTable()
  93. {
  94.     LootTemplateMap::const_iterator tab;
  95.     uint32 count = 0;
  96.  
  97.     // Clearing store (for reloading case)
  98.     Clear();
  99.  
  100.     sLog.outString( "%s :", GetName());
  101.  
  102.     //                                                 0      1     2                    3         4        5              6         7              8                 9
  103.     QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, lootmode, groupid, mincountOrRef, maxcount, lootcondition, condition_value1, condition_value2 FROM %s",GetName());
  104.  
  105.     if (result)
  106.     {
  107.         barGoLink bar(result->GetRowCount());
  108.  
  109.         do
  110.         {
  111.             Field *fields = result->Fetch();
  112.             bar.step();
  113.  
  114.             uint32 entry               = fields[0].GetUInt32();
  115.             uint32 item                = fields[1].GetUInt32();
  116.             float  chanceOrQuestChance = fields[2].GetFloat();
  117.             uint16 lootmode            = fields[3].GetUInt16();
  118.             uint8  group               = fields[4].GetUInt8();
  119.             int32  mincountOrRef       = fields[5].GetInt32();
  120.             int32  maxcount            = fields[6].GetInt32();
  121.             ConditionType condition    = (ConditionType)fields[7].GetUInt8();
  122.             uint32 cond_value1         = fields[8].GetUInt32();
  123.             uint32 cond_value2         = fields[9].GetUInt32();
  124.  
  125.             if(maxcount > std::numeric_limits<uint8>::max())
  126.             {
  127.                 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());
  128.                 continue;                                   // error already printed to log/console.
  129.             }
  130.  
  131.             if(!PlayerCondition::IsValid(condition,cond_value1, cond_value2))
  132.             {
  133.                 sLog.outErrorDb("... in table '%s' entry %u item %u", GetName(), entry, item);
  134.                 continue;                                   // error already printed to log/console.
  135.             }
  136.  
  137.             // (condition + cond_value1/2) are converted into single conditionId
  138.             uint16 conditionId = objmgr.GetConditionId(condition, cond_value1, cond_value2);
  139.  
  140.             LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, lootmode, group, conditionId, mincountOrRef, maxcount);
  141.  
  142.             if (!storeitem.IsValid(*this,entry))            // Validity checks
  143.                 continue;
  144.  
  145.             // Looking for the template of the entry
  146.                                                             // often entries are put together
  147.             if (m_LootTemplates.empty() || tab->first != entry)
  148.             {
  149.                 // Searching the template (in case template Id changed)
  150.                 tab = m_LootTemplates.find(entry);
  151.                 if ( tab == m_LootTemplates.end() )
  152.                 {
  153.                     std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate));
  154.                     tab = pr.first;
  155.                 }
  156.             }
  157.             // else is empty - template Id and iter are the same
  158.             // finally iter refers to already existed or just created <entry, LootTemplate>
  159.  
  160.             // Adds current row to the template
  161.             tab->second->AddEntry(storeitem);
  162.             ++count;
  163.  
  164.         } while (result->NextRow());
  165.  
  166.         Verify();                                           // Checks validity of the loot store
  167.  
  168.         sLog.outString();
  169.         sLog.outString( ">> Loaded %u loot definitions (%lu templates)", count, (unsigned long)m_LootTemplates.size());
  170.     }
  171.     else
  172.     {
  173.         sLog.outString();
  174.         sLog.outErrorDb( ">> Loaded 0 loot definitions. DB table `%s` is empty.",GetName() );
  175.     }
  176. }
  177.  
  178. bool LootStore::HaveQuestLootFor(uint32 loot_id) const
  179. {
  180.     LootTemplateMap::const_iterator itr = m_LootTemplates.find(loot_id);
  181.     if(itr == m_LootTemplates.end())
  182.         return false;
  183.  
  184.     // scan loot for quest items
  185.     return itr->second->HasQuestDrop(m_LootTemplates);
  186. }
  187.  
  188. bool LootStore::HaveQuestLootForPlayer(uint32 loot_id,Player* player) const
  189. {
  190.     LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
  191.     if (tab != m_LootTemplates.end())
  192.         if (tab->second->HasQuestDropForPlayer(m_LootTemplates, player))
  193.             return true;
  194.  
  195.     return false;
  196. }
  197.  
  198. LootTemplate const* LootStore::GetLootFor(uint32 loot_id) const
  199. {
  200.     LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
  201.  
  202.     if (tab == m_LootTemplates.end())
  203.         return NULL;
  204.  
  205.     return tab->second;
  206. }
  207.  
  208. void LootStore::LoadAndCollectLootIds(LootIdSet& ids_set)
  209. {
  210.     LoadLootTable();
  211.  
  212.     for (LootTemplateMap::const_iterator tab = m_LootTemplates.begin(); tab != m_LootTemplates.end(); ++tab)
  213.         ids_set.insert(tab->first);
  214. }
  215.  
  216. void LootStore::CheckLootRefs(LootIdSet* ref_set) const
  217. {
  218.     for (LootTemplateMap::const_iterator ltItr = m_LootTemplates.begin(); ltItr != m_LootTemplates.end(); ++ltItr)
  219.         ltItr->second->CheckLootRefs(m_LootTemplates,ref_set);
  220. }
  221.  
  222. void LootStore::ReportUnusedIds(LootIdSet const& ids_set) const
  223. {
  224.     // all still listed ids isn't referenced
  225.     for (LootIdSet::const_iterator itr = ids_set.begin(); itr != ids_set.end(); ++itr)
  226.         sLog.outErrorDb("Table '%s' entry %d isn't %s and not referenced from loot, and then useless.", GetName(), *itr,GetEntryName());
  227. }
  228.  
  229. void LootStore::ReportNotExistedId(uint32 id) const
  230. {
  231.     sLog.outErrorDb("Table '%s' entry %d (%s) not exist but used as loot id in DB.", GetName(), id,GetEntryName());
  232. }
  233.  
  234. //
  235. // --------- LootStoreItem ---------
  236. //
  237.  
  238. // Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
  239. // RATE_DROP_ITEMS is no longer used for all types of entries
  240. bool LootStoreItem::Roll(bool rate) const
  241. {
  242.     if(chance >= 100.0f)
  243.         return true;
  244.  
  245.     if(mincountOrRef < 0)                                   // reference case
  246.         return roll_chance_f(chance* (rate ? sWorld.getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
  247.  
  248.     ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid);
  249.  
  250.     float qualityModifier = pProto && rate ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
  251.  
  252.     return roll_chance_f(chance*qualityModifier);
  253. }
  254.  
  255. // Checks correctness of values
  256. bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
  257. {
  258.     if(group >= 1 << 7)                                     // it stored in 7 bit field
  259.     {
  260.         sLog.outErrorDb("Table '%s' entry %d item %d: group (%u) must be less %u - skipped", store.GetName(), entry, itemid, group, 1 << 7);
  261.         return false;
  262.     }
  263.  
  264.     if (mincountOrRef == 0)
  265.     {
  266.         sLog.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincountOrRef);
  267.         return false;
  268.     }
  269.  
  270.     if (mincountOrRef > 0)                                  // item (quest or non-quest) entry, maybe grouped
  271.     {
  272.         ItemPrototype const *proto = objmgr.GetItemPrototype(itemid);
  273.         if(!proto)
  274.         {
  275.             sLog.outErrorDb("Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store.GetName(), entry, itemid);
  276.             return false;
  277.         }
  278.  
  279.         if( chance == 0 && group == 0)                      // Zero chance is allowed for grouped entries only
  280.         {
  281.             sLog.outErrorDb("Table '%s' entry %d item %d: equal-chanced grouped entry, but group not defined - skipped", store.GetName(), entry, itemid);
  282.             return false;
  283.         }
  284.  
  285.         if( chance != 0 && chance < 0.000001f )             // loot with low chance
  286.         {
  287.             sLog.outErrorDb("Table '%s' entry %d item %d: low chance (%f) - skipped",
  288.                 store.GetName(), entry, itemid, chance);
  289.             return false;
  290.         }
  291.  
  292.         if( maxcount < mincountOrRef)                       // wrong max count
  293.         {
  294.             sLog.outErrorDb("Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store.GetName(), entry, itemid, int32(maxcount), mincountOrRef);
  295.             return false;
  296.         }
  297.  
  298.     }
  299.     else                                                    // mincountOrRef < 0
  300.     {
  301.         if (needs_quest)
  302.             sLog.outErrorDb("Table '%s' entry %d item %d: quest chance will be treated as non-quest chance", store.GetName(), entry, itemid);
  303.         else if( chance == 0 )                              // no chance for the reference
  304.         {
  305.             sLog.outErrorDb("Table '%s' entry %d item %d: zero chance is specified for a reference, skipped", store.GetName(), entry, itemid);
  306.             return false;
  307.         }
  308.     }
  309.     return true;                                            // Referenced template existence is checked at whole store level
  310. }
  311.  
  312. //
  313. // --------- LootItem ---------
  314. //
  315.  
  316. // Constructor, copies most fields from LootStoreItem and generates random count
  317. LootItem::LootItem(LootStoreItem const& li)
  318. {
  319.     itemid      = li.itemid;
  320.     conditionId = li.conditionId;
  321.  
  322.     ItemPrototype const* proto = objmgr.GetItemPrototype(itemid);
  323.     freeforall  = proto && (proto->Flags & ITEM_FLAGS_PARTY_LOOT);
  324.  
  325.     needs_quest = li.needs_quest;
  326.  
  327.     count       = urand(li.mincountOrRef, li.maxcount);     // constructor called for mincountOrRef > 0 only
  328.     randomSuffix = GenerateEnchSuffixFactor(itemid);
  329.     randomPropertyId = Item::GenerateItemRandomPropertyId(itemid);
  330.     is_looted = 0;
  331.     is_blocked = 0;
  332.     is_underthreshold = 0;
  333.     is_counted = 0;
  334. }
  335.  
  336. // Basic checks for player/item compatibility - if false no chance to see the item in the loot
  337. bool LootItem::AllowedForPlayer(Player const * player) const
  338. {
  339.     // DB conditions check
  340.     if (!objmgr.IsPlayerMeetToCondition(player,conditionId))
  341.         return false;
  342.  
  343.     if (needs_quest)
  344.     {
  345.         // Checking quests for quest-only drop (check only quests requirements in this case)
  346.         if (!player->HasQuestForItem(itemid))
  347.             return false;
  348.     }
  349.     else
  350.     {
  351.         // Not quest only drop (check quest starting items for already accepted non-repeatable quests)
  352.         if (ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid))
  353.             if (pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE && !player->HasQuestForItem(itemid))
  354.                 return false;
  355.     }
  356.  
  357.     return true;
  358. }
  359.  
  360. //
  361. // --------- Loot ---------
  362. //
  363.  
  364. // Inserts the item into the loot (called by LootTemplate processors)
  365. void Loot::AddItem(LootStoreItem const & item)
  366. {
  367.     if (item.needs_quest)                                   // Quest drop
  368.     {
  369.         if (quest_items.size() < MAX_NR_QUEST_ITEMS)
  370.             quest_items.push_back(LootItem(item));
  371.     }
  372.     else if (items.size() < MAX_NR_LOOT_ITEMS)              // Non-quest drop
  373.     {
  374.         items.push_back(LootItem(item));
  375.  
  376.         // non-conditional one-player only items are counted here,
  377.         // free for all items are counted in FillFFALoot(),
  378.         // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
  379.         if (!item.conditionId)
  380.         {
  381.             ItemPrototype const* proto = objmgr.GetItemPrototype(item.itemid);
  382.             if (!proto || (proto->Flags & ITEM_FLAGS_PARTY_LOOT) == 0)
  383.                 ++unlootedCount;
  384.         }
  385.     }
  386. }
  387.  
  388. // Calls processor of corresponding LootTemplate (which handles everything including references)
  389. bool Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner, bool personal, bool noEmptyError, uint16 lootMode /*= LOOT_MODE_DEFAULT*/)
  390. {
  391.     // Must be provided
  392.     if (!loot_owner)
  393.         return false;
  394.  
  395.     LootTemplate const* tab = store.GetLootFor(loot_id);
  396.  
  397.     if (!tab)
  398.     {
  399.         if (!noEmptyError)
  400.             sLog.outErrorDb("Table '%s' loot id #%u used but it doesn't have records.",store.GetName(),loot_id);
  401.         return false;
  402.     }
  403.  
  404.     items.reserve(MAX_NR_LOOT_ITEMS);
  405.     quest_items.reserve(MAX_NR_QUEST_ITEMS);
  406.  
  407.     tab->Process(*this, store, store.IsRatesAllowed(), lootMode);     // Processing is done there, callback via Loot::AddItem()
  408.  
  409.     // Setting access rights for group loot case
  410.     Group * pGroup = loot_owner->GetGroup();
  411.     if(!personal && pGroup)
  412.     {
  413.         for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
  414.             if(Player* pl = itr->getSource())
  415.                 FillNotNormalLootFor(pl);
  416.     }
  417.     // ... for personal loot
  418.     else
  419.         FillNotNormalLootFor(loot_owner);
  420.  
  421.     return true;
  422. }
  423.  
  424. void Loot::FillNotNormalLootFor(Player* pl)
  425. {
  426.     uint32 plguid = pl->GetGUIDLow();
  427.  
  428.     QuestItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid);
  429.     if (qmapitr == PlayerQuestItems.end())
  430.         FillQuestLoot(pl);
  431.  
  432.     qmapitr = PlayerFFAItems.find(plguid);
  433.     if (qmapitr == PlayerFFAItems.end())
  434.         FillFFALoot(pl);
  435.  
  436.     qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
  437.     if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
  438.         FillNonQuestNonFFAConditionalLoot(pl);
  439. }
  440.  
  441. QuestItemList* Loot::FillFFALoot(Player* player)
  442. {
  443.     QuestItemList *ql = new QuestItemList();
  444.  
  445.     for (uint8 i = 0; i < items.size(); ++i)
  446.     {
  447.         LootItem &item = items[i];
  448.         if(!item.is_looted && item.freeforall && item.AllowedForPlayer(player) )
  449.         {
  450.             ql->push_back(QuestItem(i));
  451.             ++unlootedCount;
  452.         }
  453.     }
  454.     if (ql->empty())
  455.     {
  456.         delete ql;
  457.         return NULL;
  458.     }
  459.  
  460.     PlayerFFAItems[player->GetGUIDLow()] = ql;
  461.     return ql;
  462. }
  463.  
  464. QuestItemList* Loot::FillQuestLoot(Player* player)
  465. {
  466.     if (items.size() == MAX_NR_LOOT_ITEMS) return NULL;
  467.     QuestItemList *ql = new QuestItemList();
  468.  
  469.     for (uint8 i = 0; i < quest_items.size(); ++i)
  470.     {
  471.         LootItem &item = quest_items[i];
  472.         if (!item.is_looted && item.AllowedForPlayer(player))
  473.         {
  474.             ql->push_back(QuestItem(i));
  475.  
  476.             // questitems get blocked when they first appear in a
  477.             // player's quest vector
  478.             //
  479.             // increase once if one looter only, looter-times if free for all
  480.             if (item.freeforall || !item.is_blocked)
  481.                 ++unlootedCount;
  482.  
  483.             item.is_blocked = true;
  484.  
  485.             if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS)
  486.                 break;
  487.         }
  488.     }
  489.     if (ql->empty())
  490.     {
  491.         delete ql;
  492.         return NULL;
  493.     }
  494.  
  495.     PlayerQuestItems[player->GetGUIDLow()] = ql;
  496.     return ql;
  497. }
  498.  
  499. QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player)
  500. {
  501.     QuestItemList *ql = new QuestItemList();
  502.  
  503.     for (uint8 i = 0; i < items.size(); ++i)
  504.     {
  505.         LootItem &item = items[i];
  506.         if(!item.is_looted && !item.freeforall && item.conditionId && item.AllowedForPlayer(player))
  507.         {
  508.             ql->push_back(QuestItem(i));
  509.             if(!item.is_counted)
  510.             {
  511.                 ++unlootedCount;
  512.                 item.is_counted = true;
  513.             }
  514.         }
  515.     }
  516.     if (ql->empty())
  517.     {
  518.         delete ql;
  519.         return NULL;
  520.     }
  521.  
  522.     PlayerNonQuestNonFFAConditionalItems[player->GetGUIDLow()] = ql;
  523.     return ql;
  524. }
  525.  
  526. //===================================================
  527.  
  528. void Loot::NotifyItemRemoved(uint8 lootIndex)
  529. {
  530.     // notify all players that are looting this that the item was removed
  531.     // convert the index to the slot the player sees
  532.     std::set<uint64>::iterator i_next;
  533.     for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
  534.     {
  535.         i_next = i;
  536.         ++i_next;
  537.         if(Player* pl = ObjectAccessor::FindPlayer(*i))
  538.             pl->SendNotifyLootItemRemoved(lootIndex);
  539.         else
  540.             PlayersLooting.erase(i);
  541.     }
  542. }
  543.  
  544. void Loot::NotifyMoneyRemoved()
  545. {
  546.     // notify all players that are looting this that the money was removed
  547.     std::set<uint64>::iterator i_next;
  548.     for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
  549.     {
  550.         i_next = i;
  551.         ++i_next;
  552.         if(Player* pl = ObjectAccessor::FindPlayer(*i))
  553.             pl->SendNotifyLootMoneyRemoved();
  554.         else
  555.             PlayersLooting.erase(i);
  556.     }
  557. }
  558.  
  559. void Loot::NotifyQuestItemRemoved(uint8 questIndex)
  560. {
  561.     // when a free for all questitem is looted
  562.     // all players will get notified of it being removed
  563.     // (other questitems can be looted by each group member)
  564.     // bit inefficient but isn't called often
  565.  
  566.     std::set<uint64>::iterator i_next;
  567.     for (std::set<uint64>::iterator i = PlayersLooting.begin(); i != PlayersLooting.end(); i = i_next)
  568.     {
  569.         i_next = i;
  570.         ++i_next;
  571.         if(Player* pl = ObjectAccessor::FindPlayer(*i))
  572.         {
  573.             QuestItemMap::const_iterator pq = PlayerQuestItems.find(pl->GetGUIDLow());
  574.             if (pq != PlayerQuestItems.end() && pq->second)
  575.             {
  576.                 // find where/if the player has the given item in it's vector
  577.                 QuestItemList& pql = *pq->second;
  578.  
  579.                 uint8 j;
  580.                 for (j = 0; j < pql.size(); ++j)
  581.                     if (pql[j].index == questIndex)
  582.                         break;
  583.  
  584.                 if (j < pql.size())
  585.                     pl->SendNotifyLootItemRemoved(items.size()+j);
  586.             }
  587.         }
  588.         else
  589.             PlayersLooting.erase(i);
  590.     }
  591. }
  592.  
  593. void Loot::generateMoneyLoot( uint32 minAmount, uint32 maxAmount )
  594. {
  595.     if (maxAmount > 0)
  596.     {
  597.         if (maxAmount <= minAmount)
  598.             gold = uint32(maxAmount * sWorld.getRate(RATE_DROP_MONEY));
  599.         else if ((maxAmount - minAmount) < 32700)
  600.             gold = uint32(urand(minAmount, maxAmount) * sWorld.getRate(RATE_DROP_MONEY));
  601.         else
  602.             gold = uint32(urand(minAmount >> 8, maxAmount >> 8) * sWorld.getRate(RATE_DROP_MONEY)) << 8;
  603.     }
  604. }
  605.  
  606. LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qitem, QuestItem **ffaitem, QuestItem **conditem)
  607. {
  608.     LootItem* item = NULL;
  609.     bool is_looted = true;
  610.     if (lootSlot >= items.size())
  611.     {
  612.         uint32 questSlot = lootSlot - items.size();
  613.         QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
  614.         if (itr != PlayerQuestItems.end() && questSlot < itr->second->size())
  615.         {
  616.             QuestItem *qitem2 = &itr->second->at(questSlot);
  617.             if(qitem)
  618.                 *qitem = qitem2;
  619.             item = &quest_items[qitem2->index];
  620.             is_looted = qitem2->is_looted;
  621.         }
  622.     }
  623.     else
  624.     {
  625.         item = &items[lootSlot];
  626.         is_looted = item->is_looted;
  627.         if(item->freeforall)
  628.         {
  629.             QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUIDLow());
  630.             if (itr != PlayerFFAItems.end())
  631.             {
  632.                 for (QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
  633.                     if(iter->index==lootSlot)
  634.                     {
  635.                         QuestItem *ffaitem2 = (QuestItem*)&(*iter);
  636.                         if(ffaitem)
  637.                             *ffaitem = ffaitem2;
  638.                         is_looted = ffaitem2->is_looted;
  639.                         break;
  640.                     }
  641.             }
  642.         }
  643.         else if(item->conditionId)
  644.         {
  645.             QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
  646.             if (itr != PlayerNonQuestNonFFAConditionalItems.end())
  647.             {
  648.                 for (QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
  649.                 {
  650.                     if(iter->index==lootSlot)
  651.                     {
  652.                         QuestItem *conditem2 = (QuestItem*)&(*iter);
  653.                         if(conditem)
  654.                             *conditem = conditem2;
  655.                         is_looted = conditem2->is_looted;
  656.                         break;
  657.                     }
  658.                 }
  659.             }
  660.         }
  661.     }
  662.  
  663.     if(is_looted)
  664.         return NULL;
  665.  
  666.     return item;
  667. }
  668.  
  669. uint32 Loot::GetMaxSlotInLootFor(Player* player) const
  670. {
  671.     QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
  672.     return items.size() + (itr != PlayerQuestItems.end() ?  itr->second->size() : 0);
  673. }
  674.  
  675. ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
  676. {
  677.     b << uint32(li.itemid);
  678.     b << uint32(li.count);                                  // nr of items of this type
  679.     b << uint32(objmgr.GetItemPrototype(li.itemid)->DisplayInfoID);
  680.     b << uint32(li.randomSuffix);
  681.     b << uint32(li.randomPropertyId);
  682.     //b << uint8(0);                                        // slot type - will send after this function call
  683.     return b;
  684. }
  685.  
  686. ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
  687. {
  688.     if (lv.permission == NONE_PERMISSION)
  689.     {
  690.         b << uint32(0);                                     //gold
  691.         b << uint8(0);                                      // item count
  692.         return b;                                           // nothing output more
  693.     }
  694.  
  695.     Loot &l = lv.loot;
  696.  
  697.     uint8 itemsShown = 0;
  698.  
  699.     //gold
  700.     b << uint32(l.gold);
  701.  
  702.     size_t count_pos = b.wpos();                            // pos of item count byte
  703.     b << uint8(0);                                          // item count placeholder
  704.  
  705.     switch (lv.permission)
  706.     {
  707.         case GROUP_PERMISSION:
  708.         {
  709.             // You are not the items proprietary, so you can only see
  710.             // blocked rolled items and quest items, and !ffa items
  711.             for (uint8 i = 0; i < l.items.size(); ++i)
  712.             {
  713.                 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
  714.                 {
  715.                     uint8 slot_type = (l.items[i].is_blocked || l.items[i].is_underthreshold) ? 0 : 1;
  716.  
  717.                     b << uint8(i) << l.items[i];            //send the index and the item if it's not looted, and blocked or under threshold, free for all items will be sent later, only one-player loots here
  718.                     b << uint8(slot_type);                  // 0 - get 1 - look only
  719.                     ++itemsShown;
  720.                 }
  721.             }
  722.             break;
  723.         }
  724.         case ALL_PERMISSION:
  725.         case MASTER_PERMISSION:
  726.         {
  727.             uint8 slot_type = (lv.permission==MASTER_PERMISSION) ? 2 : 0;
  728.             for (uint8 i = 0; i < l.items.size(); ++i)
  729.             {
  730.                 if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
  731.                 {
  732.                     b << uint8(i) << l.items[i];            //only send one-player loot items now, free for all will be sent later
  733.                     b << uint8(slot_type);                  // 0 - get 2 - master selection
  734.                     ++itemsShown;
  735.                 }
  736.             }
  737.             break;
  738.         }
  739.         default:
  740.             return b;                                       // nothing output more
  741.     }
  742.  
  743.     QuestItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems();
  744.     QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUIDLow());
  745.     if (q_itr != lootPlayerQuestItems.end())
  746.     {
  747.         QuestItemList *q_list = q_itr->second;
  748.         for (QuestItemList::const_iterator qi = q_list->begin() ; qi != q_list->end(); ++qi)
  749.         {
  750.             LootItem &item = l.quest_items[qi->index];
  751.             if (!qi->is_looted && !item.is_looted)
  752.             {
  753.                 b << uint8(l.items.size() + (qi - q_list->begin()));
  754.                 b << item;
  755.                 b << uint8(0);                              // allow loot
  756.                 ++itemsShown;
  757.             }
  758.         }
  759.     }
  760.  
  761.     QuestItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems();
  762.     QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUIDLow());
  763.     if (ffa_itr != lootPlayerFFAItems.end())
  764.     {
  765.         QuestItemList *ffa_list = ffa_itr->second;
  766.         for (QuestItemList::const_iterator fi = ffa_list->begin() ; fi != ffa_list->end(); ++fi)
  767.         {
  768.             LootItem &item = l.items[fi->index];
  769.             if (!fi->is_looted && !item.is_looted)
  770.             {
  771.                 b << uint8(fi->index) << item;
  772.                 b << uint8(0);                              // allow loot
  773.                 ++itemsShown;
  774.             }
  775.         }
  776.     }
  777.  
  778.     QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems();
  779.     QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUIDLow());
  780.     if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
  781.     {
  782.         QuestItemList *conditional_list =  nn_itr->second;
  783.         for (QuestItemList::const_iterator ci = conditional_list->begin() ; ci != conditional_list->end(); ++ci)
  784.         {
  785.             LootItem &item = l.items[ci->index];
  786.             if (!ci->is_looted && !item.is_looted)
  787.             {
  788.                 b << uint8(ci->index) << item;
  789.                 b << uint8(0);                              // allow loot
  790.                 ++itemsShown;
  791.             }
  792.         }
  793.     }
  794.  
  795.     //update number of items shown
  796.     b.put<uint8>(count_pos,itemsShown);
  797.  
  798.     return b;
  799. }
  800.  
  801. //
  802. // --------- LootTemplate::LootGroup ---------
  803. //
  804.  
  805. // Adds an entry to the group (at loading stage)
  806. void LootTemplate::LootGroup::AddEntry(LootStoreItem& item)
  807. {
  808.     if (item.chance != 0)
  809.         ExplicitlyChanced.push_back(item);
  810.     else
  811.         EqualChanced.push_back(item);
  812. }
  813.  
  814. // Rolls an item from the group, returns NULL if all miss their chances
  815. LootStoreItem const * LootTemplate::LootGroup::Roll() const
  816. {
  817.     if (!ExplicitlyChanced.empty())                             // First explicitly chanced entries are checked
  818.     {
  819.         float Roll = rand_chance();
  820.  
  821.         for (uint32 i = 0; i < ExplicitlyChanced.size(); ++i)   // check each explicitly chanced entry in the template and modify its chance based on quality.
  822.         {
  823.             if (ExplicitlyChanced[i].chance >= 100.0f)
  824.                 return &ExplicitlyChanced[i];
  825.  
  826.             Roll -= ExplicitlyChanced[i].chance;
  827.             if (Roll < 0)
  828.                 return &ExplicitlyChanced[i];
  829.         }
  830.     }
  831.     if (!EqualChanced.empty())                              // If nothing selected yet - an item is taken from equal-chanced part
  832.         return &EqualChanced[irand(0, EqualChanced.size()-1)];
  833.  
  834.     return NULL;                                            // Empty drop from the group
  835. }
  836.  
  837. // True if group includes at least 1 quest drop entry
  838. bool LootTemplate::LootGroup::HasQuestDrop() const
  839. {
  840.     for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
  841.         if (i->needs_quest)
  842.             return true;
  843.     for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i)
  844.         if (i->needs_quest)
  845.             return true;
  846.     return false;
  847. }
  848.  
  849. // True if group includes at least 1 quest drop entry for active quests of the player
  850. bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const
  851. {
  852.     for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
  853.         if (player->HasQuestForItem(i->itemid))
  854.             return true;
  855.     for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
  856.         if (player->HasQuestForItem(i->itemid))
  857.             return true;
  858.     return false;
  859. }
  860.  
  861. // Rolls an item from the group (if any takes its chance) and adds the item to the loot
  862. void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const
  863. {
  864.     // build up list of possible drops
  865.     LootStoreItemList EqualPossibleDrops = EqualChanced;
  866.     LootStoreItemList ExplicitPossibleDrops = ExplicitlyChanced;
  867.  
  868.     uint8 uiAttemptCount = 0;
  869.     const uint8 uiMaxAttempts = ExplicitlyChanced.size() + EqualChanced.size();
  870.  
  871.     while (!ExplicitPossibleDrops.empty() || !EqualPossibleDrops.empty())
  872.     {
  873.         if (uiAttemptCount == uiMaxAttempts)             // already tried rolling too many times, just abort
  874.             return;
  875.  
  876.         LootStoreItem *item = NULL;
  877.  
  878.         // begin rolling (normally called via Roll())
  879.         LootStoreItemList::iterator itr;
  880.         uint8 itemSource = 0;
  881.         if (!ExplicitPossibleDrops.empty())              // First explicitly chanced entries are checked
  882.         {
  883.             itemSource = 1;
  884.             float Roll = rand_chance();
  885.             // check each explicitly chanced entry in the template and modify its chance based on quality
  886.             for (itr = ExplicitPossibleDrops.begin(); itr != ExplicitPossibleDrops.end(); itr = ExplicitPossibleDrops.erase(itr))
  887.             {
  888.                 if (itr->chance >= 100.0f)
  889.                 {
  890.                     item = &*itr;
  891.                     break;
  892.                 }
  893.  
  894.                 Roll -= itr->chance;
  895.                 if (Roll < 0)
  896.                 {
  897.                     item = &*itr;
  898.                     break;
  899.                 }
  900.             }
  901.         }
  902.         if (item == NULL && !EqualPossibleDrops.empty()) // If nothing selected yet - an item is taken from equal-chanced part
  903.         {
  904.             itemSource = 2;
  905.             itr = EqualPossibleDrops.begin();
  906.             std::advance(itr, irand(0, EqualPossibleDrops.size()-1));
  907.             item = &*itr;
  908.         }
  909.         // finish rolling
  910.  
  911.         ++uiAttemptCount;
  912.  
  913.         if (item != NULL && item->lootmode & lootMode)   // only add this item if roll succeeds and the mode matches
  914.         {
  915.             bool duplicate = false;
  916.             if (ItemPrototype const *_proto = sItemStorage.LookupEntry<ItemPrototype>(item->itemid))
  917.             {
  918.                 uint8 _item_counter = 0;
  919.                 for (LootItemList::const_iterator _item = loot.items.begin(); _item != loot.items.end(); ++_item)
  920.                     if (_item->itemid == item->itemid)                             // search through the items that have already dropped
  921.                     {
  922.                         ++_item_counter;
  923.                         if (_proto->InventoryType == 0 && _item_counter == 3)      // Non-equippable items are limited to 3 drops
  924.                             duplicate = true;
  925.                         else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop
  926.                             duplicate = true;
  927.                     }
  928.             }
  929.             if (duplicate) // if item->itemid is a duplicate, remove it
  930.                 switch (itemSource)
  931.                 {
  932.                     case 1: // item came from ExplicitPossibleDrops
  933.                         ExplicitPossibleDrops.erase(itr);
  934.                         break;
  935.                     case 2: // item came from EqualPossibleDrops
  936.                         EqualPossibleDrops.erase(itr);
  937.                         break;
  938.                 }
  939.             else           // otherwise, add the item and exit the function
  940.             {
  941.                 loot.AddItem(*item);
  942.                 return;
  943.             }
  944.         }
  945.     }
  946. }
  947.  
  948. // Overall chance for the group without equal chanced items
  949. float LootTemplate::LootGroup::RawTotalChance() const
  950. {
  951.     float result = 0;
  952.  
  953.     for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
  954.         if ( !i->needs_quest )
  955.             result += i->chance;
  956.  
  957.     return result;
  958. }
  959.  
  960. // Overall chance for the group
  961. float LootTemplate::LootGroup::TotalChance() const
  962. {
  963.     float result = RawTotalChance();
  964.  
  965.     if (!EqualChanced.empty() && result < 100.0f)
  966.         return 100.0f;
  967.  
  968.     return result;
  969. }
  970.  
  971. void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const
  972. {
  973.     float chance = RawTotalChance();
  974.     if (chance > 101.0f)                                    // TODO: replace with 100% when DBs will be ready
  975.     {
  976.         sLog.outErrorDb("Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore.GetName(), id, group_id, chance);
  977.     }
  978.  
  979.     if(chance >= 100.0f && !EqualChanced.empty())
  980.     {
  981.         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);
  982.     }
  983. }
  984.  
  985. void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const
  986. {
  987.     for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
  988.     {
  989.         if(ieItr->mincountOrRef < 0)
  990.         {
  991.             if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
  992.                 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
  993.             else if(ref_set)
  994.                 ref_set->erase(-ieItr->mincountOrRef);
  995.         }
  996.     }
  997.  
  998.     for (LootStoreItemList::const_iterator ieItr=EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
  999.     {
  1000.         if(ieItr->mincountOrRef < 0)
  1001.         {
  1002.             if(!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
  1003.                 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
  1004.             else if(ref_set)
  1005.                 ref_set->erase(-ieItr->mincountOrRef);
  1006.         }
  1007.     }
  1008. }
  1009.  
  1010. //
  1011. // --------- LootTemplate ---------
  1012. //
  1013.  
  1014. // Adds an entry to the group (at loading stage)
  1015. void LootTemplate::AddEntry(LootStoreItem& item)
  1016. {
  1017.     if (item.group > 0 && item.mincountOrRef > 0)           // Group
  1018.     {
  1019.         if (item.group >= Groups.size())
  1020.             Groups.resize(item.group);                      // Adds new group the the loot template if needed
  1021.         Groups[item.group-1].AddEntry(item);                // Adds new entry to the group
  1022.     }
  1023.     else                                                    // Non-grouped entries and references are stored together
  1024.         Entries.push_back(item);
  1025. }
  1026.  
  1027. // Rolls for every item in the template and adds the rolled items the the loot
  1028. void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint16 lootMode, uint8 groupId) const
  1029. {
  1030.     if (groupId)                                            // Group reference uses own processing of the group
  1031.     {
  1032.         if (groupId > Groups.size())
  1033.             return;                                         // Error message already printed at loading stage
  1034.  
  1035.         Groups[groupId-1].Process(loot, lootMode);
  1036.         return;
  1037.     }
  1038.  
  1039.     // Rolling non-grouped items
  1040.     for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
  1041.     {
  1042.         if (i->lootmode &~ lootMode)                          // Do not add if mode mismatch
  1043.             continue;
  1044.  
  1045.         if (!i->Roll(rate))
  1046.             continue;                                         // Bad luck for the entry
  1047.  
  1048.         if (ItemPrototype const *_proto = sItemStorage.LookupEntry<ItemPrototype>(i->itemid))
  1049.         {
  1050.             uint8 _item_counter = 0;
  1051.             LootItemList::const_iterator _item = loot.items.begin();
  1052.             for (; _item != loot.items.end(); ++_item)
  1053.                 if (_item->itemid == i->itemid)                               // search through the items that have already dropped
  1054.                 {
  1055.                     ++_item_counter;
  1056.                     if (_proto->InventoryType == 0 && _item_counter == 3)     // Non-equippable items are limited to 3 drops
  1057.                         continue;
  1058.                     else if(_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop
  1059.                         continue;
  1060.                 }
  1061.             if (_item != loot.items.end())
  1062.                 continue;
  1063.         }
  1064.  
  1065.         if (i->mincountOrRef < 0)                             // References processing
  1066.         {
  1067.             LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef);
  1068.  
  1069.             if (!Referenced)
  1070.                 continue;                                     // Error message already printed at loading stage
  1071.  
  1072.             for (uint32 loop = 0; loop < i->maxcount; ++loop) // Ref multiplicator
  1073.                 Referenced->Process(loot, store, rate, lootMode, i->group);
  1074.         }
  1075.         else                                                  // Plain entries (not a reference, not grouped)
  1076.             loot.AddItem(*i);                                 // Chance is already checked, just add
  1077.     }
  1078.  
  1079.     // Now processing groups
  1080.     for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
  1081.         i->Process(loot, lootMode);
  1082. }
  1083.  
  1084. // True if template includes at least 1 quest drop entry
  1085. bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) const
  1086. {
  1087.     if (groupId)                                            // Group reference
  1088.     {
  1089.         if (groupId > Groups.size())
  1090.             return false;                                   // Error message [should be] already printed at loading stage
  1091.         return Groups[groupId-1].HasQuestDrop();
  1092.     }
  1093.  
  1094.     for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
  1095.     {
  1096.         if (i->mincountOrRef < 0)                           // References
  1097.         {
  1098.             LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
  1099.             if( Referenced ==store.end())
  1100.                 continue;                                   // Error message [should be] already printed at loading stage
  1101.             if (Referenced->second->HasQuestDrop(store, i->group))
  1102.                 return true;
  1103.         }
  1104.         else if (i->needs_quest)
  1105.             return true;                                    // quest drop found
  1106.     }
  1107.  
  1108.     // Now processing groups
  1109.     for (LootGroups::const_iterator i = Groups.begin() ; i != Groups.end(); ++i)
  1110.         if (i->HasQuestDrop())
  1111.             return true;
  1112.  
  1113.     return false;
  1114. }
  1115.  
  1116. // True if template includes at least 1 quest drop for an active quest of the player
  1117. bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player const* player, uint8 groupId) const
  1118. {
  1119.     if (groupId)                                            // Group reference
  1120.     {
  1121.         if (groupId > Groups.size())
  1122.             return false;                                   // Error message already printed at loading stage
  1123.         return Groups[groupId-1].HasQuestDropForPlayer(player);
  1124.     }
  1125.  
  1126.     // Checking non-grouped entries
  1127.     for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end(); ++i)
  1128.     {
  1129.         if (i->mincountOrRef < 0)                           // References processing
  1130.         {
  1131.             LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef);
  1132.             if (Referenced == store.end())
  1133.                 continue;                                   // Error message already printed at loading stage
  1134.             if (Referenced->second->HasQuestDropForPlayer(store, player, i->group))
  1135.                 return true;
  1136.         }
  1137.         else if (player->HasQuestForItem(i->itemid))
  1138.             return true;                                    // active quest drop found
  1139.     }
  1140.  
  1141.     // Now checking groups
  1142.     for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
  1143.         if (i->HasQuestDropForPlayer(player))
  1144.             return true;
  1145.  
  1146.     return false;
  1147. }
  1148.  
  1149. // Checks integrity of the template
  1150. void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const
  1151. {
  1152.     // Checking group chances
  1153.     for (uint32 i=0; i < Groups.size(); ++i)
  1154.         Groups[i].Verify(lootstore,id,i+1);
  1155.  
  1156.     // TODO: References validity checks
  1157. }
  1158.  
  1159. void LootTemplate::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const
  1160. {
  1161.     for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
  1162.     {
  1163.         if (ieItr->mincountOrRef < 0)
  1164.         {
  1165.             if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef))
  1166.                 LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef);
  1167.             else if (ref_set)
  1168.                 ref_set->erase(-ieItr->mincountOrRef);
  1169.         }
  1170.     }
  1171.  
  1172.     for (LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
  1173.         grItr->CheckLootRefs(store,ref_set);
  1174. }
  1175.  
  1176. void LoadLootTemplates_Creature()
  1177. {
  1178.     LootIdSet ids_set, ids_setUsed;
  1179.     LootTemplates_Creature.LoadAndCollectLootIds(ids_set);
  1180.  
  1181.     // remove real entries and check existence loot
  1182.     for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
  1183.     {
  1184.         if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
  1185.         {
  1186.             if (uint32 lootid = cInfo->lootid)
  1187.             {
  1188.                 if (ids_set.find(lootid) == ids_set.end())
  1189.                     LootTemplates_Creature.ReportNotExistedId(lootid);
  1190.                 else
  1191.                     ids_setUsed.insert(lootid);
  1192.             }
  1193.         }
  1194.     }
  1195.     for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
  1196.         ids_set.erase(*itr);
  1197.  
  1198.     // output error for any still listed (not referenced from appropriate table) ids
  1199.     LootTemplates_Creature.ReportUnusedIds(ids_set);
  1200. }
  1201.  
  1202. void LoadLootTemplates_Disenchant()
  1203. {
  1204.     LootIdSet ids_set, ids_setUsed;
  1205.     LootTemplates_Disenchant.LoadAndCollectLootIds(ids_set);
  1206.  
  1207.     // remove real entries and check existence loot
  1208.     for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
  1209.     {
  1210.         if (ItemPrototype const *proto = sItemStorage.LookupEntry<ItemPrototype>(i))
  1211.         {
  1212.             if (uint32 lootid = proto->DisenchantID)
  1213.             {
  1214.                 if (ids_set.find(lootid) == ids_set.end())
  1215.                     LootTemplates_Disenchant.ReportNotExistedId(lootid);
  1216.                 else
  1217.                     ids_setUsed.insert(lootid);
  1218.             }
  1219.         }
  1220.     }
  1221.     for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
  1222.         ids_set.erase(*itr);
  1223.     // output error for any still listed (not referenced from appropriate table) ids
  1224.     LootTemplates_Disenchant.ReportUnusedIds(ids_set);
  1225. }
  1226.  
  1227. void LoadLootTemplates_Fishing()
  1228. {
  1229.     LootIdSet ids_set;
  1230.     LootTemplates_Fishing.LoadAndCollectLootIds(ids_set);
  1231.  
  1232.     // remove real entries and check existence loot
  1233.     for (uint32 i = 1; i < sAreaStore.GetNumRows(); ++i)
  1234.         if (AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
  1235.             if (ids_set.find(areaEntry->ID) != ids_set.end())
  1236.                 ids_set.erase(areaEntry->ID);
  1237.  
  1238.     // output error for any still listed (not referenced from appropriate table) ids
  1239.     LootTemplates_Fishing.ReportUnusedIds(ids_set);
  1240. }
  1241.  
  1242. void LoadLootTemplates_Gameobject()
  1243. {
  1244.     LootIdSet ids_set, ids_setUsed;
  1245.     LootTemplates_Gameobject.LoadAndCollectLootIds(ids_set);
  1246.  
  1247.     // remove real entries and check existence loot
  1248.     for (uint32 i = 1; i < sGOStorage.MaxEntry; ++i)
  1249.     {
  1250.         if (GameObjectInfo const* gInfo = sGOStorage.LookupEntry<GameObjectInfo>(i))
  1251.         {
  1252.             if (uint32 lootid = gInfo->GetLootId())
  1253.             {
  1254.                 if (objmgr.IsGoOfSpecificEntrySpawned(gInfo->id) && ids_set.find(lootid) == ids_set.end())
  1255.                     LootTemplates_Gameobject.ReportNotExistedId(lootid);
  1256.                 else
  1257.                     ids_setUsed.insert(lootid);
  1258.             }
  1259.         }
  1260.     }
  1261.     for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
  1262.         ids_set.erase(*itr);
  1263.  
  1264.     // output error for any still listed (not referenced from appropriate table) ids
  1265.     LootTemplates_Gameobject.ReportUnusedIds(ids_set);
  1266. }
  1267.  
  1268. void LoadLootTemplates_Item()
  1269. {
  1270.     LootIdSet ids_set;
  1271.     LootTemplates_Item.LoadAndCollectLootIds(ids_set);
  1272.  
  1273.     // remove real entries and check existence loot
  1274.     for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
  1275.         if (ItemPrototype const *proto = sItemStorage.LookupEntry<ItemPrototype>(i))
  1276.             if (ids_set.find(proto->ItemId) != ids_set.end())
  1277.                 ids_set.erase(proto->ItemId);
  1278.  
  1279.     // output error for any still listed (not referenced from appropriate table) ids
  1280.     LootTemplates_Item.ReportUnusedIds(ids_set);
  1281. }
  1282.  
  1283. void LoadLootTemplates_Milling()
  1284. {
  1285.     LootIdSet ids_set;
  1286.     LootTemplates_Milling.LoadAndCollectLootIds(ids_set);
  1287.  
  1288.     // remove real entries and check existence loot
  1289.     for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
  1290.     {
  1291.         ItemPrototype const *proto = sItemStorage.LookupEntry<ItemPrototype>(i);
  1292.         if (!proto)
  1293.             continue;
  1294.  
  1295.         if ((proto->BagFamily & BAG_FAMILY_MASK_HERBS) == 0)
  1296.             continue;
  1297.  
  1298.         if (ids_set.find(proto->ItemId) != ids_set.end())
  1299.             ids_set.erase(proto->ItemId);
  1300.     }
  1301.  
  1302.     // output error for any still listed (not referenced from appropriate table) ids
  1303.     LootTemplates_Milling.ReportUnusedIds(ids_set);
  1304. }
  1305.  
  1306. void LoadLootTemplates_Pickpocketing()
  1307. {
  1308.     LootIdSet ids_set, ids_setUsed;
  1309.     LootTemplates_Pickpocketing.LoadAndCollectLootIds(ids_set);
  1310.  
  1311.     // remove real entries and check existence loot
  1312.     for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
  1313.     {
  1314.         if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
  1315.         {
  1316.             if(uint32 lootid = cInfo->pickpocketLootId)
  1317.             {
  1318.                 if (ids_set.find(lootid) == ids_set.end())
  1319.                     LootTemplates_Pickpocketing.ReportNotExistedId(lootid);
  1320.                 else
  1321.                     ids_setUsed.insert(lootid);
  1322.             }
  1323.         }
  1324.     }
  1325.     for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
  1326.         ids_set.erase(*itr);
  1327.  
  1328.     // output error for any still listed (not referenced from appropriate table) ids
  1329.     LootTemplates_Pickpocketing.ReportUnusedIds(ids_set);
  1330. }
  1331.  
  1332. void LoadLootTemplates_Prospecting()
  1333. {
  1334.     LootIdSet ids_set;
  1335.     LootTemplates_Prospecting.LoadAndCollectLootIds(ids_set);
  1336.  
  1337.     // remove real entries and check existence loot
  1338.     for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
  1339.     {
  1340.         ItemPrototype const *proto = sItemStorage.LookupEntry<ItemPrototype>(i);
  1341.         if (!proto)
  1342.             continue;
  1343.  
  1344.         if ((proto->BagFamily & BAG_FAMILY_MASK_MINING_SUPP) == 0)
  1345.             continue;
  1346.  
  1347.         if (ids_set.find(proto->ItemId) != ids_set.end())
  1348.             ids_set.erase(proto->ItemId);
  1349.     }
  1350.  
  1351.     // output error for any still listed (not referenced from appropriate table) ids
  1352.     LootTemplates_Prospecting.ReportUnusedIds(ids_set);
  1353. }
  1354.  
  1355. void LoadLootTemplates_Mail()
  1356. {
  1357.     LootIdSet ids_set;
  1358.     LootTemplates_Mail.LoadAndCollectLootIds(ids_set);
  1359.  
  1360.     // remove real entries and check existence loot
  1361.     for(uint32 i = 1; i < sMailTemplateStore.GetNumRows(); ++i)
  1362.         if(sMailTemplateStore.LookupEntry(i))
  1363.             if (ids_set.find(i) != ids_set.end())
  1364.                 ids_set.erase(i);
  1365.  
  1366.     // output error for any still listed (not referenced from appropriate table) ids
  1367.     LootTemplates_Mail.ReportUnusedIds(ids_set);
  1368. }
  1369.  
  1370. void LoadLootTemplates_Skinning()
  1371. {
  1372.     LootIdSet ids_set, ids_setUsed;
  1373.     LootTemplates_Skinning.LoadAndCollectLootIds(ids_set);
  1374.  
  1375.     // remove real entries and check existence loot
  1376.     for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
  1377.     {
  1378.         if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
  1379.         {
  1380.             if (uint32 lootid = cInfo->SkinLootId)
  1381.             {
  1382.                 if (ids_set.find(lootid) == ids_set.end())
  1383.                     LootTemplates_Skinning.ReportNotExistedId(lootid);
  1384.                 else
  1385.                     ids_setUsed.insert(lootid);
  1386.             }
  1387.         }
  1388.     }
  1389.     for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
  1390.         ids_set.erase(*itr);
  1391.  
  1392.     // output error for any still listed (not referenced from appropriate table) ids
  1393.     LootTemplates_Skinning.ReportUnusedIds(ids_set);
  1394. }
  1395.  
  1396. void LoadLootTemplates_Spell()
  1397. {
  1398.     LootIdSet ids_set;
  1399.     LootTemplates_Spell.LoadAndCollectLootIds(ids_set);
  1400.  
  1401.     // remove real entries and check existence loot
  1402.     for (uint32 spell_id = 1; spell_id < sSpellStore.GetNumRows(); ++spell_id)
  1403.     {
  1404.         SpellEntry const* spellInfo = sSpellStore.LookupEntry (spell_id);
  1405.         if(!spellInfo)
  1406.             continue;
  1407.  
  1408.         // possible cases
  1409.         if( !IsLootCraftingSpell(spellInfo))
  1410.             continue;
  1411.  
  1412.         if (ids_set.find(spell_id) == ids_set.end())
  1413.         {
  1414.             // not report about not trainable spells (optionally supported by DB)
  1415.             // ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
  1416.             if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_TRADESPELL))
  1417.             {
  1418.                 LootTemplates_Spell.ReportNotExistedId(spell_id);
  1419.             }
  1420.         }
  1421.         else
  1422.             ids_set.erase(spell_id);
  1423.     }
  1424.  
  1425.     // output error for any still listed (not referenced from appropriate table) ids
  1426.     LootTemplates_Spell.ReportUnusedIds(ids_set);
  1427. }
  1428.  
  1429. void LoadLootTemplates_Reference()
  1430. {
  1431.     LootIdSet ids_set;
  1432.     LootTemplates_Reference.LoadAndCollectLootIds(ids_set);
  1433.  
  1434.     // check references and remove used
  1435.     LootTemplates_Creature.CheckLootRefs(&ids_set);
  1436.     LootTemplates_Fishing.CheckLootRefs(&ids_set);
  1437.     LootTemplates_Gameobject.CheckLootRefs(&ids_set);
  1438.     LootTemplates_Item.CheckLootRefs(&ids_set);
  1439.     LootTemplates_Milling.CheckLootRefs(&ids_set);
  1440.     LootTemplates_Pickpocketing.CheckLootRefs(&ids_set);
  1441.     LootTemplates_Skinning.CheckLootRefs(&ids_set);
  1442.     LootTemplates_Disenchant.CheckLootRefs(&ids_set);
  1443.     LootTemplates_Prospecting.CheckLootRefs(&ids_set);
  1444.     LootTemplates_Mail.CheckLootRefs(&ids_set);
  1445.     LootTemplates_Reference.CheckLootRefs(&ids_set);
  1446.  
  1447.     // output error for any still listed ids (not referenced from any loot table)
  1448.     LootTemplates_Reference.ReportUnusedIds(ids_set);
  1449. }
Submit a correction or amendment below. [ previous version ] | [ difference ] | Make A New Post
To highlight particular lines, prefix each line with @h@
Syntax highlighting:
Post expiration:
Post exposure:
Name / Title:
Email: