2008-10-02 16:23:55 -05:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2009-02-04 12:04:12 +01:00
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
2008-10-02 16:23:55 -05:00
*
* 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
2008-10-14 11:57:03 -05:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-02 16:23:55 -05:00
* 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
2008-10-14 11:57:03 -05:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-02 16:23:55 -05:00
*/
#include "LootMgr.h"
#include "Log.h"
#include "ObjectMgr.h"
#include "ProgressBar.h"
#include "World.h"
#include "Util.h"
#include "SharedDefines.h"
2009-01-21 16:18:57 -06:00
#include "SpellMgr.h"
2008-10-02 16:23:55 -05:00
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
};
2009-01-21 16:18:57 -06:00
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_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_QuestMail ( "quest_mail_loot_template" , "quest id (with mail template)",false) ;
LootStore LootTemplates_Reference ( "reference_loot_template" , "reference id" , false );
LootStore LootTemplates_Skinning ( "skinning_loot_template" , "creature skinning id" , true );
2009-05-26 16:10:42 -05:00
LootStore LootTemplates_Spell ( "spell_loot_template" , "spell id (random item creating)",false) ;
2008-10-02 16:23:55 -05:00
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
2009-02-27 12:24:09 -06:00
void Process ( Loot & loot ) const ; // Rolls an item from the group (if any) and adds the item to the loot
2008-10-02 16:23:55 -05:00
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 , uint32 group_id ) const ;
void CollectLootIds ( LootIdSet & set ) const ;
void CheckLootRefs ( LootTemplateMap const & store , LootIdSet * ref_set ) const ;
private :
LootStoreItemList ExplicitlyChanced ; // Entries with chances defined in DB
LootStoreItemList EqualChanced ; // Zero chances - every entry takes the same chance
2009-02-27 12:24:09 -06:00
LootStoreItem const * Roll () const ; // Rolls an item from the group, returns NULL if all miss their chances
2008-10-02 16:23:55 -05:00
};
//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 ()
{
2009-04-29 00:26:07 -05:00
LootTemplateMap :: const_iterator tab ;
2008-10-02 16:23:55 -05:00
uint32 count = 0 ;
// Clearing store (for reloading case)
Clear ();
sLog . outString ( "%s :" , GetName ());
// 0 1 2 3 4 5 6 7 8
QueryResult * result = WorldDatabase . PQuery ( "SELECT entry, item, ChanceOrQuestChance, groupid, mincountOrRef, maxcount, lootcondition, condition_value1, condition_value2 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 ();
uint8 group = fields [ 3 ]. GetUInt8 ();
int32 mincountOrRef = fields [ 4 ]. GetInt32 ();
2009-03-06 19:39:42 -06:00
uint32 maxcount = fields [ 5 ]. GetUInt32 ();
2008-10-02 16:23:55 -05:00
ConditionType condition = ( ConditionType ) fields [ 6 ]. GetUInt8 ();
uint32 cond_value1 = fields [ 7 ]. GetUInt32 ();
uint32 cond_value2 = fields [ 8 ]. GetUInt32 ();
2009-03-06 19:39:42 -06:00
if ( maxcount > std :: numeric_limits < uint8 >:: max ())
{
2009-03-07 10:43:27 -06:00
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 ());
2009-03-06 19:39:42 -06:00
continue ; // error already printed to log/console.
}
2008-10-02 16:23:55 -05:00
if ( ! PlayerCondition :: IsValid ( condition , cond_value1 , cond_value2 ))
{
sLog . outErrorDb ( "... in table '%s' entry %u item %u" , GetName (), entry , item );
continue ; // error already printed to log/console.
}
// (condition + cond_value1/2) are converted into single conditionId
uint16 conditionId = objmgr . GetConditionId ( condition , cond_value1 , cond_value2 );
LootStoreItem storeitem = LootStoreItem ( item , chanceOrQuestChance , group , conditionId , 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 () )
{
2009-04-29 00:31:33 -05:00
std :: pair < LootTemplateMap :: iterator , bool > pr = m_LootTemplates . insert ( LootTemplateMap :: value_type ( entry , new LootTemplate ));
2008-10-02 16:23:55 -05:00
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 ());
delete result ;
Verify (); // Checks validity of the loot store
2009-04-03 16:36:20 -06:00
sLog . outString ();
2009-03-24 17:38:14 -06:00
sLog . outString ( ">> Loaded %u loot definitions (%lu templates)" , count , ( unsigned long ) m_LootTemplates . size ());
2008-10-02 16:23:55 -05:00
}
else
{
2009-04-03 16:36:20 -06:00
sLog . outString ();
2008-10-02 16:23:55 -05:00
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 ;
}
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 ;
}
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
2009-01-21 16:18:57 -06:00
bool LootStoreItem :: Roll ( bool rate ) const
2008-10-02 16:23:55 -05:00
{
2009-05-21 10:52:35 -05:00
if ( chance >= 100.0f )
2008-10-02 16:23:55 -05:00
return true ;
if ( mincountOrRef < 0 ) // reference case
2009-01-21 16:18:57 -06:00
return roll_chance_f ( chance * ( rate ? sWorld . getRate ( RATE_DROP_ITEM_REFERENCED ) : 1.0f ));
2008-10-02 16:23:55 -05:00
ItemPrototype const * pProto = objmgr . GetItemPrototype ( itemid );
2009-01-21 16:18:57 -06:00
float qualityModifier = pProto && rate ? sWorld . getRate ( qualityToRate [ pProto -> Quality ]) : 1.0f ;
2008-10-02 16:23:55 -05:00
return roll_chance_f ( chance * qualityModifier );
}
// Checks correctness of values
bool LootStoreItem :: IsValid ( LootStore const & store , uint32 entry ) const
{
2009-03-06 19:39:42 -06:00
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 ;
}
2008-10-02 16:23:55 -05:00
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
{
2008-11-14 17:03:03 -06:00
sLog . outErrorDb ( "Table '%s' entry %d item %d: low chance (%f) - skipped" ,
store . GetName (), entry , itemid , chance );
2008-10-02 16:23:55 -05:00
return false ;
}
2009-03-06 15:23:25 -06:00
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 , uint32 ( maxcount ), mincountOrRef );
return false ;
}
2008-10-02 16:23:55 -05:00
}
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 ;
conditionId = li . conditionId ;
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 ( ! objmgr . IsPlayerMeetToCondition ( player , conditionId ) )
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)
ItemPrototype const * pProto = objmgr . GetItemPrototype ( itemid );
if ( pProto && 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 . conditionId )
{
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)
2009-02-08 21:45:31 -06:00
void Loot :: FillLoot ( uint32 loot_id , LootStore const & store , Player * loot_owner , bool personal )
2008-10-02 16:23:55 -05:00
{
2009-02-08 21:45:31 -06:00
// Must be provided
if ( ! loot_owner )
return ;
2008-10-02 16:23:55 -05:00
LootTemplate const * tab = store . GetLootFor ( loot_id );
if ( ! tab )
{
sLog . outErrorDb ( "Table '%s' loot id #%u used but it doesn't have records." , store . GetName (), loot_id );
return ;
}
items . reserve ( MAX_NR_LOOT_ITEMS );
quest_items . reserve ( MAX_NR_QUEST_ITEMS );
2009-01-21 16:18:57 -06:00
tab -> Process ( * this , store , store . IsRatesAllowed ()); // Processing is done there, callback via Loot::AddItem()
2008-10-02 16:23:55 -05:00
2009-02-08 21:45:31 -06:00
// Setting access rights for group loot case
2008-10-02 16:23:55 -05:00
Group * pGroup = loot_owner -> GetGroup ();
2009-02-08 21:45:31 -06:00
if ( ! personal && pGroup )
2008-10-02 16:23:55 -05:00
{
2009-02-08 21:45:31 -06:00
for ( GroupReference * itr = pGroup -> GetFirstMember (); itr != NULL ; itr = itr -> next ())
if ( Player * pl = itr -> getSource ())
FillNotNormalLootFor ( pl );
2008-10-02 16:23:55 -05:00
}
2009-02-08 21:45:31 -06:00
// ... for personal loot
else
FillNotNormalLootFor ( loot_owner );
}
void Loot :: FillNotNormalLootFor ( Player * pl )
{
uint32 plguid = pl -> GetGUIDLow ();
2009-04-29 00:26:07 -05:00
QuestItemMap :: const_iterator qmapitr = PlayerQuestItems . find ( plguid );
2009-02-08 21:45:31 -06:00
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 );
2008-10-02 16:23:55 -05:00
}
QuestItemList * Loot :: FillFFALoot ( Player * player )
{
QuestItemList * ql = new QuestItemList ();
2009-04-29 00:26:07 -05:00
for ( uint8 i = 0 ; i < items . size (); ++ i )
2008-10-02 16:23:55 -05:00
{
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 ();
2009-04-29 00:26:07 -05:00
for ( uint8 i = 0 ; i < quest_items . size (); ++ i )
2008-10-02 16:23:55 -05:00
{
LootItem & item = quest_items [ i ];
if ( ! item . is_looted && item . AllowedForPlayer ( player ) )
{
ql -> push_back ( QuestItem ( i ));
// questitems get blocked when they first apper 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 . conditionId && 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)
2008-11-14 16:28:45 -06:00
// bit inefficient but isn't called often
2008-10-02 16:23:55 -05:00
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 ))
{
2009-04-29 00:26:07 -05:00
QuestItemMap :: const_iterator pq = PlayerQuestItems . find ( pl -> GetGUIDLow ());
2008-10-02 16:23:55 -05:00
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 ())
{
2009-04-29 00:26:07 -05:00
for ( QuestItemList :: const_iterator iter = itr -> second -> begin (); iter != itr -> second -> end (); ++ iter )
2008-10-02 16:23:55 -05:00
if ( iter -> index == lootSlot )
{
QuestItem * ffaitem2 = ( QuestItem * ) & ( * iter );
if ( ffaitem )
* ffaitem = ffaitem2 ;
is_looted = ffaitem2 -> is_looted ;
break ;
}
}
}
else if ( item -> conditionId )
{
QuestItemMap :: const_iterator itr = PlayerNonQuestNonFFAConditionalItems . find ( player -> GetGUIDLow ());
if ( itr != PlayerNonQuestNonFFAConditionalItems . end ())
{
2009-04-29 00:26:07 -05:00
for ( QuestItemList :: const_iterator iter = itr -> second -> begin (); iter != itr -> second -> end (); ++ iter )
2008-10-02 16:23:55 -05:00
{
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 ;
}
2009-02-08 21:54:13 -06:00
uint32 Loot :: GetMaxSlotInLootFor ( Player * player ) const
{
QuestItemMap :: const_iterator itr = PlayerQuestItems . find ( player -> GetGUIDLow ());
return items . size () + ( itr != PlayerQuestItems . end () ? itr -> second -> size () : 0 );
}
2008-10-02 16:23:55 -05:00
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 )
{
2009-02-08 21:45:31 -06:00
if ( lv . permission == NONE_PERMISSION )
{
b << uint32 ( 0 ); //gold
b << uint8 ( 0 ); // item count
return b ; // nothing output more
}
2008-10-02 16:23:55 -05:00
Loot & l = lv . loot ;
uint8 itemsShown = 0 ;
//gold
2009-02-08 21:45:31 -06:00
b << uint32 ( l . gold );
2008-10-02 16:23:55 -05:00
size_t count_pos = b . wpos (); // pos of item count byte
b << uint8 ( 0 ); // item count placeholder
switch ( lv . permission )
{
case GROUP_PERMISSION :
{
// You are not the items proprietary, so 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 ]. conditionId && l . items [ i ]. AllowedForPlayer ( lv . viewer ))
{
uint8 slot_type = ( l . items [ i ]. is_blocked || l . items [ i ]. is_underthreshold ) ? 0 : 1 ;
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
b << uint8 ( slot_type ); // 0 - get 1 - look only
++ itemsShown ;
}
}
break ;
}
case ALL_PERMISSION :
case MASTER_PERMISSION :
{
uint8 slot_type = ( lv . permission == MASTER_PERMISSION ) ? 2 : 0 ;
for ( uint8 i = 0 ; i < l . items . size (); ++ i )
{
if ( ! l . items [ i ]. is_looted && ! l . items [ i ]. freeforall && ! l . items [ i ]. conditionId && l . items [ i ]. AllowedForPlayer ( lv . viewer ))
{
b << uint8 ( i ) << l . items [ i ]; //only send one-player loot items now, free for all will be sent later
b << uint8 ( slot_type ); // 0 - get 2 - master selection
++ itemsShown ;
}
}
break ;
}
default :
return b ; // nothing output more
}
2009-02-08 21:45:31 -06:00
QuestItemMap const & lootPlayerQuestItems = l . GetPlayerQuestItems ();
QuestItemMap :: const_iterator q_itr = lootPlayerQuestItems . find ( lv . viewer -> GetGUIDLow ());
if ( q_itr != lootPlayerQuestItems . end ())
2008-10-02 16:23:55 -05:00
{
2009-02-08 21:45:31 -06:00
QuestItemList * q_list = q_itr -> second ;
2009-04-29 00:26:07 -05:00
for ( QuestItemList :: const_iterator qi = q_list -> begin () ; qi != q_list -> end (); ++ qi )
2008-10-02 16:23:55 -05:00
{
LootItem & item = l . quest_items [ qi -> index ];
if ( ! qi -> is_looted && ! item . is_looted )
{
2009-02-08 21:45:31 -06:00
b << uint8 ( l . items . size () + ( qi - q_list -> begin ()));
2008-10-02 16:23:55 -05:00
b << item ;
b << uint8 ( 0 ); // allow loot
++ itemsShown ;
}
}
}
2009-02-08 21:45:31 -06:00
QuestItemMap const & lootPlayerFFAItems = l . GetPlayerFFAItems ();
QuestItemMap :: const_iterator ffa_itr = lootPlayerFFAItems . find ( lv . viewer -> GetGUIDLow ());
if ( ffa_itr != lootPlayerFFAItems . end ())
2008-10-02 16:23:55 -05:00
{
2009-02-08 21:45:31 -06:00
QuestItemList * ffa_list = ffa_itr -> second ;
2009-04-29 00:26:07 -05:00
for ( QuestItemList :: const_iterator fi = ffa_list -> begin () ; fi != ffa_list -> end (); ++ fi )
2008-10-02 16:23:55 -05:00
{
LootItem & item = l . items [ fi -> index ];
if ( ! fi -> is_looted && ! item . is_looted )
{
b << uint8 ( fi -> index ) << item ;
b << uint8 ( 0 ); // allow loot
++ itemsShown ;
}
}
}
2009-02-08 21:45:31 -06:00
QuestItemMap const & lootPlayerNonQuestNonFFAConditionalItems = l . GetPlayerNonQuestNonFFAConditionalItems ();
QuestItemMap :: const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems . find ( lv . viewer -> GetGUIDLow ());
if ( nn_itr != lootPlayerNonQuestNonFFAConditionalItems . end ())
2008-10-02 16:23:55 -05:00
{
2009-02-08 21:45:31 -06:00
QuestItemList * conditional_list = nn_itr -> second ;
2009-04-29 00:26:07 -05:00
for ( QuestItemList :: const_iterator ci = conditional_list -> begin () ; ci != conditional_list -> end (); ++ ci )
2008-10-02 16:23:55 -05:00
{
LootItem & item = l . items [ ci -> index ];
if ( ! ci -> is_looted && ! item . is_looted )
{
b << uint8 ( ci -> index ) << item ;
b << uint8 ( 0 ); // 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
2009-02-27 12:24:09 -06:00
LootStoreItem const * LootTemplate :: LootGroup :: Roll () const
2008-10-02 16:23:55 -05:00
{
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.
{
2009-05-21 10:52:35 -05:00
if ( ExplicitlyChanced [ i ]. chance >= 100.0f )
2008-10-02 16:23:55 -05:00
return & ExplicitlyChanced [ i ];
2009-02-27 12:24:09 -06:00
Roll -= ExplicitlyChanced [ i ]. chance ;
2008-10-02 16:23:55 -05:00
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 ;
}
// Rolls an item from the group (if any takes its chance) and adds the item to the loot
2009-02-27 12:24:09 -06:00
void LootTemplate :: LootGroup :: Process ( Loot & loot ) const
2008-10-02 16:23:55 -05:00
{
2009-02-27 12:24:09 -06:00
LootStoreItem const * item = Roll ();
2008-10-02 16:23:55 -05:00
if ( item != NULL )
loot . AddItem ( * item );
}
// 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 , uint32 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 );
}
// Rolls for every item in the template and adds the rolled items the the loot
2009-01-21 16:18:57 -06:00
void LootTemplate :: Process ( Loot & loot , LootStore const & store , bool rate , uint8 groupId ) const
2008-10-02 16:23:55 -05:00
{
if ( groupId ) // Group reference uses own processing of the group
{
if ( groupId > Groups . size ())
return ; // Error message already printed at loading stage
2009-02-27 12:24:09 -06:00
Groups [ groupId - 1 ]. Process ( loot );
2008-10-02 16:23:55 -05:00
return ;
}
// Rolling non-grouped items
2008-12-08 16:34:03 -06:00
for ( LootStoreItemList :: const_iterator i = Entries . begin () ; i != Entries . end () ; ++ i )
2008-10-02 16:23:55 -05:00
{
2009-01-21 16:18:57 -06:00
if ( ! i -> Roll ( rate ))
2008-10-02 16:23:55 -05:00
continue ; // Bad luck for the entry
if ( i -> mincountOrRef < 0 ) // References processing
{
LootTemplate const * Referenced = LootTemplates_Reference . GetLootFor ( - i -> mincountOrRef );
if ( ! Referenced )
continue ; // Error message already printed at loading stage
for ( uint32 loop = 0 ; loop < i -> maxcount ; ++ loop ) // Ref multiplicator
2009-01-21 16:18:57 -06:00
Referenced -> Process ( loot , store , rate , i -> group );
2008-10-02 16:23:55 -05:00
}
else // Plain entries (not a reference, not grouped)
loot . AddItem ( * i ); // Chance is already checked, just add
}
// Now processing groups
2008-12-08 16:34:03 -06:00
for ( LootGroups :: const_iterator i = Groups . begin ( ) ; i != Groups . end ( ) ; ++ i )
2009-02-27 12:24:09 -06:00
i -> Process ( loot );
2008-10-02 16:23:55 -05:00
}
// 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
2008-12-08 16:34:03 -06:00
for ( LootGroups :: const_iterator i = Groups . begin () ; i != Groups . end () ; ++ i )
2008-10-02 16:23:55 -05:00
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
2008-12-08 16:34:03 -06:00
for ( LootStoreItemList :: const_iterator i = Entries . begin () ; i != Entries . end () ; ++ i )
2008-10-02 16:23:55 -05:00
{
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 )
2009-02-01 16:30:14 -06:00
if ( i -> HasQuestDropForPlayer ( player ))
2008-10-02 16:23:55 -05:00
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 );
}
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 . count ( lootid ))
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 . count ( lootid ))
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 . count ( areaEntry -> ID ))
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 ))
{
2009-07-16 12:06:07 +08:00
if ( uint32 lootid = gInfo -> GetLootId ())
2008-10-02 16:23:55 -05:00
{
if ( ! ids_set . count ( lootid ))
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 . count ( proto -> ItemId ))
ids_set . erase ( proto -> ItemId );
// output error for any still listed (not referenced from appropriate table) ids
LootTemplates_Item . ReportUnusedIds ( ids_set );
}
2008-12-24 09:58:26 -06:00
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 )
2009-01-21 16:18:57 -06:00
{
ItemPrototype const * proto = sItemStorage . LookupEntry < ItemPrototype > ( i );
if ( ! proto )
continue ;
if (( proto -> BagFamily & BAG_FAMILY_MASK_HERBS ) == 0 )
continue ;
if ( ids_set . count ( proto -> ItemId ))
ids_set . erase ( proto -> ItemId );
}
2008-12-24 09:58:26 -06:00
// output error for any still listed (not referenced from appropriate table) ids
LootTemplates_Milling . ReportUnusedIds ( ids_set );
}
2008-10-02 16:23:55 -05:00
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 . count ( lootid ))
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 )
2009-01-21 16:18:57 -06:00
{
ItemPrototype const * proto = sItemStorage . LookupEntry < ItemPrototype > ( i );
if ( ! proto )
continue ;
if (( proto -> BagFamily & BAG_FAMILY_MASK_MINING_SUPP ) == 0 )
continue ;
if ( ids_set . count ( proto -> ItemId ))
ids_set . erase ( proto -> ItemId );
}
2008-10-02 16:23:55 -05:00
// output error for any still listed (not referenced from appropriate table) ids
LootTemplates_Prospecting . ReportUnusedIds ( ids_set );
}
void LoadLootTemplates_QuestMail ()
{
LootIdSet ids_set ;
LootTemplates_QuestMail . LoadAndCollectLootIds ( ids_set );
// remove real entries and check existence loot
ObjectMgr :: QuestMap const & questMap = objmgr . GetQuestTemplates ();
for ( ObjectMgr :: QuestMap :: const_iterator itr = questMap . begin (); itr != questMap . end (); ++ itr )
2009-01-21 16:18:57 -06:00
{
if ( ! itr -> second -> GetRewMailTemplateId ())
continue ;
2008-10-02 16:23:55 -05:00
if ( ids_set . count ( itr -> first ))
ids_set . erase ( itr -> first );
2009-01-21 16:18:57 -06:00
/* disabled reporting: some quest mails not include items
else
LootTemplates_QuestMail.ReportNotExistedId(itr->first);
*/
}
2008-10-02 16:23:55 -05:00
// output error for any still listed (not referenced from appropriate table) ids
LootTemplates_QuestMail . 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 . count ( lootid ))
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 );
}
2009-01-21 16:18:57 -06:00
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
2009-02-05 23:02:07 -06:00
if ( ! IsLootCraftingSpell ( spellInfo ))
2009-01-21 16:18:57 -06:00
continue ;
if ( ! ids_set . count ( spell_id ))
{
2009-06-23 14:44:16 +02:00
// 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_UNK5 ))
{
2009-06-27 17:39:51 -05:00
LootTemplates_Spell . ReportNotExistedId ( spell_id );
2009-06-23 14:44:16 +02:00
}
2009-01-21 16:18:57 -06:00
}
else
ids_set . erase ( spell_id );
}
// output error for any still listed (not referenced from appropriate table) ids
2009-06-02 17:42:59 -05:00
LootTemplates_Spell . ReportUnusedIds ( ids_set );
2009-01-21 16:18:57 -06:00
}
2008-10-02 16:23:55 -05:00
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 );
2008-12-24 09:58:26 -06:00
LootTemplates_Milling . CheckLootRefs ( & ids_set );
2008-10-02 16:23:55 -05:00
LootTemplates_Pickpocketing . CheckLootRefs ( & ids_set );
LootTemplates_Skinning . CheckLootRefs ( & ids_set );
LootTemplates_Disenchant . CheckLootRefs ( & ids_set );
LootTemplates_Prospecting . CheckLootRefs ( & ids_set );
LootTemplates_QuestMail . 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 );
}
2009-02-17 20:07:49 -06:00